From 312d22dc93b9ceb7095795b61c7ca1feff0dc998 Mon Sep 17 00:00:00 2001 From: Matt Wilson <152443343+mwsis@users.noreply.github.com> Date: Wed, 30 Sep 2026 06:46:50 +1000 Subject: [PATCH 01/31] 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. --- test/component/inetstl/util/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 0 .../platformstl/diagnostics/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../platformstl/system/CMakeLists.txt | 6 ++--- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/component/stlsoft/system/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/component/unixstl/dl/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../unixstl/filesystem/CMakeLists.txt | 8 +++---- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/component/unixstl/system/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/component/winstl/dl/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../winstl/filesystem/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.c | 4 ++-- test/component/winstl/registry/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/component/winstl/synch/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/component/winstl/system/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/performance/CMakeLists.txt | 22 ++----------------- test/performance/platformstl/CMakeLists.txt | 5 +++++ .../platformstl/diagnostics/CMakeLists.txt | 8 +++++++ .../diagnostics/stopwatch}/CMakeLists.txt | 0 .../diagnostics/stopwatch}/main.cpp | 4 ++-- test/performance/stlsoft/CMakeLists.txt | 10 +++++++++ .../stlsoft/containers/CMakeLists.txt | 8 +++++++ .../containers/frequency_map}/CMakeLists.txt | 0 .../containers/frequency_map}/main.cpp | 4 ++-- .../stlsoft/conversion/CMakeLists.txt | 8 +++++++ .../integer_to_string}/CMakeLists.txt | 0 .../conversion/integer_to_string}/main.cpp | 4 ++-- .../stlsoft/diagnostics/CMakeLists.txt | 9 ++++++++ .../diagnostics/doomgram}/CMakeLists.txt | 0 .../diagnostics/doomgram}/main.cpp | 4 ++-- .../diagnostics/gram_utils}/CMakeLists.txt | 0 .../diagnostics/gram_utils}/main.cpp | 4 ++-- .../performance/stlsoft/memory/CMakeLists.txt | 8 +++++++ .../memory/auto_buffer}/CMakeLists.txt | 0 .../memory/auto_buffer}/main.cpp | 4 ++-- .../performance/stlsoft/string/CMakeLists.txt | 9 ++++++++ .../simple_string.compare}/CMakeLists.txt | 0 .../string/simple_string.compare}/main.cpp | 4 ++-- .../simple_string.op_eq}/CMakeLists.txt | 0 .../string/simple_string.op_eq}/main.cpp | 4 ++-- test/performance/stlsoft/util/CMakeLists.txt | 8 +++++++ .../util/count_digits}/CMakeLists.txt | 0 .../util/count_digits}/main.cpp | 4 ++-- .../scratch/platformstl/system/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../main.cpp | 0 test/scratch/stlsoft/cccap/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../main.cpp | 0 .../scratch/stlsoft/conversion/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../main.c | 4 ++-- test/scratch/unixstl/synch/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../main.cpp | 0 test/scratch/unixstl/system/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../main.c | 0 .../scratch/winstl/diagnostics/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../main.c | 4 ++-- test/scratch/winstl/synch/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../main.cpp | 0 test/scratch/winstl/system/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../main.c | 0 .../CMakeLists.txt | 0 .../main.cpp | 0 test/unit/CMakeLists.txt | 2 +- .../acestl/shims/access/string/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/comstl/memory/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.c | 4 ++-- test/unit/comstl/string/CMakeLists.txt | 2 +- test/unit/comstl/util/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.c | 4 ++-- .../CMakeLists.txt | 0 .../entry.c | 4 ++-- .../shims/access/string/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/mfcstl/memory/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/platformstl/system/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/stlsoft/api/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/stlsoft/containers/CMakeLists.txt | 6 ++--- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/stlsoft/conversion/CMakeLists.txt | 14 ++++++------ .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../stlsoft/conversion/number/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/stlsoft/diagnostics/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/stlsoft/filesystem/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/stlsoft/iterator/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/stlsoft/limits/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/stlsoft/memory/CMakeLists.txt | 10 ++++----- .../CMakeLists.txt | 0 .../entry.c | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/stlsoft/smartptr/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/stlsoft/string/CMakeLists.txt | 14 ++++++------ .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/stlsoft/system/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/stlsoft/traits/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/stlsoft/util/CMakeLists.txt | 14 ++++++------ .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/unixstl/filesystem/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../shims/access/string/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/winstl/api/internal/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.c | 4 ++-- .../CMakeLists.txt | 0 .../entry.c | 4 ++-- .../winstl/conversion/number/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/winstl/diagnostics/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.c | 4 ++-- test/unit/winstl/filesystem/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/winstl/memory/CMakeLists.txt | 8 +++---- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/winstl/system/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- test/unit/winstl/util/CMakeLists.txt | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- .../CMakeLists.txt | 0 .../entry.cpp | 4 ++-- 275 files changed, 371 insertions(+), 316 deletions(-) rename test/component/inetstl/util/{test.component.inetstl.util.uds_helpers => uds_helpers}/CMakeLists.txt (100%) rename test/component/inetstl/util/{test.component.inetstl.util.uds_helpers => uds_helpers}/entry.cpp (100%) rename test/component/platformstl/diagnostics/{test.component.platformstl.diagnostics.stopwatch => stopwatch}/CMakeLists.txt (100%) rename test/component/platformstl/diagnostics/{test.component.platformstl.diagnostics.stopwatch => stopwatch}/entry.cpp (97%) rename test/component/platformstl/system/{test.component.platformstl.system.environment_variable_scope => environment_variable_scope}/CMakeLists.txt (100%) rename test/component/platformstl/system/{test.component.platformstl.system.environment_variable_scope => environment_variable_scope}/entry.cpp (96%) rename test/component/platformstl/system/{test.component.platformstl.system.environment_variable_traits => environment_variable_traits}/CMakeLists.txt (100%) rename test/component/platformstl/system/{test.component.platformstl.system.environment_variable_traits => environment_variable_traits}/entry.cpp (96%) rename test/component/platformstl/system/{test.component.platformstl.system.system_traits => system_traits}/CMakeLists.txt (100%) rename test/component/platformstl/system/{test.component.platformstl.system.system_traits => system_traits}/entry.cpp (97%) rename test/component/stlsoft/system/{test.component.stlsoft.system.environment_block => environment_block}/CMakeLists.txt (100%) rename test/component/stlsoft/system/{test.component.stlsoft.system.environment_block => environment_block}/entry.cpp (96%) rename test/component/unixstl/dl/{test.component.unixstl.dl.dl_call => dl_call}/CMakeLists.txt (100%) rename test/component/unixstl/dl/{test.component.unixstl.dl.dl_call => dl_call}/entry.cpp (98%) rename test/component/unixstl/filesystem/{test.component.unixstl.filesystem.glob_sequence => glob_sequence}/CMakeLists.txt (100%) rename test/component/unixstl/filesystem/{test.component.unixstl.filesystem.glob_sequence => glob_sequence}/entry.cpp (99%) rename test/component/unixstl/filesystem/{test.component.unixstl.filesystem.memory_mapped_file => memory_mapped_file}/CMakeLists.txt (100%) rename test/component/unixstl/filesystem/{test.component.unixstl.filesystem.memory_mapped_file => memory_mapped_file}/entry.cpp (96%) rename test/component/unixstl/filesystem/{test.component.unixstl.filesystem.readdir_sequence => readdir_sequence}/CMakeLists.txt (100%) rename test/component/unixstl/filesystem/{test.component.unixstl.filesystem.readdir_sequence => readdir_sequence}/entry.cpp (98%) rename test/component/unixstl/filesystem/{test.component.unixstl.filesystem.readonly_memory_mapped_file => readonly_memory_mapped_file}/CMakeLists.txt (100%) rename test/component/unixstl/filesystem/{test.component.unixstl.filesystem.readonly_memory_mapped_file => readonly_memory_mapped_file}/entry.cpp (97%) rename test/component/unixstl/system/{test.component.unixstl.system.environment_variable => environment_variable}/CMakeLists.txt (100%) rename test/component/unixstl/system/{test.component.unixstl.system.environment_variable => environment_variable}/entry.cpp (94%) rename test/component/winstl/dl/{test.component.winstl.dl.dl_call => dl_call}/CMakeLists.txt (100%) rename test/component/winstl/dl/{test.component.winstl.dl.dl_call => dl_call}/entry.cpp (98%) rename test/component/winstl/filesystem/{test.component.winstl.filesystem.filesystem_traits => filesystem_traits}/CMakeLists.txt (100%) rename test/component/winstl/filesystem/{test.component.winstl.filesystem.filesystem_traits => filesystem_traits}/entry.cpp (98%) rename test/component/winstl/filesystem/{test.component.winstl.filesystem.memory_map_functions.C => memory_map_functions.C}/CMakeLists.txt (100%) rename test/component/winstl/filesystem/{test.component.winstl.filesystem.memory_map_functions.C => memory_map_functions.C}/entry.c (98%) rename test/component/winstl/registry/{test.component.winstl.registry.reg_value => reg_value}/CMakeLists.txt (100%) rename test/component/winstl/registry/{test.component.winstl.registry.reg_value => reg_value}/entry.cpp (98%) rename test/component/winstl/registry/{test.component.winstl.registry.reg_value_sequence => reg_value_sequence}/CMakeLists.txt (100%) rename test/component/winstl/registry/{test.component.winstl.registry.reg_value_sequence => reg_value_sequence}/entry.cpp (97%) rename test/component/winstl/synch/{test.component.winstl.synch.atomic_functions => atomic_functions}/CMakeLists.txt (100%) rename test/component/winstl/synch/{test.component.winstl.synch.atomic_functions => atomic_functions}/entry.cpp (99%) rename test/component/winstl/synch/{test.component.winstl.synch.spin_mutex => spin_mutex}/CMakeLists.txt (100%) rename test/component/winstl/synch/{test.component.winstl.synch.spin_mutex => spin_mutex}/entry.cpp (99%) rename test/component/winstl/system/{test.component.winstl.system.directory_functions => directory_functions}/CMakeLists.txt (100%) rename test/component/winstl/system/{test.component.winstl.system.directory_functions => directory_functions}/entry.cpp (98%) create mode 100644 test/performance/platformstl/CMakeLists.txt create mode 100644 test/performance/platformstl/diagnostics/CMakeLists.txt rename test/performance/{test.performance.platformstl.stopwatch => platformstl/diagnostics/stopwatch}/CMakeLists.txt (100%) rename test/performance/{test.performance.platformstl.stopwatch => platformstl/diagnostics/stopwatch}/main.cpp (99%) create mode 100644 test/performance/stlsoft/CMakeLists.txt create mode 100644 test/performance/stlsoft/containers/CMakeLists.txt rename test/performance/{test.performance.stlsoft.frequency_map => stlsoft/containers/frequency_map}/CMakeLists.txt (100%) rename test/performance/{test.performance.stlsoft.frequency_map => stlsoft/containers/frequency_map}/main.cpp (99%) create mode 100644 test/performance/stlsoft/conversion/CMakeLists.txt rename test/performance/{test.performance.stlsoft.conversion.integer_to_string => stlsoft/conversion/integer_to_string}/CMakeLists.txt (100%) rename test/performance/{test.performance.stlsoft.conversion.integer_to_string => stlsoft/conversion/integer_to_string}/main.cpp (99%) create mode 100644 test/performance/stlsoft/diagnostics/CMakeLists.txt rename test/performance/{test.performance.stlsoft.doomgram => stlsoft/diagnostics/doomgram}/CMakeLists.txt (100%) rename test/performance/{test.performance.stlsoft.doomgram => stlsoft/diagnostics/doomgram}/main.cpp (99%) rename test/performance/{test.performance.stlsoft.gram_utils => stlsoft/diagnostics/gram_utils}/CMakeLists.txt (100%) rename test/performance/{test.performance.stlsoft.gram_utils => stlsoft/diagnostics/gram_utils}/main.cpp (96%) create mode 100644 test/performance/stlsoft/memory/CMakeLists.txt rename test/performance/{test.performance.stlsoft.auto_buffer => stlsoft/memory/auto_buffer}/CMakeLists.txt (100%) rename test/performance/{test.performance.stlsoft.auto_buffer => stlsoft/memory/auto_buffer}/main.cpp (99%) create mode 100644 test/performance/stlsoft/string/CMakeLists.txt rename test/performance/{test.performance.stlsoft.simple_string.compare => stlsoft/string/simple_string.compare}/CMakeLists.txt (100%) rename test/performance/{test.performance.stlsoft.simple_string.compare => stlsoft/string/simple_string.compare}/main.cpp (99%) rename test/performance/{test.performance.stlsoft.simple_string.op_eq => stlsoft/string/simple_string.op_eq}/CMakeLists.txt (100%) rename test/performance/{test.performance.stlsoft.simple_string.op_eq => stlsoft/string/simple_string.op_eq}/main.cpp (99%) create mode 100644 test/performance/stlsoft/util/CMakeLists.txt rename test/performance/{test.performance.stlsoft.count_digits => stlsoft/util/count_digits}/CMakeLists.txt (100%) rename test/performance/{test.performance.stlsoft.count_digits => stlsoft/util/count_digits}/main.cpp (98%) rename test/scratch/platformstl/system/{test.scratch.platformstl.system.directory_functions => directory_functions}/CMakeLists.txt (100%) rename test/scratch/platformstl/system/{test.scratch.platformstl.system.directory_functions => directory_functions}/main.cpp (100%) rename test/scratch/stlsoft/cccap/{test.scratch.stlsoft.cccap.distinct_integer_types => distinct_integer_types}/CMakeLists.txt (100%) rename test/scratch/stlsoft/cccap/{test.scratch.stlsoft.cccap.distinct_integer_types => distinct_integer_types}/main.cpp (100%) rename test/scratch/stlsoft/conversion/{test.scratch.stlsoft.conversion.itoslice => itoslice}/CMakeLists.txt (100%) rename test/scratch/stlsoft/conversion/{test.scratch.stlsoft.conversion.itoslice => itoslice}/main.c (97%) rename test/scratch/unixstl/synch/{test.scratch.unixstl.synch.semaphore => semaphore}/CMakeLists.txt (100%) rename test/scratch/unixstl/synch/{test.scratch.unixstl.synch.semaphore => semaphore}/main.cpp (100%) rename test/scratch/unixstl/system/{test.scratch.unixstl.system.get_console_width => get_console_width}/CMakeLists.txt (100%) rename test/scratch/unixstl/system/{test.scratch.unixstl.system.get_console_width => get_console_width}/main.c (100%) rename test/scratch/winstl/diagnostics/{test.scratch.winstl.diagnostics.output_debug_line.C => output_debug_line.C}/CMakeLists.txt (100%) rename test/scratch/winstl/diagnostics/{test.scratch.winstl.diagnostics.output_debug_line.C => output_debug_line.C}/main.c (91%) rename test/scratch/winstl/synch/{test.scratch.winstl.micro_sleep => micro_sleep}/CMakeLists.txt (100%) rename test/scratch/winstl/synch/{test.scratch.winstl.micro_sleep => micro_sleep}/main.cpp (100%) rename test/scratch/winstl/system/{test.scratch.winstl.system.console_functions.C => console_functions.C}/CMakeLists.txt (100%) rename test/scratch/winstl/system/{test.scratch.winstl.system.console_functions.C => console_functions.C}/main.c (100%) rename test/scratch/winstl/system/{test.scratch.winstl.system.versions => versions}/CMakeLists.txt (100%) rename test/scratch/winstl/system/{test.scratch.winstl.system.versions => versions}/main.cpp (100%) rename test/unit/acestl/shims/access/string/{test.unit.acestl.shims.access.string.string_base => string_base}/CMakeLists.txt (100%) rename test/unit/acestl/shims/access/string/{test.unit.acestl.shims.access.string.string_base => string_base}/entry.cpp (96%) rename test/unit/acestl/shims/access/string/{test.unit.acestl.shims.access.string.time_value => time_value}/CMakeLists.txt (100%) rename test/unit/acestl/shims/access/string/{test.unit.acestl.shims.access.string.time_value => time_value}/entry.cpp (97%) rename test/unit/comstl/memory/{test.unit.comstl.memory.task_allocator => task_allocator}/CMakeLists.txt (100%) rename test/unit/comstl/memory/{test.unit.comstl.memory.task_allocator => task_allocator}/entry.cpp (96%) rename test/unit/comstl/string/{test.unit.comstl.string.BSTR_functions.C => BSTR_functions.C}/CMakeLists.txt (100%) rename test/unit/comstl/string/{test.unit.comstl.string.BSTR_functions.C => BSTR_functions.C}/entry.c (98%) rename test/unit/comstl/util/{test.unit.comstl.util.GUID_functions.C => GUID_functions.C}/CMakeLists.txt (100%) rename test/unit/comstl/util/{test.unit.comstl.util.GUID_functions.C => GUID_functions.C}/entry.c (97%) rename test/unit/comstl/util/{test.unit.comstl.util.VARIANT_functions.C => VARIANT_functions.C}/CMakeLists.txt (100%) rename test/unit/comstl/util/{test.unit.comstl.util.VARIANT_functions.C => VARIANT_functions.C}/entry.c (99%) rename test/unit/inetstl/shims/access/string/{test.unit.inetstl.shims.access.string.std.in_addr => std.in_addr}/CMakeLists.txt (100%) rename test/unit/inetstl/shims/access/string/{test.unit.inetstl.shims.access.string.std.in_addr => std.in_addr}/entry.cpp (98%) rename test/unit/mfcstl/memory/{test.unit.mfcstl.memory.afx_allocator => afx_allocator}/CMakeLists.txt (100%) rename test/unit/mfcstl/memory/{test.unit.mfcstl.memory.afx_allocator => afx_allocator}/entry.cpp (96%) rename test/unit/platformstl/system/{test.unit.platformstl.system.commandline_parser => commandline_parser}/CMakeLists.txt (100%) rename test/unit/platformstl/system/{test.unit.platformstl.system.commandline_parser => commandline_parser}/entry.cpp (98%) rename test/unit/platformstl/system/{test.unit.platformstl.system.pid_sequence => pid_sequence}/CMakeLists.txt (100%) rename test/unit/platformstl/system/{test.unit.platformstl.system.pid_sequence => pid_sequence}/entry.cpp (97%) rename test/unit/stlsoft/api/{test.unit.stlsoft.api.external.string => external.string}/CMakeLists.txt (100%) rename test/unit/stlsoft/api/{test.unit.stlsoft.api.external.string => external.string}/entry.cpp (98%) rename test/unit/stlsoft/containers/{test.unit.stlsoft.containers.frequency_map => frequency_map}/CMakeLists.txt (100%) rename test/unit/stlsoft/containers/{test.unit.stlsoft.containers.frequency_map => frequency_map}/entry.cpp (99%) rename test/unit/stlsoft/containers/{test.unit.stlsoft.containers.pod_vector => pod_vector}/CMakeLists.txt (100%) rename test/unit/stlsoft/containers/{test.unit.stlsoft.containers.pod_vector => pod_vector}/entry.cpp (99%) rename test/unit/stlsoft/containers/{test.unit.stlsoft.containers.unicode_point_map => unicode_point_map}/CMakeLists.txt (100%) rename test/unit/stlsoft/containers/{test.unit.stlsoft.containers.unicode_point_map => unicode_point_map}/entry.cpp (99%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.byte_format_functions => byte_format_functions}/CMakeLists.txt (100%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.byte_format_functions => byte_format_functions}/entry.cpp (99%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.integer_to_base32_string => integer_to_base32_string}/CMakeLists.txt (100%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.integer_to_base32_string => integer_to_base32_string}/entry.cpp (99%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.integer_to_base36_string => integer_to_base36_string}/CMakeLists.txt (100%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.integer_to_base36_string => integer_to_base36_string}/entry.cpp (99%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.integer_to_lc_string => integer_to_lc_string}/CMakeLists.txt (100%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.integer_to_lc_string => integer_to_lc_string}/entry.cpp (99%) rename test/unit/stlsoft/conversion/number/{test.unit.stlsoft.conversion.number.group_functions => group_functions}/CMakeLists.txt (100%) rename test/unit/stlsoft/conversion/number/{test.unit.stlsoft.conversion.number.group_functions => group_functions}/entry.cpp (99%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.string_to_integer => string_to_integer}/CMakeLists.txt (100%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.string_to_integer => string_to_integer}/entry.cpp (99%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.truncation_test => truncation_test}/CMakeLists.txt (100%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.truncation_test => truncation_test}/entry.cpp (99%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.try_parse_to => try_parse_to}/CMakeLists.txt (100%) rename test/unit/stlsoft/conversion/{test.unit.stlsoft.conversion.try_parse_to => try_parse_to}/entry.cpp (99%) rename test/unit/stlsoft/diagnostics/{test.unit.stlsoft.diagnostics.doomgram => doomgram}/CMakeLists.txt (100%) rename test/unit/stlsoft/diagnostics/{test.unit.stlsoft.diagnostics.doomgram => doomgram}/entry.cpp (99%) rename test/unit/stlsoft/diagnostics/{test.unit.stlsoft.diagnostics.gram_scope => gram_scope}/CMakeLists.txt (100%) rename test/unit/stlsoft/diagnostics/{test.unit.stlsoft.diagnostics.gram_scope => gram_scope}/entry.cpp (96%) rename test/unit/stlsoft/filesystem/{test.unit.stlsoft.filesystem.io_functions.read_line => io_functions.read_line}/CMakeLists.txt (100%) rename test/unit/stlsoft/filesystem/{test.unit.stlsoft.filesystem.io_functions.read_line => io_functions.read_line}/entry.cpp (99%) rename test/unit/stlsoft/filesystem/{test.unit.stlsoft.filesystem.io_functions.write_string => io_functions.write_string}/CMakeLists.txt (100%) rename test/unit/stlsoft/filesystem/{test.unit.stlsoft.filesystem.io_functions.write_string => io_functions.write_string}/entry.cpp (98%) rename test/unit/stlsoft/iterator/{test.unit.stlsoft.iterator.FILE_iterator => FILE_iterator}/CMakeLists.txt (100%) rename test/unit/stlsoft/iterator/{test.unit.stlsoft.iterator.FILE_iterator => FILE_iterator}/entry.cpp (96%) rename test/unit/stlsoft/limits/{test.unit.stlsoft.limits.integral_limits => integral_limits}/CMakeLists.txt (100%) rename test/unit/stlsoft/limits/{test.unit.stlsoft.limits.integral_limits => integral_limits}/entry.cpp (97%) rename test/unit/stlsoft/memory/{test.unit.stlsoft.memory.auto_buffer.C => auto_buffer.C}/CMakeLists.txt (100%) rename test/unit/stlsoft/memory/{test.unit.stlsoft.memory.auto_buffer.C => auto_buffer.C}/entry.c (98%) rename test/unit/stlsoft/memory/{test.unit.stlsoft.memory.auto_buffer => auto_buffer}/CMakeLists.txt (100%) rename test/unit/stlsoft/memory/{test.unit.stlsoft.memory.auto_buffer => auto_buffer}/entry.cpp (99%) rename test/unit/stlsoft/memory/{test.unit.stlsoft.memory.malloc_allocator => malloc_allocator}/CMakeLists.txt (100%) rename test/unit/stlsoft/memory/{test.unit.stlsoft.memory.malloc_allocator => malloc_allocator}/entry.cpp (96%) rename test/unit/stlsoft/memory/{test.unit.stlsoft.memory.new_allocator => new_allocator}/CMakeLists.txt (100%) rename test/unit/stlsoft/memory/{test.unit.stlsoft.memory.new_allocator => new_allocator}/entry.cpp (96%) rename test/unit/stlsoft/memory/{test.unit.stlsoft.memory.null_allocator => null_allocator}/CMakeLists.txt (100%) rename test/unit/stlsoft/memory/{test.unit.stlsoft.memory.null_allocator => null_allocator}/entry.cpp (96%) rename test/unit/stlsoft/smartptr/{test.unit.stlsoft.smartptr.scoped_handle => scoped_handle}/CMakeLists.txt (100%) rename test/unit/stlsoft/smartptr/{test.unit.stlsoft.smartptr.scoped_handle => scoped_handle}/entry.cpp (99%) rename test/unit/stlsoft/smartptr/{test.unit.stlsoft.smartptr.shared_ptr => shared_ptr}/CMakeLists.txt (100%) rename test/unit/stlsoft/smartptr/{test.unit.stlsoft.smartptr.shared_ptr => shared_ptr}/entry.cpp (99%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.copy_functions => copy_functions}/CMakeLists.txt (100%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.copy_functions => copy_functions}/entry.cpp (99%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.exception_string => exception_string}/CMakeLists.txt (100%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.exception_string => exception_string}/entry.cpp (99%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.shim_string => shim_string}/CMakeLists.txt (100%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.shim_string => shim_string}/entry.cpp (99%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.simple_string => simple_string}/CMakeLists.txt (100%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.simple_string => simple_string}/entry.cpp (99%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.static_string => static_string}/CMakeLists.txt (100%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.static_string => static_string}/entry.cpp (99%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.string_slice => string_slice}/CMakeLists.txt (100%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.string_slice => string_slice}/entry.cpp (99%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.string_view => string_view}/CMakeLists.txt (100%) rename test/unit/stlsoft/string/{test.unit.stlsoft.string.string_view => string_view}/entry.cpp (99%) rename test/unit/stlsoft/system/{test.unit.stlsoft.system.cmdargs => cmdargs}/CMakeLists.txt (100%) rename test/unit/stlsoft/system/{test.unit.stlsoft.system.cmdargs => cmdargs}/entry.cpp (99%) rename test/unit/stlsoft/traits/{test.unit.stlsoft.traits.integral_printf_format_traits => integral_printf_format_traits}/CMakeLists.txt (100%) rename test/unit/stlsoft/traits/{test.unit.stlsoft.traits.integral_printf_format_traits => integral_printf_format_traits}/entry.cpp (99%) rename test/unit/stlsoft/traits/{test.unit.stlsoft.traits.integral_traits => integral_traits}/CMakeLists.txt (100%) rename test/unit/stlsoft/traits/{test.unit.stlsoft.traits.integral_traits => integral_traits}/entry.cpp (98%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.bit_functions => bit_functions}/CMakeLists.txt (100%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.bit_functions => bit_functions}/entry.cpp (99%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.count_decimal_digits => count_decimal_digits}/CMakeLists.txt (100%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.count_decimal_digits => count_decimal_digits}/entry.cpp (98%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.count_hexadecimal_digits => count_hexadecimal_digits}/CMakeLists.txt (100%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.count_hexadecimal_digits => count_hexadecimal_digits}/entry.cpp (98%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.string.snprintf => string.snprintf}/CMakeLists.txt (100%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.string.snprintf => string.snprintf}/entry.cpp (98%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.string_insertion => string_insertion}/CMakeLists.txt (100%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.string_insertion => string_insertion}/entry.cpp (98%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.string_switch => string_switch}/CMakeLists.txt (100%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.string_switch => string_switch}/entry.cpp (99%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.true_typedef => true_typedef}/CMakeLists.txt (100%) rename test/unit/stlsoft/util/{test.unit.stlsoft.util.true_typedef => true_typedef}/entry.cpp (99%) rename test/unit/unixstl/filesystem/{test.unit.unixstl.filesystem.path => path}/CMakeLists.txt (100%) rename test/unit/unixstl/filesystem/{test.unit.unixstl.filesystem.path => path}/entry.cpp (99%) rename test/unit/unixstl/filesystem/{test.unit.unixstl.filesystem.squeeze_functions => squeeze_functions}/CMakeLists.txt (100%) rename test/unit/unixstl/filesystem/{test.unit.unixstl.filesystem.squeeze_functions => squeeze_functions}/entry.cpp (99%) rename test/unit/unixstl/shims/access/string/{test.unit.unixstl.shims.access.string.timeval => timeval}/CMakeLists.txt (100%) rename test/unit/unixstl/shims/access/string/{test.unit.unixstl.shims.access.string.timeval => timeval}/entry.cpp (98%) rename test/unit/{test.unit.versions => versions}/CMakeLists.txt (100%) rename test/unit/{test.unit.versions => versions}/entry.cpp (98%) rename test/unit/winstl/api/internal/{test.unit.winstl.api.internal.DynamicLinkLibrary.C => DynamicLinkLibrary.C}/CMakeLists.txt (100%) rename test/unit/winstl/api/internal/{test.unit.winstl.api.internal.DynamicLinkLibrary.C => DynamicLinkLibrary.C}/entry.c (98%) rename test/unit/winstl/api/internal/{test.unit.winstl.api.internal.SystemInformation.C => SystemInformation.C}/CMakeLists.txt (100%) rename test/unit/winstl/api/internal/{test.unit.winstl.api.internal.SystemInformation.C => SystemInformation.C}/entry.c (98%) rename test/unit/winstl/conversion/number/{test.unit.winstl.conversion.number.grouping_functions => grouping_functions}/CMakeLists.txt (100%) rename test/unit/winstl/conversion/number/{test.unit.winstl.conversion.number.grouping_functions => grouping_functions}/entry.cpp (98%) rename test/unit/winstl/diagnostics/{test.unit.winstl.diagnostics.output_debug_line.C => output_debug_line.C}/CMakeLists.txt (100%) rename test/unit/winstl/diagnostics/{test.unit.winstl.diagnostics.output_debug_line.C => output_debug_line.C}/entry.c (98%) rename test/unit/winstl/filesystem/{test.unit.winstl.filesystem.filesystem_traits => filesystem_traits}/CMakeLists.txt (100%) rename test/unit/winstl/filesystem/{test.unit.winstl.filesystem.filesystem_traits => filesystem_traits}/entry.cpp (99%) rename test/unit/winstl/filesystem/{test.unit.winstl.filesystem.squeeze_functions => squeeze_functions}/CMakeLists.txt (100%) rename test/unit/winstl/filesystem/{test.unit.winstl.filesystem.squeeze_functions => squeeze_functions}/entry.cpp (99%) rename test/unit/winstl/memory/{test.unit.winstl.memory.global_allocator => global_allocator}/CMakeLists.txt (100%) rename test/unit/winstl/memory/{test.unit.winstl.memory.global_allocator => global_allocator}/entry.cpp (96%) rename test/unit/winstl/memory/{test.unit.winstl.memory.netapi_allocator => netapi_allocator}/CMakeLists.txt (100%) rename test/unit/winstl/memory/{test.unit.winstl.memory.netapi_allocator => netapi_allocator}/entry.cpp (96%) rename test/unit/winstl/memory/{test.unit.winstl.memory.processheap_allocator => processheap_allocator}/CMakeLists.txt (100%) rename test/unit/winstl/memory/{test.unit.winstl.memory.processheap_allocator => processheap_allocator}/entry.cpp (96%) rename test/unit/winstl/memory/{test.unit.winstl.memory.shell_allocator => shell_allocator}/CMakeLists.txt (100%) rename test/unit/winstl/memory/{test.unit.winstl.memory.shell_allocator => shell_allocator}/entry.cpp (96%) rename test/unit/winstl/system/{test.unit.winstl.system.system_traits => system_traits}/CMakeLists.txt (100%) rename test/unit/winstl/system/{test.unit.winstl.system.system_traits => system_traits}/entry.cpp (99%) rename test/unit/winstl/util/{test.unit.winstl.util.struct_comparers => struct_comparers}/CMakeLists.txt (100%) rename test/unit/winstl/util/{test.unit.winstl.util.struct_comparers => struct_comparers}/entry.cpp (97%) rename test/unit/winstl/util/{test.unit.winstl.util.struct_initialisers => struct_initialisers}/CMakeLists.txt (100%) rename test/unit/winstl/util/{test.unit.winstl.util.struct_initialisers => struct_initialisers}/entry.cpp (99%) diff --git a/test/component/inetstl/util/CMakeLists.txt b/test/component/inetstl/util/CMakeLists.txt index 405fb83f..285b12d3 100644 --- a/test/component/inetstl/util/CMakeLists.txt +++ b/test/component/inetstl/util/CMakeLists.txt @@ -1,4 +1,4 @@ if(UNIX) - add_subdirectory(test.component.inetstl.util.uds_helpers) + add_subdirectory(uds_helpers) endif(UNIX) diff --git a/test/component/inetstl/util/test.component.inetstl.util.uds_helpers/CMakeLists.txt b/test/component/inetstl/util/uds_helpers/CMakeLists.txt similarity index 100% rename from test/component/inetstl/util/test.component.inetstl.util.uds_helpers/CMakeLists.txt rename to test/component/inetstl/util/uds_helpers/CMakeLists.txt diff --git a/test/component/inetstl/util/test.component.inetstl.util.uds_helpers/entry.cpp b/test/component/inetstl/util/uds_helpers/entry.cpp similarity index 100% rename from test/component/inetstl/util/test.component.inetstl.util.uds_helpers/entry.cpp rename to test/component/inetstl/util/uds_helpers/entry.cpp diff --git a/test/component/platformstl/diagnostics/CMakeLists.txt b/test/component/platformstl/diagnostics/CMakeLists.txt index 154aa879..635ae2bb 100644 --- a/test/component/platformstl/diagnostics/CMakeLists.txt +++ b/test/component/platformstl/diagnostics/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.component.platformstl.diagnostics.stopwatch) +add_subdirectory(stopwatch) diff --git a/test/component/platformstl/diagnostics/test.component.platformstl.diagnostics.stopwatch/CMakeLists.txt b/test/component/platformstl/diagnostics/stopwatch/CMakeLists.txt similarity index 100% rename from test/component/platformstl/diagnostics/test.component.platformstl.diagnostics.stopwatch/CMakeLists.txt rename to test/component/platformstl/diagnostics/stopwatch/CMakeLists.txt diff --git a/test/component/platformstl/diagnostics/test.component.platformstl.diagnostics.stopwatch/entry.cpp b/test/component/platformstl/diagnostics/stopwatch/entry.cpp similarity index 97% rename from test/component/platformstl/diagnostics/test.component.platformstl.diagnostics.stopwatch/entry.cpp rename to test/component/platformstl/diagnostics/stopwatch/entry.cpp index 4b7e2f86..07417b73 100644 --- a/test/component/platformstl/diagnostics/test.component.platformstl.diagnostics.stopwatch/entry.cpp +++ b/test/component/platformstl/diagnostics/stopwatch/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.platformstl.diagnostics.stopwatch/entry.cpp + * File: stopwatch/entry.cpp * * Purpose: Unit-tests for `platformstl::stopwatch`. * * Created: 19th November 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/platformstl/system/CMakeLists.txt b/test/component/platformstl/system/CMakeLists.txt index 87f920d9..10202fa1 100644 --- a/test/component/platformstl/system/CMakeLists.txt +++ b/test/component/platformstl/system/CMakeLists.txt @@ -1,4 +1,4 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.component.platformstl.system.environment_variable_scope) -add_subdirectory(test.component.platformstl.system.environment_variable_traits) -add_subdirectory(test.component.platformstl.system.system_traits) +add_subdirectory(environment_variable_scope) +add_subdirectory(environment_variable_traits) +add_subdirectory(system_traits) diff --git a/test/component/platformstl/system/test.component.platformstl.system.environment_variable_scope/CMakeLists.txt b/test/component/platformstl/system/environment_variable_scope/CMakeLists.txt similarity index 100% rename from test/component/platformstl/system/test.component.platformstl.system.environment_variable_scope/CMakeLists.txt rename to test/component/platformstl/system/environment_variable_scope/CMakeLists.txt diff --git a/test/component/platformstl/system/test.component.platformstl.system.environment_variable_scope/entry.cpp b/test/component/platformstl/system/environment_variable_scope/entry.cpp similarity index 96% rename from test/component/platformstl/system/test.component.platformstl.system.environment_variable_scope/entry.cpp rename to test/component/platformstl/system/environment_variable_scope/entry.cpp index b689c63f..ce066ce8 100644 --- a/test/component/platformstl/system/test.component.platformstl.system.environment_variable_scope/entry.cpp +++ b/test/component/platformstl/system/environment_variable_scope/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.platformstl.system.environment_variable_scope/entry.cpp + * File: environment_variable_scope/entry.cpp * * Purpose: Unit-tests for `platformstl::environment_variable_scope`. * * Created: 26th April 2025 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/platformstl/system/test.component.platformstl.system.environment_variable_traits/CMakeLists.txt b/test/component/platformstl/system/environment_variable_traits/CMakeLists.txt similarity index 100% rename from test/component/platformstl/system/test.component.platformstl.system.environment_variable_traits/CMakeLists.txt rename to test/component/platformstl/system/environment_variable_traits/CMakeLists.txt diff --git a/test/component/platformstl/system/test.component.platformstl.system.environment_variable_traits/entry.cpp b/test/component/platformstl/system/environment_variable_traits/entry.cpp similarity index 96% rename from test/component/platformstl/system/test.component.platformstl.system.environment_variable_traits/entry.cpp rename to test/component/platformstl/system/environment_variable_traits/entry.cpp index a6c5afbf..1aebcba6 100644 --- a/test/component/platformstl/system/test.component.platformstl.system.environment_variable_traits/entry.cpp +++ b/test/component/platformstl/system/environment_variable_traits/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.platformstl.system.environment_variable_traits/entry.cpp + * File: environment_variable_traits/entry.cpp * * Purpose: Unit-tests for `platformstl::environment_variable_traits`. * * Created: 30th December 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/platformstl/system/test.component.platformstl.system.system_traits/CMakeLists.txt b/test/component/platformstl/system/system_traits/CMakeLists.txt similarity index 100% rename from test/component/platformstl/system/test.component.platformstl.system.system_traits/CMakeLists.txt rename to test/component/platformstl/system/system_traits/CMakeLists.txt diff --git a/test/component/platformstl/system/test.component.platformstl.system.system_traits/entry.cpp b/test/component/platformstl/system/system_traits/entry.cpp similarity index 97% rename from test/component/platformstl/system/test.component.platformstl.system.system_traits/entry.cpp rename to test/component/platformstl/system/system_traits/entry.cpp index 1343ffd2..cdacce5d 100644 --- a/test/component/platformstl/system/test.component.platformstl.system.system_traits/entry.cpp +++ b/test/component/platformstl/system/system_traits/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.platformstl.system.system_traits/entry.cpp + * File: system_traits/entry.cpp * * Purpose: Unit-tests for `platformstl::system_traits`. * * Created: 29th January 2013 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/stlsoft/system/CMakeLists.txt b/test/component/stlsoft/system/CMakeLists.txt index df598fd1..b7d0db4c 100644 --- a/test/component/stlsoft/system/CMakeLists.txt +++ b/test/component/stlsoft/system/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.component.stlsoft.system.environment_block) +add_subdirectory(environment_block) diff --git a/test/component/stlsoft/system/test.component.stlsoft.system.environment_block/CMakeLists.txt b/test/component/stlsoft/system/environment_block/CMakeLists.txt similarity index 100% rename from test/component/stlsoft/system/test.component.stlsoft.system.environment_block/CMakeLists.txt rename to test/component/stlsoft/system/environment_block/CMakeLists.txt diff --git a/test/component/stlsoft/system/test.component.stlsoft.system.environment_block/entry.cpp b/test/component/stlsoft/system/environment_block/entry.cpp similarity index 96% rename from test/component/stlsoft/system/test.component.stlsoft.system.environment_block/entry.cpp rename to test/component/stlsoft/system/environment_block/entry.cpp index 7ffa1fed..25906352 100644 --- a/test/component/stlsoft/system/test.component.stlsoft.system.environment_block/entry.cpp +++ b/test/component/stlsoft/system/environment_block/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.stlsoft.system.environment_block/entry.cpp + * File: environment_block/entry.cpp * * Purpose: Unit-tests for `stlsoft::environment_block`. * * Created: 11th August 2010 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/unixstl/dl/CMakeLists.txt b/test/component/unixstl/dl/CMakeLists.txt index 0915f0c2..6536edce 100644 --- a/test/component/unixstl/dl/CMakeLists.txt +++ b/test/component/unixstl/dl/CMakeLists.txt @@ -2,6 +2,6 @@ if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) if(UNIX) - add_subdirectory(test.component.unixstl.dl.dl_call) + add_subdirectory(dl_call) endif(UNIX) endif() diff --git a/test/component/unixstl/dl/test.component.unixstl.dl.dl_call/CMakeLists.txt b/test/component/unixstl/dl/dl_call/CMakeLists.txt similarity index 100% rename from test/component/unixstl/dl/test.component.unixstl.dl.dl_call/CMakeLists.txt rename to test/component/unixstl/dl/dl_call/CMakeLists.txt diff --git a/test/component/unixstl/dl/test.component.unixstl.dl.dl_call/entry.cpp b/test/component/unixstl/dl/dl_call/entry.cpp similarity index 98% rename from test/component/unixstl/dl/test.component.unixstl.dl.dl_call/entry.cpp rename to test/component/unixstl/dl/dl_call/entry.cpp index 38c514c2..ffeb9e41 100644 --- a/test/component/unixstl/dl/test.component.unixstl.dl.dl_call/entry.cpp +++ b/test/component/unixstl/dl/dl_call/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.unixstl.dl.dl_call/entry.cpp + * File: dl_call/entry.cpp * * Purpose: Component test for `unixstl::dl_call`. * * Created: 9th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/unixstl/filesystem/CMakeLists.txt b/test/component/unixstl/filesystem/CMakeLists.txt index ea2ef6e7..7d8d9318 100644 --- a/test/component/unixstl/filesystem/CMakeLists.txt +++ b/test/component/unixstl/filesystem/CMakeLists.txt @@ -1,5 +1,5 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.component.unixstl.filesystem.glob_sequence) -add_subdirectory(test.component.unixstl.filesystem.memory_mapped_file) -add_subdirectory(test.component.unixstl.filesystem.readdir_sequence) -add_subdirectory(test.component.unixstl.filesystem.readonly_memory_mapped_file) +add_subdirectory(glob_sequence) +add_subdirectory(memory_mapped_file) +add_subdirectory(readdir_sequence) +add_subdirectory(readonly_memory_mapped_file) diff --git a/test/component/unixstl/filesystem/test.component.unixstl.filesystem.glob_sequence/CMakeLists.txt b/test/component/unixstl/filesystem/glob_sequence/CMakeLists.txt similarity index 100% rename from test/component/unixstl/filesystem/test.component.unixstl.filesystem.glob_sequence/CMakeLists.txt rename to test/component/unixstl/filesystem/glob_sequence/CMakeLists.txt diff --git a/test/component/unixstl/filesystem/test.component.unixstl.filesystem.glob_sequence/entry.cpp b/test/component/unixstl/filesystem/glob_sequence/entry.cpp similarity index 99% rename from test/component/unixstl/filesystem/test.component.unixstl.filesystem.glob_sequence/entry.cpp rename to test/component/unixstl/filesystem/glob_sequence/entry.cpp index 8cfb2310..55cbb378 100644 --- a/test/component/unixstl/filesystem/test.component.unixstl.filesystem.glob_sequence/entry.cpp +++ b/test/component/unixstl/filesystem/glob_sequence/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.unixstl.filesystem.glob_sequence/entry.cpp + * File: glob_sequence/entry.cpp * * Purpose: Component test for `unixstl::glob_sequence`. * * Created: 24th January 2009 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/unixstl/filesystem/test.component.unixstl.filesystem.memory_mapped_file/CMakeLists.txt b/test/component/unixstl/filesystem/memory_mapped_file/CMakeLists.txt similarity index 100% rename from test/component/unixstl/filesystem/test.component.unixstl.filesystem.memory_mapped_file/CMakeLists.txt rename to test/component/unixstl/filesystem/memory_mapped_file/CMakeLists.txt diff --git a/test/component/unixstl/filesystem/test.component.unixstl.filesystem.memory_mapped_file/entry.cpp b/test/component/unixstl/filesystem/memory_mapped_file/entry.cpp similarity index 96% rename from test/component/unixstl/filesystem/test.component.unixstl.filesystem.memory_mapped_file/entry.cpp rename to test/component/unixstl/filesystem/memory_mapped_file/entry.cpp index f5ea4f9e..608e43e9 100644 --- a/test/component/unixstl/filesystem/test.component.unixstl.filesystem.memory_mapped_file/entry.cpp +++ b/test/component/unixstl/filesystem/memory_mapped_file/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.unixstl.filesystem.memory_mapped_file/entry.cpp + * File: memory_mapped_file/entry.cpp * * Purpose: Component test for `unixstl::memory_mapped_file`. * * Created: sometime in 2010s - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/unixstl/filesystem/test.component.unixstl.filesystem.readdir_sequence/CMakeLists.txt b/test/component/unixstl/filesystem/readdir_sequence/CMakeLists.txt similarity index 100% rename from test/component/unixstl/filesystem/test.component.unixstl.filesystem.readdir_sequence/CMakeLists.txt rename to test/component/unixstl/filesystem/readdir_sequence/CMakeLists.txt diff --git a/test/component/unixstl/filesystem/test.component.unixstl.filesystem.readdir_sequence/entry.cpp b/test/component/unixstl/filesystem/readdir_sequence/entry.cpp similarity index 98% rename from test/component/unixstl/filesystem/test.component.unixstl.filesystem.readdir_sequence/entry.cpp rename to test/component/unixstl/filesystem/readdir_sequence/entry.cpp index 5b584d34..339ffcb5 100644 --- a/test/component/unixstl/filesystem/test.component.unixstl.filesystem.readdir_sequence/entry.cpp +++ b/test/component/unixstl/filesystem/readdir_sequence/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.unixstl.filesystem.readdir_sequence/entry.cpp + * File: readdir_sequence/entry.cpp * * Purpose: Component test for `unixstl::readdir_sequence`. * * Created: sometime in 2010s - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/unixstl/filesystem/test.component.unixstl.filesystem.readonly_memory_mapped_file/CMakeLists.txt b/test/component/unixstl/filesystem/readonly_memory_mapped_file/CMakeLists.txt similarity index 100% rename from test/component/unixstl/filesystem/test.component.unixstl.filesystem.readonly_memory_mapped_file/CMakeLists.txt rename to test/component/unixstl/filesystem/readonly_memory_mapped_file/CMakeLists.txt diff --git a/test/component/unixstl/filesystem/test.component.unixstl.filesystem.readonly_memory_mapped_file/entry.cpp b/test/component/unixstl/filesystem/readonly_memory_mapped_file/entry.cpp similarity index 97% rename from test/component/unixstl/filesystem/test.component.unixstl.filesystem.readonly_memory_mapped_file/entry.cpp rename to test/component/unixstl/filesystem/readonly_memory_mapped_file/entry.cpp index 00ea0992..d6dda687 100644 --- a/test/component/unixstl/filesystem/test.component.unixstl.filesystem.readonly_memory_mapped_file/entry.cpp +++ b/test/component/unixstl/filesystem/readonly_memory_mapped_file/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.unixstl.filesystem.readonly_memory_mapped_file/entry.cpp + * File: readonly_memory_mapped_file/entry.cpp * * Purpose: Component test for `unixstl::readonly_memory_mapped_file`. * * Created: sometime in 2010s - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/unixstl/system/CMakeLists.txt b/test/component/unixstl/system/CMakeLists.txt index 70bf9792..eefe07f3 100644 --- a/test/component/unixstl/system/CMakeLists.txt +++ b/test/component/unixstl/system/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.component.unixstl.system.environment_variable) +add_subdirectory(environment_variable) diff --git a/test/component/unixstl/system/test.component.unixstl.system.environment_variable/CMakeLists.txt b/test/component/unixstl/system/environment_variable/CMakeLists.txt similarity index 100% rename from test/component/unixstl/system/test.component.unixstl.system.environment_variable/CMakeLists.txt rename to test/component/unixstl/system/environment_variable/CMakeLists.txt diff --git a/test/component/unixstl/system/test.component.unixstl.system.environment_variable/entry.cpp b/test/component/unixstl/system/environment_variable/entry.cpp similarity index 94% rename from test/component/unixstl/system/test.component.unixstl.system.environment_variable/entry.cpp rename to test/component/unixstl/system/environment_variable/entry.cpp index 001be1bf..0fff3573 100644 --- a/test/component/unixstl/system/test.component.unixstl.system.environment_variable/entry.cpp +++ b/test/component/unixstl/system/environment_variable/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.unixstl.system.environment_variable/entry.cpp + * File: environment_variable/entry.cpp * * Purpose: Unit-tests for `unixstl::environment_variable`. * * Created: 11th August 2010 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/winstl/dl/CMakeLists.txt b/test/component/winstl/dl/CMakeLists.txt index 5c394eb5..06b79d92 100644 --- a/test/component/winstl/dl/CMakeLists.txt +++ b/test/component/winstl/dl/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.component.winstl.dl.dl_call) +add_subdirectory(dl_call) diff --git a/test/component/winstl/dl/test.component.winstl.dl.dl_call/CMakeLists.txt b/test/component/winstl/dl/dl_call/CMakeLists.txt similarity index 100% rename from test/component/winstl/dl/test.component.winstl.dl.dl_call/CMakeLists.txt rename to test/component/winstl/dl/dl_call/CMakeLists.txt diff --git a/test/component/winstl/dl/test.component.winstl.dl.dl_call/entry.cpp b/test/component/winstl/dl/dl_call/entry.cpp similarity index 98% rename from test/component/winstl/dl/test.component.winstl.dl.dl_call/entry.cpp rename to test/component/winstl/dl/dl_call/entry.cpp index 8598d0c5..4745ca6c 100644 --- a/test/component/winstl/dl/test.component.winstl.dl.dl_call/entry.cpp +++ b/test/component/winstl/dl/dl_call/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.winstl.dl.dl_call/entry.cpp + * File: dl_call/entry.cpp * * Purpose: Component test for `winstl::dl_call`. * * Created: 9th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/winstl/filesystem/CMakeLists.txt b/test/component/winstl/filesystem/CMakeLists.txt index e01d32fc..93379cc3 100644 --- a/test/component/winstl/filesystem/CMakeLists.txt +++ b/test/component/winstl/filesystem/CMakeLists.txt @@ -1,3 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.component.winstl.filesystem.filesystem_traits) -add_subdirectory(test.component.winstl.filesystem.memory_map_functions.C) +add_subdirectory(filesystem_traits) +add_subdirectory(memory_map_functions.C) diff --git a/test/component/winstl/filesystem/test.component.winstl.filesystem.filesystem_traits/CMakeLists.txt b/test/component/winstl/filesystem/filesystem_traits/CMakeLists.txt similarity index 100% rename from test/component/winstl/filesystem/test.component.winstl.filesystem.filesystem_traits/CMakeLists.txt rename to test/component/winstl/filesystem/filesystem_traits/CMakeLists.txt diff --git a/test/component/winstl/filesystem/test.component.winstl.filesystem.filesystem_traits/entry.cpp b/test/component/winstl/filesystem/filesystem_traits/entry.cpp similarity index 98% rename from test/component/winstl/filesystem/test.component.winstl.filesystem.filesystem_traits/entry.cpp rename to test/component/winstl/filesystem/filesystem_traits/entry.cpp index cd6185f5..add20243 100644 --- a/test/component/winstl/filesystem/test.component.winstl.filesystem.filesystem_traits/entry.cpp +++ b/test/component/winstl/filesystem/filesystem_traits/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.winstl.filesystem.filesystem_traits/entry.cpp + * File: filesystem_traits/entry.cpp * * Purpose: Component-tests for `winstl::filesystem_traits`. * * Created: 31st December 2008 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/winstl/filesystem/test.component.winstl.filesystem.memory_map_functions.C/CMakeLists.txt b/test/component/winstl/filesystem/memory_map_functions.C/CMakeLists.txt similarity index 100% rename from test/component/winstl/filesystem/test.component.winstl.filesystem.memory_map_functions.C/CMakeLists.txt rename to test/component/winstl/filesystem/memory_map_functions.C/CMakeLists.txt diff --git a/test/component/winstl/filesystem/test.component.winstl.filesystem.memory_map_functions.C/entry.c b/test/component/winstl/filesystem/memory_map_functions.C/entry.c similarity index 98% rename from test/component/winstl/filesystem/test.component.winstl.filesystem.memory_map_functions.C/entry.c rename to test/component/winstl/filesystem/memory_map_functions.C/entry.c index c1813f36..6e5ef2b8 100644 --- a/test/component/winstl/filesystem/test.component.winstl.filesystem.memory_map_functions.C/entry.c +++ b/test/component/winstl/filesystem/memory_map_functions.C/entry.c @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.winstl.filesystem.memory_map_functions.C/entry.c + * File: memory_map_functions.C/entry.c * * Purpose: Scratch test for memory-map functions. * * Created: 26th August 2010 - * Updated: 12th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/winstl/registry/CMakeLists.txt b/test/component/winstl/registry/CMakeLists.txt index f6a8690b..930b67fd 100644 --- a/test/component/winstl/registry/CMakeLists.txt +++ b/test/component/winstl/registry/CMakeLists.txt @@ -1,3 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.component.winstl.registry.reg_value) -add_subdirectory(test.component.winstl.registry.reg_value_sequence) +add_subdirectory(reg_value) +add_subdirectory(reg_value_sequence) diff --git a/test/component/winstl/registry/test.component.winstl.registry.reg_value/CMakeLists.txt b/test/component/winstl/registry/reg_value/CMakeLists.txt similarity index 100% rename from test/component/winstl/registry/test.component.winstl.registry.reg_value/CMakeLists.txt rename to test/component/winstl/registry/reg_value/CMakeLists.txt diff --git a/test/component/winstl/registry/test.component.winstl.registry.reg_value/entry.cpp b/test/component/winstl/registry/reg_value/entry.cpp similarity index 98% rename from test/component/winstl/registry/test.component.winstl.registry.reg_value/entry.cpp rename to test/component/winstl/registry/reg_value/entry.cpp index ee1ab3bf..919c177d 100644 --- a/test/component/winstl/registry/test.component.winstl.registry.reg_value/entry.cpp +++ b/test/component/winstl/registry/reg_value/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.winstl.registry.reg_value/entry.cpp + * File: reg_value/entry.cpp * * Purpose: Unit-tests for `winstl::reg_value`. * * Created: 23rd February 2009 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/winstl/registry/test.component.winstl.registry.reg_value_sequence/CMakeLists.txt b/test/component/winstl/registry/reg_value_sequence/CMakeLists.txt similarity index 100% rename from test/component/winstl/registry/test.component.winstl.registry.reg_value_sequence/CMakeLists.txt rename to test/component/winstl/registry/reg_value_sequence/CMakeLists.txt diff --git a/test/component/winstl/registry/test.component.winstl.registry.reg_value_sequence/entry.cpp b/test/component/winstl/registry/reg_value_sequence/entry.cpp similarity index 97% rename from test/component/winstl/registry/test.component.winstl.registry.reg_value_sequence/entry.cpp rename to test/component/winstl/registry/reg_value_sequence/entry.cpp index 869ce62d..2eb99011 100644 --- a/test/component/winstl/registry/test.component.winstl.registry.reg_value_sequence/entry.cpp +++ b/test/component/winstl/registry/reg_value_sequence/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.winstl.registry.reg_value_sequence/entry.cpp + * File: reg_value_sequence/entry.cpp * * Purpose: Unit-tests for `winstl::reg_value_sequence`. * * Created: 22nd October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/winstl/synch/CMakeLists.txt b/test/component/winstl/synch/CMakeLists.txt index 374ac429..d7312ce6 100644 --- a/test/component/winstl/synch/CMakeLists.txt +++ b/test/component/winstl/synch/CMakeLists.txt @@ -1,6 +1,6 @@ if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) - add_subdirectory(test.component.winstl.synch.atomic_functions) - add_subdirectory(test.component.winstl.synch.spin_mutex) + add_subdirectory(atomic_functions) + add_subdirectory(spin_mutex) endif() diff --git a/test/component/winstl/synch/test.component.winstl.synch.atomic_functions/CMakeLists.txt b/test/component/winstl/synch/atomic_functions/CMakeLists.txt similarity index 100% rename from test/component/winstl/synch/test.component.winstl.synch.atomic_functions/CMakeLists.txt rename to test/component/winstl/synch/atomic_functions/CMakeLists.txt diff --git a/test/component/winstl/synch/test.component.winstl.synch.atomic_functions/entry.cpp b/test/component/winstl/synch/atomic_functions/entry.cpp similarity index 99% rename from test/component/winstl/synch/test.component.winstl.synch.atomic_functions/entry.cpp rename to test/component/winstl/synch/atomic_functions/entry.cpp index b2ab16c5..7da50c67 100644 --- a/test/component/winstl/synch/test.component.winstl.synch.atomic_functions/entry.cpp +++ b/test/component/winstl/synch/atomic_functions/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.winstl.synch.atomic_functions/entry.cpp + * File: atomic_functions/entry.cpp * * Purpose: Component test for WinSTL atomic_functions. * * Created: sometime in 2015 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/winstl/synch/test.component.winstl.synch.spin_mutex/CMakeLists.txt b/test/component/winstl/synch/spin_mutex/CMakeLists.txt similarity index 100% rename from test/component/winstl/synch/test.component.winstl.synch.spin_mutex/CMakeLists.txt rename to test/component/winstl/synch/spin_mutex/CMakeLists.txt diff --git a/test/component/winstl/synch/test.component.winstl.synch.spin_mutex/entry.cpp b/test/component/winstl/synch/spin_mutex/entry.cpp similarity index 99% rename from test/component/winstl/synch/test.component.winstl.synch.spin_mutex/entry.cpp rename to test/component/winstl/synch/spin_mutex/entry.cpp index 8fb879d5..58deca61 100644 --- a/test/component/winstl/synch/test.component.winstl.synch.spin_mutex/entry.cpp +++ b/test/component/winstl/synch/spin_mutex/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.winstl.synch.spin_mutex/entry.cpp + * File: spin_mutex/entry.cpp * * Purpose: Component test for `winstl::spin_mutex`. * * Created: sometime in 2015 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/winstl/system/CMakeLists.txt b/test/component/winstl/system/CMakeLists.txt index 22f73f43..f200ec6e 100644 --- a/test/component/winstl/system/CMakeLists.txt +++ b/test/component/winstl/system/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.component.winstl.system.directory_functions) +add_subdirectory(directory_functions) diff --git a/test/component/winstl/system/test.component.winstl.system.directory_functions/CMakeLists.txt b/test/component/winstl/system/directory_functions/CMakeLists.txt similarity index 100% rename from test/component/winstl/system/test.component.winstl.system.directory_functions/CMakeLists.txt rename to test/component/winstl/system/directory_functions/CMakeLists.txt diff --git a/test/component/winstl/system/test.component.winstl.system.directory_functions/entry.cpp b/test/component/winstl/system/directory_functions/entry.cpp similarity index 98% rename from test/component/winstl/system/test.component.winstl.system.directory_functions/entry.cpp rename to test/component/winstl/system/directory_functions/entry.cpp index 58a9e961..42d65f28 100644 --- a/test/component/winstl/system/test.component.winstl.system.directory_functions/entry.cpp +++ b/test/component/winstl/system/directory_functions/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.winstl.system.directory_functions/entry.cpp + * File: directory_functions/entry.cpp * * Purpose: Component test for WinSTL atomic_functions. * * Created: sometime in 2015 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/performance/CMakeLists.txt b/test/performance/CMakeLists.txt index 1e025c0e..22d6592b 100644 --- a/test/performance/CMakeLists.txt +++ b/test/performance/CMakeLists.txt @@ -1,24 +1,6 @@ -if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) - - add_subdirectory(test.performance.platformstl.stopwatch) -endif() - -if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2014) - - add_subdirectory(test.performance.stlsoft.auto_buffer) -endif() - -if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) - - add_subdirectory(test.performance.stlsoft.conversion.integer_to_string) - add_subdirectory(test.performance.stlsoft.count_digits) - add_subdirectory(test.performance.stlsoft.doomgram) - add_subdirectory(test.performance.stlsoft.frequency_map) - add_subdirectory(test.performance.stlsoft.gram_utils) - add_subdirectory(test.performance.stlsoft.simple_string.compare) - add_subdirectory(test.performance.stlsoft.simple_string.op_eq) -endif() +add_subdirectory(platformstl) +add_subdirectory(stlsoft) # ############################## end of file ############################# # diff --git a/test/performance/platformstl/CMakeLists.txt b/test/performance/platformstl/CMakeLists.txt new file mode 100644 index 00000000..8a495afb --- /dev/null +++ b/test/performance/platformstl/CMakeLists.txt @@ -0,0 +1,5 @@ +add_subdirectory(diagnostics) + + +# ############################## end of file ############################# # + diff --git a/test/performance/platformstl/diagnostics/CMakeLists.txt b/test/performance/platformstl/diagnostics/CMakeLists.txt new file mode 100644 index 00000000..285002d8 --- /dev/null +++ b/test/performance/platformstl/diagnostics/CMakeLists.txt @@ -0,0 +1,8 @@ +if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) + + add_subdirectory(stopwatch) +endif() + + +# ############################## end of file ############################# # + diff --git a/test/performance/test.performance.platformstl.stopwatch/CMakeLists.txt b/test/performance/platformstl/diagnostics/stopwatch/CMakeLists.txt similarity index 100% rename from test/performance/test.performance.platformstl.stopwatch/CMakeLists.txt rename to test/performance/platformstl/diagnostics/stopwatch/CMakeLists.txt diff --git a/test/performance/test.performance.platformstl.stopwatch/main.cpp b/test/performance/platformstl/diagnostics/stopwatch/main.cpp similarity index 99% rename from test/performance/test.performance.platformstl.stopwatch/main.cpp rename to test/performance/platformstl/diagnostics/stopwatch/main.cpp index c58ebdec..b448478b 100644 --- a/test/performance/test.performance.platformstl.stopwatch/main.cpp +++ b/test/performance/platformstl/diagnostics/stopwatch/main.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.performance.platformstl.stopwatch/main.cpp + * File: stopwatch/main.cpp * * Purpose: Perf-test for stopwatch types. * * Created: 15th March 2024 - * Updated: 16th December 2024 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/performance/stlsoft/CMakeLists.txt b/test/performance/stlsoft/CMakeLists.txt new file mode 100644 index 00000000..9c1cdd1c --- /dev/null +++ b/test/performance/stlsoft/CMakeLists.txt @@ -0,0 +1,10 @@ +add_subdirectory(containers) +add_subdirectory(conversion) +add_subdirectory(diagnostics) +add_subdirectory(memory) +add_subdirectory(string) +add_subdirectory(util) + + +# ############################## end of file ############################# # + diff --git a/test/performance/stlsoft/containers/CMakeLists.txt b/test/performance/stlsoft/containers/CMakeLists.txt new file mode 100644 index 00000000..04444ab8 --- /dev/null +++ b/test/performance/stlsoft/containers/CMakeLists.txt @@ -0,0 +1,8 @@ +if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) + + add_subdirectory(frequency_map) +endif() + + +# ############################## end of file ############################# # + diff --git a/test/performance/test.performance.stlsoft.frequency_map/CMakeLists.txt b/test/performance/stlsoft/containers/frequency_map/CMakeLists.txt similarity index 100% rename from test/performance/test.performance.stlsoft.frequency_map/CMakeLists.txt rename to test/performance/stlsoft/containers/frequency_map/CMakeLists.txt diff --git a/test/performance/test.performance.stlsoft.frequency_map/main.cpp b/test/performance/stlsoft/containers/frequency_map/main.cpp similarity index 99% rename from test/performance/test.performance.stlsoft.frequency_map/main.cpp rename to test/performance/stlsoft/containers/frequency_map/main.cpp index a4238a64..7471d7da 100644 --- a/test/performance/test.performance.stlsoft.frequency_map/main.cpp +++ b/test/performance/stlsoft/containers/frequency_map/main.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.performance.stlsoft.frequency_map/main.cpp + * File: frequency_map/main.cpp * * Purpose: Perf-test for `stlsoft::frequency_map<>`. * * Created: 5th October 2024 - * Updated: 17th December 2024 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/performance/stlsoft/conversion/CMakeLists.txt b/test/performance/stlsoft/conversion/CMakeLists.txt new file mode 100644 index 00000000..1fa73651 --- /dev/null +++ b/test/performance/stlsoft/conversion/CMakeLists.txt @@ -0,0 +1,8 @@ +if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) + + add_subdirectory(integer_to_string) +endif() + + +# ############################## end of file ############################# # + diff --git a/test/performance/test.performance.stlsoft.conversion.integer_to_string/CMakeLists.txt b/test/performance/stlsoft/conversion/integer_to_string/CMakeLists.txt similarity index 100% rename from test/performance/test.performance.stlsoft.conversion.integer_to_string/CMakeLists.txt rename to test/performance/stlsoft/conversion/integer_to_string/CMakeLists.txt diff --git a/test/performance/test.performance.stlsoft.conversion.integer_to_string/main.cpp b/test/performance/stlsoft/conversion/integer_to_string/main.cpp similarity index 99% rename from test/performance/test.performance.stlsoft.conversion.integer_to_string/main.cpp rename to test/performance/stlsoft/conversion/integer_to_string/main.cpp index 43e81c8d..f0e74748 100644 --- a/test/performance/test.performance.stlsoft.conversion.integer_to_string/main.cpp +++ b/test/performance/stlsoft/conversion/integer_to_string/main.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.performance.stlsoft.conversion.integer_to_string/main.cpp + * File: integer_to_string/main.cpp * * Purpose: Perf-test for `stlsoft::integer_to_string<>`. * * Created: 29th October 2016 - * Updated: 29th May 2025 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/performance/stlsoft/diagnostics/CMakeLists.txt b/test/performance/stlsoft/diagnostics/CMakeLists.txt new file mode 100644 index 00000000..e87573f7 --- /dev/null +++ b/test/performance/stlsoft/diagnostics/CMakeLists.txt @@ -0,0 +1,9 @@ +if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) + + add_subdirectory(doomgram) + add_subdirectory(gram_utils) +endif() + + +# ############################## end of file ############################# # + diff --git a/test/performance/test.performance.stlsoft.doomgram/CMakeLists.txt b/test/performance/stlsoft/diagnostics/doomgram/CMakeLists.txt similarity index 100% rename from test/performance/test.performance.stlsoft.doomgram/CMakeLists.txt rename to test/performance/stlsoft/diagnostics/doomgram/CMakeLists.txt diff --git a/test/performance/test.performance.stlsoft.doomgram/main.cpp b/test/performance/stlsoft/diagnostics/doomgram/main.cpp similarity index 99% rename from test/performance/test.performance.stlsoft.doomgram/main.cpp rename to test/performance/stlsoft/diagnostics/doomgram/main.cpp index 8b7e4e12..58077af3 100644 --- a/test/performance/test.performance.stlsoft.doomgram/main.cpp +++ b/test/performance/stlsoft/diagnostics/doomgram/main.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.performance.stlsoft.doomgram/main.cpp + * File: doomgram/main.cpp * * Purpose: Perf-test for `stlsoft::doomgram<>`. * * Created: 11th December 2024 - * Updated: 17th December 2024 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/performance/test.performance.stlsoft.gram_utils/CMakeLists.txt b/test/performance/stlsoft/diagnostics/gram_utils/CMakeLists.txt similarity index 100% rename from test/performance/test.performance.stlsoft.gram_utils/CMakeLists.txt rename to test/performance/stlsoft/diagnostics/gram_utils/CMakeLists.txt diff --git a/test/performance/test.performance.stlsoft.gram_utils/main.cpp b/test/performance/stlsoft/diagnostics/gram_utils/main.cpp similarity index 96% rename from test/performance/test.performance.stlsoft.gram_utils/main.cpp rename to test/performance/stlsoft/diagnostics/gram_utils/main.cpp index 4b070b6c..90cab694 100644 --- a/test/performance/test.performance.stlsoft.gram_utils/main.cpp +++ b/test/performance/stlsoft/diagnostics/gram_utils/main.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.performance.stlsoft.gram_utils/main.cpp + * File: gram_utils/main.cpp * * Purpose: Perf-test for gram_utils * * Created: 17th December 2024 - * Updated: 19th December 2024 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/performance/stlsoft/memory/CMakeLists.txt b/test/performance/stlsoft/memory/CMakeLists.txt new file mode 100644 index 00000000..142d1837 --- /dev/null +++ b/test/performance/stlsoft/memory/CMakeLists.txt @@ -0,0 +1,8 @@ +if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2014) + + add_subdirectory(auto_buffer) +endif() + + +# ############################## end of file ############################# # + diff --git a/test/performance/test.performance.stlsoft.auto_buffer/CMakeLists.txt b/test/performance/stlsoft/memory/auto_buffer/CMakeLists.txt similarity index 100% rename from test/performance/test.performance.stlsoft.auto_buffer/CMakeLists.txt rename to test/performance/stlsoft/memory/auto_buffer/CMakeLists.txt diff --git a/test/performance/test.performance.stlsoft.auto_buffer/main.cpp b/test/performance/stlsoft/memory/auto_buffer/main.cpp similarity index 99% rename from test/performance/test.performance.stlsoft.auto_buffer/main.cpp rename to test/performance/stlsoft/memory/auto_buffer/main.cpp index 5f094b61..40d5354b 100644 --- a/test/performance/test.performance.stlsoft.auto_buffer/main.cpp +++ b/test/performance/stlsoft/memory/auto_buffer/main.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.performance.stlsoft.auto_buffer/main.cpp + * File: auto_buffer/main.cpp * * Purpose: Perf-test for `stlsoft::auto_buffer<>`. * * Created: ... mid 2010s ... - * Updated: 29th JuneMay 2025 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/performance/stlsoft/string/CMakeLists.txt b/test/performance/stlsoft/string/CMakeLists.txt new file mode 100644 index 00000000..f7818ca7 --- /dev/null +++ b/test/performance/stlsoft/string/CMakeLists.txt @@ -0,0 +1,9 @@ +if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) + + add_subdirectory(simple_string.compare) + add_subdirectory(simple_string.op_eq) +endif() + + +# ############################## end of file ############################# # + diff --git a/test/performance/test.performance.stlsoft.simple_string.compare/CMakeLists.txt b/test/performance/stlsoft/string/simple_string.compare/CMakeLists.txt similarity index 100% rename from test/performance/test.performance.stlsoft.simple_string.compare/CMakeLists.txt rename to test/performance/stlsoft/string/simple_string.compare/CMakeLists.txt diff --git a/test/performance/test.performance.stlsoft.simple_string.compare/main.cpp b/test/performance/stlsoft/string/simple_string.compare/main.cpp similarity index 99% rename from test/performance/test.performance.stlsoft.simple_string.compare/main.cpp rename to test/performance/stlsoft/string/simple_string.compare/main.cpp index 2dfa0ce3..d3d4e212 100644 --- a/test/performance/test.performance.stlsoft.simple_string.compare/main.cpp +++ b/test/performance/stlsoft/string/simple_string.compare/main.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.performance.stlsoft.simple_string.compare/main.cpp + * File: simple_string.compare/main.cpp * * Purpose: Perf-test for `stlsoft::basic_simple_string#compare()`. * * Created: 15th March 2024 - * Updated: 28th May 2024 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/performance/test.performance.stlsoft.simple_string.op_eq/CMakeLists.txt b/test/performance/stlsoft/string/simple_string.op_eq/CMakeLists.txt similarity index 100% rename from test/performance/test.performance.stlsoft.simple_string.op_eq/CMakeLists.txt rename to test/performance/stlsoft/string/simple_string.op_eq/CMakeLists.txt diff --git a/test/performance/test.performance.stlsoft.simple_string.op_eq/main.cpp b/test/performance/stlsoft/string/simple_string.op_eq/main.cpp similarity index 99% rename from test/performance/test.performance.stlsoft.simple_string.op_eq/main.cpp rename to test/performance/stlsoft/string/simple_string.op_eq/main.cpp index 4d5a4ca0..8ca3222d 100644 --- a/test/performance/test.performance.stlsoft.simple_string.op_eq/main.cpp +++ b/test/performance/stlsoft/string/simple_string.op_eq/main.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.performance.stlsoft.simple_string.op_eq/main.cpp + * File: simple_string.op_eq/main.cpp * * Purpose: Perf-test for `stlsoft::basic_simple_string#operator ==()`. * * Created: 15th March 2024 - * Updated: 28th May 2024 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/performance/stlsoft/util/CMakeLists.txt b/test/performance/stlsoft/util/CMakeLists.txt new file mode 100644 index 00000000..e4cf965b --- /dev/null +++ b/test/performance/stlsoft/util/CMakeLists.txt @@ -0,0 +1,8 @@ +if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) + + add_subdirectory(count_digits) +endif() + + +# ############################## end of file ############################# # + diff --git a/test/performance/test.performance.stlsoft.count_digits/CMakeLists.txt b/test/performance/stlsoft/util/count_digits/CMakeLists.txt similarity index 100% rename from test/performance/test.performance.stlsoft.count_digits/CMakeLists.txt rename to test/performance/stlsoft/util/count_digits/CMakeLists.txt diff --git a/test/performance/test.performance.stlsoft.count_digits/main.cpp b/test/performance/stlsoft/util/count_digits/main.cpp similarity index 98% rename from test/performance/test.performance.stlsoft.count_digits/main.cpp rename to test/performance/stlsoft/util/count_digits/main.cpp index fbeaa792..72f2fa81 100644 --- a/test/performance/test.performance.stlsoft.count_digits/main.cpp +++ b/test/performance/stlsoft/util/count_digits/main.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.performance.stlsoft.count_digits/main.cpp + * File: count_digits/main.cpp * * Purpose: Perf-test for digit-counting functions. * * Created: 18th December 2024 - * Updated: 18th December 2024 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/scratch/platformstl/system/CMakeLists.txt b/test/scratch/platformstl/system/CMakeLists.txt index a3c4191d..f200ec6e 100644 --- a/test/scratch/platformstl/system/CMakeLists.txt +++ b/test/scratch/platformstl/system/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.scratch.platformstl.system.directory_functions) +add_subdirectory(directory_functions) diff --git a/test/scratch/platformstl/system/test.scratch.platformstl.system.directory_functions/CMakeLists.txt b/test/scratch/platformstl/system/directory_functions/CMakeLists.txt similarity index 100% rename from test/scratch/platformstl/system/test.scratch.platformstl.system.directory_functions/CMakeLists.txt rename to test/scratch/platformstl/system/directory_functions/CMakeLists.txt diff --git a/test/scratch/platformstl/system/test.scratch.platformstl.system.directory_functions/main.cpp b/test/scratch/platformstl/system/directory_functions/main.cpp similarity index 100% rename from test/scratch/platformstl/system/test.scratch.platformstl.system.directory_functions/main.cpp rename to test/scratch/platformstl/system/directory_functions/main.cpp diff --git a/test/scratch/stlsoft/cccap/CMakeLists.txt b/test/scratch/stlsoft/cccap/CMakeLists.txt index 3b1da3e2..a9127136 100644 --- a/test/scratch/stlsoft/cccap/CMakeLists.txt +++ b/test/scratch/stlsoft/cccap/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.scratch.stlsoft.cccap.distinct_integer_types) +add_subdirectory(distinct_integer_types) diff --git a/test/scratch/stlsoft/cccap/test.scratch.stlsoft.cccap.distinct_integer_types/CMakeLists.txt b/test/scratch/stlsoft/cccap/distinct_integer_types/CMakeLists.txt similarity index 100% rename from test/scratch/stlsoft/cccap/test.scratch.stlsoft.cccap.distinct_integer_types/CMakeLists.txt rename to test/scratch/stlsoft/cccap/distinct_integer_types/CMakeLists.txt diff --git a/test/scratch/stlsoft/cccap/test.scratch.stlsoft.cccap.distinct_integer_types/main.cpp b/test/scratch/stlsoft/cccap/distinct_integer_types/main.cpp similarity index 100% rename from test/scratch/stlsoft/cccap/test.scratch.stlsoft.cccap.distinct_integer_types/main.cpp rename to test/scratch/stlsoft/cccap/distinct_integer_types/main.cpp diff --git a/test/scratch/stlsoft/conversion/CMakeLists.txt b/test/scratch/stlsoft/conversion/CMakeLists.txt index e6257271..5f6fe6d5 100644 --- a/test/scratch/stlsoft/conversion/CMakeLists.txt +++ b/test/scratch/stlsoft/conversion/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.scratch.stlsoft.conversion.itoslice) +add_subdirectory(itoslice) diff --git a/test/scratch/stlsoft/conversion/test.scratch.stlsoft.conversion.itoslice/CMakeLists.txt b/test/scratch/stlsoft/conversion/itoslice/CMakeLists.txt similarity index 100% rename from test/scratch/stlsoft/conversion/test.scratch.stlsoft.conversion.itoslice/CMakeLists.txt rename to test/scratch/stlsoft/conversion/itoslice/CMakeLists.txt diff --git a/test/scratch/stlsoft/conversion/test.scratch.stlsoft.conversion.itoslice/main.c b/test/scratch/stlsoft/conversion/itoslice/main.c similarity index 97% rename from test/scratch/stlsoft/conversion/test.scratch.stlsoft.conversion.itoslice/main.c rename to test/scratch/stlsoft/conversion/itoslice/main.c index fc29b581..91eb9c78 100644 --- a/test/scratch/stlsoft/conversion/test.scratch.stlsoft.conversion.itoslice/main.c +++ b/test/scratch/stlsoft/conversion/itoslice/main.c @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: itoslice.c + * File: itoslice/main.c * * Purpose: Scratch test for `stlsoft_C_itoslice_a()` etc. * * Created: 18th December 2016 - * Updated: 30th May 2025 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/scratch/unixstl/synch/CMakeLists.txt b/test/scratch/unixstl/synch/CMakeLists.txt index 453f75cb..3600b1e1 100644 --- a/test/scratch/unixstl/synch/CMakeLists.txt +++ b/test/scratch/unixstl/synch/CMakeLists.txt @@ -2,6 +2,6 @@ if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) if(UNIX) - add_subdirectory(test.scratch.unixstl.synch.semaphore) + add_subdirectory(semaphore) endif(UNIX) endif() diff --git a/test/scratch/unixstl/synch/test.scratch.unixstl.synch.semaphore/CMakeLists.txt b/test/scratch/unixstl/synch/semaphore/CMakeLists.txt similarity index 100% rename from test/scratch/unixstl/synch/test.scratch.unixstl.synch.semaphore/CMakeLists.txt rename to test/scratch/unixstl/synch/semaphore/CMakeLists.txt diff --git a/test/scratch/unixstl/synch/test.scratch.unixstl.synch.semaphore/main.cpp b/test/scratch/unixstl/synch/semaphore/main.cpp similarity index 100% rename from test/scratch/unixstl/synch/test.scratch.unixstl.synch.semaphore/main.cpp rename to test/scratch/unixstl/synch/semaphore/main.cpp diff --git a/test/scratch/unixstl/system/CMakeLists.txt b/test/scratch/unixstl/system/CMakeLists.txt index 3b2fccec..a718aec9 100644 --- a/test/scratch/unixstl/system/CMakeLists.txt +++ b/test/scratch/unixstl/system/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.scratch.unixstl.system.get_console_width) +add_subdirectory(get_console_width) diff --git a/test/scratch/unixstl/system/test.scratch.unixstl.system.get_console_width/CMakeLists.txt b/test/scratch/unixstl/system/get_console_width/CMakeLists.txt similarity index 100% rename from test/scratch/unixstl/system/test.scratch.unixstl.system.get_console_width/CMakeLists.txt rename to test/scratch/unixstl/system/get_console_width/CMakeLists.txt diff --git a/test/scratch/unixstl/system/test.scratch.unixstl.system.get_console_width/main.c b/test/scratch/unixstl/system/get_console_width/main.c similarity index 100% rename from test/scratch/unixstl/system/test.scratch.unixstl.system.get_console_width/main.c rename to test/scratch/unixstl/system/get_console_width/main.c diff --git a/test/scratch/winstl/diagnostics/CMakeLists.txt b/test/scratch/winstl/diagnostics/CMakeLists.txt index 454c72ec..f63ab0bd 100644 --- a/test/scratch/winstl/diagnostics/CMakeLists.txt +++ b/test/scratch/winstl/diagnostics/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.scratch.winstl.diagnostics.output_debug_line.C) +add_subdirectory(output_debug_line.C) diff --git a/test/scratch/winstl/diagnostics/test.scratch.winstl.diagnostics.output_debug_line.C/CMakeLists.txt b/test/scratch/winstl/diagnostics/output_debug_line.C/CMakeLists.txt similarity index 100% rename from test/scratch/winstl/diagnostics/test.scratch.winstl.diagnostics.output_debug_line.C/CMakeLists.txt rename to test/scratch/winstl/diagnostics/output_debug_line.C/CMakeLists.txt diff --git a/test/scratch/winstl/diagnostics/test.scratch.winstl.diagnostics.output_debug_line.C/main.c b/test/scratch/winstl/diagnostics/output_debug_line.C/main.c similarity index 91% rename from test/scratch/winstl/diagnostics/test.scratch.winstl.diagnostics.output_debug_line.C/main.c rename to test/scratch/winstl/diagnostics/output_debug_line.C/main.c index 8265440f..fd400a8e 100644 --- a/test/scratch/winstl/diagnostics/test.scratch.winstl.diagnostics.output_debug_line.C/main.c +++ b/test/scratch/winstl/diagnostics/output_debug_line.C/main.c @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.scratch.winstl.diagnostics.C.output_debug_line.c + * File: output_debug_line.C/main.c * * Purpose: Scratch test for `winstl_C_diagnostics_output_debug_line_1_m()`, etc. * * Created: 5th January 2011 - * Updated: 23rd August 2025 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/scratch/winstl/synch/CMakeLists.txt b/test/scratch/winstl/synch/CMakeLists.txt index 27d1f377..12e0713f 100644 --- a/test/scratch/winstl/synch/CMakeLists.txt +++ b/test/scratch/winstl/synch/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.scratch.winstl.micro_sleep) +add_subdirectory(micro_sleep) diff --git a/test/scratch/winstl/synch/test.scratch.winstl.micro_sleep/CMakeLists.txt b/test/scratch/winstl/synch/micro_sleep/CMakeLists.txt similarity index 100% rename from test/scratch/winstl/synch/test.scratch.winstl.micro_sleep/CMakeLists.txt rename to test/scratch/winstl/synch/micro_sleep/CMakeLists.txt diff --git a/test/scratch/winstl/synch/test.scratch.winstl.micro_sleep/main.cpp b/test/scratch/winstl/synch/micro_sleep/main.cpp similarity index 100% rename from test/scratch/winstl/synch/test.scratch.winstl.micro_sleep/main.cpp rename to test/scratch/winstl/synch/micro_sleep/main.cpp diff --git a/test/scratch/winstl/system/CMakeLists.txt b/test/scratch/winstl/system/CMakeLists.txt index 22268e72..f074cdb1 100644 --- a/test/scratch/winstl/system/CMakeLists.txt +++ b/test/scratch/winstl/system/CMakeLists.txt @@ -1,3 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.scratch.winstl.system.console_functions.C) -add_subdirectory(test.scratch.winstl.system.versions) +add_subdirectory(console_functions.C) +add_subdirectory(versions) diff --git a/test/scratch/winstl/system/test.scratch.winstl.system.console_functions.C/CMakeLists.txt b/test/scratch/winstl/system/console_functions.C/CMakeLists.txt similarity index 100% rename from test/scratch/winstl/system/test.scratch.winstl.system.console_functions.C/CMakeLists.txt rename to test/scratch/winstl/system/console_functions.C/CMakeLists.txt diff --git a/test/scratch/winstl/system/test.scratch.winstl.system.console_functions.C/main.c b/test/scratch/winstl/system/console_functions.C/main.c similarity index 100% rename from test/scratch/winstl/system/test.scratch.winstl.system.console_functions.C/main.c rename to test/scratch/winstl/system/console_functions.C/main.c diff --git a/test/scratch/winstl/system/test.scratch.winstl.system.versions/CMakeLists.txt b/test/scratch/winstl/system/versions/CMakeLists.txt similarity index 100% rename from test/scratch/winstl/system/test.scratch.winstl.system.versions/CMakeLists.txt rename to test/scratch/winstl/system/versions/CMakeLists.txt diff --git a/test/scratch/winstl/system/test.scratch.winstl.system.versions/main.cpp b/test/scratch/winstl/system/versions/main.cpp similarity index 100% rename from test/scratch/winstl/system/test.scratch.winstl.system.versions/main.cpp rename to test/scratch/winstl/system/versions/main.cpp diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index efbe40c7..abe0463e 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -24,7 +24,7 @@ if(_BUILD_AS_WIN32) add_subdirectory(winstl) endif(_BUILD_AS_WIN32) -add_subdirectory(test.unit.versions) +add_subdirectory(versions) # ############################## end of file ############################# # diff --git a/test/unit/acestl/shims/access/string/CMakeLists.txt b/test/unit/acestl/shims/access/string/CMakeLists.txt index 5418729f..59d8244b 100644 --- a/test/unit/acestl/shims/access/string/CMakeLists.txt +++ b/test/unit/acestl/shims/access/string/CMakeLists.txt @@ -1,5 +1,5 @@ -add_subdirectory(test.unit.acestl.shims.access.string.string_base) -add_subdirectory(test.unit.acestl.shims.access.string.time_value) +add_subdirectory(string_base) +add_subdirectory(time_value) # ############################## end of file ############################# # diff --git a/test/unit/acestl/shims/access/string/test.unit.acestl.shims.access.string.string_base/CMakeLists.txt b/test/unit/acestl/shims/access/string/string_base/CMakeLists.txt similarity index 100% rename from test/unit/acestl/shims/access/string/test.unit.acestl.shims.access.string.string_base/CMakeLists.txt rename to test/unit/acestl/shims/access/string/string_base/CMakeLists.txt diff --git a/test/unit/acestl/shims/access/string/test.unit.acestl.shims.access.string.string_base/entry.cpp b/test/unit/acestl/shims/access/string/string_base/entry.cpp similarity index 96% rename from test/unit/acestl/shims/access/string/test.unit.acestl.shims.access.string.string_base/entry.cpp rename to test/unit/acestl/shims/access/string/string_base/entry.cpp index 48a8dd71..b9444092 100644 --- a/test/unit/acestl/shims/access/string/test.unit.acestl.shims.access.string.string_base/entry.cpp +++ b/test/unit/acestl/shims/access/string/string_base/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.acestl.shims.access.string.string_base/entry.cpp + * File: string_base/entry.cpp * * Purpose: Unit-tests for string-access-shims for `ACE_String_Base`. * * Created: 7th August 2026 - * Updated: 7th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/acestl/shims/access/string/test.unit.acestl.shims.access.string.time_value/CMakeLists.txt b/test/unit/acestl/shims/access/string/time_value/CMakeLists.txt similarity index 100% rename from test/unit/acestl/shims/access/string/test.unit.acestl.shims.access.string.time_value/CMakeLists.txt rename to test/unit/acestl/shims/access/string/time_value/CMakeLists.txt diff --git a/test/unit/acestl/shims/access/string/test.unit.acestl.shims.access.string.time_value/entry.cpp b/test/unit/acestl/shims/access/string/time_value/entry.cpp similarity index 97% rename from test/unit/acestl/shims/access/string/test.unit.acestl.shims.access.string.time_value/entry.cpp rename to test/unit/acestl/shims/access/string/time_value/entry.cpp index 9d38d457..569ef828 100644 --- a/test/unit/acestl/shims/access/string/test.unit.acestl.shims.access.string.time_value/entry.cpp +++ b/test/unit/acestl/shims/access/string/time_value/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.acestl.shims.access.string.time_value/entry.cpp + * File: time_value/entry.cpp * * Purpose: Unit-tests for string-access-shims for `ACE_Time_Value`. * * Created: 7th August 2026 - * Updated: 7th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/comstl/memory/CMakeLists.txt b/test/unit/comstl/memory/CMakeLists.txt index 1665552f..80f4aeaf 100644 --- a/test/unit/comstl/memory/CMakeLists.txt +++ b/test/unit/comstl/memory/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.comstl.memory.task_allocator) +add_subdirectory(task_allocator) diff --git a/test/unit/comstl/memory/test.unit.comstl.memory.task_allocator/CMakeLists.txt b/test/unit/comstl/memory/task_allocator/CMakeLists.txt similarity index 100% rename from test/unit/comstl/memory/test.unit.comstl.memory.task_allocator/CMakeLists.txt rename to test/unit/comstl/memory/task_allocator/CMakeLists.txt diff --git a/test/unit/comstl/memory/test.unit.comstl.memory.task_allocator/entry.cpp b/test/unit/comstl/memory/task_allocator/entry.cpp similarity index 96% rename from test/unit/comstl/memory/test.unit.comstl.memory.task_allocator/entry.cpp rename to test/unit/comstl/memory/task_allocator/entry.cpp index 986b2423..acdd7c61 100644 --- a/test/unit/comstl/memory/test.unit.comstl.memory.task_allocator/entry.cpp +++ b/test/unit/comstl/memory/task_allocator/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.comstl.memory.task_allocator/entry.cpp + * File: task_allocator/entry.cpp * * Purpose: Unit-tests for `comstl::task_allocator`. * * Created: 18th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/comstl/string/test.unit.comstl.string.BSTR_functions.C/CMakeLists.txt b/test/unit/comstl/string/BSTR_functions.C/CMakeLists.txt similarity index 100% rename from test/unit/comstl/string/test.unit.comstl.string.BSTR_functions.C/CMakeLists.txt rename to test/unit/comstl/string/BSTR_functions.C/CMakeLists.txt diff --git a/test/unit/comstl/string/test.unit.comstl.string.BSTR_functions.C/entry.c b/test/unit/comstl/string/BSTR_functions.C/entry.c similarity index 98% rename from test/unit/comstl/string/test.unit.comstl.string.BSTR_functions.C/entry.c rename to test/unit/comstl/string/BSTR_functions.C/entry.c index 1b32bfeb..7436ad43 100644 --- a/test/unit/comstl/string/test.unit.comstl.string.BSTR_functions.C/entry.c +++ b/test/unit/comstl/string/BSTR_functions.C/entry.c @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.comstl.string.BSTR_functions.C/entry.c + * File: BSTR_functions.C/entry.c * * Purpose: Scratch test for BSTR functions. * * Created: 31st May 2010 - * Updated: 12th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/comstl/string/CMakeLists.txt b/test/unit/comstl/string/CMakeLists.txt index 657b0265..1c649c5c 100644 --- a/test/unit/comstl/string/CMakeLists.txt +++ b/test/unit/comstl/string/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.comstl.string.BSTR_functions.C) +add_subdirectory(BSTR_functions.C) diff --git a/test/unit/comstl/util/CMakeLists.txt b/test/unit/comstl/util/CMakeLists.txt index b170a95f..71c7ee02 100644 --- a/test/unit/comstl/util/CMakeLists.txt +++ b/test/unit/comstl/util/CMakeLists.txt @@ -1,3 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.comstl.util.GUID_functions.C) -add_subdirectory(test.unit.comstl.util.VARIANT_functions.C) +add_subdirectory(GUID_functions.C) +add_subdirectory(VARIANT_functions.C) diff --git a/test/unit/comstl/util/test.unit.comstl.util.GUID_functions.C/CMakeLists.txt b/test/unit/comstl/util/GUID_functions.C/CMakeLists.txt similarity index 100% rename from test/unit/comstl/util/test.unit.comstl.util.GUID_functions.C/CMakeLists.txt rename to test/unit/comstl/util/GUID_functions.C/CMakeLists.txt diff --git a/test/unit/comstl/util/test.unit.comstl.util.GUID_functions.C/entry.c b/test/unit/comstl/util/GUID_functions.C/entry.c similarity index 97% rename from test/unit/comstl/util/test.unit.comstl.util.GUID_functions.C/entry.c rename to test/unit/comstl/util/GUID_functions.C/entry.c index 28cea4b6..46a80006 100644 --- a/test/unit/comstl/util/test.unit.comstl.util.GUID_functions.C/entry.c +++ b/test/unit/comstl/util/GUID_functions.C/entry.c @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.comstl.util.GUID_functions.C/entry.c + * File: GUID_functions.C/entry.c * * Purpose: Scratch test for GUID functions. * * Created: 12th May 2010 - * Updated: 12th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/comstl/util/test.unit.comstl.util.VARIANT_functions.C/CMakeLists.txt b/test/unit/comstl/util/VARIANT_functions.C/CMakeLists.txt similarity index 100% rename from test/unit/comstl/util/test.unit.comstl.util.VARIANT_functions.C/CMakeLists.txt rename to test/unit/comstl/util/VARIANT_functions.C/CMakeLists.txt diff --git a/test/unit/comstl/util/test.unit.comstl.util.VARIANT_functions.C/entry.c b/test/unit/comstl/util/VARIANT_functions.C/entry.c similarity index 99% rename from test/unit/comstl/util/test.unit.comstl.util.VARIANT_functions.C/entry.c rename to test/unit/comstl/util/VARIANT_functions.C/entry.c index 884e9f6d..afd94b4d 100644 --- a/test/unit/comstl/util/test.unit.comstl.util.VARIANT_functions.C/entry.c +++ b/test/unit/comstl/util/VARIANT_functions.C/entry.c @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.comstl.util.VARIANT_functions.C/entry.c + * File: VARIANT_functions.C/entry.c * * Purpose: Scratch test for VARIANT functions. * * Created: 26th October 2008 - * Updated: 12th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/inetstl/shims/access/string/CMakeLists.txt b/test/unit/inetstl/shims/access/string/CMakeLists.txt index 0ee3d7b5..726c60b2 100644 --- a/test/unit/inetstl/shims/access/string/CMakeLists.txt +++ b/test/unit/inetstl/shims/access/string/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.inetstl.shims.access.string.std.in_addr) +add_subdirectory(std.in_addr) diff --git a/test/unit/inetstl/shims/access/string/test.unit.inetstl.shims.access.string.std.in_addr/CMakeLists.txt b/test/unit/inetstl/shims/access/string/std.in_addr/CMakeLists.txt similarity index 100% rename from test/unit/inetstl/shims/access/string/test.unit.inetstl.shims.access.string.std.in_addr/CMakeLists.txt rename to test/unit/inetstl/shims/access/string/std.in_addr/CMakeLists.txt diff --git a/test/unit/inetstl/shims/access/string/test.unit.inetstl.shims.access.string.std.in_addr/entry.cpp b/test/unit/inetstl/shims/access/string/std.in_addr/entry.cpp similarity index 98% rename from test/unit/inetstl/shims/access/string/test.unit.inetstl.shims.access.string.std.in_addr/entry.cpp rename to test/unit/inetstl/shims/access/string/std.in_addr/entry.cpp index 82e834d7..c763b4fe 100644 --- a/test/unit/inetstl/shims/access/string/test.unit.inetstl.shims.access.string.std.in_addr/entry.cpp +++ b/test/unit/inetstl/shims/access/string/std.in_addr/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.inetstl.shims.access.string.std.in_addr/entry.cpp + * File: std.in_addr/entry.cpp * * Purpose: Unit-tests for string-access-shims for `struct in_addr`. * * Created: ... - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/mfcstl/memory/CMakeLists.txt b/test/unit/mfcstl/memory/CMakeLists.txt index d908f913..b2996a00 100644 --- a/test/unit/mfcstl/memory/CMakeLists.txt +++ b/test/unit/mfcstl/memory/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.mfcstl.memory.afx_allocator) +add_subdirectory(afx_allocator) diff --git a/test/unit/mfcstl/memory/test.unit.mfcstl.memory.afx_allocator/CMakeLists.txt b/test/unit/mfcstl/memory/afx_allocator/CMakeLists.txt similarity index 100% rename from test/unit/mfcstl/memory/test.unit.mfcstl.memory.afx_allocator/CMakeLists.txt rename to test/unit/mfcstl/memory/afx_allocator/CMakeLists.txt diff --git a/test/unit/mfcstl/memory/test.unit.mfcstl.memory.afx_allocator/entry.cpp b/test/unit/mfcstl/memory/afx_allocator/entry.cpp similarity index 96% rename from test/unit/mfcstl/memory/test.unit.mfcstl.memory.afx_allocator/entry.cpp rename to test/unit/mfcstl/memory/afx_allocator/entry.cpp index 1d1f9631..4544d060 100644 --- a/test/unit/mfcstl/memory/test.unit.mfcstl.memory.afx_allocator/entry.cpp +++ b/test/unit/mfcstl/memory/afx_allocator/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.mfcstl.memory.afx_allocator/entry.cpp + * File: afx_allocator/entry.cpp * * Purpose: Unit-tests for `mfcstl::afx_allocator`. * * Created: 18th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/platformstl/system/CMakeLists.txt b/test/unit/platformstl/system/CMakeLists.txt index 7e199af3..42bf1f55 100644 --- a/test/unit/platformstl/system/CMakeLists.txt +++ b/test/unit/platformstl/system/CMakeLists.txt @@ -1,3 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.platformstl.system.commandline_parser) -add_subdirectory(test.unit.platformstl.system.pid_sequence) +add_subdirectory(commandline_parser) +add_subdirectory(pid_sequence) diff --git a/test/unit/platformstl/system/test.unit.platformstl.system.commandline_parser/CMakeLists.txt b/test/unit/platformstl/system/commandline_parser/CMakeLists.txt similarity index 100% rename from test/unit/platformstl/system/test.unit.platformstl.system.commandline_parser/CMakeLists.txt rename to test/unit/platformstl/system/commandline_parser/CMakeLists.txt diff --git a/test/unit/platformstl/system/test.unit.platformstl.system.commandline_parser/entry.cpp b/test/unit/platformstl/system/commandline_parser/entry.cpp similarity index 98% rename from test/unit/platformstl/system/test.unit.platformstl.system.commandline_parser/entry.cpp rename to test/unit/platformstl/system/commandline_parser/entry.cpp index ccc6c56f..b86494f2 100644 --- a/test/unit/platformstl/system/test.unit.platformstl.system.commandline_parser/entry.cpp +++ b/test/unit/platformstl/system/commandline_parser/entry.cpp @@ -1,11 +1,11 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.platformstl.system.commandline_parser/entry.cpp + * File: commandline_parser/entry.cpp * * Purpose: Unit-tests for `stlsoft::commandline_parser` / `winstl::commandline_parser`. * * Created: 29th December 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/platformstl/system/test.unit.platformstl.system.pid_sequence/CMakeLists.txt b/test/unit/platformstl/system/pid_sequence/CMakeLists.txt similarity index 100% rename from test/unit/platformstl/system/test.unit.platformstl.system.pid_sequence/CMakeLists.txt rename to test/unit/platformstl/system/pid_sequence/CMakeLists.txt diff --git a/test/unit/platformstl/system/test.unit.platformstl.system.pid_sequence/entry.cpp b/test/unit/platformstl/system/pid_sequence/entry.cpp similarity index 97% rename from test/unit/platformstl/system/test.unit.platformstl.system.pid_sequence/entry.cpp rename to test/unit/platformstl/system/pid_sequence/entry.cpp index fb1fd576..4146d642 100644 --- a/test/unit/platformstl/system/test.unit.platformstl.system.pid_sequence/entry.cpp +++ b/test/unit/platformstl/system/pid_sequence/entry.cpp @@ -1,11 +1,11 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.platformstl.system.pid_sequence/entry.cpp + * File: pid_sequence/entry.cpp * * Purpose: Unit-tests for `platformstl::pid_sequence`. * * Created: 22nd August 2025 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/api/CMakeLists.txt b/test/unit/stlsoft/api/CMakeLists.txt index 5438df91..a431f2cd 100644 --- a/test/unit/stlsoft/api/CMakeLists.txt +++ b/test/unit/stlsoft/api/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.stlsoft.api.external.string) +add_subdirectory(external.string) diff --git a/test/unit/stlsoft/api/test.unit.stlsoft.api.external.string/CMakeLists.txt b/test/unit/stlsoft/api/external.string/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/api/test.unit.stlsoft.api.external.string/CMakeLists.txt rename to test/unit/stlsoft/api/external.string/CMakeLists.txt diff --git a/test/unit/stlsoft/api/test.unit.stlsoft.api.external.string/entry.cpp b/test/unit/stlsoft/api/external.string/entry.cpp similarity index 98% rename from test/unit/stlsoft/api/test.unit.stlsoft.api.external.string/entry.cpp rename to test/unit/stlsoft/api/external.string/entry.cpp index 961a4627..d2613735 100644 --- a/test/unit/stlsoft/api/test.unit.stlsoft.api.external.string/entry.cpp +++ b/test/unit/stlsoft/api/external.string/entry.cpp @@ -1,11 +1,11 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.api.external.string/entry.cpp + * File: external.string/entry.cpp * * Purpose: Unit-tests for `stlsoft/api/external/string.h` case-insensitive * aliases (`STLSOFT_API_EXTERNAL_string_stricmp` and kin). * * Created: 17th September 2026 - * Updated: 17th September 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/containers/CMakeLists.txt b/test/unit/stlsoft/containers/CMakeLists.txt index cb8b263d..ffa72966 100644 --- a/test/unit/stlsoft/containers/CMakeLists.txt +++ b/test/unit/stlsoft/containers/CMakeLists.txt @@ -1,4 +1,4 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.stlsoft.containers.frequency_map) -add_subdirectory(test.unit.stlsoft.containers.pod_vector) -add_subdirectory(test.unit.stlsoft.containers.unicode_point_map) +add_subdirectory(frequency_map) +add_subdirectory(pod_vector) +add_subdirectory(unicode_point_map) diff --git a/test/unit/stlsoft/containers/test.unit.stlsoft.containers.frequency_map/CMakeLists.txt b/test/unit/stlsoft/containers/frequency_map/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/containers/test.unit.stlsoft.containers.frequency_map/CMakeLists.txt rename to test/unit/stlsoft/containers/frequency_map/CMakeLists.txt diff --git a/test/unit/stlsoft/containers/test.unit.stlsoft.containers.frequency_map/entry.cpp b/test/unit/stlsoft/containers/frequency_map/entry.cpp similarity index 99% rename from test/unit/stlsoft/containers/test.unit.stlsoft.containers.frequency_map/entry.cpp rename to test/unit/stlsoft/containers/frequency_map/entry.cpp index 726a56fd..b7ed0411 100644 --- a/test/unit/stlsoft/containers/test.unit.stlsoft.containers.frequency_map/entry.cpp +++ b/test/unit/stlsoft/containers/frequency_map/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.containers.frequency_map/entry.cpp + * File: frequency_map/entry.cpp * * Purpose: Unit-tests for `stlsoft::frequency_map`. * * Created: 12th February 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/containers/test.unit.stlsoft.containers.pod_vector/CMakeLists.txt b/test/unit/stlsoft/containers/pod_vector/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/containers/test.unit.stlsoft.containers.pod_vector/CMakeLists.txt rename to test/unit/stlsoft/containers/pod_vector/CMakeLists.txt diff --git a/test/unit/stlsoft/containers/test.unit.stlsoft.containers.pod_vector/entry.cpp b/test/unit/stlsoft/containers/pod_vector/entry.cpp similarity index 99% rename from test/unit/stlsoft/containers/test.unit.stlsoft.containers.pod_vector/entry.cpp rename to test/unit/stlsoft/containers/pod_vector/entry.cpp index d15a058e..864c973b 100644 --- a/test/unit/stlsoft/containers/test.unit.stlsoft.containers.pod_vector/entry.cpp +++ b/test/unit/stlsoft/containers/pod_vector/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.containers.pod_vector/entry.cpp + * File: pod_vector/entry.cpp * * Purpose: Unit-tests for `stlsoft::pod_vector` * * Created: 1st December 2008 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/containers/test.unit.stlsoft.containers.unicode_point_map/CMakeLists.txt b/test/unit/stlsoft/containers/unicode_point_map/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/containers/test.unit.stlsoft.containers.unicode_point_map/CMakeLists.txt rename to test/unit/stlsoft/containers/unicode_point_map/CMakeLists.txt diff --git a/test/unit/stlsoft/containers/test.unit.stlsoft.containers.unicode_point_map/entry.cpp b/test/unit/stlsoft/containers/unicode_point_map/entry.cpp similarity index 99% rename from test/unit/stlsoft/containers/test.unit.stlsoft.containers.unicode_point_map/entry.cpp rename to test/unit/stlsoft/containers/unicode_point_map/entry.cpp index 6ab9323e..289f1680 100644 --- a/test/unit/stlsoft/containers/test.unit.stlsoft.containers.unicode_point_map/entry.cpp +++ b/test/unit/stlsoft/containers/unicode_point_map/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.containers.unicode_point_map/entry.cpp + * File: unicode_point_map/entry.cpp * * Purpose: Unit-tests for `stlsoft::unicode_point_map`. * * Created: 5th November 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/conversion/CMakeLists.txt b/test/unit/stlsoft/conversion/CMakeLists.txt index 8f8266ec..28b6afcd 100644 --- a/test/unit/stlsoft/conversion/CMakeLists.txt +++ b/test/unit/stlsoft/conversion/CMakeLists.txt @@ -1,13 +1,13 @@ add_subdirectory(number) -add_subdirectory(test.unit.stlsoft.conversion.byte_format_functions) -add_subdirectory(test.unit.stlsoft.conversion.integer_to_base32_string) -add_subdirectory(test.unit.stlsoft.conversion.integer_to_base36_string) -add_subdirectory(test.unit.stlsoft.conversion.integer_to_lc_string) -add_subdirectory(test.unit.stlsoft.conversion.string_to_integer) -add_subdirectory(test.unit.stlsoft.conversion.truncation_test) -add_subdirectory(test.unit.stlsoft.conversion.try_parse_to) +add_subdirectory(byte_format_functions) +add_subdirectory(integer_to_base32_string) +add_subdirectory(integer_to_base36_string) +add_subdirectory(integer_to_lc_string) +add_subdirectory(string_to_integer) +add_subdirectory(truncation_test) +add_subdirectory(try_parse_to) # ############################## end of file ############################# # diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.byte_format_functions/CMakeLists.txt b/test/unit/stlsoft/conversion/byte_format_functions/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.byte_format_functions/CMakeLists.txt rename to test/unit/stlsoft/conversion/byte_format_functions/CMakeLists.txt diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.byte_format_functions/entry.cpp b/test/unit/stlsoft/conversion/byte_format_functions/entry.cpp similarity index 99% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.byte_format_functions/entry.cpp rename to test/unit/stlsoft/conversion/byte_format_functions/entry.cpp index 78cbe548..f448f46e 100644 --- a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.byte_format_functions/entry.cpp +++ b/test/unit/stlsoft/conversion/byte_format_functions/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.conversion.byte_format_functions/entry.cpp + * File: byte_format_functions/entry.cpp * * Purpose: Unit-tests for `stlsoft::basic_simple_string`. * * Created: 12th September 2019 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_base32_string/CMakeLists.txt b/test/unit/stlsoft/conversion/integer_to_base32_string/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_base32_string/CMakeLists.txt rename to test/unit/stlsoft/conversion/integer_to_base32_string/CMakeLists.txt diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_base32_string/entry.cpp b/test/unit/stlsoft/conversion/integer_to_base32_string/entry.cpp similarity index 99% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_base32_string/entry.cpp rename to test/unit/stlsoft/conversion/integer_to_base32_string/entry.cpp index 69918778..788777f9 100644 --- a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_base32_string/entry.cpp +++ b/test/unit/stlsoft/conversion/integer_to_base32_string/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.conversion.integer_to_base32_string/entry.cpp + * File: integer_to_base32_string/entry.cpp * * Purpose: Unit-tests for `stlsoft::integer_to_base32_string`. * * Created: 17th February 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_base36_string/CMakeLists.txt b/test/unit/stlsoft/conversion/integer_to_base36_string/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_base36_string/CMakeLists.txt rename to test/unit/stlsoft/conversion/integer_to_base36_string/CMakeLists.txt diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_base36_string/entry.cpp b/test/unit/stlsoft/conversion/integer_to_base36_string/entry.cpp similarity index 99% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_base36_string/entry.cpp rename to test/unit/stlsoft/conversion/integer_to_base36_string/entry.cpp index 72055e21..8f73528a 100644 --- a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_base36_string/entry.cpp +++ b/test/unit/stlsoft/conversion/integer_to_base36_string/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.conversion.integer_to_base36_string/entry.cpp + * File: integer_to_base36_string/entry.cpp * * Purpose: Unit-tests for `stlsoft::integer_to_base36_string`. * * Created: 14th February 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_lc_string/CMakeLists.txt b/test/unit/stlsoft/conversion/integer_to_lc_string/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_lc_string/CMakeLists.txt rename to test/unit/stlsoft/conversion/integer_to_lc_string/CMakeLists.txt diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_lc_string/entry.cpp b/test/unit/stlsoft/conversion/integer_to_lc_string/entry.cpp similarity index 99% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_lc_string/entry.cpp rename to test/unit/stlsoft/conversion/integer_to_lc_string/entry.cpp index 4f2db479..bd77502e 100644 --- a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.integer_to_lc_string/entry.cpp +++ b/test/unit/stlsoft/conversion/integer_to_lc_string/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.conversion.integer_to_lc_string/entry.cpp + * File: integer_to_lc_string/entry.cpp * * Purpose: Unit-tests for `stlsoft::integer_to_lc_string`. * * Created: 1st November 2011 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/conversion/number/CMakeLists.txt b/test/unit/stlsoft/conversion/number/CMakeLists.txt index 9e77c636..03d7d1e6 100644 --- a/test/unit/stlsoft/conversion/number/CMakeLists.txt +++ b/test/unit/stlsoft/conversion/number/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.stlsoft.conversion.number.group_functions) +add_subdirectory(group_functions) diff --git a/test/unit/stlsoft/conversion/number/test.unit.stlsoft.conversion.number.group_functions/CMakeLists.txt b/test/unit/stlsoft/conversion/number/group_functions/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/conversion/number/test.unit.stlsoft.conversion.number.group_functions/CMakeLists.txt rename to test/unit/stlsoft/conversion/number/group_functions/CMakeLists.txt diff --git a/test/unit/stlsoft/conversion/number/test.unit.stlsoft.conversion.number.group_functions/entry.cpp b/test/unit/stlsoft/conversion/number/group_functions/entry.cpp similarity index 99% rename from test/unit/stlsoft/conversion/number/test.unit.stlsoft.conversion.number.group_functions/entry.cpp rename to test/unit/stlsoft/conversion/number/group_functions/entry.cpp index 22a7aca4..98e12daa 100644 --- a/test/unit/stlsoft/conversion/number/test.unit.stlsoft.conversion.number.group_functions/entry.cpp +++ b/test/unit/stlsoft/conversion/number/group_functions/entry.cpp @@ -1,11 +1,11 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.conversion.number.group_functions/entry.cpp + * File: group_functions/entry.cpp * * Purpose: Unit-tests for `stlsoft::format_thousands` and * `stlsoft::translate_thousands`. * * Created: 28th March 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.string_to_integer/CMakeLists.txt b/test/unit/stlsoft/conversion/string_to_integer/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.string_to_integer/CMakeLists.txt rename to test/unit/stlsoft/conversion/string_to_integer/CMakeLists.txt diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.string_to_integer/entry.cpp b/test/unit/stlsoft/conversion/string_to_integer/entry.cpp similarity index 99% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.string_to_integer/entry.cpp rename to test/unit/stlsoft/conversion/string_to_integer/entry.cpp index a50ceb0e..c4471e1f 100644 --- a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.string_to_integer/entry.cpp +++ b/test/unit/stlsoft/conversion/string_to_integer/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.conversion.string_to_integer/entry.cpp + * File: string_to_integer/entry.cpp * * Purpose: Unit-tests for `stlsoft::string_to_integer`. * * Created: 18th November 2008 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.truncation_test/CMakeLists.txt b/test/unit/stlsoft/conversion/truncation_test/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.truncation_test/CMakeLists.txt rename to test/unit/stlsoft/conversion/truncation_test/CMakeLists.txt diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.truncation_test/entry.cpp b/test/unit/stlsoft/conversion/truncation_test/entry.cpp similarity index 99% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.truncation_test/entry.cpp rename to test/unit/stlsoft/conversion/truncation_test/entry.cpp index 0389224f..1f5f54cc 100644 --- a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.truncation_test/entry.cpp +++ b/test/unit/stlsoft/conversion/truncation_test/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.conversion.truncation_test/entry.cpp + * File: truncation_test/entry.cpp * * Purpose: Unit-tests for `stlsoft::truncation_test<>`. * * Created: 7th November 2008 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.try_parse_to/CMakeLists.txt b/test/unit/stlsoft/conversion/try_parse_to/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.try_parse_to/CMakeLists.txt rename to test/unit/stlsoft/conversion/try_parse_to/CMakeLists.txt diff --git a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.try_parse_to/entry.cpp b/test/unit/stlsoft/conversion/try_parse_to/entry.cpp similarity index 99% rename from test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.try_parse_to/entry.cpp rename to test/unit/stlsoft/conversion/try_parse_to/entry.cpp index 171445bd..096ec5b5 100644 --- a/test/unit/stlsoft/conversion/test.unit.stlsoft.conversion.try_parse_to/entry.cpp +++ b/test/unit/stlsoft/conversion/try_parse_to/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.conversion.try_parse_to/entry.cpp + * File: try_parse_to/entry.cpp * * Purpose: Unit-tests for `stlsoft::try_parse_to`. * * Created: 18th November 2008 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/diagnostics/CMakeLists.txt b/test/unit/stlsoft/diagnostics/CMakeLists.txt index 7c041a06..f693cd4b 100644 --- a/test/unit/stlsoft/diagnostics/CMakeLists.txt +++ b/test/unit/stlsoft/diagnostics/CMakeLists.txt @@ -1,3 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.stlsoft.diagnostics.doomgram) -add_subdirectory(test.unit.stlsoft.diagnostics.gram_scope) +add_subdirectory(doomgram) +add_subdirectory(gram_scope) diff --git a/test/unit/stlsoft/diagnostics/test.unit.stlsoft.diagnostics.doomgram/CMakeLists.txt b/test/unit/stlsoft/diagnostics/doomgram/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/diagnostics/test.unit.stlsoft.diagnostics.doomgram/CMakeLists.txt rename to test/unit/stlsoft/diagnostics/doomgram/CMakeLists.txt diff --git a/test/unit/stlsoft/diagnostics/test.unit.stlsoft.diagnostics.doomgram/entry.cpp b/test/unit/stlsoft/diagnostics/doomgram/entry.cpp similarity index 99% rename from test/unit/stlsoft/diagnostics/test.unit.stlsoft.diagnostics.doomgram/entry.cpp rename to test/unit/stlsoft/diagnostics/doomgram/entry.cpp index afeaae86..3114bc0e 100644 --- a/test/unit/stlsoft/diagnostics/test.unit.stlsoft.diagnostics.doomgram/entry.cpp +++ b/test/unit/stlsoft/diagnostics/doomgram/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.diagnostics.doomgram/entry.cpp + * File: doomgram/entry.cpp * * Purpose: Unit-tests for `stlsoft::doomgram`. * * Created: 13th May 2013 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/diagnostics/test.unit.stlsoft.diagnostics.gram_scope/CMakeLists.txt b/test/unit/stlsoft/diagnostics/gram_scope/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/diagnostics/test.unit.stlsoft.diagnostics.gram_scope/CMakeLists.txt rename to test/unit/stlsoft/diagnostics/gram_scope/CMakeLists.txt diff --git a/test/unit/stlsoft/diagnostics/test.unit.stlsoft.diagnostics.gram_scope/entry.cpp b/test/unit/stlsoft/diagnostics/gram_scope/entry.cpp similarity index 96% rename from test/unit/stlsoft/diagnostics/test.unit.stlsoft.diagnostics.gram_scope/entry.cpp rename to test/unit/stlsoft/diagnostics/gram_scope/entry.cpp index dd7cfe7f..44156429 100644 --- a/test/unit/stlsoft/diagnostics/test.unit.stlsoft.diagnostics.gram_scope/entry.cpp +++ b/test/unit/stlsoft/diagnostics/gram_scope/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.diagnostics.gram_scope/entry.cpp + * File: gram_scope/entry.cpp * * Purpose: Unit-tests for `stlsoft::gram_scope`. * * Created: 15th December 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/filesystem/CMakeLists.txt b/test/unit/stlsoft/filesystem/CMakeLists.txt index 4d16c4b3..6f05c694 100644 --- a/test/unit/stlsoft/filesystem/CMakeLists.txt +++ b/test/unit/stlsoft/filesystem/CMakeLists.txt @@ -1,3 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.stlsoft.filesystem.io_functions.read_line) -add_subdirectory(test.unit.stlsoft.filesystem.io_functions.write_string) +add_subdirectory(io_functions.read_line) +add_subdirectory(io_functions.write_string) diff --git a/test/unit/stlsoft/filesystem/test.unit.stlsoft.filesystem.io_functions.read_line/CMakeLists.txt b/test/unit/stlsoft/filesystem/io_functions.read_line/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/filesystem/test.unit.stlsoft.filesystem.io_functions.read_line/CMakeLists.txt rename to test/unit/stlsoft/filesystem/io_functions.read_line/CMakeLists.txt diff --git a/test/unit/stlsoft/filesystem/test.unit.stlsoft.filesystem.io_functions.read_line/entry.cpp b/test/unit/stlsoft/filesystem/io_functions.read_line/entry.cpp similarity index 99% rename from test/unit/stlsoft/filesystem/test.unit.stlsoft.filesystem.io_functions.read_line/entry.cpp rename to test/unit/stlsoft/filesystem/io_functions.read_line/entry.cpp index 150248a3..bc3c5c82 100644 --- a/test/unit/stlsoft/filesystem/test.unit.stlsoft.filesystem.io_functions.read_line/entry.cpp +++ b/test/unit/stlsoft/filesystem/io_functions.read_line/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.filesystem.io_functions.read_line/entry.cpp + * File: io_functions.read_line/entry.cpp * * Purpose: Unit-test * * Created: 11th August 2008 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/filesystem/test.unit.stlsoft.filesystem.io_functions.write_string/CMakeLists.txt b/test/unit/stlsoft/filesystem/io_functions.write_string/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/filesystem/test.unit.stlsoft.filesystem.io_functions.write_string/CMakeLists.txt rename to test/unit/stlsoft/filesystem/io_functions.write_string/CMakeLists.txt diff --git a/test/unit/stlsoft/filesystem/test.unit.stlsoft.filesystem.io_functions.write_string/entry.cpp b/test/unit/stlsoft/filesystem/io_functions.write_string/entry.cpp similarity index 98% rename from test/unit/stlsoft/filesystem/test.unit.stlsoft.filesystem.io_functions.write_string/entry.cpp rename to test/unit/stlsoft/filesystem/io_functions.write_string/entry.cpp index 24f63e1b..991a7072 100644 --- a/test/unit/stlsoft/filesystem/test.unit.stlsoft.filesystem.io_functions.write_string/entry.cpp +++ b/test/unit/stlsoft/filesystem/io_functions.write_string/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.filesystem.io_functions.write_string/entry.cpp + * File: io_functions.write_string/entry.cpp * * Purpose: Unit-tests for `stlsoft::write_string<>()`. * * Created: 22nd January 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/iterator/CMakeLists.txt b/test/unit/stlsoft/iterator/CMakeLists.txt index fc79dc7e..490e693d 100644 --- a/test/unit/stlsoft/iterator/CMakeLists.txt +++ b/test/unit/stlsoft/iterator/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.stlsoft.iterator.FILE_iterator) +add_subdirectory(FILE_iterator) diff --git a/test/unit/stlsoft/iterator/test.unit.stlsoft.iterator.FILE_iterator/CMakeLists.txt b/test/unit/stlsoft/iterator/FILE_iterator/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/iterator/test.unit.stlsoft.iterator.FILE_iterator/CMakeLists.txt rename to test/unit/stlsoft/iterator/FILE_iterator/CMakeLists.txt diff --git a/test/unit/stlsoft/iterator/test.unit.stlsoft.iterator.FILE_iterator/entry.cpp b/test/unit/stlsoft/iterator/FILE_iterator/entry.cpp similarity index 96% rename from test/unit/stlsoft/iterator/test.unit.stlsoft.iterator.FILE_iterator/entry.cpp rename to test/unit/stlsoft/iterator/FILE_iterator/entry.cpp index 0c951fa1..fc7d7561 100644 --- a/test/unit/stlsoft/iterator/test.unit.stlsoft.iterator.FILE_iterator/entry.cpp +++ b/test/unit/stlsoft/iterator/FILE_iterator/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.iterator.FILE_iterator/entry.cpp + * File: FILE_iterator/entry.cpp * * Purpose: Unit-tests for `stlsoft::FILE_iterator`. * * Created: 24th March 2025 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/limits/CMakeLists.txt b/test/unit/stlsoft/limits/CMakeLists.txt index 210778bb..74059d52 100644 --- a/test/unit/stlsoft/limits/CMakeLists.txt +++ b/test/unit/stlsoft/limits/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.stlsoft.limits.integral_limits) +add_subdirectory(integral_limits) diff --git a/test/unit/stlsoft/limits/test.unit.stlsoft.limits.integral_limits/CMakeLists.txt b/test/unit/stlsoft/limits/integral_limits/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/limits/test.unit.stlsoft.limits.integral_limits/CMakeLists.txt rename to test/unit/stlsoft/limits/integral_limits/CMakeLists.txt diff --git a/test/unit/stlsoft/limits/test.unit.stlsoft.limits.integral_limits/entry.cpp b/test/unit/stlsoft/limits/integral_limits/entry.cpp similarity index 97% rename from test/unit/stlsoft/limits/test.unit.stlsoft.limits.integral_limits/entry.cpp rename to test/unit/stlsoft/limits/integral_limits/entry.cpp index 7097753d..f9328824 100644 --- a/test/unit/stlsoft/limits/test.unit.stlsoft.limits.integral_limits/entry.cpp +++ b/test/unit/stlsoft/limits/integral_limits/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.limits.integral_limits/entry.cpp + * File: integral_limits/entry.cpp * * Purpose: Unit-tests for `stlsoft::integral_limits`. * * Created: 21st November 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/memory/CMakeLists.txt b/test/unit/stlsoft/memory/CMakeLists.txt index 473c1d3d..f1cad5a4 100644 --- a/test/unit/stlsoft/memory/CMakeLists.txt +++ b/test/unit/stlsoft/memory/CMakeLists.txt @@ -1,6 +1,6 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.stlsoft.memory.auto_buffer) -add_subdirectory(test.unit.stlsoft.memory.auto_buffer.C) -add_subdirectory(test.unit.stlsoft.memory.malloc_allocator) -add_subdirectory(test.unit.stlsoft.memory.new_allocator) -add_subdirectory(test.unit.stlsoft.memory.null_allocator) +add_subdirectory(auto_buffer) +add_subdirectory(auto_buffer.C) +add_subdirectory(malloc_allocator) +add_subdirectory(new_allocator) +add_subdirectory(null_allocator) diff --git a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.auto_buffer.C/CMakeLists.txt b/test/unit/stlsoft/memory/auto_buffer.C/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/memory/test.unit.stlsoft.memory.auto_buffer.C/CMakeLists.txt rename to test/unit/stlsoft/memory/auto_buffer.C/CMakeLists.txt diff --git a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.auto_buffer.C/entry.c b/test/unit/stlsoft/memory/auto_buffer.C/entry.c similarity index 98% rename from test/unit/stlsoft/memory/test.unit.stlsoft.memory.auto_buffer.C/entry.c rename to test/unit/stlsoft/memory/auto_buffer.C/entry.c index 9562fd91..24e5e6e7 100644 --- a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.auto_buffer.C/entry.c +++ b/test/unit/stlsoft/memory/auto_buffer.C/entry.c @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.memory.auto_buffer.C/entry.c + * File: auto_buffer.C/entry.c * * Purpose: Scratch test for `STLSOFT_C_AUTO_BUFFER()`, etc. * * Created: 5th August 2011 - * Updated: 12th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.auto_buffer/CMakeLists.txt b/test/unit/stlsoft/memory/auto_buffer/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/memory/test.unit.stlsoft.memory.auto_buffer/CMakeLists.txt rename to test/unit/stlsoft/memory/auto_buffer/CMakeLists.txt diff --git a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.auto_buffer/entry.cpp b/test/unit/stlsoft/memory/auto_buffer/entry.cpp similarity index 99% rename from test/unit/stlsoft/memory/test.unit.stlsoft.memory.auto_buffer/entry.cpp rename to test/unit/stlsoft/memory/auto_buffer/entry.cpp index fc2a9275..50cb2dcb 100644 --- a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.auto_buffer/entry.cpp +++ b/test/unit/stlsoft/memory/auto_buffer/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.memory.auto_buffer/entry.cpp + * File: auto_buffer/entry.cpp * * Purpose: Unit-tests for `stlsoft::auto_buffer`. * * Created: 25th February 2009 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.malloc_allocator/CMakeLists.txt b/test/unit/stlsoft/memory/malloc_allocator/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/memory/test.unit.stlsoft.memory.malloc_allocator/CMakeLists.txt rename to test/unit/stlsoft/memory/malloc_allocator/CMakeLists.txt diff --git a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.malloc_allocator/entry.cpp b/test/unit/stlsoft/memory/malloc_allocator/entry.cpp similarity index 96% rename from test/unit/stlsoft/memory/test.unit.stlsoft.memory.malloc_allocator/entry.cpp rename to test/unit/stlsoft/memory/malloc_allocator/entry.cpp index c11bd661..cb55838f 100644 --- a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.malloc_allocator/entry.cpp +++ b/test/unit/stlsoft/memory/malloc_allocator/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.memory.malloc_allocator/entry.cpp + * File: malloc_allocator/entry.cpp * * Purpose: Unit-tests for `stlsoft::malloc_allocator`. * * Created: 18th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.new_allocator/CMakeLists.txt b/test/unit/stlsoft/memory/new_allocator/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/memory/test.unit.stlsoft.memory.new_allocator/CMakeLists.txt rename to test/unit/stlsoft/memory/new_allocator/CMakeLists.txt diff --git a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.new_allocator/entry.cpp b/test/unit/stlsoft/memory/new_allocator/entry.cpp similarity index 96% rename from test/unit/stlsoft/memory/test.unit.stlsoft.memory.new_allocator/entry.cpp rename to test/unit/stlsoft/memory/new_allocator/entry.cpp index 531520cc..3fb2dcdd 100644 --- a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.new_allocator/entry.cpp +++ b/test/unit/stlsoft/memory/new_allocator/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.memory.new_allocator/entry.cpp + * File: new_allocator/entry.cpp * * Purpose: Unit-tests for `stlsoft::new_allocator`. * * Created: 18th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.null_allocator/CMakeLists.txt b/test/unit/stlsoft/memory/null_allocator/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/memory/test.unit.stlsoft.memory.null_allocator/CMakeLists.txt rename to test/unit/stlsoft/memory/null_allocator/CMakeLists.txt diff --git a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.null_allocator/entry.cpp b/test/unit/stlsoft/memory/null_allocator/entry.cpp similarity index 96% rename from test/unit/stlsoft/memory/test.unit.stlsoft.memory.null_allocator/entry.cpp rename to test/unit/stlsoft/memory/null_allocator/entry.cpp index 19585942..8a2c96b0 100644 --- a/test/unit/stlsoft/memory/test.unit.stlsoft.memory.null_allocator/entry.cpp +++ b/test/unit/stlsoft/memory/null_allocator/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.memory.null_allocator/entry.cpp + * File: null_allocator/entry.cpp * * Purpose: Unit-tests for `stlsoft::null_allocator`. * * Created: 18th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/smartptr/CMakeLists.txt b/test/unit/stlsoft/smartptr/CMakeLists.txt index 42724b95..74b8aef2 100644 --- a/test/unit/stlsoft/smartptr/CMakeLists.txt +++ b/test/unit/stlsoft/smartptr/CMakeLists.txt @@ -1,3 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.stlsoft.smartptr.scoped_handle) -add_subdirectory(test.unit.stlsoft.smartptr.shared_ptr) +add_subdirectory(scoped_handle) +add_subdirectory(shared_ptr) diff --git a/test/unit/stlsoft/smartptr/test.unit.stlsoft.smartptr.scoped_handle/CMakeLists.txt b/test/unit/stlsoft/smartptr/scoped_handle/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/smartptr/test.unit.stlsoft.smartptr.scoped_handle/CMakeLists.txt rename to test/unit/stlsoft/smartptr/scoped_handle/CMakeLists.txt diff --git a/test/unit/stlsoft/smartptr/test.unit.stlsoft.smartptr.scoped_handle/entry.cpp b/test/unit/stlsoft/smartptr/scoped_handle/entry.cpp similarity index 99% rename from test/unit/stlsoft/smartptr/test.unit.stlsoft.smartptr.scoped_handle/entry.cpp rename to test/unit/stlsoft/smartptr/scoped_handle/entry.cpp index 666164da..1a40cb74 100644 --- a/test/unit/stlsoft/smartptr/test.unit.stlsoft.smartptr.scoped_handle/entry.cpp +++ b/test/unit/stlsoft/smartptr/scoped_handle/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.smartptr.scoped_handle/entry.cpp + * File: scoped_handle/entry.cpp * * Purpose: Unit-tests for `stlsoft::scoped_handle`. * * Created: 16th October 2008 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/smartptr/test.unit.stlsoft.smartptr.shared_ptr/CMakeLists.txt b/test/unit/stlsoft/smartptr/shared_ptr/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/smartptr/test.unit.stlsoft.smartptr.shared_ptr/CMakeLists.txt rename to test/unit/stlsoft/smartptr/shared_ptr/CMakeLists.txt diff --git a/test/unit/stlsoft/smartptr/test.unit.stlsoft.smartptr.shared_ptr/entry.cpp b/test/unit/stlsoft/smartptr/shared_ptr/entry.cpp similarity index 99% rename from test/unit/stlsoft/smartptr/test.unit.stlsoft.smartptr.shared_ptr/entry.cpp rename to test/unit/stlsoft/smartptr/shared_ptr/entry.cpp index dd1efa65..9c3f5f61 100644 --- a/test/unit/stlsoft/smartptr/test.unit.stlsoft.smartptr.shared_ptr/entry.cpp +++ b/test/unit/stlsoft/smartptr/shared_ptr/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.smartptr.shared_ptr/entry.cpp + * File: shared_ptr/entry.cpp * * Purpose: Unit-tests for `stlsoft::shared_ptr`. * * Created: 7th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/string/CMakeLists.txt b/test/unit/stlsoft/string/CMakeLists.txt index 3e63c28e..682c6f42 100644 --- a/test/unit/stlsoft/string/CMakeLists.txt +++ b/test/unit/stlsoft/string/CMakeLists.txt @@ -1,8 +1,8 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.stlsoft.string.copy_functions) -add_subdirectory(test.unit.stlsoft.string.exception_string) -add_subdirectory(test.unit.stlsoft.string.shim_string) -add_subdirectory(test.unit.stlsoft.string.simple_string) -add_subdirectory(test.unit.stlsoft.string.static_string) -add_subdirectory(test.unit.stlsoft.string.string_slice) -add_subdirectory(test.unit.stlsoft.string.string_view) +add_subdirectory(copy_functions) +add_subdirectory(exception_string) +add_subdirectory(shim_string) +add_subdirectory(simple_string) +add_subdirectory(static_string) +add_subdirectory(string_slice) +add_subdirectory(string_view) diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.copy_functions/CMakeLists.txt b/test/unit/stlsoft/string/copy_functions/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.copy_functions/CMakeLists.txt rename to test/unit/stlsoft/string/copy_functions/CMakeLists.txt diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.copy_functions/entry.cpp b/test/unit/stlsoft/string/copy_functions/entry.cpp similarity index 99% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.copy_functions/entry.cpp rename to test/unit/stlsoft/string/copy_functions/entry.cpp index a3e9bc23..46b07197 100644 --- a/test/unit/stlsoft/string/test.unit.stlsoft.string.copy_functions/entry.cpp +++ b/test/unit/stlsoft/string/copy_functions/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.string.copy_functions/entry.cpp + * File: copy_functions/entry.cpp * * Purpose: Scratch test for string copy functions. * * Created: 29th September 2016 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.exception_string/CMakeLists.txt b/test/unit/stlsoft/string/exception_string/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.exception_string/CMakeLists.txt rename to test/unit/stlsoft/string/exception_string/CMakeLists.txt diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.exception_string/entry.cpp b/test/unit/stlsoft/string/exception_string/entry.cpp similarity index 99% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.exception_string/entry.cpp rename to test/unit/stlsoft/string/exception_string/entry.cpp index 967c90ed..311b9425 100644 --- a/test/unit/stlsoft/string/test.unit.stlsoft.string.exception_string/entry.cpp +++ b/test/unit/stlsoft/string/exception_string/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.string.exception_string/entry.cpp + * File: exception_string/entry.cpp * * Purpose: Unit-tests for `stlsoft::exception_string`. * * Created: 3rd February 2011 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.shim_string/CMakeLists.txt b/test/unit/stlsoft/string/shim_string/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.shim_string/CMakeLists.txt rename to test/unit/stlsoft/string/shim_string/CMakeLists.txt diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.shim_string/entry.cpp b/test/unit/stlsoft/string/shim_string/entry.cpp similarity index 99% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.shim_string/entry.cpp rename to test/unit/stlsoft/string/shim_string/entry.cpp index dee16d6a..15fd8628 100644 --- a/test/unit/stlsoft/string/test.unit.stlsoft.string.shim_string/entry.cpp +++ b/test/unit/stlsoft/string/shim_string/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.string.shim_string/entry.cpp + * File: shim_string/entry.cpp * * Purpose: Unit-tests for `stlsoft::basic_shim_string`. * * Created: 9th November 2008 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.simple_string/CMakeLists.txt b/test/unit/stlsoft/string/simple_string/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.simple_string/CMakeLists.txt rename to test/unit/stlsoft/string/simple_string/CMakeLists.txt diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.simple_string/entry.cpp b/test/unit/stlsoft/string/simple_string/entry.cpp similarity index 99% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.simple_string/entry.cpp rename to test/unit/stlsoft/string/simple_string/entry.cpp index 9b957a63..bc69bfd0 100644 --- a/test/unit/stlsoft/string/test.unit.stlsoft.string.simple_string/entry.cpp +++ b/test/unit/stlsoft/string/simple_string/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.string.simple_string/entry.cpp + * File: simple_string/entry.cpp * * Purpose: Unit-tests for `stlsoft::basic_simple_string`. * * Created: 4th November 2008 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.static_string/CMakeLists.txt b/test/unit/stlsoft/string/static_string/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.static_string/CMakeLists.txt rename to test/unit/stlsoft/string/static_string/CMakeLists.txt diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.static_string/entry.cpp b/test/unit/stlsoft/string/static_string/entry.cpp similarity index 99% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.static_string/entry.cpp rename to test/unit/stlsoft/string/static_string/entry.cpp index 123ca9e0..393b5f5c 100644 --- a/test/unit/stlsoft/string/test.unit.stlsoft.string.static_string/entry.cpp +++ b/test/unit/stlsoft/string/static_string/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.string.static_string/entry.cpp + * File: static_string/entry.cpp * * Purpose: Unit-tests for `stlsoft::basic_static_string`. * * Created: 4th November 2008 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.string_slice/CMakeLists.txt b/test/unit/stlsoft/string/string_slice/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.string_slice/CMakeLists.txt rename to test/unit/stlsoft/string/string_slice/CMakeLists.txt diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.string_slice/entry.cpp b/test/unit/stlsoft/string/string_slice/entry.cpp similarity index 99% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.string_slice/entry.cpp rename to test/unit/stlsoft/string/string_slice/entry.cpp index c3a8ac40..de01c365 100644 --- a/test/unit/stlsoft/string/test.unit.stlsoft.string.string_slice/entry.cpp +++ b/test/unit/stlsoft/string/string_slice/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.string.string_slice/entry.cpp + * File: string_slice/entry.cpp * * Purpose: Unit-tests for `stlsoft::basic_string_slice`. * * Created: 19th February 2010 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.string_view/CMakeLists.txt b/test/unit/stlsoft/string/string_view/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.string_view/CMakeLists.txt rename to test/unit/stlsoft/string/string_view/CMakeLists.txt diff --git a/test/unit/stlsoft/string/test.unit.stlsoft.string.string_view/entry.cpp b/test/unit/stlsoft/string/string_view/entry.cpp similarity index 99% rename from test/unit/stlsoft/string/test.unit.stlsoft.string.string_view/entry.cpp rename to test/unit/stlsoft/string/string_view/entry.cpp index 675ffca6..bc6ce4f0 100644 --- a/test/unit/stlsoft/string/test.unit.stlsoft.string.string_view/entry.cpp +++ b/test/unit/stlsoft/string/string_view/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.string.string_view/entry.cpp + * File: string_view/entry.cpp * * Purpose: Unit-tests for `stlsoft::basic_string_view`. * * Created: 4th November 2008 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/system/CMakeLists.txt b/test/unit/stlsoft/system/CMakeLists.txt index 180f1ac4..b960b977 100644 --- a/test/unit/stlsoft/system/CMakeLists.txt +++ b/test/unit/stlsoft/system/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.stlsoft.system.cmdargs) +add_subdirectory(cmdargs) diff --git a/test/unit/stlsoft/system/test.unit.stlsoft.system.cmdargs/CMakeLists.txt b/test/unit/stlsoft/system/cmdargs/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/system/test.unit.stlsoft.system.cmdargs/CMakeLists.txt rename to test/unit/stlsoft/system/cmdargs/CMakeLists.txt diff --git a/test/unit/stlsoft/system/test.unit.stlsoft.system.cmdargs/entry.cpp b/test/unit/stlsoft/system/cmdargs/entry.cpp similarity index 99% rename from test/unit/stlsoft/system/test.unit.stlsoft.system.cmdargs/entry.cpp rename to test/unit/stlsoft/system/cmdargs/entry.cpp index 4c339a99..ef22ae2d 100644 --- a/test/unit/stlsoft/system/test.unit.stlsoft.system.cmdargs/entry.cpp +++ b/test/unit/stlsoft/system/cmdargs/entry.cpp @@ -1,11 +1,11 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.system.cmdargs/entry.cpp + * File: cmdargs/entry.cpp * * Purpose: Unit-tests for `stlsoft::cmdargs`. * * Created: 29th December 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/traits/CMakeLists.txt b/test/unit/stlsoft/traits/CMakeLists.txt index e83fed35..0737db5a 100644 --- a/test/unit/stlsoft/traits/CMakeLists.txt +++ b/test/unit/stlsoft/traits/CMakeLists.txt @@ -1,3 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.stlsoft.traits.integral_printf_format_traits) -add_subdirectory(test.unit.stlsoft.traits.integral_traits) +add_subdirectory(integral_printf_format_traits) +add_subdirectory(integral_traits) diff --git a/test/unit/stlsoft/traits/test.unit.stlsoft.traits.integral_printf_format_traits/CMakeLists.txt b/test/unit/stlsoft/traits/integral_printf_format_traits/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/traits/test.unit.stlsoft.traits.integral_printf_format_traits/CMakeLists.txt rename to test/unit/stlsoft/traits/integral_printf_format_traits/CMakeLists.txt diff --git a/test/unit/stlsoft/traits/test.unit.stlsoft.traits.integral_printf_format_traits/entry.cpp b/test/unit/stlsoft/traits/integral_printf_format_traits/entry.cpp similarity index 99% rename from test/unit/stlsoft/traits/test.unit.stlsoft.traits.integral_printf_format_traits/entry.cpp rename to test/unit/stlsoft/traits/integral_printf_format_traits/entry.cpp index 3acc6924..17ac0753 100644 --- a/test/unit/stlsoft/traits/test.unit.stlsoft.traits.integral_printf_format_traits/entry.cpp +++ b/test/unit/stlsoft/traits/integral_printf_format_traits/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.traits.integral_printf_format_traits/entry.cpp + * File: integral_printf_format_traits/entry.cpp * * Purpose: Unit-tests for `stlsoft::integral_printf_format_traits`. * * Created: 20th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/traits/test.unit.stlsoft.traits.integral_traits/CMakeLists.txt b/test/unit/stlsoft/traits/integral_traits/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/traits/test.unit.stlsoft.traits.integral_traits/CMakeLists.txt rename to test/unit/stlsoft/traits/integral_traits/CMakeLists.txt diff --git a/test/unit/stlsoft/traits/test.unit.stlsoft.traits.integral_traits/entry.cpp b/test/unit/stlsoft/traits/integral_traits/entry.cpp similarity index 98% rename from test/unit/stlsoft/traits/test.unit.stlsoft.traits.integral_traits/entry.cpp rename to test/unit/stlsoft/traits/integral_traits/entry.cpp index 977dceec..cc2df103 100644 --- a/test/unit/stlsoft/traits/test.unit.stlsoft.traits.integral_traits/entry.cpp +++ b/test/unit/stlsoft/traits/integral_traits/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.traits.integral_traits/entry.cpp + * File: integral_traits/entry.cpp * * Purpose: Unit-tests for `stlsoft::integral_traits`. * * Created: 21st November 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/util/CMakeLists.txt b/test/unit/stlsoft/util/CMakeLists.txt index ad65f09a..aff0fe68 100644 --- a/test/unit/stlsoft/util/CMakeLists.txt +++ b/test/unit/stlsoft/util/CMakeLists.txt @@ -1,11 +1,11 @@ -add_subdirectory(test.unit.stlsoft.util.bit_functions) -add_subdirectory(test.unit.stlsoft.util.count_decimal_digits) -add_subdirectory(test.unit.stlsoft.util.count_hexadecimal_digits) +add_subdirectory(bit_functions) +add_subdirectory(count_decimal_digits) +add_subdirectory(count_hexadecimal_digits) if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) - add_subdirectory(test.unit.stlsoft.util.string_insertion) + add_subdirectory(string_insertion) endif() -add_subdirectory(test.unit.stlsoft.util.string.snprintf) -add_subdirectory(test.unit.stlsoft.util.string_switch) -add_subdirectory(test.unit.stlsoft.util.true_typedef) +add_subdirectory(string.snprintf) +add_subdirectory(string_switch) +add_subdirectory(true_typedef) diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.bit_functions/CMakeLists.txt b/test/unit/stlsoft/util/bit_functions/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.bit_functions/CMakeLists.txt rename to test/unit/stlsoft/util/bit_functions/CMakeLists.txt diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.bit_functions/entry.cpp b/test/unit/stlsoft/util/bit_functions/entry.cpp similarity index 99% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.bit_functions/entry.cpp rename to test/unit/stlsoft/util/bit_functions/entry.cpp index 97e2584f..6a333419 100644 --- a/test/unit/stlsoft/util/test.unit.stlsoft.util.bit_functions/entry.cpp +++ b/test/unit/stlsoft/util/bit_functions/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.util.bit_functions/entry.cpp + * File: bit_functions/entry.cpp * * Purpose: Unit-tests for `stlsoft::bit_functions`. * * Created: 19th March 2010 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.count_decimal_digits/CMakeLists.txt b/test/unit/stlsoft/util/count_decimal_digits/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.count_decimal_digits/CMakeLists.txt rename to test/unit/stlsoft/util/count_decimal_digits/CMakeLists.txt diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.count_decimal_digits/entry.cpp b/test/unit/stlsoft/util/count_decimal_digits/entry.cpp similarity index 98% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.count_decimal_digits/entry.cpp rename to test/unit/stlsoft/util/count_decimal_digits/entry.cpp index 173d480d..d2a4db08 100644 --- a/test/unit/stlsoft/util/test.unit.stlsoft.util.count_decimal_digits/entry.cpp +++ b/test/unit/stlsoft/util/count_decimal_digits/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.util.count_decimal_digits/entry.cpp + * File: count_decimal_digits/entry.cpp * * Purpose: Unit-tests for `stlsoft::count_decimal_digits`. * * Created: 18th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.count_hexadecimal_digits/CMakeLists.txt b/test/unit/stlsoft/util/count_hexadecimal_digits/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.count_hexadecimal_digits/CMakeLists.txt rename to test/unit/stlsoft/util/count_hexadecimal_digits/CMakeLists.txt diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.count_hexadecimal_digits/entry.cpp b/test/unit/stlsoft/util/count_hexadecimal_digits/entry.cpp similarity index 98% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.count_hexadecimal_digits/entry.cpp rename to test/unit/stlsoft/util/count_hexadecimal_digits/entry.cpp index ceb5c1da..9aea5936 100644 --- a/test/unit/stlsoft/util/test.unit.stlsoft.util.count_hexadecimal_digits/entry.cpp +++ b/test/unit/stlsoft/util/count_hexadecimal_digits/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.util.count_hexadecimal_digits/entry.cpp + * File: count_hexadecimal_digits/entry.cpp * * Purpose: Unit-tests for `stlsoft::count_hexadecimal_digits`. * * Created: 18th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.string.snprintf/CMakeLists.txt b/test/unit/stlsoft/util/string.snprintf/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.string.snprintf/CMakeLists.txt rename to test/unit/stlsoft/util/string.snprintf/CMakeLists.txt diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.string.snprintf/entry.cpp b/test/unit/stlsoft/util/string.snprintf/entry.cpp similarity index 98% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.string.snprintf/entry.cpp rename to test/unit/stlsoft/util/string.snprintf/entry.cpp index d021fe03..fd65beb2 100644 --- a/test/unit/stlsoft/util/test.unit.stlsoft.util.string.snprintf/entry.cpp +++ b/test/unit/stlsoft/util/string.snprintf/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.util.string.snprintf/entry.cpp + * File: string.snprintf/entry.cpp * * Purpose: Unit-tests for `stlsoft::snprintf`, `stlsoft::snwprintf`. * * Created: 23rd March 2025 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.string_insertion/CMakeLists.txt b/test/unit/stlsoft/util/string_insertion/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.string_insertion/CMakeLists.txt rename to test/unit/stlsoft/util/string_insertion/CMakeLists.txt diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.string_insertion/entry.cpp b/test/unit/stlsoft/util/string_insertion/entry.cpp similarity index 98% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.string_insertion/entry.cpp rename to test/unit/stlsoft/util/string_insertion/entry.cpp index 9bbbeb92..f61487c8 100644 --- a/test/unit/stlsoft/util/test.unit.stlsoft.util.string_insertion/entry.cpp +++ b/test/unit/stlsoft/util/string_insertion/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.util.string_insertion/entry.cpp + * File: string_insertion/entry.cpp * * Purpose: Unit-tests for `stlsoft::string_insert`. * * Created: 14th November 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.string_switch/CMakeLists.txt b/test/unit/stlsoft/util/string_switch/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.string_switch/CMakeLists.txt rename to test/unit/stlsoft/util/string_switch/CMakeLists.txt diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.string_switch/entry.cpp b/test/unit/stlsoft/util/string_switch/entry.cpp similarity index 99% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.string_switch/entry.cpp rename to test/unit/stlsoft/util/string_switch/entry.cpp index b475879d..874e1304 100644 --- a/test/unit/stlsoft/util/test.unit.stlsoft.util.string_switch/entry.cpp +++ b/test/unit/stlsoft/util/string_switch/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.util.string_switch/entry.cpp + * File: string_switch/entry.cpp * * Purpose: Unit-tests for `stlsoft::count_hexadecimal_digits`. * * Created: 9th June 2010 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.true_typedef/CMakeLists.txt b/test/unit/stlsoft/util/true_typedef/CMakeLists.txt similarity index 100% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.true_typedef/CMakeLists.txt rename to test/unit/stlsoft/util/true_typedef/CMakeLists.txt diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.true_typedef/entry.cpp b/test/unit/stlsoft/util/true_typedef/entry.cpp similarity index 99% rename from test/unit/stlsoft/util/test.unit.stlsoft.util.true_typedef/entry.cpp rename to test/unit/stlsoft/util/true_typedef/entry.cpp index 725fad31..d93cc368 100644 --- a/test/unit/stlsoft/util/test.unit.stlsoft.util.true_typedef/entry.cpp +++ b/test/unit/stlsoft/util/true_typedef/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.stlsoft.util.true_typedef/entry.cpp + * File: true_typedef/entry.cpp * * Purpose: Unit-tests for `stlsoft::true_typedef`. * * Created: 27th February 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/unixstl/filesystem/CMakeLists.txt b/test/unit/unixstl/filesystem/CMakeLists.txt index b7e9ca40..7bfdcb84 100644 --- a/test/unit/unixstl/filesystem/CMakeLists.txt +++ b/test/unit/unixstl/filesystem/CMakeLists.txt @@ -1,3 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.unixstl.filesystem.path) -add_subdirectory(test.unit.unixstl.filesystem.squeeze_functions) +add_subdirectory(path) +add_subdirectory(squeeze_functions) diff --git a/test/unit/unixstl/filesystem/test.unit.unixstl.filesystem.path/CMakeLists.txt b/test/unit/unixstl/filesystem/path/CMakeLists.txt similarity index 100% rename from test/unit/unixstl/filesystem/test.unit.unixstl.filesystem.path/CMakeLists.txt rename to test/unit/unixstl/filesystem/path/CMakeLists.txt diff --git a/test/unit/unixstl/filesystem/test.unit.unixstl.filesystem.path/entry.cpp b/test/unit/unixstl/filesystem/path/entry.cpp similarity index 99% rename from test/unit/unixstl/filesystem/test.unit.unixstl.filesystem.path/entry.cpp rename to test/unit/unixstl/filesystem/path/entry.cpp index e0459028..375386d7 100644 --- a/test/unit/unixstl/filesystem/test.unit.unixstl.filesystem.path/entry.cpp +++ b/test/unit/unixstl/filesystem/path/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.unixstl.filesystem.path/entry.cpp + * File: path/entry.cpp * * Purpose: Unit-tests for `unixstl::basic_path`. * * Created: 16th February 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/unixstl/filesystem/test.unit.unixstl.filesystem.squeeze_functions/CMakeLists.txt b/test/unit/unixstl/filesystem/squeeze_functions/CMakeLists.txt similarity index 100% rename from test/unit/unixstl/filesystem/test.unit.unixstl.filesystem.squeeze_functions/CMakeLists.txt rename to test/unit/unixstl/filesystem/squeeze_functions/CMakeLists.txt diff --git a/test/unit/unixstl/filesystem/test.unit.unixstl.filesystem.squeeze_functions/entry.cpp b/test/unit/unixstl/filesystem/squeeze_functions/entry.cpp similarity index 99% rename from test/unit/unixstl/filesystem/test.unit.unixstl.filesystem.squeeze_functions/entry.cpp rename to test/unit/unixstl/filesystem/squeeze_functions/entry.cpp index 5180cb47..45172789 100644 --- a/test/unit/unixstl/filesystem/test.unit.unixstl.filesystem.squeeze_functions/entry.cpp +++ b/test/unit/unixstl/filesystem/squeeze_functions/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.unixstl.filesystem.squeeze_functions/entry.cpp + * File: squeeze_functions/entry.cpp * * Purpose: Unit-tests for `unixstl::squeeze_path`. * * Created: 29th October 2016 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/unixstl/shims/access/string/CMakeLists.txt b/test/unit/unixstl/shims/access/string/CMakeLists.txt index 63a9d535..b40a6427 100644 --- a/test/unit/unixstl/shims/access/string/CMakeLists.txt +++ b/test/unit/unixstl/shims/access/string/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.unixstl.shims.access.string.timeval) +add_subdirectory(timeval) diff --git a/test/unit/unixstl/shims/access/string/test.unit.unixstl.shims.access.string.timeval/CMakeLists.txt b/test/unit/unixstl/shims/access/string/timeval/CMakeLists.txt similarity index 100% rename from test/unit/unixstl/shims/access/string/test.unit.unixstl.shims.access.string.timeval/CMakeLists.txt rename to test/unit/unixstl/shims/access/string/timeval/CMakeLists.txt diff --git a/test/unit/unixstl/shims/access/string/test.unit.unixstl.shims.access.string.timeval/entry.cpp b/test/unit/unixstl/shims/access/string/timeval/entry.cpp similarity index 98% rename from test/unit/unixstl/shims/access/string/test.unit.unixstl.shims.access.string.timeval/entry.cpp rename to test/unit/unixstl/shims/access/string/timeval/entry.cpp index 702e1e77..ca5c347a 100644 --- a/test/unit/unixstl/shims/access/string/test.unit.unixstl.shims.access.string.timeval/entry.cpp +++ b/test/unit/unixstl/shims/access/string/timeval/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.unixstl.shims.access.string.timeval/entry.cpp + * File: timeval/entry.cpp * * Purpose: Unit-tests for string-access-shims for UNIX `timeval`. * * Created: 5th May 2014 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/test.unit.versions/CMakeLists.txt b/test/unit/versions/CMakeLists.txt similarity index 100% rename from test/unit/test.unit.versions/CMakeLists.txt rename to test/unit/versions/CMakeLists.txt diff --git a/test/unit/test.unit.versions/entry.cpp b/test/unit/versions/entry.cpp similarity index 98% rename from test/unit/test.unit.versions/entry.cpp rename to test/unit/versions/entry.cpp index 83be0623..c71e968d 100644 --- a/test/unit/test.unit.versions/entry.cpp +++ b/test/unit/versions/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.versions/entry.cpp + * File: versions/entry.cpp * * Purpose: Unit-tests for versions * * Created: 23rd August 2025 - * Updated: 21st September 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/winstl/api/internal/CMakeLists.txt b/test/unit/winstl/api/internal/CMakeLists.txt index 59146510..f39d027d 100644 --- a/test/unit/winstl/api/internal/CMakeLists.txt +++ b/test/unit/winstl/api/internal/CMakeLists.txt @@ -1,3 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.winstl.api.internal.DynamicLinkLibrary.C) -add_subdirectory(test.unit.winstl.api.internal.SystemInformation.C) +add_subdirectory(DynamicLinkLibrary.C) +add_subdirectory(SystemInformation.C) diff --git a/test/unit/winstl/api/internal/test.unit.winstl.api.internal.DynamicLinkLibrary.C/CMakeLists.txt b/test/unit/winstl/api/internal/DynamicLinkLibrary.C/CMakeLists.txt similarity index 100% rename from test/unit/winstl/api/internal/test.unit.winstl.api.internal.DynamicLinkLibrary.C/CMakeLists.txt rename to test/unit/winstl/api/internal/DynamicLinkLibrary.C/CMakeLists.txt diff --git a/test/unit/winstl/api/internal/test.unit.winstl.api.internal.DynamicLinkLibrary.C/entry.c b/test/unit/winstl/api/internal/DynamicLinkLibrary.C/entry.c similarity index 98% rename from test/unit/winstl/api/internal/test.unit.winstl.api.internal.DynamicLinkLibrary.C/entry.c rename to test/unit/winstl/api/internal/DynamicLinkLibrary.C/entry.c index 1b8a8390..2220ce77 100644 --- a/test/unit/winstl/api/internal/test.unit.winstl.api.internal.DynamicLinkLibrary.C/entry.c +++ b/test/unit/winstl/api/internal/DynamicLinkLibrary.C/entry.c @@ -1,8 +1,8 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.winstl.api.internal.DynamicLinkLibrary.C/entry.c + * File: DynamicLinkLibrary.C/entry.c * * Created: 25th May 2025 - * Updated: 12th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/winstl/api/internal/test.unit.winstl.api.internal.SystemInformation.C/CMakeLists.txt b/test/unit/winstl/api/internal/SystemInformation.C/CMakeLists.txt similarity index 100% rename from test/unit/winstl/api/internal/test.unit.winstl.api.internal.SystemInformation.C/CMakeLists.txt rename to test/unit/winstl/api/internal/SystemInformation.C/CMakeLists.txt diff --git a/test/unit/winstl/api/internal/test.unit.winstl.api.internal.SystemInformation.C/entry.c b/test/unit/winstl/api/internal/SystemInformation.C/entry.c similarity index 98% rename from test/unit/winstl/api/internal/test.unit.winstl.api.internal.SystemInformation.C/entry.c rename to test/unit/winstl/api/internal/SystemInformation.C/entry.c index 4629ecbc..0e68ef9d 100644 --- a/test/unit/winstl/api/internal/test.unit.winstl.api.internal.SystemInformation.C/entry.c +++ b/test/unit/winstl/api/internal/SystemInformation.C/entry.c @@ -1,8 +1,8 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.winstl.api.internal.SystemInformation.C/entry.c + * File: SystemInformation.C/entry.c * * Created: 25th May 2025 - * Updated: 12th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/winstl/conversion/number/CMakeLists.txt b/test/unit/winstl/conversion/number/CMakeLists.txt index f919022b..697b206e 100644 --- a/test/unit/winstl/conversion/number/CMakeLists.txt +++ b/test/unit/winstl/conversion/number/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.winstl.conversion.number.grouping_functions) +add_subdirectory(grouping_functions) diff --git a/test/unit/winstl/conversion/number/test.unit.winstl.conversion.number.grouping_functions/CMakeLists.txt b/test/unit/winstl/conversion/number/grouping_functions/CMakeLists.txt similarity index 100% rename from test/unit/winstl/conversion/number/test.unit.winstl.conversion.number.grouping_functions/CMakeLists.txt rename to test/unit/winstl/conversion/number/grouping_functions/CMakeLists.txt diff --git a/test/unit/winstl/conversion/number/test.unit.winstl.conversion.number.grouping_functions/entry.cpp b/test/unit/winstl/conversion/number/grouping_functions/entry.cpp similarity index 98% rename from test/unit/winstl/conversion/number/test.unit.winstl.conversion.number.grouping_functions/entry.cpp rename to test/unit/winstl/conversion/number/grouping_functions/entry.cpp index ab5566f8..e7ce7847 100644 --- a/test/unit/winstl/conversion/number/test.unit.winstl.conversion.number.grouping_functions/entry.cpp +++ b/test/unit/winstl/conversion/number/grouping_functions/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.winstl.conversion.number.grouping_functions/entry.cpp + * File: grouping_functions/entry.cpp * * Purpose: Unit-tests for `winstl::format_thousands`. * * Created: 30th November 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/winstl/diagnostics/CMakeLists.txt b/test/unit/winstl/diagnostics/CMakeLists.txt index 3146e9a0..a6a429b7 100644 --- a/test/unit/winstl/diagnostics/CMakeLists.txt +++ b/test/unit/winstl/diagnostics/CMakeLists.txt @@ -1,4 +1,4 @@ if(cstring_FOUND) - add_subdirectory(test.unit.winstl.diagnostics.output_debug_line.C) + add_subdirectory(output_debug_line.C) endif(cstring_FOUND) diff --git a/test/unit/winstl/diagnostics/test.unit.winstl.diagnostics.output_debug_line.C/CMakeLists.txt b/test/unit/winstl/diagnostics/output_debug_line.C/CMakeLists.txt similarity index 100% rename from test/unit/winstl/diagnostics/test.unit.winstl.diagnostics.output_debug_line.C/CMakeLists.txt rename to test/unit/winstl/diagnostics/output_debug_line.C/CMakeLists.txt diff --git a/test/unit/winstl/diagnostics/test.unit.winstl.diagnostics.output_debug_line.C/entry.c b/test/unit/winstl/diagnostics/output_debug_line.C/entry.c similarity index 98% rename from test/unit/winstl/diagnostics/test.unit.winstl.diagnostics.output_debug_line.C/entry.c rename to test/unit/winstl/diagnostics/output_debug_line.C/entry.c index ed437a85..0d14e404 100644 --- a/test/unit/winstl/diagnostics/test.unit.winstl.diagnostics.output_debug_line.C/entry.c +++ b/test/unit/winstl/diagnostics/output_debug_line.C/entry.c @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.winstl.diagnostics.output_debug_line.C/entry.c + * File: output_debug_line.C/entry.c * * Purpose: Unit test for `winstl_C_diagnostics_output_debug_line_1_m()`, etc. * * Created: 22nd November 2011 - * Updated: 12th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/winstl/filesystem/CMakeLists.txt b/test/unit/winstl/filesystem/CMakeLists.txt index fb460617..3bb7b8b3 100644 --- a/test/unit/winstl/filesystem/CMakeLists.txt +++ b/test/unit/winstl/filesystem/CMakeLists.txt @@ -1,3 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.winstl.filesystem.filesystem_traits) -add_subdirectory(test.unit.winstl.filesystem.squeeze_functions) +add_subdirectory(filesystem_traits) +add_subdirectory(squeeze_functions) diff --git a/test/unit/winstl/filesystem/test.unit.winstl.filesystem.filesystem_traits/CMakeLists.txt b/test/unit/winstl/filesystem/filesystem_traits/CMakeLists.txt similarity index 100% rename from test/unit/winstl/filesystem/test.unit.winstl.filesystem.filesystem_traits/CMakeLists.txt rename to test/unit/winstl/filesystem/filesystem_traits/CMakeLists.txt diff --git a/test/unit/winstl/filesystem/test.unit.winstl.filesystem.filesystem_traits/entry.cpp b/test/unit/winstl/filesystem/filesystem_traits/entry.cpp similarity index 99% rename from test/unit/winstl/filesystem/test.unit.winstl.filesystem.filesystem_traits/entry.cpp rename to test/unit/winstl/filesystem/filesystem_traits/entry.cpp index 6f8e94d6..6d3706e6 100644 --- a/test/unit/winstl/filesystem/test.unit.winstl.filesystem.filesystem_traits/entry.cpp +++ b/test/unit/winstl/filesystem/filesystem_traits/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.winstl.filesystem.filesystem_traits/entry.cpp + * File: filesystem_traits/entry.cpp * * Purpose: Unit-tests for `winstl::filesystem_traits`. * * Created: 31st December 2008 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/winstl/filesystem/test.unit.winstl.filesystem.squeeze_functions/CMakeLists.txt b/test/unit/winstl/filesystem/squeeze_functions/CMakeLists.txt similarity index 100% rename from test/unit/winstl/filesystem/test.unit.winstl.filesystem.squeeze_functions/CMakeLists.txt rename to test/unit/winstl/filesystem/squeeze_functions/CMakeLists.txt diff --git a/test/unit/winstl/filesystem/test.unit.winstl.filesystem.squeeze_functions/entry.cpp b/test/unit/winstl/filesystem/squeeze_functions/entry.cpp similarity index 99% rename from test/unit/winstl/filesystem/test.unit.winstl.filesystem.squeeze_functions/entry.cpp rename to test/unit/winstl/filesystem/squeeze_functions/entry.cpp index 1791ca71..d9b6efb2 100644 --- a/test/unit/winstl/filesystem/test.unit.winstl.filesystem.squeeze_functions/entry.cpp +++ b/test/unit/winstl/filesystem/squeeze_functions/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.winstl.filesystem.squeeze_functions/entry.cpp + * File: squeeze_functions/entry.cpp * * Purpose: Unit-tests for `winstl::squeeze_path`. * * Created: 29th October 2016 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/winstl/memory/CMakeLists.txt b/test/unit/winstl/memory/CMakeLists.txt index c8b44a97..5df5ca73 100644 --- a/test/unit/winstl/memory/CMakeLists.txt +++ b/test/unit/winstl/memory/CMakeLists.txt @@ -1,5 +1,5 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.winstl.memory.global_allocator) -add_subdirectory(test.unit.winstl.memory.netapi_allocator) -add_subdirectory(test.unit.winstl.memory.processheap_allocator) -add_subdirectory(test.unit.winstl.memory.shell_allocator) +add_subdirectory(global_allocator) +add_subdirectory(netapi_allocator) +add_subdirectory(processheap_allocator) +add_subdirectory(shell_allocator) diff --git a/test/unit/winstl/memory/test.unit.winstl.memory.global_allocator/CMakeLists.txt b/test/unit/winstl/memory/global_allocator/CMakeLists.txt similarity index 100% rename from test/unit/winstl/memory/test.unit.winstl.memory.global_allocator/CMakeLists.txt rename to test/unit/winstl/memory/global_allocator/CMakeLists.txt diff --git a/test/unit/winstl/memory/test.unit.winstl.memory.global_allocator/entry.cpp b/test/unit/winstl/memory/global_allocator/entry.cpp similarity index 96% rename from test/unit/winstl/memory/test.unit.winstl.memory.global_allocator/entry.cpp rename to test/unit/winstl/memory/global_allocator/entry.cpp index 1cd580b9..a7f7e62a 100644 --- a/test/unit/winstl/memory/test.unit.winstl.memory.global_allocator/entry.cpp +++ b/test/unit/winstl/memory/global_allocator/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.winstl.memory.global_allocator/entry.cpp + * File: global_allocator/entry.cpp * * Purpose: Unit-tests for `winstl::global_allocator`. * * Created: 18th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/winstl/memory/test.unit.winstl.memory.netapi_allocator/CMakeLists.txt b/test/unit/winstl/memory/netapi_allocator/CMakeLists.txt similarity index 100% rename from test/unit/winstl/memory/test.unit.winstl.memory.netapi_allocator/CMakeLists.txt rename to test/unit/winstl/memory/netapi_allocator/CMakeLists.txt diff --git a/test/unit/winstl/memory/test.unit.winstl.memory.netapi_allocator/entry.cpp b/test/unit/winstl/memory/netapi_allocator/entry.cpp similarity index 96% rename from test/unit/winstl/memory/test.unit.winstl.memory.netapi_allocator/entry.cpp rename to test/unit/winstl/memory/netapi_allocator/entry.cpp index e559928e..5f8f3d3f 100644 --- a/test/unit/winstl/memory/test.unit.winstl.memory.netapi_allocator/entry.cpp +++ b/test/unit/winstl/memory/netapi_allocator/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.winstl.memory.netapi_allocator/entry.cpp + * File: netapi_allocator/entry.cpp * * Purpose: Unit-tests for `winstl::netapi_allocator`. * * Created: 18th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/winstl/memory/test.unit.winstl.memory.processheap_allocator/CMakeLists.txt b/test/unit/winstl/memory/processheap_allocator/CMakeLists.txt similarity index 100% rename from test/unit/winstl/memory/test.unit.winstl.memory.processheap_allocator/CMakeLists.txt rename to test/unit/winstl/memory/processheap_allocator/CMakeLists.txt diff --git a/test/unit/winstl/memory/test.unit.winstl.memory.processheap_allocator/entry.cpp b/test/unit/winstl/memory/processheap_allocator/entry.cpp similarity index 96% rename from test/unit/winstl/memory/test.unit.winstl.memory.processheap_allocator/entry.cpp rename to test/unit/winstl/memory/processheap_allocator/entry.cpp index 43298f45..45210dbe 100644 --- a/test/unit/winstl/memory/test.unit.winstl.memory.processheap_allocator/entry.cpp +++ b/test/unit/winstl/memory/processheap_allocator/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.winstl.memory.processheap_allocator/entry.cpp + * File: processheap_allocator/entry.cpp * * Purpose: Unit-tests for `winstl::processheap_allocator`. * * Created: 18th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/winstl/memory/test.unit.winstl.memory.shell_allocator/CMakeLists.txt b/test/unit/winstl/memory/shell_allocator/CMakeLists.txt similarity index 100% rename from test/unit/winstl/memory/test.unit.winstl.memory.shell_allocator/CMakeLists.txt rename to test/unit/winstl/memory/shell_allocator/CMakeLists.txt diff --git a/test/unit/winstl/memory/test.unit.winstl.memory.shell_allocator/entry.cpp b/test/unit/winstl/memory/shell_allocator/entry.cpp similarity index 96% rename from test/unit/winstl/memory/test.unit.winstl.memory.shell_allocator/entry.cpp rename to test/unit/winstl/memory/shell_allocator/entry.cpp index 4365b36d..b20a2e9e 100644 --- a/test/unit/winstl/memory/test.unit.winstl.memory.shell_allocator/entry.cpp +++ b/test/unit/winstl/memory/shell_allocator/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.winstl.memory.shell_allocator/entry.cpp + * File: shell_allocator/entry.cpp * * Purpose: Unit-tests for `winstl::shell_allocator`. * * Created: 18th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/winstl/system/CMakeLists.txt b/test/unit/winstl/system/CMakeLists.txt index bce641af..aabe6a2b 100644 --- a/test/unit/winstl/system/CMakeLists.txt +++ b/test/unit/winstl/system/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.winstl.system.system_traits) +add_subdirectory(system_traits) diff --git a/test/unit/winstl/system/test.unit.winstl.system.system_traits/CMakeLists.txt b/test/unit/winstl/system/system_traits/CMakeLists.txt similarity index 100% rename from test/unit/winstl/system/test.unit.winstl.system.system_traits/CMakeLists.txt rename to test/unit/winstl/system/system_traits/CMakeLists.txt diff --git a/test/unit/winstl/system/test.unit.winstl.system.system_traits/entry.cpp b/test/unit/winstl/system/system_traits/entry.cpp similarity index 99% rename from test/unit/winstl/system/test.unit.winstl.system.system_traits/entry.cpp rename to test/unit/winstl/system/system_traits/entry.cpp index afb6220b..75f2a317 100644 --- a/test/unit/winstl/system/test.unit.winstl.system.system_traits/entry.cpp +++ b/test/unit/winstl/system/system_traits/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.winstl.system.system_traits/entry.cpp + * File: system_traits/entry.cpp * * Purpose: Unit-tests for `winstl::system_traits`. * * Created: 22nd May 2025 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/winstl/util/CMakeLists.txt b/test/unit/winstl/util/CMakeLists.txt index 4aea6ed3..219d0be9 100644 --- a/test/unit/winstl/util/CMakeLists.txt +++ b/test/unit/winstl/util/CMakeLists.txt @@ -1,3 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.unit.winstl.util.struct_comparers) -add_subdirectory(test.unit.winstl.util.struct_initialisers) +add_subdirectory(struct_comparers) +add_subdirectory(struct_initialisers) diff --git a/test/unit/winstl/util/test.unit.winstl.util.struct_comparers/CMakeLists.txt b/test/unit/winstl/util/struct_comparers/CMakeLists.txt similarity index 100% rename from test/unit/winstl/util/test.unit.winstl.util.struct_comparers/CMakeLists.txt rename to test/unit/winstl/util/struct_comparers/CMakeLists.txt diff --git a/test/unit/winstl/util/test.unit.winstl.util.struct_comparers/entry.cpp b/test/unit/winstl/util/struct_comparers/entry.cpp similarity index 97% rename from test/unit/winstl/util/test.unit.winstl.util.struct_comparers/entry.cpp rename to test/unit/winstl/util/struct_comparers/entry.cpp index 770441ea..f8ffcd8a 100644 --- a/test/unit/winstl/util/test.unit.winstl.util.struct_comparers/entry.cpp +++ b/test/unit/winstl/util/struct_comparers/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.winstl.util.struct_comparers/entry.cpp + * File: struct_comparers/entry.cpp * * Purpose: Component test for `winstl::struct_comparers`. * * Created: 9th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/unit/winstl/util/test.unit.winstl.util.struct_initialisers/CMakeLists.txt b/test/unit/winstl/util/struct_initialisers/CMakeLists.txt similarity index 100% rename from test/unit/winstl/util/test.unit.winstl.util.struct_initialisers/CMakeLists.txt rename to test/unit/winstl/util/struct_initialisers/CMakeLists.txt diff --git a/test/unit/winstl/util/test.unit.winstl.util.struct_initialisers/entry.cpp b/test/unit/winstl/util/struct_initialisers/entry.cpp similarity index 99% rename from test/unit/winstl/util/test.unit.winstl.util.struct_initialisers/entry.cpp rename to test/unit/winstl/util/struct_initialisers/entry.cpp index 9980171c..cdd641d9 100644 --- a/test/unit/winstl/util/test.unit.winstl.util.struct_initialisers/entry.cpp +++ b/test/unit/winstl/util/struct_initialisers/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.unit.winstl.util.struct_initialisers/entry.cpp + * File: struct_initialisers/entry.cpp * * Purpose: Component test for `winstl::struct_initialisers`. * * Created: 9th October 2024 - * Updated: 9th August 2026 + * Updated: 29th September 2026 * * ////////////////////////////////////////////////////////////////////// */ From 1d8b9ce1cb34a1c981623738447144a77c8d7676 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Wed, 30 Sep 2026 06:53:58 +1000 Subject: [PATCH 02/31] 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**; --- CHANGES.md | 7 +++++++ INSTALL.md | 18 +++++++++--------- NEWS.md | 1 + include/stlsoft/stlsoft.h | 5 +++-- test/unit/versions/entry.cpp | 4 ++-- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index edead870..acc0fe87 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,13 @@ # STLSoft - CHANGES +## 1.11.1-rc7 - 30th September 2026 + +* Test tree — leaf directories under **test/component**, **test/unit**, **test/scratch**, and **test/performance** renamed from `test..…` to the subject name (for example **glob_sequence**); executable target names unchanged; +* **test/performance** — programs nested by sub-project and area (**platformstl/diagnostics**, **stlsoft/containers**, **stlsoft/conversion**, **stlsoft/diagnostics**, **stlsoft/memory**, **stlsoft/string**, **stlsoft/util**); +* **test.unit.versions** — aligned with **1.11.1-rc7** (**_STLSOFT_VER_1_11_1_RC7**); + + ## 1.11.1-rc6 - 21st September 2026 * CMake/CI — optional **ACE** discovery (**cmake/FindACE.cmake**, **NO_ACE** / **prepare_cmake.sh --no-ace**); dedicated **cell-ace** job (**with-ace**); diff --git a/INSTALL.md b/INSTALL.md index be4359ba..dcb57aaa 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -23,17 +23,17 @@ There are three options for installing **STLSoft**, depending on how you obtain If you obtain the latest release as an archive from the [**STLSoft** GitHub Releases](https://github.com/synesissoftware/STLSoft/releases) page (legacy archives may also still appear on [SourceForge](https://sourceforge.net/projects/stlsoft/)): -1. Download the latest distribution, e.g. [**STLSoft-1.11.1-rc6.zip**](https://github.com/synesissoftware/STLSoft/archive/refs/tags/1.11.1-rc6.zip); +1. Download the latest distribution, e.g. [**STLSoft-1.11.1-rc7.zip**](https://github.com/synesissoftware/STLSoft/archive/refs/tags/1.11.1-rc7.zip); 2. Unzip it to a directory of your choice, as in: ```bash $ mkdir -p ~/open-source $ cd ~/open-source -$ unzip STLSoft-1.11.1-rc6.zip +$ unzip STLSoft-1.11.1-rc7.zip ``` -3. Define an environment variable `STLSOFT`, whose value is the directory in which you unzipped it, e.g. `STLSOFT=~/open-source/STLSoft-1.11.1-rc6`, and then specify `$(STLSOFT)/include` (**UNIX**) or `%STLSOFT%\include` (**Windows**) in your project files and makefiles; +3. Define an environment variable `STLSOFT`, whose value is the directory in which you unzipped it, e.g. `STLSOFT=~/open-source/STLSoft-1.11.1-rc7`, and then specify `$(STLSOFT)/include` (**UNIX**) or `%STLSOFT%\include` (**Windows**) in your project files and makefiles; ### Cloning project, using environment variables @@ -100,16 +100,16 @@ $ sudo cmake --install ${SIS_CMAKE_BUILD_DIR:-./_build} --config Release Unless you are certain that your projects, and all the projects upon which they depend, all use **STLSoft** via **CMake** then it is recommended that you define an `STLSOFT` environment variable. For example, if you're using **UNIX** and you install to -**/usr/local/stlsoft/STLSoft-1.11.1-rc6** +**/usr/local/stlsoft/STLSoft-1.11.1-rc7** then you should set the environment variable `STLSOFT` to -**/usr/local/stlsoft/STLSoft-1.11.1-rc6** -in which case the file `stlsoft/stlsoft.h`, for example, will be located in `/usr/local/stlsoft/STLSoft-1.11.1-rc6/include/stlsoft/stlsoft.h`. +**/usr/local/stlsoft/STLSoft-1.11.1-rc7** +in which case the file `stlsoft/stlsoft.h`, for example, will be located in `/usr/local/stlsoft/STLSoft-1.11.1-rc7/include/stlsoft/stlsoft.h`. Conversely, if you're using **Windows** and you install to -**C:\3pty\STLSoft\STLSoft-1.11.1-rc6** +**C:\3pty\STLSoft\STLSoft-1.11.1-rc7** then you should set the environment variable `STLSOFT` to -**C:\3pty\STLSoft\STLSoft-1.11.1-rc6** -in which case the file `stlsoft/stlsoft.h`, for example, will be located in `C:\3pty\STLSoft\STLSoft-1.11.1-rc6\include\stlsoft\stlsoft.h`. +**C:\3pty\STLSoft\STLSoft-1.11.1-rc7** +in which case the file `stlsoft/stlsoft.h`, for example, will be located in `C:\3pty\STLSoft\STLSoft-1.11.1-rc7\include\stlsoft\stlsoft.h`. The makefiles / project files of several other open-source projects expect this symbol, including: diff --git a/NEWS.md b/NEWS.md index 4c133f6c..107ad0b1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ | Date | News Item | Details | | ------------------- | ----------------------------------- | ------- | +| 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | shortened test directories; nested **test/performance** | | 21st September 2026 | Release of [STLSoft 1.11.1-rc6](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc6) | ACE/ATL/MFC CI; Clang/macOS `stricmp` aliases | | 4th August 2026 | Release of [STLSoft 1.11.1-rc5](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc5) | `basic_simple_string<>#resize()`; **CHANGES.md**; docs | | 29th July 2026 | Release of [STLSoft 1.11.1-rc4](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc4) | GitHub Actions CI; VC++ 18.x; MinGW | diff --git a/include/stlsoft/stlsoft.h b/include/stlsoft/stlsoft.h index 1d7130cb..a2f991e6 100644 --- a/include/stlsoft/stlsoft.h +++ b/include/stlsoft/stlsoft.h @@ -5,7 +5,7 @@ * and platform discriminations, and definitions of types. * * Created: 15th January 2002 - * Updated: 21st September 2026 + * Updated: 30th September 2026 * * Home: http://stlsoft.org/ * @@ -421,12 +421,13 @@ # define _STLSOFT_VER_1_11_1_RC4 0x010b01c4 /*!< Version 1.11.1 rc 4 (1st July 2026) */ # define _STLSOFT_VER_1_11_1_RC5 0x010b01c5 /*!< Version 1.11.1 rc 5 (4th August 2026) */ # define _STLSOFT_VER_1_11_1_RC6 0x010b01c6 /*!< Version 1.11.1 rc 6 (21st September 2026) */ +# define _STLSOFT_VER_1_11_1_RC7 0x010b01c7 /*!< Version 1.11.1 rc 7 (30th September 2026) */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ #define _STLSOFT_VER_MAJOR 1 #define _STLSOFT_VER_MINOR 11 #define _STLSOFT_VER_PATCH 1 -#define _STLSOFT_VER_ALPHABETA 0xc6 +#define _STLSOFT_VER_ALPHABETA 0xc7 #define _STLSOFT_VER \ (0\ diff --git a/test/unit/versions/entry.cpp b/test/unit/versions/entry.cpp index c71e968d..a08232d5 100644 --- a/test/unit/versions/entry.cpp +++ b/test/unit/versions/entry.cpp @@ -4,7 +4,7 @@ * Purpose: Unit-tests for versions * * Created: 23rd August 2025 - * Updated: 29th September 2026 + * Updated: 30th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -133,7 +133,7 @@ namespace { static void TEST__STLSOFT_VER() { - TEST_INT_EQ(_STLSOFT_VER_1_11_1_RC6, _STLSOFT_VER); + TEST_INT_EQ(_STLSOFT_VER_1_11_1_RC7, _STLSOFT_VER); } #ifdef STLSOFT_HAS_ACE From 9621c2e4ab21c06f14cc5ecabde6a075935a507d Mon Sep 17 00:00:00 2001 From: Matt Wilson <152443343+mwsis@users.noreply.github.com> Date: Wed, 30 Sep 2026 07:44:21 +1000 Subject: [PATCH 03/31] 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 --- include/winstl/memory/netapi_allocator.hpp | 10 +- .../comstl/memory/task_allocator/entry.cpp | 87 +- .../mfcstl/memory/afx_allocator/entry.cpp | 87 +- .../byte_format_functions/entry.cpp | 64 -- .../stlsoft/conversion/try_parse_to/entry.cpp | 21 - .../io_functions.read_line/entry.cpp | 790 ------------------ .../stlsoft/memory/malloc_allocator/entry.cpp | 87 +- .../stlsoft/memory/new_allocator/entry.cpp | 87 +- .../stlsoft/memory/null_allocator/entry.cpp | 60 +- .../stlsoft/smartptr/scoped_handle/entry.cpp | 79 -- .../stlsoft/smartptr/shared_ptr/entry.cpp | 6 - .../unit/stlsoft/string/shim_string/entry.cpp | 43 - .../stlsoft/string/simple_string/entry.cpp | 21 - .../stlsoft/string/static_string/entry.cpp | 67 -- test/unit/stlsoft/util/true_typedef/entry.cpp | 7 - .../filesystem/filesystem_traits/entry.cpp | 26 - .../winstl/memory/global_allocator/entry.cpp | 87 +- .../memory/netapi_allocator/CMakeLists.txt | 8 +- .../winstl/memory/netapi_allocator/entry.cpp | 87 +- .../memory/processheap_allocator/entry.cpp | 87 +- .../winstl/memory/shell_allocator/entry.cpp | 87 +- 21 files changed, 744 insertions(+), 1154 deletions(-) diff --git a/include/winstl/memory/netapi_allocator.hpp b/include/winstl/memory/netapi_allocator.hpp index 22073a9c..476bb4c3 100644 --- a/include/winstl/memory/netapi_allocator.hpp +++ b/include/winstl/memory/netapi_allocator.hpp @@ -4,11 +4,11 @@ * Purpose: netapi_allocator class. * * Created: 23rd March 2006 - * Updated: 20th March 2025 + * Updated: 30th September 2026 * * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2006-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -54,7 +54,7 @@ # define WINSTL_VER_WINSTL_MEMORY_HPP_NETAPI_ALLOCATOR_MAJOR 1 # define WINSTL_VER_WINSTL_MEMORY_HPP_NETAPI_ALLOCATOR_MINOR 1 # define WINSTL_VER_WINSTL_MEMORY_HPP_NETAPI_ALLOCATOR_REVISION 9 -# define WINSTL_VER_WINSTL_MEMORY_HPP_NETAPI_ALLOCATOR_EDIT 31 +# define WINSTL_VER_WINSTL_MEMORY_HPP_NETAPI_ALLOCATOR_EDIT 32 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -167,8 +167,10 @@ class netapi_allocator { STLSOFT_SUPPRESS_UNUSED(hint); + size_type const bytes = n * sizeof(value_type); + DWORD const byte_count = static_cast(bytes); LPVOID pv; - NET_API_STATUS status = ::NetApiBufferAllocate(n * sizeof(value_type), &pv); + NET_API_STATUS status = ::NetApiBufferAllocate(byte_count, &pv); return (NERR_Success == status) ? static_cast(pv) : NULL; } diff --git a/test/unit/comstl/memory/task_allocator/entry.cpp b/test/unit/comstl/memory/task_allocator/entry.cpp index acdd7c61..8f072858 100644 --- a/test/unit/comstl/memory/task_allocator/entry.cpp +++ b/test/unit/comstl/memory/task_allocator/entry.cpp @@ -29,9 +29,12 @@ #include /* STLSoft header files */ +#include #include /* Standard C++ header files */ +#include +#include /* Standard C header files */ #include @@ -92,39 +95,117 @@ int main(int argc, char *argv[]) namespace { +typedef comstl::task_allocator allocator_t; + +static void exercise_allocate(allocator_t::size_type n) +{ + allocator_t ator; + allocator_t::pointer p = ator.allocate(n); + + TEST_PTR_NE(NULL, p); + + for (allocator_t::size_type i = 0; i != n; ++i) + { + ator.construct(&p[i], static_cast(i)); + } + + for (allocator_t::size_type i = 0; i != n; ++i) + { + TEST_INT_EQ(static_cast(i), p[i]); + + ator.destroy(&p[i]); + } + + ator.deallocate(p, n); +} + static void test_alloc_0() { + allocator_t a1; + allocator_t a2; + + TEST_BOOLEAN_TRUE(a1 == a2); + TEST_BOOLEAN_FALSE(a1 != a2); + + allocator_t::pointer p = a1.allocate(0); + + TEST_PTR_NE(NULL, p); + a1.deallocate(p); } static void test_alloc_small() { - + exercise_allocate(4); } static void test_alloc_medium() { - + exercise_allocate(256); } static void test_alloc_large() { - + exercise_allocate(4096); } static void test_alloc_toolarge() { + allocator_t ator; + allocator_t::size_type const too_large = ator.max_size() + 1; + + try + { + static_cast(ator.allocate(too_large)); + TEST_FAIL("should not get here"); + } + catch (stlsoft::out_of_memory_exception&) + { + TEST_PASSED(); + } } static void test_specialise_list() { + typedef std::list list_t; + list_t items; + + items.push_back(10); + items.push_back(20); + items.push_back(30); + + TEST_INT_EQ(3u, items.size()); + + list_t::const_iterator it = items.begin(); + + TEST_INT_EQ(10, *it); + ++it; + TEST_INT_EQ(20, *it); + ++it; + TEST_INT_EQ(30, *it); } static void test_specialise_vector() { + typedef std::vector vector_t; + + vector_t v; + + v.push_back(10); + v.push_back(20); + v.push_back(30); + + TEST_INT_EQ(3u, v.size()); + TEST_INT_EQ(10, v[0]); + TEST_INT_EQ(20, v[1]); + TEST_INT_EQ(30, v[2]); + + v.resize(1); + TEST_INT_EQ(1u, v.size()); + TEST_INT_EQ(10, v[0]); } } // anonymous namespace diff --git a/test/unit/mfcstl/memory/afx_allocator/entry.cpp b/test/unit/mfcstl/memory/afx_allocator/entry.cpp index 4544d060..8742fed2 100644 --- a/test/unit/mfcstl/memory/afx_allocator/entry.cpp +++ b/test/unit/mfcstl/memory/afx_allocator/entry.cpp @@ -29,9 +29,12 @@ #include /* STLSoft header files */ +#include #include /* Standard C++ header files */ +#include +#include /* Standard C header files */ #include @@ -92,39 +95,117 @@ int main(int argc, char *argv[]) namespace { +typedef mfcstl::afx_allocator allocator_t; + +static void exercise_allocate(allocator_t::size_type n) +{ + allocator_t ator; + allocator_t::pointer p = ator.allocate(n); + + TEST_PTR_NE(NULL, p); + + for (allocator_t::size_type i = 0; i != n; ++i) + { + ator.construct(&p[i], static_cast(i)); + } + + for (allocator_t::size_type i = 0; i != n; ++i) + { + TEST_INT_EQ(static_cast(i), p[i]); + + ator.destroy(&p[i]); + } + + ator.deallocate(p, n); +} + static void test_alloc_0() { + allocator_t a1; + allocator_t a2; + + TEST_BOOLEAN_TRUE(a1 == a2); + TEST_BOOLEAN_FALSE(a1 != a2); + + allocator_t::pointer p = a1.allocate(0); + + TEST_PTR_NE(NULL, p); + a1.deallocate(p); } static void test_alloc_small() { - + exercise_allocate(4); } static void test_alloc_medium() { - + exercise_allocate(256); } static void test_alloc_large() { - + exercise_allocate(4096); } static void test_alloc_toolarge() { + allocator_t ator; + allocator_t::size_type const too_large = ator.max_size() + 1; + + try + { + static_cast(ator.allocate(too_large)); + TEST_FAIL("should not get here"); + } + catch (stlsoft::out_of_memory_exception&) + { + TEST_PASSED(); + } } static void test_specialise_list() { + typedef std::list list_t; + list_t items; + + items.push_back(10); + items.push_back(20); + items.push_back(30); + + TEST_INT_EQ(3u, items.size()); + + list_t::const_iterator it = items.begin(); + + TEST_INT_EQ(10, *it); + ++it; + TEST_INT_EQ(20, *it); + ++it; + TEST_INT_EQ(30, *it); } static void test_specialise_vector() { + typedef std::vector vector_t; + + vector_t v; + + v.push_back(10); + v.push_back(20); + v.push_back(30); + + TEST_INT_EQ(3u, v.size()); + TEST_INT_EQ(10, v[0]); + TEST_INT_EQ(20, v[1]); + TEST_INT_EQ(30, v[2]); + + v.resize(1); + TEST_INT_EQ(1u, v.size()); + TEST_INT_EQ(10, v[0]); } } // anonymous namespace diff --git a/test/unit/stlsoft/conversion/byte_format_functions/entry.cpp b/test/unit/stlsoft/conversion/byte_format_functions/entry.cpp index f448f46e..4c4a6b64 100644 --- a/test/unit/stlsoft/conversion/byte_format_functions/entry.cpp +++ b/test/unit/stlsoft/conversion/byte_format_functions/entry.cpp @@ -61,17 +61,6 @@ namespace { static void test_format_bytes_5_byte_4_grouping(); static void test_format_bytes_5_byte_8_grouping(); static void test_format_bytes_5_byte_16_grouping(); - - static void test_1_21(); - static void test_1_22(); - static void test_1_23(); - static void test_1_24(); - static void test_1_25(); - static void test_1_26(); - static void test_1_27(); - static void test_1_28(); - static void test_1_29(); - static void test_1_30(); } // anonymous namespace @@ -104,17 +93,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_format_bytes_5_byte_8_grouping); XTESTS_RUN_CASE(test_format_bytes_5_byte_16_grouping); - XTESTS_RUN_CASE(test_1_21); - XTESTS_RUN_CASE(test_1_22); - XTESTS_RUN_CASE(test_1_23); - XTESTS_RUN_CASE(test_1_24); - XTESTS_RUN_CASE(test_1_25); - XTESTS_RUN_CASE(test_1_26); - XTESTS_RUN_CASE(test_1_27); - XTESTS_RUN_CASE(test_1_28); - XTESTS_RUN_CASE(test_1_29); - XTESTS_RUN_CASE(test_1_30); - #ifdef STLSOFT_USE_XCOVER XCOVER_REPORT_FILE_COVERAGE("*stlsoft*/simple_string.hpp", NULL); #endif /* STLSOFT_USE_XCOVER */ @@ -207,7 +185,6 @@ static void test_format_bytes_1_byte_16_grouping() TEST_MS_EQ_N("00000000000000000000000000000001", sz, static_cast(n)); } - static void test_format_bytes_5_byte_1_grouping() { char sz[1001]; @@ -277,47 +254,6 @@ static void test_format_bytes_5_byte_16_grouping() TEST_MS_EQ_N("00000000000000000000000504030201", sz, static_cast(n)); } - - -static void test_1_21() -{ -} - -static void test_1_22() -{ -} - -static void test_1_23() -{ -} - -static void test_1_24() -{ -} - -static void test_1_25() -{ -} - -static void test_1_26() -{ -} - -static void test_1_27() -{ -} - -static void test_1_28() -{ -} - -static void test_1_29() -{ -} - -static void test_1_30() -{ -} } // anonymous namespace diff --git a/test/unit/stlsoft/conversion/try_parse_to/entry.cpp b/test/unit/stlsoft/conversion/try_parse_to/entry.cpp index 096ec5b5..78fe4af4 100644 --- a/test/unit/stlsoft/conversion/try_parse_to/entry.cpp +++ b/test/unit/stlsoft/conversion/try_parse_to/entry.cpp @@ -94,9 +94,6 @@ namespace static void test_try_hex_5_int(void); static void test_try_hex_6_int(void); static void test_try_hex_7_int(void); - static void test_try_hex_8_int(void); - static void test_try_hex_9_int(void); - static void test_try_hex_10_int(void); } // anonymous namespace @@ -145,9 +142,6 @@ int main(int argc, char **argv) XTESTS_RUN_CASE(test_try_hex_5_int); XTESTS_RUN_CASE(test_try_hex_6_int); XTESTS_RUN_CASE(test_try_hex_7_int); - XTESTS_RUN_CASE(test_try_hex_8_int); - XTESTS_RUN_CASE(test_try_hex_9_int); - XTESTS_RUN_CASE(test_try_hex_10_int); XTESTS_PRINT_RESULTS(); @@ -600,7 +594,6 @@ static void test_try_12_int() #endif } - static void test_try_1_uint64() { uint64_t i; @@ -710,8 +703,6 @@ static void test_try_10_uint64() TEST_MS_EQ("a", endptr); } - - static void test_try_hex_1_int() { uint64_t i; @@ -781,18 +772,6 @@ static void test_try_hex_7_int() TEST_INT_EQ(-10, i); TEST_MS_EQ("Z", endptr); } - -static void test_try_hex_8_int() -{ -} - -static void test_try_hex_9_int() -{ -} - -static void test_try_hex_10_int() -{ -} } // anonymous namespace diff --git a/test/unit/stlsoft/filesystem/io_functions.read_line/entry.cpp b/test/unit/stlsoft/filesystem/io_functions.read_line/entry.cpp index bc3c5c82..7983f4bc 100644 --- a/test/unit/stlsoft/filesystem/io_functions.read_line/entry.cpp +++ b/test/unit/stlsoft/filesystem/io_functions.read_line/entry.cpp @@ -55,15 +55,6 @@ namespace { static void test_1_8(); static void test_1_9(); static void test_1_10(); - static void test_1_11(); - static void test_1_12(); - static void test_1_13(); - static void test_1_14(); - static void test_1_15(); - static void test_1_16(); - static void test_1_17(); - static void test_1_18(); - static void test_1_19(); // CR-only static void test_2_0(); @@ -77,15 +68,6 @@ namespace { static void test_2_8(); static void test_2_9(); static void test_2_10(); - static void test_2_11(); - static void test_2_12(); - static void test_2_13(); - static void test_2_14(); - static void test_2_15(); - static void test_2_16(); - static void test_2_17(); - static void test_2_18(); - static void test_2_19(); // CRLF-only static void test_3_0(); @@ -99,15 +81,6 @@ namespace { static void test_3_8(); static void test_3_9(); static void test_3_10(); - static void test_3_11(); - static void test_3_12(); - static void test_3_13(); - static void test_3_14(); - static void test_3_15(); - static void test_3_16(); - static void test_3_17(); - static void test_3_18(); - static void test_3_19(); // LF or CR (but not CRLF) static void test_4_0(); @@ -121,15 +94,6 @@ namespace { static void test_4_8(); static void test_4_9(); static void test_4_10(); - static void test_4_11(); - static void test_4_12(); - static void test_4_13(); - static void test_4_14(); - static void test_4_15(); - static void test_4_16(); - static void test_4_17(); - static void test_4_18(); - static void test_4_19(); // LF or CRLF static void test_5_0(); @@ -143,15 +107,6 @@ namespace { static void test_5_8(); static void test_5_9(); static void test_5_10(); - static void test_5_11(); - static void test_5_12(); - static void test_5_13(); - static void test_5_14(); - static void test_5_15(); - static void test_5_16(); - static void test_5_17(); - static void test_5_18(); - static void test_5_19(); // CR or CRLF static void test_6_0(); @@ -165,15 +120,6 @@ namespace { static void test_6_8(); static void test_6_9(); static void test_6_10(); - static void test_6_11(); - static void test_6_12(); - static void test_6_13(); - static void test_6_14(); - static void test_6_15(); - static void test_6_16(); - static void test_6_17(); - static void test_6_18(); - static void test_6_19(); // 0 === (LF or CR or CRLF) static void test_7_0(); @@ -187,15 +133,6 @@ namespace { static void test_7_8(); static void test_7_9(); static void test_7_10(); - static void test_7_11(); - static void test_7_12(); - static void test_7_13(); - static void test_7_14(); - static void test_7_15(); - static void test_7_16(); - static void test_7_17(); - static void test_7_18(); - static void test_7_19(); // LF-only @@ -210,15 +147,6 @@ namespace { static void test_8_8(); static void test_8_9(); static void test_8_10(); - static void test_8_11(); - static void test_8_12(); - static void test_8_13(); - static void test_8_14(); - static void test_8_15(); - static void test_8_16(); - static void test_8_17(); - static void test_8_18(); - static void test_8_19(); // CR-only static void test_9_0(); @@ -232,15 +160,6 @@ namespace { static void test_9_8(); static void test_9_9(); static void test_9_10(); - static void test_9_11(); - static void test_9_12(); - static void test_9_13(); - static void test_9_14(); - static void test_9_15(); - static void test_9_16(); - static void test_9_17(); - static void test_9_18(); - static void test_9_19(); // CRLF-only static void test_10_0(); @@ -254,15 +173,6 @@ namespace { static void test_10_8(); static void test_10_9(); static void test_10_10(); - static void test_10_11(); - static void test_10_12(); - static void test_10_13(); - static void test_10_14(); - static void test_10_15(); - static void test_10_16(); - static void test_10_17(); - static void test_10_18(); - static void test_10_19(); // LF or CR (but not CRLF) static void test_11_0(); @@ -276,15 +186,6 @@ namespace { static void test_11_8(); static void test_11_9(); static void test_11_10(); - static void test_11_11(); - static void test_11_12(); - static void test_11_13(); - static void test_11_14(); - static void test_11_15(); - static void test_11_16(); - static void test_11_17(); - static void test_11_18(); - static void test_11_19(); // LF or CRLF static void test_12_0(); @@ -298,15 +199,6 @@ namespace { static void test_12_8(); static void test_12_9(); static void test_12_10(); - static void test_12_11(); - static void test_12_12(); - static void test_12_13(); - static void test_12_14(); - static void test_12_15(); - static void test_12_16(); - static void test_12_17(); - static void test_12_18(); - static void test_12_19(); // CR or CRLF static void test_13_0(); @@ -320,15 +212,6 @@ namespace { static void test_13_8(); static void test_13_9(); static void test_13_10(); - static void test_13_11(); - static void test_13_12(); - static void test_13_13(); - static void test_13_14(); - static void test_13_15(); - static void test_13_16(); - static void test_13_17(); - static void test_13_18(); - static void test_13_19(); // 0 === (LF or CR or CRLF) static void test_14_0(); @@ -342,15 +225,6 @@ namespace { static void test_14_8(); static void test_14_9(); static void test_14_10(); - static void test_14_11(); - static void test_14_12(); - static void test_14_13(); - static void test_14_14(); - static void test_14_15(); - static void test_14_16(); - static void test_14_17(); - static void test_14_18(); - static void test_14_19(); } // anonymous namespace @@ -378,15 +252,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_1_8); XTESTS_RUN_CASE(test_1_9); XTESTS_RUN_CASE(test_1_10); - XTESTS_RUN_CASE(test_1_11); - XTESTS_RUN_CASE(test_1_12); - XTESTS_RUN_CASE(test_1_13); - XTESTS_RUN_CASE(test_1_14); - XTESTS_RUN_CASE(test_1_15); - XTESTS_RUN_CASE(test_1_16); - XTESTS_RUN_CASE(test_1_17); - XTESTS_RUN_CASE(test_1_18); - XTESTS_RUN_CASE(test_1_19); XTESTS_RUN_CASE(test_2_0); XTESTS_RUN_CASE(test_2_1); @@ -399,15 +264,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_2_8); XTESTS_RUN_CASE(test_2_9); XTESTS_RUN_CASE(test_2_10); - XTESTS_RUN_CASE(test_2_11); - XTESTS_RUN_CASE(test_2_12); - XTESTS_RUN_CASE(test_2_13); - XTESTS_RUN_CASE(test_2_14); - XTESTS_RUN_CASE(test_2_15); - XTESTS_RUN_CASE(test_2_16); - XTESTS_RUN_CASE(test_2_17); - XTESTS_RUN_CASE(test_2_18); - XTESTS_RUN_CASE(test_2_19); XTESTS_RUN_CASE(test_3_0); XTESTS_RUN_CASE(test_3_1); @@ -420,15 +276,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_3_8); XTESTS_RUN_CASE(test_3_9); XTESTS_RUN_CASE(test_3_10); - XTESTS_RUN_CASE(test_3_11); - XTESTS_RUN_CASE(test_3_12); - XTESTS_RUN_CASE(test_3_13); - XTESTS_RUN_CASE(test_3_14); - XTESTS_RUN_CASE(test_3_15); - XTESTS_RUN_CASE(test_3_16); - XTESTS_RUN_CASE(test_3_17); - XTESTS_RUN_CASE(test_3_18); - XTESTS_RUN_CASE(test_3_19); XTESTS_RUN_CASE(test_4_0); XTESTS_RUN_CASE(test_4_1); @@ -441,15 +288,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_4_8); XTESTS_RUN_CASE(test_4_9); XTESTS_RUN_CASE(test_4_10); - XTESTS_RUN_CASE(test_4_11); - XTESTS_RUN_CASE(test_4_12); - XTESTS_RUN_CASE(test_4_13); - XTESTS_RUN_CASE(test_4_14); - XTESTS_RUN_CASE(test_4_15); - XTESTS_RUN_CASE(test_4_16); - XTESTS_RUN_CASE(test_4_17); - XTESTS_RUN_CASE(test_4_18); - XTESTS_RUN_CASE(test_4_19); XTESTS_RUN_CASE(test_5_0); XTESTS_RUN_CASE(test_5_1); @@ -462,15 +300,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_5_8); XTESTS_RUN_CASE(test_5_9); XTESTS_RUN_CASE(test_5_10); - XTESTS_RUN_CASE(test_5_11); - XTESTS_RUN_CASE(test_5_12); - XTESTS_RUN_CASE(test_5_13); - XTESTS_RUN_CASE(test_5_14); - XTESTS_RUN_CASE(test_5_15); - XTESTS_RUN_CASE(test_5_16); - XTESTS_RUN_CASE(test_5_17); - XTESTS_RUN_CASE(test_5_18); - XTESTS_RUN_CASE(test_5_19); XTESTS_RUN_CASE(test_6_0); XTESTS_RUN_CASE(test_6_1); @@ -483,15 +312,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_6_8); XTESTS_RUN_CASE(test_6_9); XTESTS_RUN_CASE(test_6_10); - XTESTS_RUN_CASE(test_6_11); - XTESTS_RUN_CASE(test_6_12); - XTESTS_RUN_CASE(test_6_13); - XTESTS_RUN_CASE(test_6_14); - XTESTS_RUN_CASE(test_6_15); - XTESTS_RUN_CASE(test_6_16); - XTESTS_RUN_CASE(test_6_17); - XTESTS_RUN_CASE(test_6_18); - XTESTS_RUN_CASE(test_6_19); XTESTS_RUN_CASE(test_7_0); XTESTS_RUN_CASE(test_7_1); @@ -504,15 +324,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_7_8); XTESTS_RUN_CASE(test_7_9); XTESTS_RUN_CASE(test_7_10); - XTESTS_RUN_CASE(test_7_11); - XTESTS_RUN_CASE(test_7_12); - XTESTS_RUN_CASE(test_7_13); - XTESTS_RUN_CASE(test_7_14); - XTESTS_RUN_CASE(test_7_15); - XTESTS_RUN_CASE(test_7_16); - XTESTS_RUN_CASE(test_7_17); - XTESTS_RUN_CASE(test_7_18); - XTESTS_RUN_CASE(test_7_19); XTESTS_RUN_CASE(test_8_0); XTESTS_RUN_CASE(test_8_1); @@ -525,15 +336,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_8_8); XTESTS_RUN_CASE(test_8_9); XTESTS_RUN_CASE(test_8_10); - XTESTS_RUN_CASE(test_8_11); - XTESTS_RUN_CASE(test_8_12); - XTESTS_RUN_CASE(test_8_13); - XTESTS_RUN_CASE(test_8_14); - XTESTS_RUN_CASE(test_8_15); - XTESTS_RUN_CASE(test_8_16); - XTESTS_RUN_CASE(test_8_17); - XTESTS_RUN_CASE(test_8_18); - XTESTS_RUN_CASE(test_8_19); XTESTS_RUN_CASE(test_9_0); XTESTS_RUN_CASE(test_9_1); @@ -546,15 +348,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_9_8); XTESTS_RUN_CASE(test_9_9); XTESTS_RUN_CASE(test_9_10); - XTESTS_RUN_CASE(test_9_11); - XTESTS_RUN_CASE(test_9_12); - XTESTS_RUN_CASE(test_9_13); - XTESTS_RUN_CASE(test_9_14); - XTESTS_RUN_CASE(test_9_15); - XTESTS_RUN_CASE(test_9_16); - XTESTS_RUN_CASE(test_9_17); - XTESTS_RUN_CASE(test_9_18); - XTESTS_RUN_CASE(test_9_19); XTESTS_RUN_CASE(test_10_0); XTESTS_RUN_CASE(test_10_1); @@ -567,15 +360,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_10_8); XTESTS_RUN_CASE(test_10_9); XTESTS_RUN_CASE(test_10_10); - XTESTS_RUN_CASE(test_10_11); - XTESTS_RUN_CASE(test_10_12); - XTESTS_RUN_CASE(test_10_13); - XTESTS_RUN_CASE(test_10_14); - XTESTS_RUN_CASE(test_10_15); - XTESTS_RUN_CASE(test_10_16); - XTESTS_RUN_CASE(test_10_17); - XTESTS_RUN_CASE(test_10_18); - XTESTS_RUN_CASE(test_10_19); XTESTS_RUN_CASE(test_11_0); XTESTS_RUN_CASE(test_11_1); @@ -588,15 +372,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_11_8); XTESTS_RUN_CASE(test_11_9); XTESTS_RUN_CASE(test_11_10); - XTESTS_RUN_CASE(test_11_11); - XTESTS_RUN_CASE(test_11_12); - XTESTS_RUN_CASE(test_11_13); - XTESTS_RUN_CASE(test_11_14); - XTESTS_RUN_CASE(test_11_15); - XTESTS_RUN_CASE(test_11_16); - XTESTS_RUN_CASE(test_11_17); - XTESTS_RUN_CASE(test_11_18); - XTESTS_RUN_CASE(test_11_19); XTESTS_RUN_CASE(test_12_0); XTESTS_RUN_CASE(test_12_1); @@ -609,15 +384,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_12_8); XTESTS_RUN_CASE(test_12_9); XTESTS_RUN_CASE(test_12_10); - XTESTS_RUN_CASE(test_12_11); - XTESTS_RUN_CASE(test_12_12); - XTESTS_RUN_CASE(test_12_13); - XTESTS_RUN_CASE(test_12_14); - XTESTS_RUN_CASE(test_12_15); - XTESTS_RUN_CASE(test_12_16); - XTESTS_RUN_CASE(test_12_17); - XTESTS_RUN_CASE(test_12_18); - XTESTS_RUN_CASE(test_12_19); XTESTS_RUN_CASE(test_13_0); XTESTS_RUN_CASE(test_13_1); @@ -630,15 +396,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_13_8); XTESTS_RUN_CASE(test_13_9); XTESTS_RUN_CASE(test_13_10); - XTESTS_RUN_CASE(test_13_11); - XTESTS_RUN_CASE(test_13_12); - XTESTS_RUN_CASE(test_13_13); - XTESTS_RUN_CASE(test_13_14); - XTESTS_RUN_CASE(test_13_15); - XTESTS_RUN_CASE(test_13_16); - XTESTS_RUN_CASE(test_13_17); - XTESTS_RUN_CASE(test_13_18); - XTESTS_RUN_CASE(test_13_19); XTESTS_RUN_CASE(test_14_0); XTESTS_RUN_CASE(test_14_1); @@ -651,15 +408,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_14_8); XTESTS_RUN_CASE(test_14_9); XTESTS_RUN_CASE(test_14_10); - XTESTS_RUN_CASE(test_14_11); - XTESTS_RUN_CASE(test_14_12); - XTESTS_RUN_CASE(test_14_13); - XTESTS_RUN_CASE(test_14_14); - XTESTS_RUN_CASE(test_14_15); - XTESTS_RUN_CASE(test_14_16); - XTESTS_RUN_CASE(test_14_17); - XTESTS_RUN_CASE(test_14_18); - XTESTS_RUN_CASE(test_14_19); XTESTS_PRINT_RESULTS(); @@ -889,45 +637,6 @@ static void test_1_10() TEST_MS_EQ_APPROX("", line0); } -static void test_1_11() -{ -} - -static void test_1_12() -{ -} - -static void test_1_13() -{ -} - -static void test_1_14() -{ -} - -static void test_1_15() -{ -} - -static void test_1_16() -{ -} - -static void test_1_17() -{ -} - -static void test_1_18() -{ -} - -static void test_1_19() -{ -} - - - - static void test_2_0() { read_from_char_buffer policy("", 0); @@ -1122,44 +831,6 @@ static void test_2_10() TEST_MS_EQ_APPROX("", line0); } -static void test_2_11() -{ -} - -static void test_2_12() -{ -} - -static void test_2_13() -{ -} - -static void test_2_14() -{ -} - -static void test_2_15() -{ -} - -static void test_2_16() -{ -} - -static void test_2_17() -{ -} - -static void test_2_18() -{ -} - -static void test_2_19() -{ -} - - - static void test_3_0() { read_from_char_buffer policy("", 0); @@ -1330,45 +1001,6 @@ static void test_3_10() TEST_MS_EQ_APPROX("", line0); } -static void test_3_11() -{ -} - -static void test_3_12() -{ -} - -static void test_3_13() -{ -} - -static void test_3_14() -{ -} - -static void test_3_15() -{ -} - -static void test_3_16() -{ -} - -static void test_3_17() -{ -} - -static void test_3_18() -{ -} - -static void test_3_19() -{ -} - - - - static void test_4_0() { read_from_char_buffer policy("", 0); @@ -1703,44 +1335,6 @@ static void test_4_10() TEST_MS_EQ_APPROX("", line0); } -static void test_4_11() -{ -} - -static void test_4_12() -{ -} - -static void test_4_13() -{ -} - -static void test_4_14() -{ -} - -static void test_4_15() -{ -} - -static void test_4_16() -{ -} - -static void test_4_17() -{ -} - -static void test_4_18() -{ -} - -static void test_4_19() -{ -} - - - static void test_5_0() { read_from_char_buffer policy("", 0); @@ -1939,44 +1533,6 @@ static void test_5_10() TEST_MS_EQ_APPROX("", line0); } -static void test_5_11() -{ -} - -static void test_5_12() -{ -} - -static void test_5_13() -{ -} - -static void test_5_14() -{ -} - -static void test_5_15() -{ -} - -static void test_5_16() -{ -} - -static void test_5_17() -{ -} - -static void test_5_18() -{ -} - -static void test_5_19() -{ -} - - - static void test_6_0() { read_from_char_buffer policy("", 0); @@ -2247,44 +1803,6 @@ static void test_6_10() TEST_MS_EQ_APPROX("", line0); } -static void test_6_11() -{ -} - -static void test_6_12() -{ -} - -static void test_6_13() -{ -} - -static void test_6_14() -{ -} - -static void test_6_15() -{ -} - -static void test_6_16() -{ -} - -static void test_6_17() -{ -} - -static void test_6_18() -{ -} - -static void test_6_19() -{ -} - - - static void test_7_0() { read_from_char_buffer policy("", 0); @@ -2579,48 +2097,6 @@ static void test_7_10() TEST_MS_EQ_APPROX("", line0); } -static void test_7_11() -{ -} - -static void test_7_12() -{ -} - -static void test_7_13() -{ -} - -static void test_7_14() -{ -} - -static void test_7_15() -{ -} - -static void test_7_16() -{ -} - -static void test_7_17() -{ -} - -static void test_7_18() -{ -} - -static void test_7_19() -{ -} - - - - - - - static void test_8_0() { std::string const input(""); @@ -2833,45 +2309,6 @@ static void test_8_10() TEST_MS_EQ_APPROX("", line0); } -static void test_8_11() -{ -} - -static void test_8_12() -{ -} - -static void test_8_13() -{ -} - -static void test_8_14() -{ -} - -static void test_8_15() -{ -} - -static void test_8_16() -{ -} - -static void test_8_17() -{ -} - -static void test_8_18() -{ -} - -static void test_8_19() -{ -} - - - - static void test_9_0() { std::string const input(""); @@ -3088,44 +2525,6 @@ static void test_9_10() TEST_MS_EQ_APPROX("", line0); } -static void test_9_11() -{ -} - -static void test_9_12() -{ -} - -static void test_9_13() -{ -} - -static void test_9_14() -{ -} - -static void test_9_15() -{ -} - -static void test_9_16() -{ -} - -static void test_9_17() -{ -} - -static void test_9_18() -{ -} - -static void test_9_19() -{ -} - - - static void test_10_0() { std::string const input(""); @@ -3318,45 +2717,6 @@ static void test_10_10() TEST_MS_EQ_APPROX("", line0); } -static void test_10_11() -{ -} - -static void test_10_12() -{ -} - -static void test_10_13() -{ -} - -static void test_10_14() -{ -} - -static void test_10_15() -{ -} - -static void test_10_16() -{ -} - -static void test_10_17() -{ -} - -static void test_10_18() -{ -} - -static void test_10_19() -{ -} - - - - static void test_11_0() { std::string const input(""); @@ -3713,44 +3073,6 @@ static void test_11_10() TEST_MS_EQ_APPROX("", line0); } -static void test_11_11() -{ -} - -static void test_11_12() -{ -} - -static void test_11_13() -{ -} - -static void test_11_14() -{ -} - -static void test_11_15() -{ -} - -static void test_11_16() -{ -} - -static void test_11_17() -{ -} - -static void test_11_18() -{ -} - -static void test_11_19() -{ -} - - - static void test_12_0() { std::string const input(""); @@ -3971,44 +3293,6 @@ static void test_12_10() TEST_MS_EQ_APPROX("", line0); } -static void test_12_11() -{ -} - -static void test_12_12() -{ -} - -static void test_12_13() -{ -} - -static void test_12_14() -{ -} - -static void test_12_15() -{ -} - -static void test_12_16() -{ -} - -static void test_12_17() -{ -} - -static void test_12_18() -{ -} - -static void test_12_19() -{ -} - - - static void test_13_0() { std::string const input(""); @@ -4301,44 +3585,6 @@ static void test_13_10() TEST_MS_EQ_APPROX("", line0); } -static void test_13_11() -{ -} - -static void test_13_12() -{ -} - -static void test_13_13() -{ -} - -static void test_13_14() -{ -} - -static void test_13_15() -{ -} - -static void test_13_16() -{ -} - -static void test_13_17() -{ -} - -static void test_13_18() -{ -} - -static void test_13_19() -{ -} - - - static void test_14_0() { std::string const input(""); @@ -4654,42 +3900,6 @@ static void test_14_10() TEST_INT_EQ(0u, line0.size()); TEST_MS_EQ_APPROX("", line0); } - -static void test_14_11() -{ -} - -static void test_14_12() -{ -} - -static void test_14_13() -{ -} - -static void test_14_14() -{ -} - -static void test_14_15() -{ -} - -static void test_14_16() -{ -} - -static void test_14_17() -{ -} - -static void test_14_18() -{ -} - -static void test_14_19() -{ -} } // anonymous namespace diff --git a/test/unit/stlsoft/memory/malloc_allocator/entry.cpp b/test/unit/stlsoft/memory/malloc_allocator/entry.cpp index cb55838f..60d6493b 100644 --- a/test/unit/stlsoft/memory/malloc_allocator/entry.cpp +++ b/test/unit/stlsoft/memory/malloc_allocator/entry.cpp @@ -29,9 +29,12 @@ #include /* STLSoft header files */ +#include #include /* Standard C++ header files */ +#include +#include /* Standard C header files */ #include @@ -92,39 +95,117 @@ int main(int argc, char *argv[]) namespace { +typedef stlsoft::malloc_allocator allocator_t; + +static void exercise_allocate(allocator_t::size_type n) +{ + allocator_t ator; + allocator_t::pointer p = ator.allocate(n); + + TEST_PTR_NE(NULL, p); + + for (allocator_t::size_type i = 0; i != n; ++i) + { + ator.construct(&p[i], static_cast(i)); + } + + for (allocator_t::size_type i = 0; i != n; ++i) + { + TEST_INT_EQ(static_cast(i), p[i]); + + ator.destroy(&p[i]); + } + + ator.deallocate(p, n); +} + static void test_alloc_0() { + allocator_t a1; + allocator_t a2; + + TEST_BOOLEAN_TRUE(a1 == a2); + TEST_BOOLEAN_FALSE(a1 != a2); + + allocator_t::pointer p = a1.allocate(0); + + TEST_PTR_NE(NULL, p); + a1.deallocate(p); } static void test_alloc_small() { - + exercise_allocate(4); } static void test_alloc_medium() { - + exercise_allocate(256); } static void test_alloc_large() { - + exercise_allocate(4096); } static void test_alloc_toolarge() { + allocator_t ator; + allocator_t::size_type const too_large = ator.max_size() + 1; + + try + { + static_cast(ator.allocate(too_large)); + TEST_FAIL("should not get here"); + } + catch (stlsoft::out_of_memory_exception&) + { + TEST_PASSED(); + } } static void test_specialise_list() { + typedef std::list list_t; + list_t items; + + items.push_back(10); + items.push_back(20); + items.push_back(30); + + TEST_INT_EQ(3u, items.size()); + + list_t::const_iterator it = items.begin(); + + TEST_INT_EQ(10, *it); + ++it; + TEST_INT_EQ(20, *it); + ++it; + TEST_INT_EQ(30, *it); } static void test_specialise_vector() { + typedef std::vector vector_t; + + vector_t v; + + v.push_back(10); + v.push_back(20); + v.push_back(30); + + TEST_INT_EQ(3u, v.size()); + TEST_INT_EQ(10, v[0]); + TEST_INT_EQ(20, v[1]); + TEST_INT_EQ(30, v[2]); + + v.resize(1); + TEST_INT_EQ(1u, v.size()); + TEST_INT_EQ(10, v[0]); } } // anonymous namespace diff --git a/test/unit/stlsoft/memory/new_allocator/entry.cpp b/test/unit/stlsoft/memory/new_allocator/entry.cpp index 3fb2dcdd..65725c02 100644 --- a/test/unit/stlsoft/memory/new_allocator/entry.cpp +++ b/test/unit/stlsoft/memory/new_allocator/entry.cpp @@ -29,9 +29,12 @@ #include /* STLSoft header files */ +#include #include /* Standard C++ header files */ +#include +#include /* Standard C header files */ #include @@ -92,39 +95,117 @@ int main(int argc, char *argv[]) namespace { +typedef stlsoft::new_allocator allocator_t; + +static void exercise_allocate(allocator_t::size_type n) +{ + allocator_t ator; + allocator_t::pointer p = ator.allocate(n); + + TEST_PTR_NE(NULL, p); + + for (allocator_t::size_type i = 0; i != n; ++i) + { + ator.construct(&p[i], static_cast(i)); + } + + for (allocator_t::size_type i = 0; i != n; ++i) + { + TEST_INT_EQ(static_cast(i), p[i]); + + ator.destroy(&p[i]); + } + + ator.deallocate(p, n); +} + static void test_alloc_0() { + allocator_t a1; + allocator_t a2; + + TEST_BOOLEAN_TRUE(a1 == a2); + TEST_BOOLEAN_FALSE(a1 != a2); + + allocator_t::pointer p = a1.allocate(0); + + TEST_PTR_NE(NULL, p); + a1.deallocate(p); } static void test_alloc_small() { - + exercise_allocate(4); } static void test_alloc_medium() { - + exercise_allocate(256); } static void test_alloc_large() { - + exercise_allocate(4096); } static void test_alloc_toolarge() { + allocator_t ator; + allocator_t::size_type const too_large = ator.max_size() + 1; + + try + { + static_cast(ator.allocate(too_large)); + TEST_FAIL("should not get here"); + } + catch (stlsoft::out_of_memory_exception&) + { + TEST_PASSED(); + } } static void test_specialise_list() { + typedef std::list list_t; + list_t items; + + items.push_back(10); + items.push_back(20); + items.push_back(30); + + TEST_INT_EQ(3u, items.size()); + + list_t::const_iterator it = items.begin(); + + TEST_INT_EQ(10, *it); + ++it; + TEST_INT_EQ(20, *it); + ++it; + TEST_INT_EQ(30, *it); } static void test_specialise_vector() { + typedef std::vector vector_t; + + vector_t v; + + v.push_back(10); + v.push_back(20); + v.push_back(30); + + TEST_INT_EQ(3u, v.size()); + TEST_INT_EQ(10, v[0]); + TEST_INT_EQ(20, v[1]); + TEST_INT_EQ(30, v[2]); + + v.resize(1); + TEST_INT_EQ(1u, v.size()); + TEST_INT_EQ(10, v[0]); } } // anonymous namespace diff --git a/test/unit/stlsoft/memory/null_allocator/entry.cpp b/test/unit/stlsoft/memory/null_allocator/entry.cpp index 8a2c96b0..c268b167 100644 --- a/test/unit/stlsoft/memory/null_allocator/entry.cpp +++ b/test/unit/stlsoft/memory/null_allocator/entry.cpp @@ -4,7 +4,7 @@ * Purpose: Unit-tests for `stlsoft::null_allocator`. * * Created: 18th October 2024 - * Updated: 29th September 2026 + * Updated: 30th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -29,9 +29,12 @@ #include /* STLSoft header files */ +#include #include /* Standard C++ header files */ +#include +#include /* Standard C header files */ #include @@ -92,39 +95,94 @@ int main(int argc, char *argv[]) namespace { +typedef stlsoft::null_allocator allocator_t; + +static void expect_out_of_memory(allocator_t& ator, allocator_t::size_type n) +{ + int threw = 0; + + try + { + static_cast(ator.allocate(n)); + } + catch (stlsoft::out_of_memory_exception&) + { + threw = 1; + } + + TEST_INT_EQ(1, threw); +} + static void test_alloc_0() { + allocator_t a1; + allocator_t a2; + + TEST_BOOLEAN_TRUE(a1 == a2); + TEST_BOOLEAN_FALSE(a1 != a2); + expect_out_of_memory(a1, 0); } static void test_alloc_small() { + allocator_t ator; + expect_out_of_memory(ator, 4); } static void test_alloc_medium() { + allocator_t ator; + expect_out_of_memory(ator, 256); } static void test_alloc_large() { + allocator_t ator; + expect_out_of_memory(ator, 4096); } static void test_alloc_toolarge() { + allocator_t ator; + allocator_t::size_type const too_large = ator.max_size() + 1; + expect_out_of_memory(ator, too_large); } static void test_specialise_list() { + try + { + std::list items; + + items.push_back(1); + TEST_FAIL("should not get here"); + } + catch (stlsoft::out_of_memory_exception&) + { + TEST_PASSED(); + } } static void test_specialise_vector() { + try + { + std::vector v; + + v.push_back(1); + TEST_FAIL("should not get here"); + } + catch (stlsoft::out_of_memory_exception&) + { + TEST_PASSED(); + } } } // anonymous namespace diff --git a/test/unit/stlsoft/smartptr/scoped_handle/entry.cpp b/test/unit/stlsoft/smartptr/scoped_handle/entry.cpp index 1a40cb74..a42cc740 100644 --- a/test/unit/stlsoft/smartptr/scoped_handle/entry.cpp +++ b/test/unit/stlsoft/smartptr/scoped_handle/entry.cpp @@ -48,21 +48,8 @@ namespace { static void test_1_2(); static void test_1_3(); static void test_1_4(); - static void test_1_5(); static void test_1_6(); - static void test_1_7(); - static void test_1_8(); - static void test_1_9(); static void test_1_10(); - static void test_1_11(); - static void test_1_12(); - static void test_1_13(); - static void test_1_14(); - static void test_1_15(); - static void test_1_16(); - static void test_1_17(); - static void test_1_18(); - static void test_1_19(); #endif /* compiler */ } // anonymous namespace @@ -91,21 +78,8 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_1_2); XTESTS_RUN_CASE(test_1_3); XTESTS_RUN_CASE(test_1_4); - XTESTS_RUN_CASE(test_1_5); XTESTS_RUN_CASE(test_1_6); - XTESTS_RUN_CASE(test_1_7); - XTESTS_RUN_CASE(test_1_8); - XTESTS_RUN_CASE(test_1_9); XTESTS_RUN_CASE(test_1_10); - XTESTS_RUN_CASE(test_1_11); - XTESTS_RUN_CASE(test_1_12); - XTESTS_RUN_CASE(test_1_13); - XTESTS_RUN_CASE(test_1_14); - XTESTS_RUN_CASE(test_1_15); - XTESTS_RUN_CASE(test_1_16); - XTESTS_RUN_CASE(test_1_17); - XTESTS_RUN_CASE(test_1_18); - XTESTS_RUN_CASE(test_1_19); #endif /* compiler */ XTESTS_PRINT_RESULTS(); @@ -452,10 +426,6 @@ static void test_1_4() TEST_INT_EQ(0, s_intCount); } -static void test_1_5() -{ -} - static void test_1_6() { TEST_INT_EQ(0, s_voidCount); @@ -533,18 +503,6 @@ static void test_1_6() TEST_INT_EQ(0, s_voidCount); } -static void test_1_7() -{ -} - -static void test_1_8() -{ -} - -static void test_1_9() -{ -} - static void test_1_10() { TEST_INT_EQ(0, s_intCount); @@ -604,42 +562,6 @@ static void test_1_10() TEST_INT_EQ(0, s_intCount); } - -static void test_1_11() -{ -} - -static void test_1_12() -{ -} - -static void test_1_13() -{ -} - -static void test_1_14() -{ -} - -static void test_1_15() -{ -} - -static void test_1_16() -{ -} - -static void test_1_17() -{ -} - -static void test_1_18() -{ -} - -static void test_1_19() -{ -} #endif /* compiler */ } // anonymous namespace @@ -804,4 +726,3 @@ namespace { /* ///////////////////////////// end of file //////////////////////////// */ - diff --git a/test/unit/stlsoft/smartptr/shared_ptr/entry.cpp b/test/unit/stlsoft/smartptr/shared_ptr/entry.cpp index 9c3f5f61..d71335e7 100644 --- a/test/unit/stlsoft/smartptr/shared_ptr/entry.cpp +++ b/test/unit/stlsoft/smartptr/shared_ptr/entry.cpp @@ -52,7 +52,6 @@ namespace { #endif static void test_swap(); static void test_std_swap(); - static void test_1_1(); } // anonymous namespace @@ -81,7 +80,6 @@ int main(int argc, char* argv[]) #endif XTESTS_RUN_CASE(test_swap); XTESTS_RUN_CASE(test_std_swap); - XTESTS_RUN_CASE(test_1_1); XTESTS_PRINT_RESULTS(); @@ -545,10 +543,6 @@ static void test_std_swap() TEST_INT_EQ(3u, ptr2->size()); } } - -static void test_1_1() -{ -} } // anonymous namespace diff --git a/test/unit/stlsoft/string/shim_string/entry.cpp b/test/unit/stlsoft/string/shim_string/entry.cpp index 15fd8628..b294c610 100644 --- a/test/unit/stlsoft/string/shim_string/entry.cpp +++ b/test/unit/stlsoft/string/shim_string/entry.cpp @@ -62,18 +62,11 @@ namespace { static void test_write(); static void test_truncate(); static void test_swap(); - static void test_1_8(); - static void test_1_9(); static void test_append_c_string(); static void test_append_c_string_after_truncate(); - static void test_1_12(); static void test_null_string(); static void test_reserve(); static void test_resize(); - static void test_1_16(); - static void test_1_17(); - static void test_1_18(); - static void test_1_19(); static void test_insertion_1(); static void test_insertion_2(); static void test_insertion_3(); @@ -103,18 +96,11 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_write); XTESTS_RUN_CASE(test_truncate); XTESTS_RUN_CASE(test_swap); - XTESTS_RUN_CASE(test_1_8); - XTESTS_RUN_CASE(test_1_9); XTESTS_RUN_CASE(test_append_c_string); XTESTS_RUN_CASE(test_append_c_string_after_truncate); - XTESTS_RUN_CASE(test_1_12); XTESTS_RUN_CASE(test_null_string); XTESTS_RUN_CASE(test_reserve); XTESTS_RUN_CASE(test_resize); - XTESTS_RUN_CASE(test_1_16); - XTESTS_RUN_CASE(test_1_17); - XTESTS_RUN_CASE(test_1_18); - XTESTS_RUN_CASE(test_1_19); XTESTS_RUN_CASE(test_insertion_1); XTESTS_RUN_CASE(test_insertion_2); XTESTS_RUN_CASE(test_insertion_3); @@ -382,14 +368,6 @@ static void test_swap() } } -static void test_1_8() -{ -} - -static void test_1_9() -{ -} - static void test_append_c_string() { char const* strings[] = @@ -445,10 +423,6 @@ static void test_append_c_string_after_truncate() }} } -static void test_1_12() -{ -} - static void test_null_string() { { @@ -534,22 +508,6 @@ static void test_resize() } -static void test_1_16() -{ -} - -static void test_1_17() -{ -} - -static void test_1_18() -{ -} - -static void test_1_19() -{ -} - static void test_insertion_1() { // char const* (for reference) @@ -857,7 +815,6 @@ static void test_insertion_3() } } - static void test_insertion_4() { const std::size_t FIELD_WIDTH = 2000; diff --git a/test/unit/stlsoft/string/simple_string/entry.cpp b/test/unit/stlsoft/string/simple_string/entry.cpp index bc69bfd0..3b7230ff 100644 --- a/test/unit/stlsoft/string/simple_string/entry.cpp +++ b/test/unit/stlsoft/string/simple_string/entry.cpp @@ -117,11 +117,8 @@ namespace { // attributes - static void test_size(); static void test_max_size(); - static void test_length(); static void test_capacity(); - static void test_empty(); // comparison @@ -288,11 +285,8 @@ int main(int argc, char* argv[]) // attributes - XTESTS_RUN_CASE(test_size); XTESTS_RUN_CASE(test_max_size); - XTESTS_RUN_CASE(test_length); XTESTS_RUN_CASE(test_capacity); - XTESTS_RUN_CASE(test_empty); // comparison @@ -1331,12 +1325,6 @@ static void test_erase_pos_and_cch() // attributes -static void test_size() -{ - { - - } -} static void test_max_size() { @@ -1345,11 +1333,6 @@ static void test_max_size() TEST_INT_GE(1000000u, s.max_size()); } -static void test_length() -{ - -} - static void test_capacity() { string_t s; @@ -1365,10 +1348,6 @@ static void test_capacity() TEST_INT_GE(1000u, s.capacity()); } -static void test_empty() -{ - -} // comparison diff --git a/test/unit/stlsoft/string/static_string/entry.cpp b/test/unit/stlsoft/string/static_string/entry.cpp index 393b5f5c..f6c00d8a 100644 --- a/test/unit/stlsoft/string/static_string/entry.cpp +++ b/test/unit/stlsoft/string/static_string/entry.cpp @@ -63,7 +63,6 @@ namespace { static void test_ctor_ccs_n_too_large(); static void test_ctor_n_ch(); static void test_ctor_n_ch_too_large(); - static void test_ctor_range(); static void test_ctor_range_too_large(); // `assign()` @@ -79,10 +78,7 @@ namespace { static void test_assign_n_ch_too_large(); static void test_assign_range(); static void test_assign_range_too_large(); - static void test_opassign_ccs(); static void test_opassign_ccs_too_large(); - static void test_opassign_s(); - static void test_opassign_ch(); // `append()` @@ -121,11 +117,8 @@ namespace { // attributes - static void test_size(); static void test_max_size(); - static void test_length(); static void test_capacity(); - static void test_empty(); // comparison @@ -153,9 +146,6 @@ namespace { #ifdef STLSOFT_CF_EXCEPTION_SUPPORT static void TEST_overlong_ctor(); - static void TEST_overlong_append(); - static void TEST_overlong_assign(); - static void TEST_overlong_reserve(); static void TEST_overlong_resize(); #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */ @@ -205,7 +195,6 @@ int main(int argc, char* argv[]) XTESTS_RUN_CASE_THAT_THROWS(test_ctor_ccs_n_too_large, std::length_error); XTESTS_RUN_CASE(test_ctor_n_ch); XTESTS_RUN_CASE_THAT_THROWS(test_ctor_n_ch_too_large, std::length_error); - XTESTS_RUN_CASE(test_ctor_range); XTESTS_RUN_CASE_THAT_THROWS(test_ctor_range_too_large, std::length_error); // `assign()` @@ -221,10 +210,7 @@ int main(int argc, char* argv[]) XTESTS_RUN_CASE_THAT_THROWS(test_assign_n_ch_too_large, std::length_error); XTESTS_RUN_CASE(test_assign_range); XTESTS_RUN_CASE_THAT_THROWS(test_assign_range_too_large, std::length_error); - XTESTS_RUN_CASE(test_opassign_ccs); XTESTS_RUN_CASE_THAT_THROWS(test_opassign_ccs_too_large, std::length_error); - XTESTS_RUN_CASE(test_opassign_s); - XTESTS_RUN_CASE(test_opassign_ch); // `append()` @@ -263,11 +249,8 @@ int main(int argc, char* argv[]) // attributes - XTESTS_RUN_CASE(test_size); XTESTS_RUN_CASE(test_max_size); - XTESTS_RUN_CASE(test_length); XTESTS_RUN_CASE(test_capacity); - XTESTS_RUN_CASE(test_empty); // comparison @@ -294,9 +277,6 @@ int main(int argc, char* argv[]) #ifdef STLSOFT_CF_EXCEPTION_SUPPORT XTESTS_RUN_CASE(TEST_overlong_ctor); - XTESTS_RUN_CASE(TEST_overlong_append); - XTESTS_RUN_CASE(TEST_overlong_assign); - XTESTS_RUN_CASE(TEST_overlong_reserve); XTESTS_RUN_CASE(TEST_overlong_resize); #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */ @@ -604,10 +584,6 @@ static void test_ctor_n_ch_too_large() string_t s(11, '~'); } -static void test_ctor_range() -{ -} - static void test_ctor_range_too_large() { typedef string_30_t string_t; @@ -881,11 +857,6 @@ static void test_assign_range_too_large() s.assign(&alphabet2[0], &alphabet2[0] + STLSOFT_NUM_ELEMENTS(alphabet2) -1); } -static void test_opassign_ccs() -{ - -} - static void test_opassign_ccs_too_large() { typedef string_10_t string_t; @@ -895,15 +866,7 @@ static void test_opassign_ccs_too_large() s = alphabet; } -static void test_opassign_s() -{ -} - -static void test_opassign_ch() -{ - -} // `append()` @@ -1473,12 +1436,6 @@ static void test_clear() // attributes -static void test_size() -{ - { - - } -} static void test_max_size() { @@ -1495,11 +1452,6 @@ static void test_max_size() } } -static void test_length() -{ - -} - static void test_capacity() { { @@ -1519,10 +1471,6 @@ static void test_capacity() } } -static void test_empty() -{ - -} @@ -2196,21 +2144,6 @@ static void TEST_overlong_ctor() } } -static void TEST_overlong_append() -{ - -} - -static void TEST_overlong_assign() -{ - -} - -static void TEST_overlong_reserve() -{ - -} - static void TEST_overlong_resize() { typedef string_10_t string_t; diff --git a/test/unit/stlsoft/util/true_typedef/entry.cpp b/test/unit/stlsoft/util/true_typedef/entry.cpp index d93cc368..36446c06 100644 --- a/test/unit/stlsoft/util/true_typedef/entry.cpp +++ b/test/unit/stlsoft/util/true_typedef/entry.cpp @@ -48,7 +48,6 @@ namespace { static void test_int_spec(); - static void test_Integer_spec(); static void test_double_spec(); static void test_stdstring_spec(); } // anonymous namespace @@ -68,7 +67,6 @@ int main(int argc, char *argv[]) if (XTESTS_START_RUNNER("test.unit.stlsoft.util.true_typedef", verbosity)) { XTESTS_RUN_CASE(test_int_spec); - XTESTS_RUN_CASE(test_Integer_spec); XTESTS_RUN_CASE(test_double_spec); XTESTS_RUN_CASE(test_stdstring_spec); @@ -645,11 +643,6 @@ static void test_int_spec() } } -static void test_Integer_spec() -{ - -} - static void test_double_spec() { STLSOFT_GEN_OPAQUE(h_double_tt) diff --git a/test/unit/winstl/filesystem/filesystem_traits/entry.cpp b/test/unit/winstl/filesystem/filesystem_traits/entry.cpp index 6d3706e6..0a9e3e6e 100644 --- a/test/unit/winstl/filesystem/filesystem_traits/entry.cpp +++ b/test/unit/winstl/filesystem/filesystem_traits/entry.cpp @@ -47,13 +47,10 @@ namespace { static void TEST_starts_with_dots(); static void TEST_ensure_dir_end_1(); // TODO: rename to `dirname_ensure_pns()` - static void TEST_ensure_dir_end_4(); // TODO: rename to `dirname_ensure_pns()` static void TEST_has_dir_end_1(); - static void TEST_has_dir_end_2(); static void TEST_remove_dir_end_1(); - static void TEST_remove_dir_end_3(); static void TEST_find_last_path_name_separator(); static void TEST_find_next_path_name_separator(); @@ -77,7 +74,6 @@ namespace { static void TEST_pathComparisonIsCaseSensitive(); static void TEST_str_fs_compare(); - static void TEST_str_fs_n_compare(); } // anonymous namespace @@ -98,13 +94,10 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(TEST_starts_with_dots); XTESTS_RUN_CASE(TEST_ensure_dir_end_1); - XTESTS_RUN_CASE(TEST_ensure_dir_end_4); XTESTS_RUN_CASE(TEST_has_dir_end_1); - XTESTS_RUN_CASE(TEST_has_dir_end_2); XTESTS_RUN_CASE(TEST_remove_dir_end_1); - XTESTS_RUN_CASE(TEST_remove_dir_end_3); XTESTS_RUN_CASE(TEST_path_is_absolute_1); XTESTS_RUN_CASE(TEST_path_is_absolute_2); @@ -129,7 +122,6 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(TEST_pathComparisonIsCaseSensitive); XTESTS_RUN_CASE(TEST_str_fs_compare); - XTESTS_RUN_CASE(TEST_str_fs_n_compare); XTESTS_PRINT_RESULTS(); @@ -492,10 +484,6 @@ static void TEST_ensure_dir_end_1() } } -static void TEST_ensure_dir_end_4() -{ -} - static void TEST_has_dir_end_1() { // empty string @@ -707,10 +695,6 @@ static void TEST_has_dir_end_1() } } -static void TEST_has_dir_end_2() -{ -} - static void TEST_remove_dir_end_1() { // empty string @@ -974,11 +958,6 @@ static void TEST_remove_dir_end_1() } } -static void TEST_remove_dir_end_3() -{ - -} - static void TEST_path_is_absolute_1() { { @@ -1838,11 +1817,6 @@ static void TEST_str_fs_compare() } } } - -static void TEST_str_fs_n_compare() -{ - -} } /* anonymous namespace */ diff --git a/test/unit/winstl/memory/global_allocator/entry.cpp b/test/unit/winstl/memory/global_allocator/entry.cpp index a7f7e62a..3a00b35b 100644 --- a/test/unit/winstl/memory/global_allocator/entry.cpp +++ b/test/unit/winstl/memory/global_allocator/entry.cpp @@ -29,9 +29,12 @@ #include /* STLSoft header files */ +#include #include /* Standard C++ header files */ +#include +#include /* Standard C header files */ #include @@ -92,39 +95,117 @@ int main(int argc, char *argv[]) namespace { +typedef winstl::global_allocator allocator_t; + +static void exercise_allocate(allocator_t::size_type n) +{ + allocator_t ator; + allocator_t::pointer p = ator.allocate(n); + + TEST_PTR_NE(NULL, p); + + for (allocator_t::size_type i = 0; i != n; ++i) + { + ator.construct(&p[i], static_cast(i)); + } + + for (allocator_t::size_type i = 0; i != n; ++i) + { + TEST_INT_EQ(static_cast(i), p[i]); + + ator.destroy(&p[i]); + } + + ator.deallocate(p, n); +} + static void test_alloc_0() { + allocator_t a1; + allocator_t a2; + + TEST_BOOLEAN_TRUE(a1 == a2); + TEST_BOOLEAN_FALSE(a1 != a2); + + allocator_t::pointer p = a1.allocate(0); + + TEST_PTR_NE(NULL, p); + a1.deallocate(p); } static void test_alloc_small() { - + exercise_allocate(4); } static void test_alloc_medium() { - + exercise_allocate(256); } static void test_alloc_large() { - + exercise_allocate(4096); } static void test_alloc_toolarge() { + allocator_t ator; + allocator_t::size_type const too_large = ator.max_size() + 1; + + try + { + static_cast(ator.allocate(too_large)); + TEST_FAIL("should not get here"); + } + catch (stlsoft::out_of_memory_exception&) + { + TEST_PASSED(); + } } static void test_specialise_list() { + typedef std::list list_t; + list_t items; + + items.push_back(10); + items.push_back(20); + items.push_back(30); + + TEST_INT_EQ(3u, items.size()); + + list_t::const_iterator it = items.begin(); + + TEST_INT_EQ(10, *it); + ++it; + TEST_INT_EQ(20, *it); + ++it; + TEST_INT_EQ(30, *it); } static void test_specialise_vector() { + typedef std::vector vector_t; + + vector_t v; + + v.push_back(10); + v.push_back(20); + v.push_back(30); + + TEST_INT_EQ(3u, v.size()); + TEST_INT_EQ(10, v[0]); + TEST_INT_EQ(20, v[1]); + TEST_INT_EQ(30, v[2]); + + v.resize(1); + TEST_INT_EQ(1u, v.size()); + TEST_INT_EQ(10, v[0]); } } // anonymous namespace diff --git a/test/unit/winstl/memory/netapi_allocator/CMakeLists.txt b/test/unit/winstl/memory/netapi_allocator/CMakeLists.txt index cdb2566e..8d706580 100644 --- a/test/unit/winstl/memory/netapi_allocator/CMakeLists.txt +++ b/test/unit/winstl/memory/netapi_allocator/CMakeLists.txt @@ -1,2 +1,8 @@ -# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten define_automated_test_program(test.unit.winstl.memory.netapi_allocator entry.cpp) + +if(WIN32) + + target_link_libraries(test.unit.winstl.memory.netapi_allocator + netapi32 + ) +endif() diff --git a/test/unit/winstl/memory/netapi_allocator/entry.cpp b/test/unit/winstl/memory/netapi_allocator/entry.cpp index 5f8f3d3f..94fb1ace 100644 --- a/test/unit/winstl/memory/netapi_allocator/entry.cpp +++ b/test/unit/winstl/memory/netapi_allocator/entry.cpp @@ -29,9 +29,12 @@ #include /* STLSoft header files */ +#include #include /* Standard C++ header files */ +#include +#include /* Standard C header files */ #include @@ -92,39 +95,117 @@ int main(int argc, char *argv[]) namespace { +typedef winstl::netapi_allocator allocator_t; + +static void exercise_allocate(allocator_t::size_type n) +{ + allocator_t ator; + allocator_t::pointer p = ator.allocate(n); + + TEST_PTR_NE(NULL, p); + + for (allocator_t::size_type i = 0; i != n; ++i) + { + ator.construct(&p[i], static_cast(i)); + } + + for (allocator_t::size_type i = 0; i != n; ++i) + { + TEST_INT_EQ(static_cast(i), p[i]); + + ator.destroy(&p[i]); + } + + ator.deallocate(p, n); +} + static void test_alloc_0() { + allocator_t a1; + allocator_t a2; + + TEST_BOOLEAN_TRUE(a1 == a2); + TEST_BOOLEAN_FALSE(a1 != a2); + + allocator_t::pointer p = a1.allocate(0); + + TEST_PTR_NE(NULL, p); + a1.deallocate(p); } static void test_alloc_small() { - + exercise_allocate(4); } static void test_alloc_medium() { - + exercise_allocate(256); } static void test_alloc_large() { - + exercise_allocate(4096); } static void test_alloc_toolarge() { + allocator_t ator; + allocator_t::size_type const too_large = ator.max_size() + 1; + + try + { + static_cast(ator.allocate(too_large)); + TEST_FAIL("should not get here"); + } + catch (stlsoft::out_of_memory_exception&) + { + TEST_PASSED(); + } } static void test_specialise_list() { + typedef std::list list_t; + list_t items; + + items.push_back(10); + items.push_back(20); + items.push_back(30); + + TEST_INT_EQ(3u, items.size()); + + list_t::const_iterator it = items.begin(); + + TEST_INT_EQ(10, *it); + ++it; + TEST_INT_EQ(20, *it); + ++it; + TEST_INT_EQ(30, *it); } static void test_specialise_vector() { + typedef std::vector vector_t; + + vector_t v; + + v.push_back(10); + v.push_back(20); + v.push_back(30); + + TEST_INT_EQ(3u, v.size()); + TEST_INT_EQ(10, v[0]); + TEST_INT_EQ(20, v[1]); + TEST_INT_EQ(30, v[2]); + + v.resize(1); + TEST_INT_EQ(1u, v.size()); + TEST_INT_EQ(10, v[0]); } } // anonymous namespace diff --git a/test/unit/winstl/memory/processheap_allocator/entry.cpp b/test/unit/winstl/memory/processheap_allocator/entry.cpp index 45210dbe..ab3fdb47 100644 --- a/test/unit/winstl/memory/processheap_allocator/entry.cpp +++ b/test/unit/winstl/memory/processheap_allocator/entry.cpp @@ -29,9 +29,12 @@ #include /* STLSoft header files */ +#include #include /* Standard C++ header files */ +#include +#include /* Standard C header files */ #include @@ -92,39 +95,117 @@ int main(int argc, char *argv[]) namespace { +typedef winstl::processheap_allocator allocator_t; + +static void exercise_allocate(allocator_t::size_type n) +{ + allocator_t ator; + allocator_t::pointer p = ator.allocate(n); + + TEST_PTR_NE(NULL, p); + + for (allocator_t::size_type i = 0; i != n; ++i) + { + ator.construct(&p[i], static_cast(i)); + } + + for (allocator_t::size_type i = 0; i != n; ++i) + { + TEST_INT_EQ(static_cast(i), p[i]); + + ator.destroy(&p[i]); + } + + ator.deallocate(p, n); +} + static void test_alloc_0() { + allocator_t a1; + allocator_t a2; + + TEST_BOOLEAN_TRUE(a1 == a2); + TEST_BOOLEAN_FALSE(a1 != a2); + + allocator_t::pointer p = a1.allocate(0); + + TEST_PTR_NE(NULL, p); + a1.deallocate(p); } static void test_alloc_small() { - + exercise_allocate(4); } static void test_alloc_medium() { - + exercise_allocate(256); } static void test_alloc_large() { - + exercise_allocate(4096); } static void test_alloc_toolarge() { + allocator_t ator; + allocator_t::size_type const too_large = ator.max_size() + 1; + + try + { + static_cast(ator.allocate(too_large)); + TEST_FAIL("should not get here"); + } + catch (stlsoft::out_of_memory_exception&) + { + TEST_PASSED(); + } } static void test_specialise_list() { + typedef std::list list_t; + list_t items; + + items.push_back(10); + items.push_back(20); + items.push_back(30); + + TEST_INT_EQ(3u, items.size()); + + list_t::const_iterator it = items.begin(); + + TEST_INT_EQ(10, *it); + ++it; + TEST_INT_EQ(20, *it); + ++it; + TEST_INT_EQ(30, *it); } static void test_specialise_vector() { + typedef std::vector vector_t; + + vector_t v; + + v.push_back(10); + v.push_back(20); + v.push_back(30); + + TEST_INT_EQ(3u, v.size()); + TEST_INT_EQ(10, v[0]); + TEST_INT_EQ(20, v[1]); + TEST_INT_EQ(30, v[2]); + + v.resize(1); + TEST_INT_EQ(1u, v.size()); + TEST_INT_EQ(10, v[0]); } } // anonymous namespace diff --git a/test/unit/winstl/memory/shell_allocator/entry.cpp b/test/unit/winstl/memory/shell_allocator/entry.cpp index b20a2e9e..415d5fbc 100644 --- a/test/unit/winstl/memory/shell_allocator/entry.cpp +++ b/test/unit/winstl/memory/shell_allocator/entry.cpp @@ -29,9 +29,12 @@ #include /* STLSoft header files */ +#include #include /* Standard C++ header files */ +#include +#include /* Standard C header files */ #include @@ -92,39 +95,117 @@ int main(int argc, char *argv[]) namespace { +typedef winstl::shell_allocator allocator_t; + +static void exercise_allocate(allocator_t::size_type n) +{ + allocator_t ator; + allocator_t::pointer p = ator.allocate(n); + + TEST_PTR_NE(NULL, p); + + for (allocator_t::size_type i = 0; i != n; ++i) + { + ator.construct(&p[i], static_cast(i)); + } + + for (allocator_t::size_type i = 0; i != n; ++i) + { + TEST_INT_EQ(static_cast(i), p[i]); + + ator.destroy(&p[i]); + } + + ator.deallocate(p, n); +} + static void test_alloc_0() { + allocator_t a1; + allocator_t a2; + + TEST_BOOLEAN_TRUE(a1 == a2); + TEST_BOOLEAN_FALSE(a1 != a2); + + allocator_t::pointer p = a1.allocate(0); + + TEST_PTR_NE(NULL, p); + a1.deallocate(p); } static void test_alloc_small() { - + exercise_allocate(4); } static void test_alloc_medium() { - + exercise_allocate(256); } static void test_alloc_large() { - + exercise_allocate(4096); } static void test_alloc_toolarge() { + allocator_t ator; + allocator_t::size_type const too_large = ator.max_size() + 1; + + try + { + static_cast(ator.allocate(too_large)); + TEST_FAIL("should not get here"); + } + catch (stlsoft::out_of_memory_exception&) + { + TEST_PASSED(); + } } static void test_specialise_list() { + typedef std::list list_t; + list_t items; + + items.push_back(10); + items.push_back(20); + items.push_back(30); + + TEST_INT_EQ(3u, items.size()); + + list_t::const_iterator it = items.begin(); + + TEST_INT_EQ(10, *it); + ++it; + TEST_INT_EQ(20, *it); + ++it; + TEST_INT_EQ(30, *it); } static void test_specialise_vector() { + typedef std::vector vector_t; + + vector_t v; + + v.push_back(10); + v.push_back(20); + v.push_back(30); + + TEST_INT_EQ(3u, v.size()); + TEST_INT_EQ(10, v[0]); + TEST_INT_EQ(20, v[1]); + TEST_INT_EQ(30, v[2]); + + v.resize(1); + TEST_INT_EQ(1u, v.size()); + TEST_INT_EQ(10, v[0]); } } // anonymous namespace From dfe07eea06e4dbf148401d2d105384c9ce7e3a7d Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Wed, 30 Sep 2026 07:48:34 +1000 Subject: [PATCH 04/31] `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(). --- .../platformstl/filesystem/FILE_stream.hpp | 29 +- test/component/platformstl/CMakeLists.txt | 1 + .../platformstl/filesystem/CMakeLists.txt | 2 + .../CMakeLists.txt | 2 + .../entry.cpp | 283 ++++++++++++++++++ 5 files changed, 312 insertions(+), 5 deletions(-) create mode 100644 test/component/platformstl/filesystem/CMakeLists.txt create mode 100644 test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/CMakeLists.txt create mode 100644 test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/entry.cpp diff --git a/include/platformstl/filesystem/FILE_stream.hpp b/include/platformstl/filesystem/FILE_stream.hpp index d30fd1b2..5710ce5d 100644 --- a/include/platformstl/filesystem/FILE_stream.hpp +++ b/include/platformstl/filesystem/FILE_stream.hpp @@ -4,11 +4,11 @@ * Purpose: Facade for the standard C Streams API. * * Created: 31st May 2009 - * Updated: 20th March 2025 + * Updated: 23rd September 2026 * * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2009-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -53,8 +53,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_STREAM_MAJOR 2 # define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_STREAM_MINOR 1 -# define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_STREAM_REVISION 5 -# define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_STREAM_EDIT 28 +# define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_STREAM_REVISION 6 +# define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_STREAM_EDIT 29 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -270,12 +270,31 @@ class FILE_stream_base return write_text_(ps, cch); } + /// [DEPRECATED] Writes \c cb bytes from the memory block pointed to by + /// \c pv to the underlying file stream. + /// + /// \deprecated Use write_binary() instead + /// + /// \exception X Thrown in \c cb bytes cannot be written to the + /// underlying stream + STLSOFT_DEPRECATED_("write(void const*, size_t) is deprecated and will be removed from a future version of STLSoft; use write_binary() instead") + class_type& write(void const* pv, size_type cb) + { + return write_binary(pv, cb); + } + /// Writes \c cb bytes from the memory block pointed to by \c pv to the /// underlying file stream. /// + /// \note Every byte is written, including embedded NULs. Character + /// overloads of write() stop at the first NUL. Newline + /// translation follows the stream's open mode, so open with + /// "wb" when the stored bytes must match the memory + /// block. + /// /// \exception X Thrown in \c cb bytes cannot be written to the /// underlying stream - class_type& write(void const* pv, size_type cb) + class_type& write_binary(void const* pv, size_type cb) { return write_bytes_(pv, cb); } diff --git a/test/component/platformstl/CMakeLists.txt b/test/component/platformstl/CMakeLists.txt index ead898a4..9fc02d09 100644 --- a/test/component/platformstl/CMakeLists.txt +++ b/test/component/platformstl/CMakeLists.txt @@ -1,3 +1,4 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten add_subdirectory(diagnostics) +add_subdirectory(filesystem) add_subdirectory(system) diff --git a/test/component/platformstl/filesystem/CMakeLists.txt b/test/component/platformstl/filesystem/CMakeLists.txt new file mode 100644 index 00000000..477a88a9 --- /dev/null +++ b/test/component/platformstl/filesystem/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(test.component.platformstl.filesystem.file_lines) diff --git a/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/CMakeLists.txt b/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/CMakeLists.txt new file mode 100644 index 00000000..bb50f424 --- /dev/null +++ b/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.component.platformstl.filesystem.file_lines entry.cpp) diff --git a/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/entry.cpp b/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/entry.cpp new file mode 100644 index 00000000..9628b986 --- /dev/null +++ b/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/entry.cpp @@ -0,0 +1,283 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test.component.platformstl.filesystem.file_lines/entry.cpp + * + * Purpose: Component-tests for `platformstl::file_lines`. + * + * Created: 23rd September 2026 + * Updated: 23rd September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +/* ///////////////////////////////////// + * test component header file include(s) + */ + +#include + +/* ///////////////////////////////////// + * general includes + */ + +/* xTests header files */ +#include +#include +#include + +/* STLSoft header files */ +#include +#include + +/* Standard C header files */ +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace { + + void TEST_EMPTY_FILE(); + void TEST_FILE_WITH_ONE_LINE_UNTERMINATED(); + void TEST_FILE_WITH_ONE_LINE_TERMINATED(); + void TEST_FILE_WITH_THREE_LINES(); + void TEST_FILE_WITH_ONE_LINE_TERMINATED_BY_CRLF(); + void TEST_FILE_WITH_THREE_LINES_SEPARATED_BY_CRLF(); + void TEST_FILE_WITH_CONSECUTIVE_CRLF_GIVES_EMPTY_LINE(); + void TEST_FILE_WITH_ONE_LINE_TERMINATED_BY_CR(); + void TEST_FILE_WITH_THREE_LINES_SEPARATED_BY_CR(); + void TEST_FILE_WITH_CONSECUTIVE_CR_GIVES_EMPTY_LINE(); + void TEST_FILE_CONTAINING_NUL_CHARACTER_THROWS(); +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.component.platformstl.filesystem.file_lines", verbosity)) + { + XTESTS_RUN_CASE(TEST_EMPTY_FILE); + XTESTS_RUN_CASE(TEST_FILE_WITH_ONE_LINE_UNTERMINATED); + XTESTS_RUN_CASE(TEST_FILE_WITH_ONE_LINE_TERMINATED); + XTESTS_RUN_CASE(TEST_FILE_WITH_THREE_LINES); + XTESTS_RUN_CASE(TEST_FILE_WITH_ONE_LINE_TERMINATED_BY_CRLF); + XTESTS_RUN_CASE(TEST_FILE_WITH_THREE_LINES_SEPARATED_BY_CRLF); + XTESTS_RUN_CASE(TEST_FILE_WITH_CONSECUTIVE_CRLF_GIVES_EMPTY_LINE); + XTESTS_RUN_CASE(TEST_FILE_WITH_ONE_LINE_TERMINATED_BY_CR); + XTESTS_RUN_CASE(TEST_FILE_WITH_THREE_LINES_SEPARATED_BY_CR); + XTESTS_RUN_CASE(TEST_FILE_WITH_CONSECUTIVE_CR_GIVES_EMPTY_LINE); + XTESTS_RUN_CASE_THAT_THROWS(TEST_FILE_CONTAINING_NUL_CHARACTER_THROWS, platformstl::invalid_file_type_exception); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace { + + using ::xtests::cpp::util::temp_file; + + +void TEST_EMPTY_FILE() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + platformstl::file_lines lines(f.c_str()); + + TEST_INT_EQ(0u, lines.size()); +} + +void TEST_FILE_WITH_ONE_LINE_UNTERMINATED() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "w"); + + stm.write("abc"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(1u, lines.size())); + TEST_MS_EQ("abc", lines[0]); +} + +void TEST_FILE_WITH_ONE_LINE_TERMINATED() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "w"); + + stm.write_line("abc"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(1u, lines.size())); + TEST_MS_EQ("abc", lines[0]); +} + +void TEST_FILE_WITH_THREE_LINES() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "w"); + + stm.write_line("abc"); + stm.write("\nghi"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(3u, lines.size())); + TEST_MS_EQ("abc", lines[0]); + TEST_MS_EQ("", lines[1]); + TEST_MS_EQ("ghi", lines[2]); +} + +void TEST_FILE_WITH_ONE_LINE_TERMINATED_BY_CRLF() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write("abc\r\n"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(1u, lines.size())); + TEST_MS_EQ("abc", lines[0]); +} + +void TEST_FILE_WITH_THREE_LINES_SEPARATED_BY_CRLF() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write("abc\r\ndef\r\nghi\r\n"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(3u, lines.size())); + TEST_MS_EQ("abc", lines[0]); + TEST_MS_EQ("def", lines[1]); + TEST_MS_EQ("ghi", lines[2]); +} + +void TEST_FILE_WITH_CONSECUTIVE_CRLF_GIVES_EMPTY_LINE() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write("abc\r\n\r\nghi"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(3u, lines.size())); + TEST_MS_EQ("abc", lines[0]); + TEST_MS_EQ("", lines[1]); + TEST_MS_EQ("ghi", lines[2]); +} + +void TEST_FILE_WITH_ONE_LINE_TERMINATED_BY_CR() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write("abc\r"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(1u, lines.size())); + TEST_MS_EQ("abc", lines[0]); +} + +void TEST_FILE_WITH_THREE_LINES_SEPARATED_BY_CR() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write("abc\rdef\rghi\r"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(3u, lines.size())); + TEST_MS_EQ("abc", lines[0]); + TEST_MS_EQ("def", lines[1]); + TEST_MS_EQ("ghi", lines[2]); +} + +void TEST_FILE_WITH_CONSECUTIVE_CR_GIVES_EMPTY_LINE() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write("abc\r\rghi"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(3u, lines.size())); + TEST_MS_EQ("abc", lines[0]); + TEST_MS_EQ("", lines[1]); + TEST_MS_EQ("ghi", lines[2]); +} + +void TEST_FILE_CONTAINING_NUL_CHARACTER_THROWS() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + char const contents[] = { 'a', 'b', 'c', '\0', 'd', 'e', 'f' }; + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write_binary(contents, sizeof(contents)); + } + + platformstl::file_lines lines(f.c_str()); +} +} // anonymous namespace + + +/* ///////////////////////////// end of file //////////////////////////// */ + From 3dfb174bb82ab494f1683ca97e4d19209cb3b19b Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Wed, 30 Sep 2026 07:57:34 +1000 Subject: [PATCH 05/31] Bit functions: refactoring, extension, and optimisation (#23) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 (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. --- .github/workflows/ci-cell.yml | 2 + CHANGES.md | 9 +- NEWS.md | 2 +- include/stlsoft/api/external/bitfns.h | 467 ++ include/stlsoft/api/internal/bitfns.h | 170 + include/stlsoft/internal/cccap/clang.h | 48 +- include/stlsoft/internal/cccap/gcc.h | 9 + include/stlsoft/stlsoft.h | 4 +- include/stlsoft/util/bits/count_functions.h | 320 +- include/stlsoft/util/bits/test_functions.h | 233 +- include/stlsoft/util/bits/xor_functions.h | 23 +- strategy/BIT_FUNCTIONS.md | 130 + test/performance/CMakeLists.txt | 6 +- test/performance/stlsoft/CMakeLists.txt | 5 +- test/performance/stlsoft/util/CMakeLists.txt | 1 + .../stlsoft/util/bit_functions/CMakeLists.txt | 2 + .../stlsoft/util/bit_functions/main.cpp | 3830 +++++++++++++++++ .../unit/stlsoft/util/bit_functions/entry.cpp | 529 ++- 18 files changed, 5683 insertions(+), 107 deletions(-) create mode 100644 include/stlsoft/api/external/bitfns.h create mode 100644 include/stlsoft/api/internal/bitfns.h create mode 100644 strategy/BIT_FUNCTIONS.md create mode 100644 test/performance/stlsoft/util/bit_functions/CMakeLists.txt create mode 100644 test/performance/stlsoft/util/bit_functions/main.cpp diff --git a/.github/workflows/ci-cell.yml b/.github/workflows/ci-cell.yml index b14fae42..2214d999 100644 --- a/.github/workflows/ci-cell.yml +++ b/.github/workflows/ci-cell.yml @@ -606,4 +606,6 @@ jobs: if [ "${{ inputs.c-compiler }}" = "mingw" ]; then export PATH="/mingw64/bin:$PATH" fi + # Gaps between pattern groups in the bit-functions harness. + export SIS_PERFTESTS_GROUPGAPS=1 SIS_CMAKE_BUILD_DIR="${{ github.workspace }}/build" ./execute_performance_tests.sh -M diff --git a/CHANGES.md b/CHANGES.md index acc0fe87..d120092c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,8 +3,15 @@ ## 1.11.1-rc7 - 30th September 2026 +* Added `count_bits_by_intrinsic()` and `find_highest_bit_by_intrinsic()` (unselected by default; `count_bits()` keeps the 8-bit table; `find_highest_bit()` keeps the scan); +* Added **stlsoft/api/external/bitfns.h** and **stlsoft/api/internal/bitfns.h** — detection and adaptations for `popcount` / `clz` / `_BitScanReverse` intrinsics (GCC/Clang builtins preferred over MSVC when both are visible); +* Clang cccap — `STLSOFT_CLANG_VER`; documented shared `STLSOFT_GCC_VER` (also noted in GCC cccap); +* Fixed `count_bits()` overloads when `STLSOFT_BIT_COUNT_BY_Kernighan` is defined; +* Unit tests for intrinsic popcount / highest-bit helpers; broader width coverage for bit-function overloads; +* Performance suite **test/performance/stlsoft/bit_functions** (density patterns, intrinsic rows, median / ns-per-call reporting); +* Strategy note **strategy/BIT_FUNCTIONS.md** — measurements and default choice (table for `count_bits()`; keep intrinsics unselected pending cross-toolchain evidence); * Test tree — leaf directories under **test/component**, **test/unit**, **test/scratch**, and **test/performance** renamed from `test..…` to the subject name (for example **glob_sequence**); executable target names unchanged; -* **test/performance** — programs nested by sub-project and area (**platformstl/diagnostics**, **stlsoft/containers**, **stlsoft/conversion**, **stlsoft/diagnostics**, **stlsoft/memory**, **stlsoft/string**, **stlsoft/util**); +* **test/performance** — programs nested by sub-project and area (**platformstl/diagnostics**, **stlsoft/bit_functions**, **stlsoft/containers**, **stlsoft/conversion**, **stlsoft/diagnostics**, **stlsoft/memory**, **stlsoft/string**, **stlsoft/util**); * **test.unit.versions** — aligned with **1.11.1-rc7** (**_STLSOFT_VER_1_11_1_RC7**); diff --git a/NEWS.md b/NEWS.md index 107ad0b1..e0e5a449 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,7 @@ | Date | News Item | Details | | ------------------- | ----------------------------------- | ------- | -| 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | shortened test directories; nested **test/performance** | +| 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | bit-function intrinsics; table default for `count_bits()`; nested **test/performance**; shortened test directories | | 21st September 2026 | Release of [STLSoft 1.11.1-rc6](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc6) | ACE/ATL/MFC CI; Clang/macOS `stricmp` aliases | | 4th August 2026 | Release of [STLSoft 1.11.1-rc5](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc5) | `basic_simple_string<>#resize()`; **CHANGES.md**; docs | | 29th July 2026 | Release of [STLSoft 1.11.1-rc4](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc4) | GitHub Actions CI; VC++ 18.x; MinGW | diff --git a/include/stlsoft/api/external/bitfns.h b/include/stlsoft/api/external/bitfns.h new file mode 100644 index 00000000..5a43fecc --- /dev/null +++ b/include/stlsoft/api/external/bitfns.h @@ -0,0 +1,467 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: stlsoft/api/external/bitfns.h + * + * Purpose: External adaptations for bit functions. + * + * Created: 24th September 2026 + * Updated: 25th September 2026 + * + * Home: http://stlsoft.org/ + * + * Copyright (c) 2026, Matthew Wilson and Synesis Information Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name(s) of Matthew Wilson and Synesis Information Systems + * nor the names of any contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* WARNING: this file contains undocumented external features that are + * subject to change at any time, so if you use them it is at your own risk. + */ + +#ifndef STLSOFT_INCL_STLSOFT_API_external_h_bitfns +#define STLSOFT_INCL_STLSOFT_API_external_h_bitfns + + +/* ///////////////////////////////////////////////////////////////////////// + * includes - 1 + */ + +#ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT +# include +#endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */ +#ifdef STLSOFT_TRACE_INCLUDE +# pragma message(__FILE__) +#endif /* STLSOFT_TRACE_INCLUDE */ + + +/* ///////////////////////////////////////////////////////////////////////// + * intrinsics support + * + * Detection follows p99/src/p99_portable.h. GCC and Clang builtins are + * preferred over the MSVC intrinsics when both are visible (clang-cl). + * + * Detected features/macros: + * + * 1. "Count leading zeros" + * - discriminated symbols: + * - STLSOFT_CF__BitScanReverse_SUPPORT + * - STLSOFT_CF__BitScanReverse64_SUPPORT + * - STLSOFT_CF__builtin_clz_SUPPORT + * - STLSOFT_CF__builtin_clzll_SUPPORT + * + * - Clang/GCC may provide: + * - int __builtin_clz(unsigned int) + * - int __builtin_clzll(unsigned long long) + * + * - VC++ may provide: + * - unsigned char _BitScanReverse(unsigned long*, unsigned long) + * - unsigned char _BitScanReverse64(unsigned long*, unsigned __int64) + * + * NOTE: _BitScanReverse(64)() have different semantics to clz(ll) in + * that the former find the index of the most significant bit and the + * latter find the number of leading zeros. + * + * 2. "Population count" + * + * - discriminated symbols: + * - STLSOFT_CF__builtin_popcount_SUPPORT + * - STLSOFT_CF__builtin_popcountll_SUPPORT + * - STLSOFT_CF__popcnt16_SUPPORT + * - STLSOFT_CF__popcnt_SUPPORT + * - STLSOFT_CF__popcnt64_SUPPORT + * + * - Clang/GCC may provide: + * - int __builtin_popcount(unsigned int) + * - int __builtin_popcountll(unsigned long long) + * + * - VC++ may provide: + * - unsigned short __popcnt16(unsigned short) + * - unsigned int __popcnt(unsigned int) + * - unsigned __int64 __popcnt64(unsigned __int64) + */ + + +/* ///////////////////////////////////////////////////////// + * reject any other definition of the symbols under purview + */ + +#ifdef STLSOFT_CF__BitScanReverse_SUPPORT +# error STLSOFT_CF__BitScanReverse_SUPPORT may not be defined +#endif /* STLSOFT_CF__BitScanReverse_SUPPORT */ +#ifdef STLSOFT_CF__BitScanReverse64_SUPPORT +# error STLSOFT_CF__BitScanReverse64_SUPPORT may not be defined +#endif /* STLSOFT_CF__BitScanReverse64_SUPPORT */ + +#ifdef STLSOFT_CF__builtin_clz_SUPPORT +# error STLSOFT_CF__builtin_clz_SUPPORT may not be defined +#endif /* STLSOFT_CF__builtin_clz_SUPPORT */ +#ifdef STLSOFT_CF__builtin_clzll_SUPPORT +# error STLSOFT_CF__builtin_clzll_SUPPORT may not be defined +#endif /* STLSOFT_CF__builtin_clzll_SUPPORT */ + +#ifdef STLSOFT_CF__builtin_popcount_SUPPORT +# error STLSOFT_CF__builtin_popcount_SUPPORT may not be defined +#endif /* STLSOFT_CF__builtin_popcount_SUPPORT */ +#ifdef STLSOFT_CF__builtin_popcountll_SUPPORT +# error STLSOFT_CF__builtin_popcountll_SUPPORT may not be defined +#endif /* STLSOFT_CF__builtin_popcountll_SUPPORT */ + +#ifdef STLSOFT_CF__popcnt16_SUPPORT +# error STLSOFT_CF__popcnt16_SUPPORT may not be defined +#endif /* STLSOFT_CF__popcnt16_SUPPORT */ +#ifdef STLSOFT_CF__popcnt_SUPPORT +# error STLSOFT_CF__popcnt_SUPPORT may not be defined +#endif /* STLSOFT_CF__popcnt_SUPPORT */ +#ifdef STLSOFT_CF__popcnt64_SUPPORT +# error STLSOFT_CF__popcnt64_SUPPORT may not be defined +#endif /* STLSOFT_CF__popcnt64_SUPPORT */ + + +/* ///////////////////////////////////////////////////////// + * "Count leading zeros" + * + * - STLSOFT_CF__BitScanReverse_SUPPORT + * - STLSOFT_CF__BitScanReverse64_SUPPORT + * - STLSOFT_CF__builtin_clz_SUPPORT + * - STLSOFT_CF__builtin_clzll_SUPPORT + */ + + +/* STLSOFT_CF__BitScanReverse_SUPPORT, STLSOFT_CF__BitScanReverse64_SUPPORT */ + +#if 0 +#elif defined(_MSC_VER) &&\ + _MSC_VER >= 1400 + +# define STLSOFT_CF__BitScanReverse_SUPPORT +# if 0 ||\ + defined(_M_ARM64) ||\ + defined(_M_ARM64EC) ||\ + defined(_M_X64) ||\ + 0 + +# define STLSOFT_CF__BitScanReverse64_SUPPORT +# endif +#endif + + +/* STLSOFT_CF__builtin_clz_SUPPORT, STLSOFT_CF__builtin_clzll_SUPPORT */ + +#if 0 +#elif defined(__has_builtin) + +# if __has_builtin(__builtin_clz) + +# define STLSOFT_CF__builtin_clz_SUPPORT +# endif + +# if __has_builtin(__builtin_clzll) + +# define STLSOFT_CF__builtin_clzll_SUPPORT +# endif +#endif + +#ifndef STLSOFT_CF__builtin_clz_SUPPORT + +# if 0 +# elif defined(STLSOFT_CLANG_VER) &&\ + STLSOFT_CLANG_VER >= 40000 + +# define STLSOFT_CF__builtin_clz_SUPPORT +# elif defined(STLSOFT_GCC_VER) &&\ + STLSOFT_GCC_VER >= 30400 + +# define STLSOFT_CF__builtin_clz_SUPPORT +# endif +#endif + +#ifndef STLSOFT_CF__builtin_clzll_SUPPORT + +# if 0 +# elif defined(STLSOFT_CLANG_VER) &&\ + STLSOFT_CLANG_VER >= 40000 + +# define STLSOFT_CF__builtin_clzll_SUPPORT +# elif defined(STLSOFT_GCC_VER) &&\ + STLSOFT_GCC_VER >= 30400 + +# define STLSOFT_CF__builtin_clzll_SUPPORT +# endif +#endif + + +/* ///////////////////////////////////////////////////////// + * "Population count" + * + * - STLSOFT_CF__builtin_popcount_SUPPORT + * - STLSOFT_CF__builtin_popcountll_SUPPORT + * - STLSOFT_CF__popcnt16_SUPPORT + * - STLSOFT_CF__popcnt_SUPPORT + * - STLSOFT_CF__popcnt64_SUPPORT + */ + +/* STLSOFT_CF__builtin_popcount_SUPPORT, STLSOFT_CF__builtin_popcountll_SUPPORT */ + +#if 0 +#elif defined(__has_builtin) + +# if __has_builtin(__builtin_popcount) + +# define STLSOFT_CF__builtin_popcount_SUPPORT +# endif + +# if __has_builtin(__builtin_popcountll) + +# define STLSOFT_CF__builtin_popcountll_SUPPORT +# endif +#endif + +#ifndef STLSOFT_CF__builtin_popcount_SUPPORT + +# if 0 +# elif defined(STLSOFT_CLANG_VER) &&\ + STLSOFT_CLANG_VER >= 40000 + +# define STLSOFT_CF__builtin_popcount_SUPPORT +# elif defined(STLSOFT_GCC_VER) &&\ + STLSOFT_GCC_VER >= 30400 + +# define STLSOFT_CF__builtin_popcount_SUPPORT +# endif +#endif + +#ifndef STLSOFT_CF__builtin_popcountll_SUPPORT + +# if 0 +# elif defined(STLSOFT_CLANG_VER) &&\ + STLSOFT_CLANG_VER >= 40000 + +# define STLSOFT_CF__builtin_popcountll_SUPPORT +# elif defined(STLSOFT_GCC_VER) &&\ + STLSOFT_GCC_VER >= 30400 + +# define STLSOFT_CF__builtin_popcountll_SUPPORT +# endif +#endif + + +/* STLSOFT_CF__popcnt16_SUPPORT, STLSOFT_CF__popcnt_SUPPORT + * + * x86 and x64 from MSVC 15.00. ARM64 from Visual Studio 2022 17.11 + * (_MSC_VER 1941). Not 32-bit ARM. Not ARM64EC: those two intrinsics + * are declared for x86, x64, and ARM64 only. + */ + +#if 0 +#elif 1 &&\ + defined(_MSC_VER) &&\ + _MSC_VER >= 1500 &&\ + ( 0 ||\ + defined(_M_IX86) ||\ + defined(_M_X64) ||\ + 0) &&\ + 1 + +# define STLSOFT_CF__popcnt16_SUPPORT +# define STLSOFT_CF__popcnt_SUPPORT +#elif 1 &&\ + defined(_MSC_VER) &&\ + _MSC_VER >= 1941 &&\ + defined(_M_ARM64) &&\ + 1 + +# define STLSOFT_CF__popcnt16_SUPPORT +# define STLSOFT_CF__popcnt_SUPPORT +#endif + + +/* STLSOFT_CF__popcnt64_SUPPORT + * + * x64 from MSVC 15.00. ARM64 and ARM64EC from Visual Studio 2022 17.11 + * (_MSC_VER 1941). + */ + +#if 0 +#elif defined(_MSC_VER) &&\ + _MSC_VER >= 1500 &&\ + defined(_M_X64) + +# define STLSOFT_CF__popcnt64_SUPPORT +#elif defined(_MSC_VER) &&\ + _MSC_VER >= 1941 &&\ + ( 0 ||\ + defined(_M_ARM64) ||\ + defined(_M_ARM64EC) ||\ + 0) + +# define STLSOFT_CF__popcnt64_SUPPORT +#endif + + +/* ///////////////////////////////////////////////////////////////////////// + * includes - 2 + */ + +#if 0 +#elif 0 ||\ + defined(STLSOFT_CF__popcnt16_SUPPORT) ||\ + defined(STLSOFT_CF__popcnt_SUPPORT) ||\ + defined(STLSOFT_CF__popcnt64_SUPPORT) ||\ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) ||\ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) ||\ + 0 + +# include +#endif + + +/* ///////////////////////////////////////////////////////////////////////// + * bit functions + */ + +#ifndef STLSOFT_API_EXTERNAL_bitfns_BitScanReverse_uint32 + +# if 0 +# elif defined(STLSOFT_CF__BitScanReverse_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_BitScanReverse_uint32 _BitScanReverse +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_BitScanReverse_uint32 */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_BitScanReverse_uint64 + +# if 0 +# elif defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_BitScanReverse_uint64 _BitScanReverse64 +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_BitScanReverse_uint64 */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_clz_uint + +# if 0 +# elif defined(STLSOFT_CF__builtin_clz_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_clz_uint __builtin_clz +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_clz_uint */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_clz_ullong + +# if 0 +# elif defined(STLSOFT_CF__builtin_clzll_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_clz_ullong __builtin_clzll +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_clz_ullong */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_popcount_uint + +# if 0 +# elif defined(STLSOFT_CF__builtin_popcount_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_popcount_uint __builtin_popcount +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_popcount_uint */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_popcount_ullong + +# if 0 +# elif defined(STLSOFT_CF__builtin_popcountll_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_popcount_ullong __builtin_popcountll +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_popcount_ullong */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_popcnt_uint16 + +# if 0 +# elif defined(STLSOFT_CF__popcnt16_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_popcnt_uint16 __popcnt16 +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_popcnt_uint16 */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_popcnt_uint32 + +# if 0 +# elif defined(STLSOFT_CF__popcnt_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_popcnt_uint32 __popcnt +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_popcnt_uint32 */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_popcnt_uint64 + +# if 0 +# elif defined(STLSOFT_CF__popcnt64_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_popcnt_uint64 __popcnt64 +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_popcnt_uint64 */ + + +/* ///////////////////////////////////////////////////////////////////////// + * inclusion control + */ + +#ifdef STLSOFT_CF_PRAGMA_ONCE_SUPPORT +# pragma once +#endif /* STLSOFT_CF_PRAGMA_ONCE_SUPPORT */ + +#endif /* !STLSOFT_INCL_STLSOFT_API_external_h_bitfns */ + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/include/stlsoft/api/internal/bitfns.h b/include/stlsoft/api/internal/bitfns.h new file mode 100644 index 00000000..206bc323 --- /dev/null +++ b/include/stlsoft/api/internal/bitfns.h @@ -0,0 +1,170 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: stlsoft/api/internal/bitfns.h + * + * Purpose: Internal adaptations for bit functions. + * + * Created: 24th September 2026 + * Updated: 25th September 2026 + * + * Home: http://stlsoft.org/ + * + * Copyright (c) 2026, Matthew Wilson and Synesis Information Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name(s) of Matthew Wilson and Synesis Information Systems + * nor the names of any contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* WARNING: this file contains undocumented internal features that are + * subject to change at any time, so if you use them it is at your own risk. + */ + +#ifndef STLSOFT_INCL_STLSOFT_API_internal_h_bitfns +#define STLSOFT_INCL_STLSOFT_API_internal_h_bitfns + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT +# include +#endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */ +#ifdef STLSOFT_TRACE_INCLUDE +# pragma message(__FILE__) +#endif /* STLSOFT_TRACE_INCLUDE */ + +#ifndef STLSOFT_INCL_STLSOFT_API_external_h_bitfns +# include +#endif /* !STLSOFT_INCL_STLSOFT_API_external_h_bitfns */ + + +/* ///////////////////////////////////////////////////////////////////////// + * bit functions + */ + +#ifndef STLSOFT_API_INTERNAL_bitfns_popcount_uint16 + +# if 0 ||\ + defined (STLSOFT_API_EXTERNAL_bitfns_popcount_uint) ||\ + defined (STLSOFT_API_EXTERNAL_bitfns_popcnt_uint16) ||\ + 0 + +STLSOFT_INLINE +int +STLSOFT_API_INTERNAL_bitfns_popcount_uint16( + STLSOFT_NS_QUAL(ss_uint16_t) v +) +{ +# if 0 +# elif defined(STLSOFT_API_EXTERNAL_bitfns_popcount_uint) + + return STLSOFT_API_EXTERNAL_bitfns_popcount_uint(STLSOFT_C_CAST(unsigned int, v)); +# elif defined(STLSOFT_API_EXTERNAL_bitfns_popcnt_uint16) + + return STLSOFT_API_EXTERNAL_bitfns_popcnt_uint16(STLSOFT_C_CAST(unsigned short, v)); +# else + +# error Unexpected +# endif +} +# define STLSOFT_API_INTERNAL_bitfns_popcount_uint16 STLSOFT_API_INTERNAL_bitfns_popcount_uint16 +# endif +#endif + +#ifndef STLSOFT_API_INTERNAL_bitfns_popcount_uint32 + +# if 0 ||\ + defined (STLSOFT_API_EXTERNAL_bitfns_popcount_uint) ||\ + defined (STLSOFT_API_EXTERNAL_bitfns_popcnt_uint32) ||\ + 0 + +STLSOFT_INLINE +int +STLSOFT_API_INTERNAL_bitfns_popcount_uint32( + STLSOFT_NS_QUAL(ss_uint32_t) v +) +{ +# if 0 +# elif defined(STLSOFT_API_EXTERNAL_bitfns_popcount_uint) + + return STLSOFT_API_EXTERNAL_bitfns_popcount_uint(STLSOFT_C_CAST(unsigned int, v)); +# elif defined(STLSOFT_API_EXTERNAL_bitfns_popcnt_uint32) + + return STLSOFT_API_EXTERNAL_bitfns_popcnt_uint32(STLSOFT_C_CAST(unsigned int, v)); +# else + +# error Unexpected +# endif +} +# define STLSOFT_API_INTERNAL_bitfns_popcount_uint32 STLSOFT_API_INTERNAL_bitfns_popcount_uint32 +# endif +#endif + +#ifndef STLSOFT_API_INTERNAL_bitfns_popcount_uint64 + +# if 0 ||\ + defined (STLSOFT_API_EXTERNAL_bitfns_popcount_ullong) ||\ + defined (STLSOFT_API_EXTERNAL_bitfns_popcnt_uint64) ||\ + 0 + +STLSOFT_INLINE +int +STLSOFT_API_INTERNAL_bitfns_popcount_uint64( + STLSOFT_NS_QUAL(ss_uint64_t) v +) +{ +# if 0 +# elif defined(STLSOFT_API_EXTERNAL_bitfns_popcount_ullong) + + return STLSOFT_API_EXTERNAL_bitfns_popcount_ullong(STLSOFT_C_CAST(unsigned long long, v)); +# elif defined(STLSOFT_API_EXTERNAL_bitfns_popcnt_uint64) + + return STLSOFT_C_CAST(int, STLSOFT_API_EXTERNAL_bitfns_popcnt_uint64(STLSOFT_C_CAST(unsigned __int64, v))); +# else + +# error Unexpected +# endif +} +# define STLSOFT_API_INTERNAL_bitfns_popcount_uint64 STLSOFT_API_INTERNAL_bitfns_popcount_uint64 +# endif +#endif + + +/* ///////////////////////////////////////////////////////////////////////// + * inclusion control + */ + +#ifdef STLSOFT_CF_PRAGMA_ONCE_SUPPORT +# pragma once +#endif /* STLSOFT_CF_PRAGMA_ONCE_SUPPORT */ + +#endif /* !STLSOFT_INCL_STLSOFT_API_internal_h_bitfns */ + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/include/stlsoft/internal/cccap/clang.h b/include/stlsoft/internal/cccap/clang.h index 0e049b4a..bbf78d32 100644 --- a/include/stlsoft/internal/cccap/clang.h +++ b/include/stlsoft/internal/cccap/clang.h @@ -4,7 +4,7 @@ * Purpose: Compiler feature discrimination for Clang C/C++. * * Created: 14th March 2015 - * Updated: 20th September 2026 + * Updated: 25th September 2026 * * Home: http://stlsoft.org/ * @@ -59,9 +59,9 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_MAJOR 1 -# define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_MINOR 11 -# define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_REVISION 2 -# define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_EDIT 33 +# define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_MINOR 12 +# define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_REVISION 1 +# define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_EDIT 34 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -101,6 +101,46 @@ * custom macros */ +#define STLSOFT_CLANG_VER \ + \ + ( \ + (__clang_major__ * 10000) \ + + \ + (__clang_minor__ * 100) \ + + \ + (__clang_patchlevel__ * 1) \ + ) + +#ifdef __GNUC__ + +# ifdef __GNUC_PATCHLEVEL__ + +# define STLSOFT_INTERNAL_GCC_PATCHLEVEL_ __GNUC_PATCHLEVEL__ +# else /* ? __GNUC_PATCHLEVEL__ */ + +# define STLSOFT_INTERNAL_GCC_PATCHLEVEL_ (0) +# endif /* __GNUC_PATCHLEVEL__ */ + +/** \def STLSOFT_GCC_VER A composite version object-like macro comprising + * the major*10000 + minor*100 + patch, e.g. 30401 (3.4.1). + * + * \note Because several compilers (e.g. Clang) may offer GCC compatibility, + * the presence of this symbol does NOT, in and of itself, mean that the + * compiler is actually GCC. Rather, code must first check for definition + * of STLSOFT_COMPILER_IS_GCC. + * + */ +# define STLSOFT_GCC_VER \ + \ + ( \ + (__GNUC__ * 10000) \ + + \ + (__GNUC_MINOR__ * 100) \ + + \ + (STLSOFT_INTERNAL_GCC_PATCHLEVEL_ * 1) \ + ) +#endif /* __GNUC__ */ + /* ///////////////////////////////////////////////////////////////////////// * preprocessor features diff --git a/include/stlsoft/internal/cccap/gcc.h b/include/stlsoft/internal/cccap/gcc.h index 06b90aee..3e6e759f 100644 --- a/include/stlsoft/internal/cccap/gcc.h +++ b/include/stlsoft/internal/cccap/gcc.h @@ -110,6 +110,15 @@ # define STLSOFT_INTERNAL_GCC_PATCHLEVEL_ (0) #endif /* __GNUC_PATCHLEVEL__ */ +/** \def STLSOFT_GCC_VER A composite version object-like macro comprising + * the major*10000 + minor*100 + patch, e.g. 30401 (3.4.1). + * + * \note Because several compilers (e.g. Clang) may offer GCC compatibility, + * the presence of this symbol does NOT, in and of itself, mean that the + * compiler is actually GCC. Rather, code must first check for definition + * of STLSOFT_COMPILER_IS_GCC. + * + */ #define STLSOFT_GCC_VER \ \ ( \ diff --git a/include/stlsoft/stlsoft.h b/include/stlsoft/stlsoft.h index a2f991e6..1293605b 100644 --- a/include/stlsoft/stlsoft.h +++ b/include/stlsoft/stlsoft.h @@ -55,8 +55,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_STLSOFT_H_STLSOFT_MAJOR 3 # define STLSOFT_VER_STLSOFT_H_STLSOFT_MINOR 57 -# define STLSOFT_VER_STLSOFT_H_STLSOFT_REVISION 18 -# define STLSOFT_VER_STLSOFT_H_STLSOFT_EDIT 606 +# define STLSOFT_VER_STLSOFT_H_STLSOFT_REVISION 19 +# define STLSOFT_VER_STLSOFT_H_STLSOFT_EDIT 607 #else /* ? STLSOFT_DOCUMENTATION_SKIP_SECTION */ /* # include "./internal/doxygen_defs.h" */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ diff --git a/include/stlsoft/util/bits/count_functions.h b/include/stlsoft/util/bits/count_functions.h index 8e0ada2c..90e022a9 100644 --- a/include/stlsoft/util/bits/count_functions.h +++ b/include/stlsoft/util/bits/count_functions.h @@ -1,14 +1,14 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: stlsoft/util/bits/count_functions.h + * File: stlsoft/util/bits/count_functions.h * - * Purpose: Bit count functions. + * Purpose: Bit count functions. * - * Created: 2nd June 2010 - * Updated: 11th March 2024 + * Created: 2nd June 2010 + * Updated: 25th September 2026 * - * Home: http://stlsoft.org/ + * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2024, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2010-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -51,10 +51,10 @@ #define STLSOFT_INCL_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_MAJOR 1 -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_MINOR 3 -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_REVISION 1 -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_EDIT 19 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_MAJOR 1 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_MINOR 3 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_REVISION 3 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_EDIT 23 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -76,6 +76,13 @@ # include #endif /* !STLSOFT_INCL_STLSOFT_QUALITY_H_COVER */ +#ifndef STLSOFT_INCL_STLSOFT_API_external_h_bitfns +# include +#endif /* !STLSOFT_INCL_STLSOFT_API_external_h_bitfns */ +#ifndef STLSOFT_INCL_STLSOFT_API_internal_h_bitfns +# include +#endif /* !STLSOFT_INCL_STLSOFT_API_internal_h_bitfns */ + /* ///////////////////////////////////////////////////////////////////////// * namespace @@ -364,7 +371,6 @@ namespace ximpl_bit_functions return &s_table; } - # ifdef __cplusplus } /* namespace ximpl_bit_functions */ # endif /* __cplusplus */ @@ -404,6 +410,38 @@ stlsoft_C_count_bits_in_32bit_unsigned_integer_by_Kernighan_method( return n; } +/** Counts the number of bits in an 8-bit unsigned integer, using Brian + * Kernighan's method (see TCPL). + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_8bit_unsigned_integer_by_Kernighan_method( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_32bit_unsigned_integer_by_Kernighan_method(STLSOFT_STATIC_CAST(ss_uint32_t, v)); +} + +/** Counts the number of bits in a 16-bit unsigned integer, using Brian + * Kernighan's method (see TCPL). + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_16bit_unsigned_integer_by_Kernighan_method( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_32bit_unsigned_integer_by_Kernighan_method(STLSOFT_STATIC_CAST(ss_uint32_t, v)); +} + /** Counts the number of bits in a 64-bit unsigned integer, using Brian * Kernighan's method (see TCPL). * @@ -449,6 +487,38 @@ stlsoft_C_count_bits_in_32bit_unsigned_integer_by_8bit_table( return (*ptr)[0[py]] + (*ptr)[1[py]] + (*ptr)[2[py]] + (*ptr)[3[py]]; } +/** Counts the number of bits in an 8-bit unsigned integer, using an 8-bit + * lookup table. + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_8bit_unsigned_integer_by_8bit_table( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_32bit_unsigned_integer_by_8bit_table(STLSOFT_STATIC_CAST(ss_uint32_t, v)); +} + +/** Counts the number of bits in a 16-bit unsigned integer, using an 8-bit + * lookup table. + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_16bit_unsigned_integer_by_8bit_table( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_32bit_unsigned_integer_by_8bit_table(STLSOFT_STATIC_CAST(ss_uint32_t, v)); +} + /** Counts the number of bits in a 64-bit unsigned integer, using an 8-bit. * lookup table. * @@ -467,6 +537,64 @@ stlsoft_C_count_bits_in_64bit_unsigned_integer_by_8bit_table( return n_high + n_low; } +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint16) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) + +/** Counts the number of bits in a 16-bit unsigned integer, using a + * compiler intrinsic. Not selected by count_bits(). + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_16bit_unsigned_integer_by_intrinsic( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return STLSOFT_C_CAST(unsigned, STLSOFT_API_INTERNAL_bitfns_popcount_uint16(v)); +} +#endif /* STLSOFT_API_INTERNAL_bitfns_popcount_uint16 */ +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint32) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) + +/** Counts the number of bits in a 32-bit unsigned integer, using a + * compiler intrinsic. Not selected by count_bits(). + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_32bit_unsigned_integer_by_intrinsic( + ss_uint32_t v +) STLSOFT_NOEXCEPT +{ + return STLSOFT_C_CAST(unsigned, STLSOFT_API_INTERNAL_bitfns_popcount_uint32(v)); +} +#endif /* STLSOFT_API_INTERNAL_bitfns_popcount_uint32 */ +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint64) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) + +/** Counts the number of bits in a 64-bit unsigned integer, using a + * compiler intrinsic. One instruction for the full width, not two + * 32-bit calls. Not selected by count_bits(). + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_64bit_unsigned_integer_by_intrinsic( + ss_uint64_t v +) STLSOFT_NOEXCEPT +{ + return STLSOFT_C_CAST(unsigned, STLSOFT_API_INTERNAL_bitfns_popcount_uint64(v)); +} +#endif /* STLSOFT_API_INTERNAL_bitfns_popcount_uint64 */ /* ///////////////////////////////////////////////////////////////////////// @@ -475,6 +603,32 @@ stlsoft_C_count_bits_in_64bit_unsigned_integer_by_8bit_table( #ifdef __cplusplus +/** + * + * \see stlsoft_C_count_bits_in_8bit_unsigned_integer_by_Kernighan_method + */ +inline +unsigned +count_bits_by_Kernighan_method( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_8bit_unsigned_integer_by_Kernighan_method(v); +} + +/** + * + * \see stlsoft_C_count_bits_in_16bit_unsigned_integer_by_Kernighan_method + */ +inline +unsigned +count_bits_by_Kernighan_method( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_16bit_unsigned_integer_by_Kernighan_method(v); +} + /** * * \see stlsoft_C_count_bits_in_32bit_unsigned_integer_by_Kernighan_method @@ -501,6 +655,32 @@ count_bits_by_Kernighan_method( return stlsoft_C_count_bits_in_64bit_unsigned_integer_by_Kernighan_method(v); } +/** + * + * \see stlsoft_C_count_bits_in_8bit_unsigned_integer_by_8bit_table + */ +inline +unsigned +count_bits_by_8bit_table( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_8bit_unsigned_integer_by_8bit_table(v); +} + +/** + * + * \see stlsoft_C_count_bits_in_16bit_unsigned_integer_by_8bit_table + */ +inline +unsigned +count_bits_by_8bit_table( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_16bit_unsigned_integer_by_8bit_table(v); +} + /** * * \see stlsoft_C_count_bits_in_32bit_unsigned_integer_by_8bit_table @@ -526,7 +706,108 @@ count_bits_by_8bit_table( { return stlsoft_C_count_bits_in_64bit_unsigned_integer_by_8bit_table(v); } +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint16) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) +/** + * + * \see stlsoft_C_count_bits_in_16bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +count_bits_by_intrinsic( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_16bit_unsigned_integer_by_intrinsic(v); +} + +/** + * + * \see stlsoft_C_count_bits_in_16bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +count_bits_by_intrinsic( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_16bit_unsigned_integer_by_intrinsic(STLSOFT_STATIC_CAST(ss_uint16_t, v)); +} +#endif +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint32) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) + +/** + * + * \see stlsoft_C_count_bits_in_32bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +count_bits_by_intrinsic( + ss_uint32_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_32bit_unsigned_integer_by_intrinsic(v); +} +#endif +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint64) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) + +/** + * + * \see stlsoft_C_count_bits_in_64bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +count_bits_by_intrinsic( + ss_uint64_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_64bit_unsigned_integer_by_intrinsic(v); +} +#endif + + +/** Counts the number of bits in an 8-bit unsigned integer + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +inline +unsigned +count_bits( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ +# if 0 +# elif defined(STLSOFT_BIT_COUNT_BY_Kernighan) + return count_bits_by_Kernighan_method(v); +# else + return count_bits_by_8bit_table(v); +# endif +} + +/** Counts the number of bits in a 16-bit unsigned integer + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +inline +unsigned +count_bits( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ +# if 0 +# elif defined(STLSOFT_BIT_COUNT_BY_Kernighan) + return count_bits_by_Kernighan_method(v); +# else + return count_bits_by_8bit_table(v); +# endif +} /** Counts the number of bits in a 32-bit unsigned integer * @@ -540,8 +821,9 @@ count_bits( ss_uint32_t v ) STLSOFT_NOEXCEPT { -# if defined(STLSOFT_BIT_COUNT_BY_Kernighan) - return count_bits_by_Kernighan(v); +# if 0 +# elif defined(STLSOFT_BIT_COUNT_BY_Kernighan) + return count_bits_by_Kernighan_method(v); # else return count_bits_by_8bit_table(v); # endif @@ -559,8 +841,9 @@ count_bits( ss_uint64_t v ) STLSOFT_NOEXCEPT { -# if defined(STLSOFT_BIT_COUNT_BY_Kernighan) - return count_bits_by_Kernighan(v); +# if 0 +# elif defined(STLSOFT_BIT_COUNT_BY_Kernighan) + return count_bits_by_Kernighan_method(v); # else return count_bits_by_8bit_table(v); # endif @@ -612,7 +895,10 @@ count_bits( } #endif /* __cplusplus */ -/* ////////////////////////////////////////////////////////////////////// */ + +/* ///////////////////////////////////////////////////////////////////////// + * namespace + */ #ifndef STLSOFT_NO_NAMESPACE } /* namespace stlsoft */ @@ -627,8 +913,6 @@ count_bits( # pragma once #endif /* STLSOFT_CF_PRAGMA_ONCE_SUPPORT */ -/* ////////////////////////////////////////////////////////////////////// */ - #endif /* !STLSOFT_INCL_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS */ /* ///////////////////////////// end of file //////////////////////////// */ diff --git a/include/stlsoft/util/bits/test_functions.h b/include/stlsoft/util/bits/test_functions.h index 8823df45..ac681bdc 100644 --- a/include/stlsoft/util/bits/test_functions.h +++ b/include/stlsoft/util/bits/test_functions.h @@ -1,14 +1,14 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: stlsoft/util/bits/test_functions.h + * File: stlsoft/util/bits/test_functions.h * - * Purpose: Bit test functions + * Purpose: Bit test functions * - * Created: 2nd June 2010 - * Updated: 11th March 2024 + * Created: 2nd June 2010 + * Updated: 25th September 2026 * - * Home: http://stlsoft.org/ + * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2024, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2010-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -53,8 +53,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS_MAJOR 1 # define STLSOFT_VER_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS_MINOR 0 -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS_REVISION 3 -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS_EDIT 12 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS_REVISION 5 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS_EDIT 15 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -76,6 +76,10 @@ # include #endif /* !STLSOFT_INCL_STLSOFT_QUALITY_H_COVER */ +#ifndef STLSOFT_INCL_STLSOFT_API_external_h_bitfns +# include +#endif /* !STLSOFT_INCL_STLSOFT_API_external_h_bitfns */ + /* ///////////////////////////////////////////////////////////////////////// * namespace @@ -173,6 +177,152 @@ stlsoft_C_find_highest_bit_in_64bit_unsigned_integer( return stlsoft_C_find_highest_bit_in_32bit_unsigned_integer(STLSOFT_STATIC_CAST(ss_uint32_t, v)); } +#if 0 +#elif defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + +/** Find the 1-based index of the highest set bit, using a compiler + * intrinsic. Returns 0 when \c v is 0. Not selected by find_highest_bit(). + */ +STLSOFT_INLINE +unsigned +stlsoft_C_find_highest_bit_in_8bit_unsigned_integer_by_intrinsic( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ +# if 0 +# elif defined(STLSOFT_CF__builtin_clz_SUPPORT) + + if (0u == v) + { + return 0u; + } + + return 32u - STLSOFT_STATIC_CAST(unsigned, __builtin_clz(STLSOFT_STATIC_CAST(unsigned, v))); +# elif defined(STLSOFT_CF__BitScanReverse_SUPPORT) + + unsigned long index; + + if (0 == _BitScanReverse(&index, STLSOFT_STATIC_CAST(unsigned long, v))) + { + return 0u; + } + + return STLSOFT_STATIC_CAST(unsigned, index) + 1u; +# else + +# error Unexpected +# endif +} + +/** Find the 1-based index of the highest set bit, using a compiler + * intrinsic. Returns 0 when \c v is 0. Not selected by find_highest_bit(). + */ +STLSOFT_INLINE +unsigned +stlsoft_C_find_highest_bit_in_16bit_unsigned_integer_by_intrinsic( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ +# if 0 +# elif defined(STLSOFT_CF__builtin_clz_SUPPORT) + + if (0u == v) + { + return 0u; + } + + return 32u - STLSOFT_STATIC_CAST(unsigned, __builtin_clz(STLSOFT_STATIC_CAST(unsigned, v))); +# elif defined(STLSOFT_CF__BitScanReverse_SUPPORT) + + unsigned long index; + + if (0 == _BitScanReverse(&index, STLSOFT_STATIC_CAST(unsigned long, v))) + { + return 0u; + } + + return STLSOFT_STATIC_CAST(unsigned, index) + 1u; +# else + +# error Unexpected +# endif +} + +/** Find the 1-based index of the highest set bit, using a compiler + * intrinsic. Returns 0 when \c v is 0. Not selected by find_highest_bit(). + */ +STLSOFT_INLINE +unsigned +stlsoft_C_find_highest_bit_in_32bit_unsigned_integer_by_intrinsic( + ss_uint32_t v +) STLSOFT_NOEXCEPT +{ +# if 0 +# elif defined(STLSOFT_CF__builtin_clz_SUPPORT) + + if (0u == v) + { + return 0u; + } + + return 32u - STLSOFT_STATIC_CAST(unsigned, __builtin_clz(v)); +# elif defined(STLSOFT_CF__BitScanReverse_SUPPORT) + + unsigned long index; + + if (0 == _BitScanReverse(&index, STLSOFT_STATIC_CAST(unsigned long, v))) + { + return 0u; + } + + return STLSOFT_STATIC_CAST(unsigned, index) + 1u; +# else + +# error Unexpected +# endif +} +#endif + +#if 0 +#elif defined(STLSOFT_CF__builtin_clzll_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + +/** Find the 1-based index of the highest set bit, using a compiler + * intrinsic. Returns 0 when \c v is 0. Not selected by find_highest_bit(). + */ +STLSOFT_INLINE +unsigned +stlsoft_C_find_highest_bit_in_64bit_unsigned_integer_by_intrinsic( + ss_uint64_t v +) STLSOFT_NOEXCEPT +{ +# if 0 +# elif defined(STLSOFT_CF__builtin_clzll_SUPPORT) + + if (0u == v) + { + return 0u; + } + + return 64u - STLSOFT_STATIC_CAST(unsigned, __builtin_clzll(v)); +# elif defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + + unsigned long index; + + if (0 == _BitScanReverse64(&index, v)) + { + return 0u; + } + + return STLSOFT_STATIC_CAST(unsigned, index) + 1u; +# else + +# error Unexpected +# endif +} +#endif + /* ///////////////////////////////////////////////////////////////////////// * C++ @@ -232,10 +382,73 @@ find_highest_bit( return stlsoft_C_find_highest_bit_in_8bit_unsigned_integer(v); } +#if 0 +#elif defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + +/** + * + * \see stlsoft_C_find_highest_bit_in_64bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +find_highest_bit_by_intrinsic( + ss_uint64_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_find_highest_bit_in_64bit_unsigned_integer_by_intrinsic(v); +} +#endif + +#if 0 +#elif defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + +/** + * + * \see stlsoft_C_find_highest_bit_in_32bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +find_highest_bit_by_intrinsic( + ss_uint32_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_find_highest_bit_in_32bit_unsigned_integer_by_intrinsic(v); +} + +/** + * + * \see stlsoft_C_find_highest_bit_in_16bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +find_highest_bit_by_intrinsic( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_find_highest_bit_in_16bit_unsigned_integer_by_intrinsic(v); +} +/** + * + * \see stlsoft_C_find_highest_bit_in_8bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +find_highest_bit_by_intrinsic( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_find_highest_bit_in_8bit_unsigned_integer_by_intrinsic(v); +} +#endif #endif /* __cplusplus */ -/* ////////////////////////////////////////////////////////////////////// */ + +/* ///////////////////////////////////////////////////////////////////////// + * namespace + */ #ifndef STLSOFT_NO_NAMESPACE } /* namespace stlsoft */ @@ -250,8 +463,6 @@ find_highest_bit( # pragma once #endif /* STLSOFT_CF_PRAGMA_ONCE_SUPPORT */ -/* ////////////////////////////////////////////////////////////////////// */ - #endif /* !STLSOFT_INCL_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS */ /* ///////////////////////////// end of file //////////////////////////// */ diff --git a/include/stlsoft/util/bits/xor_functions.h b/include/stlsoft/util/bits/xor_functions.h index 289447d3..27d6040c 100644 --- a/include/stlsoft/util/bits/xor_functions.h +++ b/include/stlsoft/util/bits/xor_functions.h @@ -1,14 +1,14 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: stlsoft/util/bits/xor_functions.h + * File: stlsoft/util/bits/xor_functions.h * - * Purpose: Bit XOR functions + * Purpose: Bit XOR functions * - * Created: 2nd June 2010 - * Updated: 11th March 2024 + * Created: 2nd June 2010 + * Updated: 24th September 2026 * - * Home: http://stlsoft.org/ + * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2024, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2010-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -54,7 +54,7 @@ # define STLSOFT_VER_STLSOFT_UTIL_BITS_H_XOR_FUNCTIONS_MAJOR 1 # define STLSOFT_VER_STLSOFT_UTIL_BITS_H_XOR_FUNCTIONS_MINOR 2 # define STLSOFT_VER_STLSOFT_UTIL_BITS_H_XOR_FUNCTIONS_REVISION 1 -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_XOR_FUNCTIONS_EDIT 14 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_XOR_FUNCTIONS_EDIT 15 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -253,11 +253,12 @@ calculate_xor_over_range( { return stlsoft_C_calculate_xor_over_8bit_unsigned_range(p, n); } - - #endif /* __cplusplus */ -/* ////////////////////////////////////////////////////////////////////// */ + +/* ///////////////////////////////////////////////////////////////////////// + * namespace + */ #ifndef STLSOFT_NO_NAMESPACE } /* namespace stlsoft */ @@ -272,8 +273,6 @@ calculate_xor_over_range( # pragma once #endif /* STLSOFT_CF_PRAGMA_ONCE_SUPPORT */ -/* ////////////////////////////////////////////////////////////////////// */ - #endif /* !STLSOFT_INCL_STLSOFT_UTIL_BITS_H_XOR_FUNCTIONS */ /* ///////////////////////////// end of file //////////////////////////// */ diff --git a/strategy/BIT_FUNCTIONS.md b/strategy/BIT_FUNCTIONS.md new file mode 100644 index 00000000..f736d0ed --- /dev/null +++ b/strategy/BIT_FUNCTIONS.md @@ -0,0 +1,130 @@ +# STLSoft.b - Bit Functions + +Strategy note for **STLSoft.b** bit utilities. Measurements are of the performance program **test/performance/stlsoft/bit_functions/main.cpp**. Library sources are **include/stlsoft/util/bits/count_functions.h**, **include/stlsoft/util/bits/test_functions.h**, and **include/stlsoft/util/bits/xor_functions.h**. Intrinsic detection and naming live in **include/stlsoft/api/external/bitfns.h** and **include/stlsoft/api/internal/bitfns.h**. + + +## Question + +If intrinsics are never adopted, should `count_bits()` use Kernighan on Apple and the 8-bit table everywhere else? + +**No**. The fast Kernighan numbers are Apple Clang rewriting the loop into a hardware popcount. They are not a property of Apple hardware. On every other toolchain measured here, that rewrite did not happen, and the table is several times faster. A default keyed on Apple, or on ARM, would be right only while the compiler keeps doing that rewrite, and badly wrong when it does not. + +The cost of leaving the table in place on Apple Clang is a fraction of a nanosecond per call. The cost of leaving Kernighan in place on a compiler that executes the source loop is about 10–12 ns (`uint32_t`, all ones) and about 23–33 ns (`uint64_t`, all ones), against about 1–2 ns for the table. + + +## What was measured + +Optimised release builds (`optimisation: speed`, `NDEBUG`), five-sample medians, 20,000,000 iterations. Anchors match across cells for the same input pattern. CI exports `SIS_PERFTESTS_GROUPGAPS=1` (harness banner `Env: SIS_PERFTESTS_GROUPGAPS=1` only when truey). + +* **Full CI wave (GitHub Actions), with intrinsic rows:** `linux-clang` (Clang 18.1.3), `linux-gcc` (GNU 13.3), `macos-clang` (Clang 21.0.0), `macos-gcc` (job label; harness still reports Clang 21.0.0 — Apple’s `gcc` driver), `windows-cl` (Visual C++ 18.x), `windows-mingw` (GNU 15.2). Widths `uint8_t` … `uint64_t` (+ `int` on `count_bits()`); patterns sequential `i`, `~i`, ones, `ones^1`, zero, rotating bit, both-halves-live (`/wide`). +* **Earlier pre-intrinsic matrix** (commit `74b74407875100e0f1b6f5f7658a714c9a8d57b3`) remains useful as a baseline without intrinsic columns; numbers below supersede it for policy. + + +### Population Count, CI summary (`uint32_t` / `uint64_t` ns/call) + +| Cell | Kernighan ones | Table ones | Intrinsic ones | Intrinsic sequential | +| --- | --- | --- | --- | --- | +| Linux Clang 18.1.3 | 16.48 / 33.45 | 0.92 / 2.02 | 1.29 / 1.29 | 0.85 / 0.85 | +| Linux GCC 13.3 | 9.82 / 27.58 | 0.82 / 1.58 | 2.76 / 2.75 | 2.73 / 2.73 | +| macOS Clang 21 | 0.51 / 0.93 | 1.50 / 2.16 | 0.57 / 0.53 | 0.27 / 0.24 | +| macOS “gcc” (Clang 21) | 0.39 / 0.71 | 1.13 / 1.44 | 0.43 / 0.40 | 0.23 / 0.22 | +| Windows MSVC 18 | 11.42 / 23.08 | 1.01 / 3.13 | 0.32 / 0.32 | 0.32 / 0.32 | +| Windows MinGW GCC 15.2 | 11.85 / 24.04 | 0.97 / 1.73 | 2.21 / 2.20 | 2.21 / 2.20 | + +`count_bits()` tracks the table on every cell. + + +### Population Count detail by cell + +Cells are ns/call for `uint8_t` / `uint16_t` / `uint32_t` / `uint64_t` unless noted. + +**Linux Clang 18.1.3** — table usually best on dense; intrinsic competitive (~0.85–1.3 ns) and sometimes ahead of the table on sequential. Not a flat libcall. `/bit` **deletes** the intrinsic (0 ns, anchor still `80,000,000`); Kernighan and table remain live. + +| Row | Kernighan | 8-bit table | intrinsic | +| --- | --- | --- | --- | +| sequential `i` | 1.94 / 4.14 / 5.80 / 5.78 | 0.29 / 0.43 / 1.16 / 1.11 | 1.00 / 0.92 / 0.85 / 0.85 | +| all-ones | 3.33 / 7.00 / 16.48 / 33.45 | 0.31 / 0.45 / 0.92 / 2.02 | 1.09 / 1.36 / 1.29 / 1.29 | +| rotating bit | 0.89 / 0.89 / 0.89 / 1.38 | 0.46 / 0.70 / 1.24 / 2.25 | 0 / 0 / 0 / 0 | + +**Linux GCC 13.3** — soft intrinsic, flat ~2.73 ns; table wins ~3×. + +| Row | Kernighan | 8-bit table | intrinsic | +| --- | --- | --- | --- | +| sequential `i` | 1.52 / 2.59 / 3.84 / 3.86 | 0.55 / 0.55 / 0.83 / 0.83 | 2.73 / 2.73 / 2.73 / 2.73 | +| all-ones | 2.46 / 8.73 / 9.82 / 27.58 | 0.55 / 0.56 / 0.82 / 1.58 | 2.76 / 2.76 / 2.76 / 2.75 | +| rotating bit | 0.55 / 0.55 / 0.55 / 0.81 | 1.03 / 1.03 / 0.92 / 1.64 | 2.73 / 2.73 / 2.73 / 2.73 | + +**macOS Clang 21** (and **macos-gcc**, same Clang 21 banner) — Kernighan rewritten into the intrinsic class; `/bit` deletes Kernighan (8/16/32) and intrinsic (all widths). Table stays ~0.4–2.2 ns. + +| Row (32/64) | Kernighan | 8-bit table | intrinsic | +| --- | --- | --- | --- | +| sequential `i` (clang) | 0.23 / 0.25 | 1.87 / 1.47 | 0.27 / 0.24 | +| all-ones (clang) | 0.51 / 0.93 | 1.50 / 2.16 | 0.57 / 0.53 | +| sequential `i` (“gcc”) | 0.19 / 0.20 | 1.59 / 1.19 | 0.23 / 0.22 | +| all-ones (“gcc”) | 0.39 / 0.71 | 1.13 / 1.44 | 0.43 / 0.40 | + +**Windows MSVC 18** — real hardware popcount on 16/32/64 (~0.32 ns). `uint8_t` intrinsic often slower (~1.56 sequential). Intrinsic beats the table on dense 32/64. Kernighan still executes as a loop. + +| Row | Kernighan | 8-bit table | intrinsic | +| --- | --- | --- | --- | +| sequential `i` | 3.39 / 4.47 / 6.05 / 6.82 | 1.58 / 1.89 / 2.20 / 3.14 | 1.57 / 0.33 / 0.32 / 0.32 | +| all-ones | 4.07 / 6.32 / 11.42 / 23.08 | 1.88 / 0.63 / 1.01 / 3.13 | 0.32 / 0.34 / 0.32 / 0.32 | +| rotating bit | 0.77 / 0.79 / 1.56 / 0.95 | 0.63 / 2.20 / 1.24 / 2.25 | 0.63 / 0.63 / 0.63 / 0.63 | + +**Windows MinGW GCC 15.2** — same soft-intrinsic story as Linux GCC (~2.2 ns flat); table wins. + +| Row | Kernighan | 8-bit table | intrinsic | +| --- | --- | --- | --- | +| sequential `i` | 1.83 / 3.23 / 4.82 / 5.10 | 0.64 / 0.65 / 0.95 / 0.95 | 2.19 / 2.20 / 2.21 / 2.20 | +| all-ones | 2.83 / 5.33 / 11.85 / 24.04 | 0.45 / 0.66 / 0.97 / 1.73 | 2.20 / 2.20 / 2.21 / 2.20 | + + +### Highest-bit, CI summary (sequential ns/call, 16 / 32 / 64) + +| Cell | Scan | Intrinsic | +| --- | --- | --- | +| Linux Clang 18.1.3 | 3.03 / 3.39 / 3.40 | 0.89 / 0.57 / 0.57 | +| Linux GCC 13.3 | 0.55 / 0.55 / 0.55 | 0.55 / 0.57 / 0.95 | +| macOS Clang 21 | 1.47 / 1.45 / 1.33 | 0.34 / 0.30 / 0.29 | +| macOS “gcc” (Clang 21) | 1.25 / 1.01 / 0.99 | 0.32 / 0.19 / 0.20 | +| Windows MSVC 18 | 3.77 / 3.53 / 3.99 | 1.88 / 1.57 / 2.19 | +| Windows MinGW GCC 15.2 | 1.57 / 1.73 / 1.68 | 1.57 / 1.25 / 1.57 | + +Intrinsic is a clear win on Apple Clang and Linux Clang; mixed or similar on Linux GCC / MinGW; modestly better on MSVC sequential, mixed on `/bit`. + + +## Learnings + +* **Kernighan scales with set-bit count when the compiler leaves the loop alone** (Linux Clang, Linux GCC, MSVC, MinGW). All-ones `uint64_t` is about twice all-ones `uint32_t` because of the two 32-bit calls. +* **Apple Clang rewrites Kernighan into the same class as the popcount intrinsic.** CI `macos-clang` and `macos-gcc` both report Clang 21.0.0; treat `macos-gcc` as a second Apple Clang sample, not as GNU on Darwin. +* **Intrinsics are not one story on generic x86-64:** + * **Linux GCC / MinGW:** `__builtin_popcount*` ≈ flat libcall (~2.2–2.7 ns) — slower than the table. + * **Linux Clang 18:** competitive hardware-ish popcount (~0.85–1.3 ns); sometimes beats the table on sequential, often loses on dense; `/bit` can delete the intrinsic. + * **MSVC:** `__popcnt*` is hardware on 16/32/64 (~0.32 ns) and beats the table there; `uint8_t` is weaker. +* **Zero-time `/bit` rows are optimisations, not free popcount.** Apple Clang deletes Kernighan and the intrinsic; Linux Clang deletes only the intrinsic; Linux GCC / MinGW / MSVC keep live loops. Anchors stay non-zero. +* **Sequential `uint64_t` is not a 64-bit input** (`v = i` with `i` below 2^25). Prefer ones / `~i` / `/wide` for the high half. +* **The table is density-insensitive relative to Kernighan** and remains a safe portable default. +* **`find_highest_bit_by_intrinsic` is favourable on Apple Clang and Linux Clang**, not a clear global win on GCC/MinGW, and only a modest sequential win on MSVC. +* **XOR remains a short range scan** — no SIMD case from this harness. + + +## Strategy + +* **Keep the 8-bit table as the default** for `count_bits()`, on every architecture. +* **Do not select Kernighan by Apple, by ARM, or by Clang.** The measured switch is “this compiler, on this target, rewrote this loop”. +* **Leave `STLSOFT_BIT_COUNT_BY_Kernighan` as an opt-in** for a build that has been measured. +* **Keep `count_bits_by_intrinsic()` unselected.** A global switch would win on MSVC (and often on Apple Clang) but lose ~2–3× on Linux GCC and MinGW. `count_bits()` stays on the table. +* **Keep `find_highest_bit_by_intrinsic()` unselected.** Strong on Apple Clang and Linux Clang; not justified as a portable default from GCC/MinGW/MSVC alone. +* **MSVC popcount is gated by architecture and toolset, in `external/bitfns.h`.** `__popcnt16` / `__popcnt`: x86 and x64 from MSVC 15.00, ARM64 from VS 2022 17.11 (`_MSC_VER` 1941); not 32-bit ARM or ARM64EC. `__popcnt64`: x64 from 15.00, ARM64 and ARM64EC from 17.11. `_BitScanReverse64`: ARM64, ARM64EC, and x64 from 14.00. When a GCC/Clang builtin and an MSVC intrinsic are both visible, the builtin wins. +* **Do not change `calculate_xor_over_range` for performance** on the strength of this harness. + + +## Not yet done + +* Selecting either intrinsic into the dispatchers under a **narrow, measured** gate (e.g. MSVC-only popcount, or a `POPCNT`-legal `-march` / `/arch` build). Full-matrix evidence is in; a portable default still loses on soft GCC. +* A CI (or local) cell with `-march=native` / `-mpopcnt` / `/arch:AVX2` (or equivalent) that allows `POPCNT` under GCC/Clang on Linux. +* Real **GNU GCC or non-Apple Clang on Darwin** (not the `gcc` → Clang driver). +* Correct INTERNAL `clz(0)` to full width (`32` / `64`), then optionally drive `find_highest_bit_by_intrinsic` through those adapters. + + + diff --git a/test/performance/CMakeLists.txt b/test/performance/CMakeLists.txt index 22d6592b..6845234f 100644 --- a/test/performance/CMakeLists.txt +++ b/test/performance/CMakeLists.txt @@ -1,7 +1,3 @@ - +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten add_subdirectory(platformstl) add_subdirectory(stlsoft) - - -# ############################## end of file ############################# # - diff --git a/test/performance/stlsoft/CMakeLists.txt b/test/performance/stlsoft/CMakeLists.txt index 9c1cdd1c..b207feb9 100644 --- a/test/performance/stlsoft/CMakeLists.txt +++ b/test/performance/stlsoft/CMakeLists.txt @@ -1,10 +1,7 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten add_subdirectory(containers) add_subdirectory(conversion) add_subdirectory(diagnostics) add_subdirectory(memory) add_subdirectory(string) add_subdirectory(util) - - -# ############################## end of file ############################# # - diff --git a/test/performance/stlsoft/util/CMakeLists.txt b/test/performance/stlsoft/util/CMakeLists.txt index e4cf965b..0f094827 100644 --- a/test/performance/stlsoft/util/CMakeLists.txt +++ b/test/performance/stlsoft/util/CMakeLists.txt @@ -1,5 +1,6 @@ if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) + add_subdirectory(bit_functions) add_subdirectory(count_digits) endif() diff --git a/test/performance/stlsoft/util/bit_functions/CMakeLists.txt b/test/performance/stlsoft/util/bit_functions/CMakeLists.txt new file mode 100644 index 00000000..96b868bb --- /dev/null +++ b/test/performance/stlsoft/util/bit_functions/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_example_program(test.performance.stlsoft.bit_functions main.cpp) diff --git a/test/performance/stlsoft/util/bit_functions/main.cpp b/test/performance/stlsoft/util/bit_functions/main.cpp new file mode 100644 index 00000000..b19331e8 --- /dev/null +++ b/test/performance/stlsoft/util/bit_functions/main.cpp @@ -0,0 +1,3830 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test.performance.stlsoft.bit_functions/main.cpp + * + * Purpose: Perf-test for bit functions. + * + * Created: 24th September 2026 + * Updated: 25th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * compatibility + */ + +#if !defined(__cplusplus) || \ + __cplusplus < 201103L +# error Requires C++11 or later +#endif + + +/* ///////////////////////////////////////////////////////////////////////// + * feature control + */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include + +#if __cplusplus >= 201103L +# include +#else +# include +#endif /* C++11+ */ +#include + +#include +#include +#include + +#include +#include +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * types + */ + +#if __cplusplus >= 201103L + +typedef stlsoft::std_chrono_hrc_stopwatch stopwatch_t; +#else + +typedef platformstl::stopwatch stopwatch_t; +#endif /* C++11+ */ +typedef stopwatch_t::interval_type interval_t; + +using stlsoft::ss_size_t; +using stlsoft::ss_uint8_t; +using stlsoft::ss_uint16_t; +using stlsoft::ss_uint32_t; +using stlsoft::ss_uint64_t; + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +void +emit_result_row( + char const* function_name +, interval_t const* uint8_ns +, interval_t const* uint16_ns +, interval_t const* uint32_ns +, interval_t const* uint64_ns +, interval_t const* int_ns +, ss_uint64_t anchor_value +, bool report_per_element +); + + +/* ///////////////////////////////////////////////////////////////////////// + * constants + */ + +namespace { + + ss_size_t const NUM_ITERATIONS = 20000000; + ss_size_t const NUM_SAMPLES = 5; + ss_size_t const XOR_RANGE_LEN = 64; + int const FN_COL_WIDTH = 42; + int const METRIC_COL_WIDTH = 16; + + + interval_t + median_sample( + interval_t const* samples + , ss_size_t n + ) + { + interval_t sorted[NUM_SAMPLES] = {}; + + if (0 == n) + { + return 0; + } + + if (n > NUM_SAMPLES) + { + n = NUM_SAMPLES; + } + + for (ss_size_t i = 0; n != i; ++i) + { + sorted[i] = samples[i]; + } + + for (ss_size_t i = 1; n != i; ++i) + { + interval_t const v = sorted[i]; + ss_size_t j = i; + + for (; 0 != j && sorted[j - 1] > v; --j) + { + sorted[j] = sorted[j - 1]; + } + + sorted[j] = v; + } + + return sorted[n / 2]; + } + + struct row_samples + { + interval_t u8[NUM_SAMPLES]; + interval_t u16[NUM_SAMPLES]; + interval_t u32[NUM_SAMPLES]; + interval_t u64[NUM_SAMPLES]; + interval_t si[NUM_SAMPLES]; + ss_size_t n; + ss_uint64_t anchor; + bool has_u8; + bool has_u16; + bool has_u32; + bool has_u64; + bool has_si; + + void clear() + { + n = 0; + anchor = 0; + has_u8 = false; + has_u16 = false; + has_u32 = false; + has_u64 = false; + has_si = false; + } + + void push( + interval_t const* uint8_ns + , interval_t const* uint16_ns + , interval_t const* uint32_ns + , interval_t const* uint64_ns + , interval_t const* int_ns + , ss_uint64_t anchor_value + ) + { + has_u8 = NULL != uint8_ns; + has_u16 = NULL != uint16_ns; + has_u32 = NULL != uint32_ns; + has_u64 = NULL != uint64_ns; + has_si = NULL != int_ns; + + if (has_u8) + { + u8[n] = *uint8_ns; + } + if (has_u16) + { + u16[n] = *uint16_ns; + } + if (has_u32) + { + u32[n] = *uint32_ns; + } + if (has_u64) + { + u64[n] = *uint64_ns; + } + if (has_si) + { + si[n] = *int_ns; + } + + anchor = anchor_value; + ++n; + } + + void emit( + char const* function_name + , bool report_per_element = false + ) const + { + interval_t const med_u8 = has_u8 ? median_sample(u8, n) : 0; + interval_t const med_u16 = has_u16 ? median_sample(u16, n) : 0; + interval_t const med_u32 = has_u32 ? median_sample(u32, n) : 0; + interval_t const med_u64 = has_u64 ? median_sample(u64, n) : 0; + interval_t const med_si = has_si ? median_sample(si, n) : 0; + + emit_result_row( + function_name + , has_u8 ? &med_u8 : NULL + , has_u16 ? &med_u16 : NULL + , has_u32 ? &med_u32 : NULL + , has_u64 ? &med_u64 : NULL + , has_si ? &med_si : NULL + , anchor + , report_per_element + ); + } + }; +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * functions + */ + +template +std::string +thousands( + T_integer const& v +) +{ + char dest[41]; + size_t const n = stlsoft::format_thousands(dest, STLSOFT_NUM_ELEMENTS(dest), "3;0", v); + + return std::string(dest, n); +} + +void +emit_metric_cell( + char const* s +) +{ + std::cout + << '\t' + << std::setw(METRIC_COL_WIDTH) << std::right << s; +} + +void +emit_metric_cell( + interval_t const& v +) +{ + emit_metric_cell(thousands(v).c_str()); +} + +void +emit_absent_metric_cell() +{ + emit_metric_cell("-"); +} + +void +emit_rate_cell( + interval_t const* total_ns +, double divisor +); + +void +emit_header_row() +{ + std::cout + << std::setw(FN_COL_WIDTH) << std::left << "" + ; + emit_metric_cell("uint8_t"); + emit_metric_cell("uint16_t"); + emit_metric_cell("uint32_t"); + emit_metric_cell("uint64_t"); + emit_metric_cell("int"); + emit_metric_cell("uint8_t ns"); + emit_metric_cell("uint16_t ns"); + emit_metric_cell("uint32_t ns"); + emit_metric_cell("uint64_t ns"); + emit_metric_cell("int ns"); + emit_metric_cell("uint8_t el"); + emit_metric_cell("uint16_t el"); + emit_metric_cell("uint32_t el"); + emit_metric_cell("uint64_t el"); + emit_metric_cell("anchor"); + std::cout << std::endl; +} + +bool +env_is_truey( + char const* name +) +{ +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4996) +#endif + char const* const env = ::getenv(name); +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + + if (NULL == env || '\0' == *env) + { + return false; + } + + if (0 == ::strcmp(env, "1") || + 0 == ::strcmp(env, "ok") || + 0 == ::strcmp(env, "on") || + 0 == ::strcmp(env, "true") || + 0 == ::strcmp(env, "yes") || + 0 == ::strcmp(env, "y") || + 0 == ::strcmp(env, "OK") || + 0 == ::strcmp(env, "ON") || + 0 == ::strcmp(env, "TRUE") || + 0 == ::strcmp(env, "YES") || + 0 == ::strcmp(env, "Y")) + { + return true; + } + + return false; +} + +void +maybe_emit_group_gap( + char const* function_name +) +{ + static bool have_prev = false; + static char prev_key[64] = ""; + + if (!env_is_truey("SIS_PERFTESTS_GROUPGAPS")) + { + return; + } + + char const* const slash = ::strrchr(function_name, '/'); + char const* const pattern = (NULL == slash) ? "" : slash; + char const* family = "other"; + + if (0 == ::strncmp(function_name, "count_bits", 10)) + { + family = "count"; + } + else if (0 == ::strncmp(function_name, "find_highest_bit", 16)) + { + family = "find"; + } + else if (0 == ::strncmp(function_name, "calculate_xor", 13)) + { + family = "xor"; + } + + char key[64]; + + snprintf(key, sizeof(key), "%s%s", family, pattern); + + if (have_prev && 0 != ::strcmp(prev_key, key)) + { + std::cout << std::endl; + } + + snprintf(prev_key, sizeof(prev_key), "%s", key); + have_prev = true; +} + +void +emit_result_row( + char const* function_name +, interval_t const* uint8_ns +, interval_t const* uint16_ns +, interval_t const* uint32_ns +, interval_t const* uint64_ns +, interval_t const* int_ns +, ss_uint64_t anchor_value +, bool report_per_element +) +{ + maybe_emit_group_gap(function_name); + + std::cout + << std::setw(FN_COL_WIDTH) << std::left << function_name + ; + + if (NULL != uint8_ns) + { + emit_metric_cell(*uint8_ns); + } + else + { + emit_absent_metric_cell(); + } + + if (NULL != uint16_ns) + { + emit_metric_cell(*uint16_ns); + } + else + { + emit_absent_metric_cell(); + } + + if (NULL != uint32_ns) + { + emit_metric_cell(*uint32_ns); + } + else + { + emit_absent_metric_cell(); + } + + if (NULL != uint64_ns) + { + emit_metric_cell(*uint64_ns); + } + else + { + emit_absent_metric_cell(); + } + + if (NULL != int_ns) + { + emit_metric_cell(*int_ns); + } + else + { + emit_absent_metric_cell(); + } + + double const per_call = double(NUM_ITERATIONS); + double const per_element = double(NUM_ITERATIONS) * double(XOR_RANGE_LEN + 1) / 2.0; + + emit_rate_cell(uint8_ns, per_call); + emit_rate_cell(uint16_ns, per_call); + emit_rate_cell(uint32_ns, per_call); + emit_rate_cell(uint64_ns, per_call); + emit_rate_cell(int_ns, per_call); + + if (report_per_element) + { + emit_rate_cell(uint8_ns, per_element); + emit_rate_cell(uint16_ns, per_element); + emit_rate_cell(uint32_ns, per_element); + emit_rate_cell(uint64_ns, per_element); + } + else + { + emit_absent_metric_cell(); + emit_absent_metric_cell(); + emit_absent_metric_cell(); + emit_absent_metric_cell(); + } + + emit_metric_cell(thousands(anchor_value).c_str()); + std::cout << std::endl; +} + +void +emit_rate_cell( + interval_t const* total_ns +, double divisor +) +{ + if (NULL == total_ns) + { + emit_absent_metric_cell(); + + return; + } + + char buf[32]; + double const rate = (0.0 == divisor) ? 0.0 : (double(*total_ns) / divisor); + + snprintf(buf, sizeof(buf), "%.3f", rate); + + emit_metric_cell(buf); +} + +void +emit_build_banner() +{ + std::cout << "compiler: " << STLSOFT_COMPILER_VERSION_STRING << std::endl; + std::cout << "optimisation: "; +#if 0 +#elif defined(__OPTIMIZE_SIZE__) + + std::cout << "size"; +#elif defined(__OPTIMIZE__) + + std::cout << "speed"; +#elif defined(STLSOFT_COMPILER_IS_MSVC) && \ + !defined(STLSOFT_DEBUG) + + std::cout << "speed"; +#else + + std::cout << "off"; +#endif +#ifdef NDEBUG + + std::cout << ", release"; +#else + + std::cout << ", debug-asserts"; +#endif + std::cout << std::endl; + std::cout + << "samples: " + << NUM_SAMPLES + << " (median; 1 warmup discarded)" + << std::endl; + std::cout + << "width columns are loop ns; ns columns are ns/call; el columns are ns/element" + << std::endl; + if (env_is_truey("SIS_PERFTESTS_GROUPGAPS")) + { + std::cout + << "Env: SIS_PERFTESTS_GROUPGAPS=1" + << std::endl; + } +} + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int /*argc*/, char* /*argv*/[]) +{ + ss_uint8_t xor8[XOR_RANGE_LEN]; + ss_uint16_t xor16[XOR_RANGE_LEN]; + ss_uint32_t xor32[XOR_RANGE_LEN]; + ss_uint64_t xor64[XOR_RANGE_LEN]; + + for (ss_size_t i = 0; XOR_RANGE_LEN != i; ++i) + { + xor8[i] = static_cast(i * 3u + 1u); + xor16[i] = static_cast(i * 7u + 1u); + xor32[i] = static_cast(i * 11u + 1u); + xor64[i] = static_cast(i * 13u + 1u); + } + + row_samples rows; + + emit_build_banner(); + emit_header_row(); + + + // count_bits_by_Kernighan_method + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = i; + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = i; + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()"); + } + } + + + // count_bits_by_8bit_table + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = i; + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = i; + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()"); + } + } + + + // count_bits + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = i; + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = i; + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (sequential) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = i; + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = i; + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()"); + } + } +#endif + + + // ------------------------------------------------------------------ + // Dense inputs (~i): high popcount — favourable to the table path + // ------------------------------------------------------------------ + + // count_bits_by_Kernighan_method (dense) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ~ss_uint8_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ~ss_uint16_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()/~i"); + } + } + + + // count_bits_by_8bit_table (dense) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ~ss_uint8_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ~ss_uint16_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()/~i"); + } + } + + + // count_bits (dense) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ~ss_uint8_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ~ss_uint16_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast(~ss_uint32_t(i)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()/~i"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (/~i) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ~ss_uint8_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ~ss_uint16_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()/~i"); + } + } +#endif + + + // ------------------------------------------------------------------ + // Max density (all-ones). Source via volatile so inlining cannot + // constant-fold popcount(~0) to a literal. + // ------------------------------------------------------------------ + + { + ss_uint8_t volatile ones8 = ss_uint8_t(~ss_uint8_t(0)); + ss_uint16_t volatile ones16 = ss_uint16_t(~ss_uint16_t(0)); + ss_uint32_t volatile ones32 = ~ss_uint32_t(0); + ss_uint64_t volatile ones64 = ~ss_uint64_t(0); + + + // count_bits_by_Kernighan_method (max) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ones8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ones16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ones32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ones64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()/ones"); + } + } + + + // count_bits_by_8bit_table (max) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ones8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ones16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ones32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ones64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()/ones"); + } + } + + + // count_bits (max) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ones8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ones16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ones32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ones64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast(ones32); + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()/ones"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (/ones) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ones8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ones16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ones32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ones64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()/ones"); + } + } +#endif + + } + + + // ------------------------------------------------------------------ + // Close-to-max: all-ones with one rotating bit cleared (31 / 63 ones) + // ------------------------------------------------------------------ + + // count_bits_by_Kernighan_method (close-to-max) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(~ss_uint8_t(0)) ^ (ss_uint8_t(1) << (i % 8u)); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(~ss_uint16_t(0)) ^ (ss_uint16_t(1) << (i % 16u)); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(0) ^ (ss_uint32_t(1) << (i % 32u)); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(0) ^ (ss_uint64_t(1) << (i % 64u)); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()/ones^1"); + } + } + + + // count_bits_by_8bit_table (close-to-max) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(~ss_uint8_t(0)) ^ (ss_uint8_t(1) << (i % 8u)); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(~ss_uint16_t(0)) ^ (ss_uint16_t(1) << (i % 16u)); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(0) ^ (ss_uint32_t(1) << (i % 32u)); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(0) ^ (ss_uint64_t(1) << (i % 64u)); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()/ones^1"); + } + } + + + // count_bits (close-to-max) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(~ss_uint8_t(0)) ^ (ss_uint8_t(1) << (i % 8u)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(~ss_uint16_t(0)) ^ (ss_uint16_t(1) << (i % 16u)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(0) ^ (ss_uint32_t(1) << (i % 32u)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(0) ^ (ss_uint64_t(1) << (i % 64u)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast(~ss_uint32_t(0) ^ (ss_uint32_t(1) << (i % 32u))); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()/ones^1"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (/ones^1) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(~ss_uint8_t(0)) ^ (ss_uint8_t(1) << (i % 8u)); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(~ss_uint16_t(0)) ^ (ss_uint16_t(1) << (i % 16u)); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(0) ^ (ss_uint32_t(1) << (i % 32u)); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(0) ^ (ss_uint64_t(1) << (i % 64u)); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()/ones^1"); + } + } +#endif + + + // ------------------------------------------------------------------ + // All-zero. Volatile so the call is not constant-folded to 0. + // ------------------------------------------------------------------ + + { + ss_uint8_t volatile zero8 = 0; + ss_uint16_t volatile zero16 = 0; + ss_uint32_t volatile zero32 = 0; + ss_uint64_t volatile zero64 = 0; + + + // count_bits_by_Kernighan_method (zero) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = zero8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = zero16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = zero32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = zero64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()/0"); + } + } + + + // count_bits_by_8bit_table (zero) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = zero8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = zero16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = zero32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = zero64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()/0"); + } + } + + + // count_bits (zero) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = zero8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = zero16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = zero32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = zero64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast(zero32); + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()/0"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (/0) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = zero8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = zero16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = zero32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = zero64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()/0"); + } + } +#endif + + } + + + // ------------------------------------------------------------------ + // Single rotating bit. The 64-bit shift reaches bits 32..63. + // ------------------------------------------------------------------ + + // count_bits_by_Kernighan_method (bit) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(1) << (i % 8u); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(1) << (i % 16u); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ss_uint32_t(1) << (i % 32u); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ss_uint64_t(1) << (i % 64u); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()/bit"); + } + } + + + // count_bits_by_8bit_table (bit) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(1) << (i % 8u); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(1) << (i % 16u); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ss_uint32_t(1) << (i % 32u); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ss_uint64_t(1) << (i % 64u); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()/bit"); + } + } + + + // count_bits (bit) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(1) << (i % 8u); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(1) << (i % 16u); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ss_uint32_t(1) << (i % 32u); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ss_uint64_t(1) << (i % 64u); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast(ss_uint32_t(1) << (i % 32u)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()/bit"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (/bit) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(1) << (i % 8u); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(1) << (i % 16u); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ss_uint32_t(1) << (i % 32u); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ss_uint64_t(1) << (i % 64u); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()/bit"); + } + } +#endif + + + // ------------------------------------------------------------------ + // Both halves live. uint32 high 16 bits vary; uint64 high half is i. + // ------------------------------------------------------------------ + + // count_bits_by_Kernighan_method (wide) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = (ss_uint8_t(i) << 4) | ss_uint8_t(i & 0x0fu); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = (ss_uint16_t(i) << 8) | ss_uint16_t(i & 0xffu); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = (ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = (ss_uint64_t(i) << 32) | ss_uint64_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()/wide"); + } + } + + + // count_bits_by_8bit_table (wide) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = (ss_uint8_t(i) << 4) | ss_uint8_t(i & 0x0fu); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = (ss_uint16_t(i) << 8) | ss_uint16_t(i & 0xffu); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = (ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = (ss_uint64_t(i) << 32) | ss_uint64_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()/wide"); + } + } + + + // count_bits (wide) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = (ss_uint8_t(i) << 4) | ss_uint8_t(i & 0x0fu); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = (ss_uint16_t(i) << 8) | ss_uint16_t(i & 0xffu); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = (ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = (ss_uint64_t(i) << 32) | ss_uint64_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast((ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()/wide"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (/wide) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = (ss_uint8_t(i) << 4) | ss_uint8_t(i & 0x0fu); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = (ss_uint16_t(i) << 8) | ss_uint16_t(i & 0xffu); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = (ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = (ss_uint64_t(i) << 32) | ss_uint64_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()/wide"); + } + } +#endif + + + // find_highest_bit + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = static_cast(i & 0xff); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = static_cast(i & 0xffff); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = i; + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = i; + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit()"); + } + + } + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + // find_highest_bit_by_intrinsic (sequential) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(i); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(i); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = i; + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = i; + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit_by_intrinsic()"); + } + } +#endif + + + // ------------------------------------------------------------------ + // find_highest_bit: zero, one rotating bit, both halves live. + // ------------------------------------------------------------------ + + { + ss_uint8_t volatile zero8 = 0; + ss_uint16_t volatile zero16 = 0; + ss_uint32_t volatile zero32 = 0; + ss_uint64_t volatile zero64 = 0; + + + // find_highest_bit (zero) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = zero8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = zero16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = zero32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = zero64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit()/0"); + } + + } + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + // find_highest_bit_by_intrinsic (/0) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = zero8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = zero16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = zero32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = zero64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit_by_intrinsic()/0"); + } + } +#endif + + } + + + // find_highest_bit (bit) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = static_cast(1u << (i % 8u)); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = static_cast(1u << (i % 16u)); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ss_uint32_t(1) << (i % 32u); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ss_uint64_t(1) << (i % 64u); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit()/bit"); + } + + } + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + // find_highest_bit_by_intrinsic (/bit) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = static_cast(1u << (i % 8u)); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = static_cast(1u << (i % 16u)); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ss_uint32_t(1) << (i % 32u); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ss_uint64_t(1) << (i % 64u); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit_by_intrinsic()/bit"); + } + } +#endif + + + // find_highest_bit (wide) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = static_cast(i & 0xff); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = static_cast(i & 0xffff); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = (ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = (ss_uint64_t(i) << 32) | ss_uint64_t(i); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit()/wide"); + } + + } + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + // find_highest_bit_by_intrinsic (/wide) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = static_cast(i & 0xff); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = static_cast(i & 0xffff); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = (ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = (ss_uint64_t(i) << 32) | ss_uint64_t(i); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit_by_intrinsic()/wide"); + } + } +#endif + + + // calculate_xor_over_range + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_size_t const n = (i % XOR_RANGE_LEN) + 1u; + + anchor_value += stlsoft::calculate_xor_over_range(xor8, n); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_size_t const n = (i % XOR_RANGE_LEN) + 1u; + + anchor_value += stlsoft::calculate_xor_over_range(xor16, n); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_size_t const n = (i % XOR_RANGE_LEN) + 1u; + + anchor_value += stlsoft::calculate_xor_over_range(xor32, n); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_size_t const n = (i % XOR_RANGE_LEN) + 1u; + + anchor_value += stlsoft::calculate_xor_over_range(xor64, n); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("calculate_xor_over_range()", true); + } + } + + + return EXIT_SUCCESS; +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/stlsoft/util/bit_functions/entry.cpp b/test/unit/stlsoft/util/bit_functions/entry.cpp index 6a333419..e58b5c4e 100644 --- a/test/unit/stlsoft/util/bit_functions/entry.cpp +++ b/test/unit/stlsoft/util/bit_functions/entry.cpp @@ -29,12 +29,10 @@ #include /* STLSoft header files */ -#include /* Standard C++ header files */ /* Standard C header files */ -#include #include @@ -44,11 +42,49 @@ namespace { - static void test_count_bits_Kernighan(); - static void test_count_bits_8bit_table(); - static void test_find_high_bit_32(); - static void test_find_high_bit_64(); - static void test_calculate_xor_over_range_8_bit(); + static void TEST_count_bits_Kernighan_method_FOR_8_BIT(); + static void TEST_count_bits_Kernighan_method_FOR_16_BIT(); + static void TEST_count_bits_Kernighan_method_FOR_32_BIT(); + static void TEST_count_bits_Kernighan_method_FOR_64_BIT(); + static void TEST_count_bits_8bit_table_FOR_8_BIT(); + static void TEST_count_bits_8bit_table_FOR_16_BIT(); + static void TEST_count_bits_8bit_table_FOR_32_BIT(); + static void TEST_count_bits_8bit_table_FOR_64_BIT(); + static void TEST_count_bits_FOR_8_BIT(); + static void TEST_count_bits_FOR_16_BIT(); + static void TEST_count_bits_FOR_32_BIT(); + static void TEST_count_bits_FOR_64_BIT(); + static void TEST_count_bits_FOR_int(); +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint16) + static void TEST_count_bits_by_intrinsic_FOR_8_BIT(); + static void TEST_count_bits_by_intrinsic_FOR_16_BIT(); +#endif +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + static void TEST_count_bits_by_intrinsic_FOR_32_BIT(); +#endif +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + static void TEST_count_bits_by_intrinsic_FOR_64_BIT(); +#endif +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + static void TEST_find_highest_bit_by_intrinsic_FOR_8_BIT(); + static void TEST_find_highest_bit_by_intrinsic_FOR_16_BIT(); + static void TEST_find_highest_bit_by_intrinsic_FOR_32_BIT(); +#endif +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + static void TEST_find_highest_bit_by_intrinsic_FOR_64_BIT(); +#endif + static void TEST_find_high_bit_FOR_8_BIT(); + static void TEST_find_high_bit_FOR_16_BIT(); + static void TEST_find_high_bit_FOR_32_BIT(); + static void TEST_find_high_bit_FOR_64_BIT(); + static void TEST_calculate_xor_over_range_FOR_8_BIT(); + static void TEST_calculate_xor_over_range_FOR_16_BIT(); + static void TEST_calculate_xor_over_range_FOR_32_BIT(); + static void TEST_calculate_xor_over_range_FOR_64_BIT(); } // anonymous namespace @@ -56,7 +92,7 @@ namespace { * main */ -int main(int argc, char **argv) +int main(int argc, char* argv[]) { int retCode = EXIT_SUCCESS; int verbosity = 2; @@ -65,11 +101,49 @@ int main(int argc, char **argv) if (XTESTS_START_RUNNER("test.unit.stlsoft.util.bit_functions", verbosity)) { - XTESTS_RUN_CASE(test_count_bits_Kernighan); - XTESTS_RUN_CASE(test_count_bits_8bit_table); - XTESTS_RUN_CASE(test_find_high_bit_32); - XTESTS_RUN_CASE(test_find_high_bit_64); - XTESTS_RUN_CASE(test_calculate_xor_over_range_8_bit); + XTESTS_RUN_CASE(TEST_count_bits_Kernighan_method_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_count_bits_Kernighan_method_FOR_16_BIT); + XTESTS_RUN_CASE(TEST_count_bits_Kernighan_method_FOR_32_BIT); + XTESTS_RUN_CASE(TEST_count_bits_Kernighan_method_FOR_64_BIT); + XTESTS_RUN_CASE(TEST_count_bits_8bit_table_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_count_bits_8bit_table_FOR_16_BIT); + XTESTS_RUN_CASE(TEST_count_bits_8bit_table_FOR_32_BIT); + XTESTS_RUN_CASE(TEST_count_bits_8bit_table_FOR_64_BIT); + XTESTS_RUN_CASE(TEST_count_bits_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_count_bits_FOR_16_BIT); + XTESTS_RUN_CASE(TEST_count_bits_FOR_32_BIT); + XTESTS_RUN_CASE(TEST_count_bits_FOR_64_BIT); + XTESTS_RUN_CASE(TEST_count_bits_FOR_int); +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint16) + XTESTS_RUN_CASE(TEST_count_bits_by_intrinsic_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_count_bits_by_intrinsic_FOR_16_BIT); +#endif +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + XTESTS_RUN_CASE(TEST_count_bits_by_intrinsic_FOR_32_BIT); +#endif +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + XTESTS_RUN_CASE(TEST_count_bits_by_intrinsic_FOR_64_BIT); +#endif +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + XTESTS_RUN_CASE(TEST_find_highest_bit_by_intrinsic_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_find_highest_bit_by_intrinsic_FOR_16_BIT); + XTESTS_RUN_CASE(TEST_find_highest_bit_by_intrinsic_FOR_32_BIT); +#endif +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + XTESTS_RUN_CASE(TEST_find_highest_bit_by_intrinsic_FOR_64_BIT); +#endif + XTESTS_RUN_CASE(TEST_find_high_bit_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_find_high_bit_FOR_16_BIT); + XTESTS_RUN_CASE(TEST_find_high_bit_FOR_32_BIT); + XTESTS_RUN_CASE(TEST_find_high_bit_FOR_64_BIT); + XTESTS_RUN_CASE(TEST_calculate_xor_over_range_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_calculate_xor_over_range_FOR_16_BIT); + XTESTS_RUN_CASE(TEST_calculate_xor_over_range_FOR_32_BIT); + XTESTS_RUN_CASE(TEST_calculate_xor_over_range_FOR_64_BIT); XTESTS_PRINT_RESULTS(); @@ -86,23 +160,34 @@ int main(int argc, char **argv) namespace { - using stlsoft::sint8_t; using stlsoft::uint8_t; - using stlsoft::sint16_t; using stlsoft::uint16_t; - using stlsoft::sint32_t; using stlsoft::uint32_t; - using stlsoft::sint64_t; using stlsoft::uint64_t; - using platformstl::stopwatch; -static void test_count_bits_Kernighan() +static void TEST_count_bits_Kernighan_method_FOR_8_BIT() { - stopwatch sw; + TEST_INT_EQ(0u, stlsoft::count_bits_by_Kernighan_method(uint8_t(0x00u))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint8_t(0xffu))); + TEST_INT_EQ(4u, stlsoft::count_bits_by_Kernighan_method(uint8_t(0x55u))); + TEST_INT_EQ(4u, stlsoft::count_bits_by_Kernighan_method(uint8_t(0xaau))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint8_t(0x80u))); + TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint8_t(0x81u))); +} - sw.start(); +static void TEST_count_bits_Kernighan_method_FOR_16_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_Kernighan_method(uint16_t(0x0000u))); + TEST_INT_EQ(16u, stlsoft::count_bits_by_Kernighan_method(uint16_t(0xffffu))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint16_t(0x5555u))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint16_t(0xaaaau))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint16_t(0x8000u))); + TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint16_t(0x8001u))); +} +static void TEST_count_bits_Kernighan_method_FOR_32_BIT() +{ TEST_INT_EQ(0u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0))); TEST_INT_EQ(0u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00000000))); @@ -136,14 +221,6 @@ static void test_count_bits_Kernighan() TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00200000))); TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x02000000))); TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x20000000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00000002))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00000020))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00000200))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00002000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00020000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00200000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x02000000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x20000000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00001001))); TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00001010))); @@ -151,20 +228,55 @@ static void test_count_bits_Kernighan() TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x01001000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00011000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00101000))); - TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x01001000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x10001000))); +} + +static void TEST_count_bits_Kernighan_method_FOR_64_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_Kernighan_method(uint64_t(0))); + TEST_INT_EQ(0u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000000)))); - sw.stop(); + TEST_INT_EQ(64u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xffffffffffffffff)))); - fprintf(stdout, "t: %luns\n", static_cast(sw.get_nanoseconds())); + TEST_INT_EQ(32u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x3333333333333333)))); + TEST_INT_EQ(32u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x5555555555555555)))); + TEST_INT_EQ(32u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xaaaaaaaaaaaaaaaa)))); + + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x00000000000000ff)))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x00000000ff000000)))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x000000ff00000000)))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xff00000000000000)))); + + TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000001)))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000100000000)))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000000)))); + + TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000100000001)))); + TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000001)))); } -static void test_count_bits_8bit_table() +static void TEST_count_bits_8bit_table_FOR_8_BIT() { - stopwatch sw; + TEST_INT_EQ(0u, stlsoft::count_bits_by_8bit_table(uint8_t(0x00u))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint8_t(0xffu))); + TEST_INT_EQ(4u, stlsoft::count_bits_by_8bit_table(uint8_t(0x55u))); + TEST_INT_EQ(4u, stlsoft::count_bits_by_8bit_table(uint8_t(0xaau))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint8_t(0x80u))); + TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint8_t(0x81u))); +} - sw.start(); +static void TEST_count_bits_8bit_table_FOR_16_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_8bit_table(uint16_t(0x0000u))); + TEST_INT_EQ(16u, stlsoft::count_bits_by_8bit_table(uint16_t(0xffffu))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint16_t(0x5555u))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint16_t(0xaaaau))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint16_t(0x8000u))); + TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint16_t(0x8001u))); +} +static void TEST_count_bits_8bit_table_FOR_32_BIT() +{ TEST_INT_EQ(0u, stlsoft::count_bits_by_8bit_table(uint32_t(0))); TEST_INT_EQ(0u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00000000))); @@ -198,14 +310,6 @@ static void test_count_bits_8bit_table() TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00200000))); TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x02000000))); TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x20000000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00000002))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00000020))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00000200))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00002000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00020000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00200000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x02000000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x20000000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00001001))); TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00001010))); @@ -213,15 +317,124 @@ static void test_count_bits_8bit_table() TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x01001000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00011000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00101000))); - TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x01001000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x10001000))); +} + +static void TEST_count_bits_8bit_table_FOR_64_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_8bit_table(uint64_t(0))); + TEST_INT_EQ(0u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000000)))); + + TEST_INT_EQ(64u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xffffffffffffffff)))); + + TEST_INT_EQ(32u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x3333333333333333)))); + TEST_INT_EQ(32u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x5555555555555555)))); + TEST_INT_EQ(32u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xaaaaaaaaaaaaaaaa)))); + + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x00000000000000ff)))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x00000000ff000000)))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x000000ff00000000)))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xff00000000000000)))); + + TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000001)))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000100000000)))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000000)))); + + TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000100000001)))); + TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000001)))); +} + +static void TEST_count_bits_FOR_8_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits(uint8_t(0))); + TEST_INT_EQ(8u, stlsoft::count_bits(uint8_t(0xff))); + TEST_INT_EQ(4u, stlsoft::count_bits(uint8_t(0x55))); + TEST_INT_EQ(1u, stlsoft::count_bits(uint8_t(0x80))); + TEST_INT_EQ(2u, stlsoft::count_bits(uint8_t(0x81))); +} + +static void TEST_count_bits_FOR_16_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits(uint16_t(0))); + TEST_INT_EQ(16u, stlsoft::count_bits(uint16_t(0xffff))); + TEST_INT_EQ(8u, stlsoft::count_bits(uint16_t(0x5555))); + TEST_INT_EQ(1u, stlsoft::count_bits(uint16_t(0x8000))); + TEST_INT_EQ(2u, stlsoft::count_bits(uint16_t(0x8001))); +} + +static void TEST_count_bits_FOR_32_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits(uint32_t(0))); + TEST_INT_EQ(32u, stlsoft::count_bits(uint32_t(0xffffffff))); + TEST_INT_EQ(16u, stlsoft::count_bits(uint32_t(0x55555555))); + TEST_INT_EQ(1u, stlsoft::count_bits(uint32_t(0x80000000))); + TEST_INT_EQ(2u, stlsoft::count_bits(uint32_t(0x80000001))); +} + +static void TEST_count_bits_FOR_64_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits(uint64_t(0))); + TEST_INT_EQ(64u, stlsoft::count_bits(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xffffffffffffffff)))); + TEST_INT_EQ(32u, stlsoft::count_bits(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x5555555555555555)))); + TEST_INT_EQ(1u, stlsoft::count_bits(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000000)))); + TEST_INT_EQ(2u, stlsoft::count_bits(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000001)))); +} + +static void TEST_count_bits_FOR_int() +{ + TEST_INT_EQ(0u, stlsoft::count_bits(0)); + TEST_INT_EQ(1u, stlsoft::count_bits(1)); + TEST_INT_EQ(1u, stlsoft::count_bits(2)); + TEST_INT_EQ(2u, stlsoft::count_bits(3)); + + /* Negative values are counted via their two's-complement bit pattern. */ + TEST_INT_EQ(sizeof(int) * 8u, stlsoft::count_bits(-1)); + TEST_INT_EQ(1u, stlsoft::count_bits(static_cast(1u << (sizeof(int) * 8u - 1u)))); +} + +static void TEST_find_high_bit_FOR_8_BIT() +{ + TEST_INT_EQ(0u, stlsoft::find_highest_bit(uint8_t(0))); + + TEST_INT_EQ(1u, stlsoft::find_highest_bit(uint8_t(1))); + + TEST_INT_EQ(2u, stlsoft::find_highest_bit(uint8_t(2))); + TEST_INT_EQ(2u, stlsoft::find_highest_bit(uint8_t(3))); + + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint8_t(4))); + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint8_t(5))); + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint8_t(6))); + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint8_t(7))); + + TEST_INT_EQ(5u, stlsoft::find_highest_bit(uint8_t(0x10))); + TEST_INT_EQ(5u, stlsoft::find_highest_bit(uint8_t(0x1f))); - sw.stop(); + TEST_INT_EQ(8u, stlsoft::find_highest_bit(uint8_t(0x80))); + TEST_INT_EQ(8u, stlsoft::find_highest_bit(uint8_t(0xff))); +} + +static void TEST_find_high_bit_FOR_16_BIT() +{ + TEST_INT_EQ(0u, stlsoft::find_highest_bit(uint16_t(0))); + + TEST_INT_EQ(1u, stlsoft::find_highest_bit(uint16_t(1))); - fprintf(stdout, "t: %luns\n", static_cast(sw.get_nanoseconds())); + TEST_INT_EQ(2u, stlsoft::find_highest_bit(uint16_t(2))); + TEST_INT_EQ(2u, stlsoft::find_highest_bit(uint16_t(3))); + + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint16_t(4))); + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint16_t(5))); + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint16_t(6))); + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint16_t(7))); + + TEST_INT_EQ(9u, stlsoft::find_highest_bit(uint16_t(0x0100))); + TEST_INT_EQ(9u, stlsoft::find_highest_bit(uint16_t(0x01ff))); + + TEST_INT_EQ(16u, stlsoft::find_highest_bit(uint16_t(0x8000))); + TEST_INT_EQ(16u, stlsoft::find_highest_bit(uint16_t(0xffff))); } -static void test_find_high_bit_32() +static void TEST_find_high_bit_FOR_32_BIT() { TEST_INT_EQ(0u, stlsoft::find_highest_bit(uint32_t(0))); @@ -243,7 +456,7 @@ static void test_find_high_bit_32() TEST_INT_EQ(32u, stlsoft::find_highest_bit(uint32_t(0x80000000))); } -static void test_find_high_bit_64() +static void TEST_find_high_bit_FOR_64_BIT() { TEST_INT_EQ(0u, stlsoft::find_highest_bit(uint64_t(0))); @@ -274,7 +487,7 @@ static void test_find_high_bit_64() TEST_INT_EQ(45u, stlsoft::find_highest_bit(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x1c3c3c3c3c3c)))); } -static void test_calculate_xor_over_range_8_bit() +static void TEST_calculate_xor_over_range_FOR_8_BIT() { uint8_t const elements[] = { @@ -315,7 +528,225 @@ static void test_calculate_xor_over_range_8_bit() TEST_INT_EQ(0xd0, stlsoft::calculate_xor_over_range(elements, 12u)); TEST_INT_EQ(0xf0, stlsoft::calculate_xor_over_range(elements, 13u)); } + +static void TEST_calculate_xor_over_range_FOR_16_BIT() +{ + uint16_t const elements[] = + { + 0x0000 + + , 0x0001 + , 0x0002 + , 0x0004 + , 0x0008 + + , 0x0001 + , 0x0002 + , 0x0004 + , 0x0008 + + , 0x0040 + , 0x0080 + , 0x0010 + , 0x0020 + + , 0x0100 + , 0x8000 + }; + + TEST_INT_EQ(0x0000, stlsoft::calculate_xor_over_range(elements, 0u)); + TEST_INT_EQ(0x0000, stlsoft::calculate_xor_over_range(elements, 1u)); + TEST_INT_EQ(0x0001, stlsoft::calculate_xor_over_range(elements, 2u)); + TEST_INT_EQ(0x0003, stlsoft::calculate_xor_over_range(elements, 3u)); + TEST_INT_EQ(0x0007, stlsoft::calculate_xor_over_range(elements, 4u)); + TEST_INT_EQ(0x000f, stlsoft::calculate_xor_over_range(elements, 5u)); + TEST_INT_EQ(0x000e, stlsoft::calculate_xor_over_range(elements, 6u)); + TEST_INT_EQ(0x000c, stlsoft::calculate_xor_over_range(elements, 7u)); + TEST_INT_EQ(0x0008, stlsoft::calculate_xor_over_range(elements, 8u)); + TEST_INT_EQ(0x0000, stlsoft::calculate_xor_over_range(elements, 9u)); + TEST_INT_EQ(0x0040, stlsoft::calculate_xor_over_range(elements, 10u)); + TEST_INT_EQ(0x00c0, stlsoft::calculate_xor_over_range(elements, 11u)); + TEST_INT_EQ(0x00d0, stlsoft::calculate_xor_over_range(elements, 12u)); + TEST_INT_EQ(0x00f0, stlsoft::calculate_xor_over_range(elements, 13u)); + TEST_INT_EQ(0x01f0, stlsoft::calculate_xor_over_range(elements, 14u)); + TEST_INT_EQ(0x81f0, stlsoft::calculate_xor_over_range(elements, 15u)); +} + +static void TEST_calculate_xor_over_range_FOR_32_BIT() +{ + uint32_t const elements[] = + { + 0x00000000u + + , 0x00000001u + , 0x00000002u + , 0x00000004u + , 0x00000008u + + , 0x00000001u + , 0x00000002u + , 0x00000004u + , 0x00000008u + + , 0x00000040u + , 0x00000080u + , 0x00000010u + , 0x00000020u + + , 0x00000100u + , 0x80000000u + }; + + TEST_INT_EQ(0x00000000u, stlsoft::calculate_xor_over_range(elements, 0u)); + TEST_INT_EQ(0x00000000u, stlsoft::calculate_xor_over_range(elements, 1u)); + TEST_INT_EQ(0x00000001u, stlsoft::calculate_xor_over_range(elements, 2u)); + TEST_INT_EQ(0x00000003u, stlsoft::calculate_xor_over_range(elements, 3u)); + TEST_INT_EQ(0x00000007u, stlsoft::calculate_xor_over_range(elements, 4u)); + TEST_INT_EQ(0x0000000fu, stlsoft::calculate_xor_over_range(elements, 5u)); + TEST_INT_EQ(0x0000000eu, stlsoft::calculate_xor_over_range(elements, 6u)); + TEST_INT_EQ(0x0000000cu, stlsoft::calculate_xor_over_range(elements, 7u)); + TEST_INT_EQ(0x00000008u, stlsoft::calculate_xor_over_range(elements, 8u)); + TEST_INT_EQ(0x00000000u, stlsoft::calculate_xor_over_range(elements, 9u)); + TEST_INT_EQ(0x00000040u, stlsoft::calculate_xor_over_range(elements, 10u)); + TEST_INT_EQ(0x000000c0u, stlsoft::calculate_xor_over_range(elements, 11u)); + TEST_INT_EQ(0x000000d0u, stlsoft::calculate_xor_over_range(elements, 12u)); + TEST_INT_EQ(0x000000f0u, stlsoft::calculate_xor_over_range(elements, 13u)); + TEST_INT_EQ(0x000001f0u, stlsoft::calculate_xor_over_range(elements, 14u)); + TEST_INT_EQ(0x800001f0u, stlsoft::calculate_xor_over_range(elements, 15u)); +} + +static void TEST_calculate_xor_over_range_FOR_64_BIT() +{ + uint64_t const elements[] = + { + STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000000) + + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000001) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000002) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000004) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000008) + + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000001) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000002) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000004) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000008) + + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000040) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000080) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000010) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000020) + + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000100) + , STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000000) + }; + + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000000), stlsoft::calculate_xor_over_range(elements, 0u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000000), stlsoft::calculate_xor_over_range(elements, 1u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000001), stlsoft::calculate_xor_over_range(elements, 2u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000003), stlsoft::calculate_xor_over_range(elements, 3u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000007), stlsoft::calculate_xor_over_range(elements, 4u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x000000000000000f), stlsoft::calculate_xor_over_range(elements, 5u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x000000000000000e), stlsoft::calculate_xor_over_range(elements, 6u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x000000000000000c), stlsoft::calculate_xor_over_range(elements, 7u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000008), stlsoft::calculate_xor_over_range(elements, 8u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000000), stlsoft::calculate_xor_over_range(elements, 9u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000040), stlsoft::calculate_xor_over_range(elements, 10u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x00000000000000c0), stlsoft::calculate_xor_over_range(elements, 11u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x00000000000000d0), stlsoft::calculate_xor_over_range(elements, 12u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x00000000000000f0), stlsoft::calculate_xor_over_range(elements, 13u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x00000000000001f0), stlsoft::calculate_xor_over_range(elements, 14u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x80000000000001f0), stlsoft::calculate_xor_over_range(elements, 15u)); +} +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint16) + +static void TEST_count_bits_by_intrinsic_FOR_8_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_intrinsic(uint8_t(0u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint8_t(1u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint8_t(0x80u))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_intrinsic(uint8_t(0xffu))); + TEST_INT_EQ(stlsoft::count_bits_by_8bit_table(uint8_t(0x3cu)), stlsoft::count_bits_by_intrinsic(uint8_t(0x3cu))); +} + +static void TEST_count_bits_by_intrinsic_FOR_16_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_intrinsic(uint16_t(0u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint16_t(1u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint16_t(0x8000u))); + TEST_INT_EQ(16u, stlsoft::count_bits_by_intrinsic(uint16_t(0xffffu))); + TEST_INT_EQ(stlsoft::count_bits_by_8bit_table(uint16_t(0x1234u)), stlsoft::count_bits_by_intrinsic(uint16_t(0x1234u))); +} +#endif +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + +static void TEST_count_bits_by_intrinsic_FOR_32_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_intrinsic(uint32_t(0u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint32_t(1u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint32_t(0x80000000u))); + TEST_INT_EQ(32u, stlsoft::count_bits_by_intrinsic(uint32_t(0xffffffffu))); + TEST_INT_EQ(stlsoft::count_bits_by_8bit_table(uint32_t(0x12345678u)), stlsoft::count_bits_by_intrinsic(uint32_t(0x12345678u))); +} +#endif +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + +static void TEST_count_bits_by_intrinsic_FOR_64_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_intrinsic(uint64_t(0u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint64_t(1u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000000))); + TEST_INT_EQ(64u, stlsoft::count_bits_by_intrinsic(STLSOFT_GEN_UINT64_SUFFIX(0xffffffffffffffff))); + TEST_INT_EQ( + stlsoft::count_bits_by_8bit_table(STLSOFT_GEN_UINT64_SUFFIX(0x0123456789abcdef)) + , stlsoft::count_bits_by_intrinsic(STLSOFT_GEN_UINT64_SUFFIX(0x0123456789abcdef)) + ); +} +#endif +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + +static void TEST_find_highest_bit_by_intrinsic_FOR_8_BIT() +{ + TEST_INT_EQ(0u, stlsoft::find_highest_bit_by_intrinsic(uint8_t(0u))); + TEST_INT_EQ(1u, stlsoft::find_highest_bit_by_intrinsic(uint8_t(1u))); + TEST_INT_EQ(8u, stlsoft::find_highest_bit_by_intrinsic(uint8_t(0x80u))); + TEST_INT_EQ(stlsoft::find_highest_bit(uint8_t(0x3cu)), stlsoft::find_highest_bit_by_intrinsic(uint8_t(0x3cu))); +} + +static void TEST_find_highest_bit_by_intrinsic_FOR_16_BIT() +{ + TEST_INT_EQ(0u, stlsoft::find_highest_bit_by_intrinsic(uint16_t(0u))); + TEST_INT_EQ(1u, stlsoft::find_highest_bit_by_intrinsic(uint16_t(1u))); + TEST_INT_EQ(16u, stlsoft::find_highest_bit_by_intrinsic(uint16_t(0x8000u))); + TEST_INT_EQ(stlsoft::find_highest_bit(uint16_t(0x03c0u)), stlsoft::find_highest_bit_by_intrinsic(uint16_t(0x03c0u))); +} + +static void TEST_find_highest_bit_by_intrinsic_FOR_32_BIT() +{ + TEST_INT_EQ(0u, stlsoft::find_highest_bit_by_intrinsic(uint32_t(0u))); + TEST_INT_EQ(1u, stlsoft::find_highest_bit_by_intrinsic(uint32_t(1u))); + TEST_INT_EQ(32u, stlsoft::find_highest_bit_by_intrinsic(uint32_t(0x80000000u))); + TEST_INT_EQ(stlsoft::find_highest_bit(uint32_t(0x0003c000u)), stlsoft::find_highest_bit_by_intrinsic(uint32_t(0x0003c000u))); +} +#endif +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + +static void TEST_find_highest_bit_by_intrinsic_FOR_64_BIT() +{ + TEST_INT_EQ(0u, stlsoft::find_highest_bit_by_intrinsic(uint64_t(0u))); + TEST_INT_EQ(1u, stlsoft::find_highest_bit_by_intrinsic(uint64_t(1u))); + TEST_INT_EQ(64u, stlsoft::find_highest_bit_by_intrinsic(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000000))); + TEST_INT_EQ( + stlsoft::find_highest_bit(STLSOFT_GEN_UINT64_SUFFIX(0x000000030000c000)) + , stlsoft::find_highest_bit_by_intrinsic(STLSOFT_GEN_UINT64_SUFFIX(0x000000030000c000)) + ); +} +#endif } // anonymous namespace /* ///////////////////////////// end of file //////////////////////////// */ + From 8a637125eb95517e497cf33e87eeff6ab2b0c127 Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Wed, 30 Sep 2026 08:28:36 +1000 Subject: [PATCH 06/31] 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`. --- CHANGES.md | 11 +- NEWS.md | 2 +- .../stlsoft/system/environment/functions.h | 64 +++-- .../stlsoft/system/environment/functions.hpp | 18 +- .../platformstl/filesystem/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../entry.cpp | 4 +- test/component/stlsoft/system/CMakeLists.txt | 1 + .../CMakeLists.txt | 2 + .../environment_variable_exists/entry.cpp | 259 ++++++++++++++++++ 10 files changed, 330 insertions(+), 33 deletions(-) rename test/component/platformstl/filesystem/{test.component.platformstl.filesystem.file_lines => file_lines}/CMakeLists.txt (100%) rename test/component/platformstl/filesystem/{test.component.platformstl.filesystem.file_lines => file_lines}/entry.cpp (98%) create mode 100644 test/component/stlsoft/system/environment_variable_exists/CMakeLists.txt create mode 100644 test/component/stlsoft/system/environment_variable_exists/entry.cpp diff --git a/CHANGES.md b/CHANGES.md index d120092c..e1aa8ca9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,15 +3,22 @@ ## 1.11.1-rc7 - 30th September 2026 +* Renamed `stlsoft_C_environment_variable_exists_a()` to `stlsoft_C_environment_variable_exists_m()`; the `_a` form remains as a deprecated forwarder; +* Component tests for `stlsoft::environment_variable_exists()` (**test/component/stlsoft/system/environment_variable_exists**), including `std::string` / `simple_string` shims and UNIX empty-value behaviour; * Added `count_bits_by_intrinsic()` and `find_highest_bit_by_intrinsic()` (unselected by default; `count_bits()` keeps the 8-bit table; `find_highest_bit()` keeps the scan); * Added **stlsoft/api/external/bitfns.h** and **stlsoft/api/internal/bitfns.h** — detection and adaptations for `popcount` / `clz` / `_BitScanReverse` intrinsics (GCC/Clang builtins preferred over MSVC when both are visible); * Clang cccap — `STLSOFT_CLANG_VER`; documented shared `STLSOFT_GCC_VER` (also noted in GCC cccap); * Fixed `count_bits()` overloads when `STLSOFT_BIT_COUNT_BY_Kernighan` is defined; * Unit tests for intrinsic popcount / highest-bit helpers; broader width coverage for bit-function overloads; -* Performance suite **test/performance/stlsoft/bit_functions** (density patterns, intrinsic rows, median / ns-per-call reporting); +* Performance suite **test/performance/stlsoft/util/bit_functions** (density patterns, intrinsic rows, median / ns-per-call reporting); * Strategy note **strategy/BIT_FUNCTIONS.md** — measurements and default choice (table for `count_bits()`; keep intrinsics unselected pending cross-toolchain evidence); +* CI — performance job exports **SIS_PERFTESTS_GROUPGAPS=1**; +* **platformstl::FILE_stream** — added `write_binary()` (writes every byte, including embedded NULs) and deprecated `write(void const*, size_t)` in its favour; +* Component tests for `platformstl::file_lines` (**test/component/platformstl/filesystem/file_lines**); +* Fixed `winstl::netapi_allocator` — pass a **DWORD** byte count to `NetApiBufferAllocate`; +* Unit tests — removed empty case functions; filled the nine allocator suites (round-trip sizes, `max_size()`, `std::list` / `std::vector`; `null_allocator` throws `out_of_memory_exception`); * Test tree — leaf directories under **test/component**, **test/unit**, **test/scratch**, and **test/performance** renamed from `test..…` to the subject name (for example **glob_sequence**); executable target names unchanged; -* **test/performance** — programs nested by sub-project and area (**platformstl/diagnostics**, **stlsoft/bit_functions**, **stlsoft/containers**, **stlsoft/conversion**, **stlsoft/diagnostics**, **stlsoft/memory**, **stlsoft/string**, **stlsoft/util**); +* **test/performance** — programs nested by sub-project and area (**platformstl/diagnostics**, **stlsoft/containers**, **stlsoft/conversion**, **stlsoft/diagnostics**, **stlsoft/memory**, **stlsoft/string**, **stlsoft/util**); * **test.unit.versions** — aligned with **1.11.1-rc7** (**_STLSOFT_VER_1_11_1_RC7**); diff --git a/NEWS.md b/NEWS.md index e0e5a449..ba3de638 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,7 @@ | Date | News Item | Details | | ------------------- | ----------------------------------- | ------- | -| 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | bit-function intrinsics; table default for `count_bits()`; nested **test/performance**; shortened test directories | +| 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | bit-function intrinsics; `basic_file_lines::write_binary()`; `environment_variable_exists_m()`; nested **test/performance**; shortened test directories | | 21st September 2026 | Release of [STLSoft 1.11.1-rc6](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc6) | ACE/ATL/MFC CI; Clang/macOS `stricmp` aliases | | 4th August 2026 | Release of [STLSoft 1.11.1-rc5](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc5) | `basic_simple_string<>#resize()`; **CHANGES.md**; docs | | 29th July 2026 | Release of [STLSoft 1.11.1-rc4](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc4) | GitHub Actions CI; VC++ 18.x; MinGW | diff --git a/include/stlsoft/system/environment/functions.h b/include/stlsoft/system/environment/functions.h index 11f9c10e..5b81b824 100644 --- a/include/stlsoft/system/environment/functions.h +++ b/include/stlsoft/system/environment/functions.h @@ -1,14 +1,14 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: stlsoft/system/environment/functions.h + * File: stlsoft/system/environment/functions.h * - * Purpose: Environment functions. + * Purpose: Environment functions. * - * Created: 4th March 2011 - * Updated: 11th March 2024 + * Created: 4th March 2011 + * Updated: 28th September 2026 * - * Home: http://stlsoft.org/ + * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2024, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2005-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -53,8 +53,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_MAJOR 1 # define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_MINOR 0 -# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_REVISION 1 -# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_EDIT 12 +# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_REVISION 3 +# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_EDIT 15 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -94,21 +94,21 @@ namespace stlsoft /* ///////////////////////////////////////////////////////////////////////// - * API functions + * API functions (C) */ -/** Indicates whether the named environment variable exists +/** Indicates whether the named environment variable exists. * - * \retval 0 The environment variable does not exist - * \retval !0 The environment variable does exist + * \retval 0 The environment variable does not exist; + * \retval !0 The environment variable does exist; * * \pre (NULL != name) */ STLSOFT_INLINE ss_truthy_t -stlsoft_C_environment_variable_exists_a( +stlsoft_C_environment_variable_exists_m( char const* name -) +) STLSOFT_NOEXCEPT { #if defined(STLSOFT_USING_SAFE_STR_FUNCTIONS) && \ defined(STLSOFT_COMPILER_IS_MSVC) @@ -145,15 +145,35 @@ stlsoft_C_environment_variable_exists_a( return NULL != STLSOFT_NS_GLOBAL(getenv)(name); #endif } +#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION + +/** [DEPRECATED] \see stlsoft_C_environment_variable_exists_m + * + */ +STLSOFT_DEPRECATED_("`stlsoft_C_environment_variable_exists_a()` is deprecated, and will be removed from a future release, and you should instead use `stlsoft_C_environment_variable_exists_m()`") // applied here rather than on template because above class_type precipitates +STLSOFT_INLINE +ss_truthy_t +stlsoft_C_environment_variable_exists_a( + char const* name +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_environment_variable_exists_m(name); +} +#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ /* ///////////////////////////////////////////////////////////////////////// - * C++ API functions + * language */ #ifdef __cplusplus -/** \see stlsoft_C_environment_variable_exists_a + +/* ///////////////////////////////////////////////////////////////////////// + * API functions (C++) + */ + +/** \see stlsoft_C_environment_variable_exists_m */ inline ss_truthy_t @@ -161,12 +181,20 @@ environment_variable_exists( char const* name ) { - return stlsoft_C_environment_variable_exists_a(name); + return stlsoft_C_environment_variable_exists_m(name); } + +/* ///////////////////////////////////////////////////////////////////////// + * language + */ + #endif /* __cplusplus */ -/* ////////////////////////////////////////////////////////////////////// */ + +/* ///////////////////////////////////////////////////////////////////////// + * namespace + */ #ifndef STLSOFT_NO_NAMESPACE } /* namespace stlsoft */ diff --git a/include/stlsoft/system/environment/functions.hpp b/include/stlsoft/system/environment/functions.hpp index 7d01772d..541830f4 100644 --- a/include/stlsoft/system/environment/functions.hpp +++ b/include/stlsoft/system/environment/functions.hpp @@ -1,14 +1,14 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: stlsoft/system/environment/functions.hpp + * File: stlsoft/system/environment/functions.hpp * - * Purpose: Environment functions. + * Purpose: Environment functions. * - * Created: 31st October 2019 - * Updated: 20th March 2025 + * Created: 31st October 2019 + * Updated: 28th September 2026 * - * Home: http://stlsoft.org/ + * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -53,8 +53,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_HPP_FUNCTIONS_MAJOR 1 # define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_HPP_FUNCTIONS_MINOR 0 -# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_HPP_FUNCTIONS_REVISION 1 -# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_HPP_FUNCTIONS_EDIT 4 +# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_HPP_FUNCTIONS_REVISION 2 +# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_HPP_FUNCTIONS_EDIT 5 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -101,7 +101,7 @@ struct ximpl_stlsoft_environment_functions_hpp_ char const* name ) { - return stlsoft_C_environment_variable_exists_a(name); + return stlsoft_C_environment_variable_exists_m(name); } #if 0 diff --git a/test/component/platformstl/filesystem/CMakeLists.txt b/test/component/platformstl/filesystem/CMakeLists.txt index 477a88a9..9df77afb 100644 --- a/test/component/platformstl/filesystem/CMakeLists.txt +++ b/test/component/platformstl/filesystem/CMakeLists.txt @@ -1,2 +1,2 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten -add_subdirectory(test.component.platformstl.filesystem.file_lines) +add_subdirectory(file_lines) diff --git a/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/CMakeLists.txt b/test/component/platformstl/filesystem/file_lines/CMakeLists.txt similarity index 100% rename from test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/CMakeLists.txt rename to test/component/platformstl/filesystem/file_lines/CMakeLists.txt diff --git a/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/entry.cpp b/test/component/platformstl/filesystem/file_lines/entry.cpp similarity index 98% rename from test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/entry.cpp rename to test/component/platformstl/filesystem/file_lines/entry.cpp index 9628b986..e7fc8feb 100644 --- a/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/entry.cpp +++ b/test/component/platformstl/filesystem/file_lines/entry.cpp @@ -1,10 +1,10 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: test.component.platformstl.filesystem.file_lines/entry.cpp + * File: file_lines/entry.cpp * * Purpose: Component-tests for `platformstl::file_lines`. * * Created: 23rd September 2026 - * Updated: 23rd September 2026 + * Updated: 30th September 2026 * * ////////////////////////////////////////////////////////////////////// */ diff --git a/test/component/stlsoft/system/CMakeLists.txt b/test/component/stlsoft/system/CMakeLists.txt index b7d0db4c..071c04bc 100644 --- a/test/component/stlsoft/system/CMakeLists.txt +++ b/test/component/stlsoft/system/CMakeLists.txt @@ -1,2 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten add_subdirectory(environment_block) +add_subdirectory(environment_variable_exists) diff --git a/test/component/stlsoft/system/environment_variable_exists/CMakeLists.txt b/test/component/stlsoft/system/environment_variable_exists/CMakeLists.txt new file mode 100644 index 00000000..9107eda8 --- /dev/null +++ b/test/component/stlsoft/system/environment_variable_exists/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.component.stlsoft.system.environment_variable_exists entry.cpp) diff --git a/test/component/stlsoft/system/environment_variable_exists/entry.cpp b/test/component/stlsoft/system/environment_variable_exists/entry.cpp new file mode 100644 index 00000000..93e4506a --- /dev/null +++ b/test/component/stlsoft/system/environment_variable_exists/entry.cpp @@ -0,0 +1,259 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: environment_variable_exists/entry.cpp + * + * Purpose: Component-tests for `stlsoft::environment_variable_exists()`. + * + * Created: 28th September 2026 + * Updated: 30th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +/* ///////////////////////////////////// + * test component header file include(s) + */ + +/* String-access shims must be visible before functions.hpp so the template + * overload can bind c_str_ptr() for these types. + */ +#include +#include +#include + +/* ///////////////////////////////////// + * general includes + */ + +/* xTests header files */ +#include +#include + +/* STLSoft header files */ +#include +#include + +/* Standard C++ header files */ +#include + +/* Standard C header files */ +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace { + + static void TEST_environment_variable_exists_WHEN_ABSENT(); + static void TEST_environment_variable_exists_WHEN_PRESENT(); + static void TEST_environment_variable_exists_WHEN_ERASED(); + static void TEST_environment_variable_exists_WHEN_VALUE_REPLACED(); + static void TEST_environment_variable_exists_EXACT_NAME(); + static void TEST_environment_variable_exists_WITH_std_string(); + static void TEST_environment_variable_exists_WITH_simple_string(); +#ifndef _WIN32 + static void TEST_environment_variable_exists_WHEN_EMPTY(); +#endif /* !_WIN32 */ + static void TEST_environment_variable_exists_CASE_SENSITIVITY(); +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.component.stlsoft.system.environment_variable_exists", verbosity)) + { + XTESTS_RUN_CASE(TEST_environment_variable_exists_WHEN_ABSENT); + XTESTS_RUN_CASE(TEST_environment_variable_exists_WHEN_PRESENT); + XTESTS_RUN_CASE(TEST_environment_variable_exists_WHEN_ERASED); + XTESTS_RUN_CASE(TEST_environment_variable_exists_WHEN_VALUE_REPLACED); + XTESTS_RUN_CASE(TEST_environment_variable_exists_EXACT_NAME); + XTESTS_RUN_CASE(TEST_environment_variable_exists_WITH_std_string); + XTESTS_RUN_CASE(TEST_environment_variable_exists_WITH_simple_string); +#ifndef _WIN32 + XTESTS_RUN_CASE(TEST_environment_variable_exists_WHEN_EMPTY); +#endif /* !_WIN32 */ + XTESTS_RUN_CASE(TEST_environment_variable_exists_CASE_SENSITIVITY); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * constants + */ + +namespace { + + using platformstl::environment_variable_scope; + + char const VAR_NAME[] = "STLSOFT_CT_ENV_VAR_EXISTS"; + char const VAR_NAME_EXTRA[] = "STLSOFT_CT_ENV_VAR_EXISTS_EXTRA"; + char const VAR_NAME_PREFIX[] = "STLSOFT_CT_ENV_VAR"; + char const VAR_NAME_UPPER[] = "STLSOFT_CT_ENV_VAR_EXISTS_CASE"; + char const VAR_NAME_LOWER[] = "stlsoft_ct_env_var_exists_case"; +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace { + +static void TEST_environment_variable_exists_WHEN_ABSENT() +{ + environment_variable_scope const absent(VAR_NAME, ss_nullptr_k); + + char const* const name = VAR_NAME; + + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(name)); + TEST_BOOLEAN_FALSE(stlsoft::stlsoft_C_environment_variable_exists_m(name)); + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists("STLSOFT_CT_ENV_VAR_EXISTS_NO_SUCH")); +} + +static void TEST_environment_variable_exists_WHEN_PRESENT() +{ + environment_variable_scope const present(VAR_NAME, "present"); + + char const* const name = VAR_NAME; + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); + TEST_BOOLEAN_TRUE(stlsoft::stlsoft_C_environment_variable_exists_m(name)); +} + +static void TEST_environment_variable_exists_WHEN_ERASED() +{ + environment_variable_scope const present(VAR_NAME, "present"); + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(VAR_NAME)); + + environment_variable_scope const erased(VAR_NAME, ss_nullptr_k); + + char const* const name = VAR_NAME; + + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(name)); +} + +static void TEST_environment_variable_exists_WHEN_VALUE_REPLACED() +{ + environment_variable_scope const first(VAR_NAME, "one"); + + char const* const name = VAR_NAME; + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); + + environment_variable_scope const second(VAR_NAME, "two"); + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); +} + +static void TEST_environment_variable_exists_EXACT_NAME() +{ + environment_variable_scope const extra_absent(VAR_NAME_EXTRA, ss_nullptr_k); + environment_variable_scope const prefix_absent(VAR_NAME_PREFIX, ss_nullptr_k); + environment_variable_scope const present(VAR_NAME, "value"); + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(VAR_NAME)); + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(VAR_NAME_EXTRA)); + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(VAR_NAME_PREFIX)); + + environment_variable_scope const erased(VAR_NAME, ss_nullptr_k); + environment_variable_scope const extra(VAR_NAME_EXTRA, "extra"); + + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(VAR_NAME)); + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(VAR_NAME_EXTRA)); +} + +static void TEST_environment_variable_exists_WITH_std_string() +{ + { + environment_variable_scope const absent(VAR_NAME, ss_nullptr_k); + + std::string const name(VAR_NAME); + + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(name)); + } + + environment_variable_scope const present(VAR_NAME, "present"); + + std::string const name(VAR_NAME); + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); +} + +static void TEST_environment_variable_exists_WITH_simple_string() +{ + { + environment_variable_scope const absent(VAR_NAME, ss_nullptr_k); + + stlsoft::simple_string const name(VAR_NAME); + + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(name)); + } + + environment_variable_scope const present(VAR_NAME, "present"); + + stlsoft::simple_string const name(VAR_NAME); + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); +} +#ifndef _WIN32 + +/* An empty value is a defined variable on UNIX. The Windows CRT treats an + * empty assignment as erasure, so this case is UNIX-only. + */ +static void TEST_environment_variable_exists_WHEN_EMPTY() +{ + environment_variable_scope const empty(VAR_NAME, ""); + + char const* const value = ::getenv(VAR_NAME); + + XTESTS_REQUIRE(TEST_PTR_NE(NULL, value)); + TEST_MS_EQ("", value); + + char const* const name = VAR_NAME; + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); +} +#endif /* !_WIN32 */ + +/* UNIX names are case-sensitive; the Windows CRT folds case. + */ +static void TEST_environment_variable_exists_CASE_SENSITIVITY() +{ + environment_variable_scope const lower(VAR_NAME_LOWER, ss_nullptr_k); + environment_variable_scope const upper(VAR_NAME_UPPER, "1"); + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(VAR_NAME_UPPER)); +#ifdef _WIN32 + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(VAR_NAME_LOWER)); +#else + + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(VAR_NAME_LOWER)); +#endif +} +} // anonymous namespace + + +/* ///////////////////////////// end of file //////////////////////////// */ + From 4f5f9628c8c65e42433c00418e9ca399856bfa3c Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Wed, 30 Sep 2026 12:41:01 +1000 Subject: [PATCH 07/31] `platformstl::file_lines` performance tests (#21) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 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. --- CHANGES.md | 7 +- NEWS.md | 2 +- cmake/TargetMacros.cmake | 24 + execute_performance_tests.sh | 6 +- include/platformstl/filesystem/file_lines.hpp | 82 ++-- test/performance/platformstl/CMakeLists.txt | 6 +- .../platformstl/filesystem/CMakeLists.txt | 9 + .../filesystem/file_lines/CMakeLists.txt | 2 + .../filesystem/file_lines/main.cpp | 433 ++++++++++++++++++ 9 files changed, 533 insertions(+), 38 deletions(-) create mode 100644 test/performance/platformstl/filesystem/CMakeLists.txt create mode 100644 test/performance/platformstl/filesystem/file_lines/CMakeLists.txt create mode 100644 test/performance/platformstl/filesystem/file_lines/main.cpp diff --git a/CHANGES.md b/CHANGES.md index e1aa8ca9..44931d4e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,10 +15,15 @@ * CI — performance job exports **SIS_PERFTESTS_GROUPGAPS=1**; * **platformstl::FILE_stream** — added `write_binary()` (writes every byte, including embedded NULs) and deprecated `write(void const*, size_t)` in its favour; * Component tests for `platformstl::file_lines` (**test/component/platformstl/filesystem/file_lines**); +* `platformstl::basic_file_lines<>` — parse directly from the memory-mapped base (dropped the full-file `m_contents` heap copy); fold the binary/NUL reject into the parse loop; C++11+ `emplace_back`; floor line-reservation at 128; +* Approximate measured gains for `platformstl::basic_file_lines<>` on the new harness (1000×64 LF): view-based forms (~`stlsoft::string_view` / `std::string_view`) about **10–20×** faster than `fgetc` line accumulation and typically **comparable to or slightly ahead of** `std::getline` (~1.2× on MinGW CI); owning-string forms remain competitive with `std::getline` while avoiding the extra full-file copy; +* Performance suite **test/performance/platformstl/filesystem/file_lines** — comparative harness vs `fgetc` / `std::getline` (LF / CRLF / CR; mid-size and small-file shapes; C++11+); +* CMake — Windows GNU (**MinGW**) test/example programs static-link **libgcc** / **libstdc++** so PE images load when runner **PATH** does not match the build toolchain; +* **execute_performance_tests.sh** — capture the child exit code after optional `expand` piping (was overwriting a failed status with `$?` from the success branch); * Fixed `winstl::netapi_allocator` — pass a **DWORD** byte count to `NetApiBufferAllocate`; * Unit tests — removed empty case functions; filled the nine allocator suites (round-trip sizes, `max_size()`, `std::list` / `std::vector`; `null_allocator` throws `out_of_memory_exception`); * Test tree — leaf directories under **test/component**, **test/unit**, **test/scratch**, and **test/performance** renamed from `test..…` to the subject name (for example **glob_sequence**); executable target names unchanged; -* **test/performance** — programs nested by sub-project and area (**platformstl/diagnostics**, **stlsoft/containers**, **stlsoft/conversion**, **stlsoft/diagnostics**, **stlsoft/memory**, **stlsoft/string**, **stlsoft/util**); +* **test/performance** — programs nested by sub-project and area (**platformstl/diagnostics**, **platformstl/filesystem**, **stlsoft/containers**, **stlsoft/conversion**, **stlsoft/diagnostics**, **stlsoft/memory**, **stlsoft/string**, **stlsoft/util**); * **test.unit.versions** — aligned with **1.11.1-rc7** (**_STLSOFT_VER_1_11_1_RC7**); diff --git a/NEWS.md b/NEWS.md index ba3de638..b6ac5cb8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,7 @@ | Date | News Item | Details | | ------------------- | ----------------------------------- | ------- | -| 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | bit-function intrinsics; `basic_file_lines::write_binary()`; `environment_variable_exists_m()`; nested **test/performance**; shortened test directories | +| 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | bit-function intrinsics; `FILE_stream::write_binary()`; `basic_file_lines<>` mmap parse (~10–20× vs `fgetc`); **file_lines** perf; MinGW static runtime; nested **test/performance** | | 21st September 2026 | Release of [STLSoft 1.11.1-rc6](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc6) | ACE/ATL/MFC CI; Clang/macOS `stricmp` aliases | | 4th August 2026 | Release of [STLSoft 1.11.1-rc5](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc5) | `basic_simple_string<>#resize()`; **CHANGES.md**; docs | | 29th July 2026 | Release of [STLSoft 1.11.1-rc4](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc4) | GitHub Actions CI; VC++ 18.x; MinGW | diff --git a/cmake/TargetMacros.cmake b/cmake/TargetMacros.cmake index 07dc987a..69f22c41 100644 --- a/cmake/TargetMacros.cmake +++ b/cmake/TargetMacros.cmake @@ -53,6 +53,20 @@ function(define_automated_test_program program_name entry_point_source_name) ) endif() + # MinGW PE images that dynamically link libgcc/libstdc++ can fail at + # process load (exit 127, no user code) when the runner PATH does not + # match the toolchain that built the binary. Static-link those runtimes + # on Windows GNU targets so test/example/performance exes are self- + # contained for the C++ runtime. + if(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + + target_link_options(${program_name} + PRIVATE + -static-libgcc + -static-libstdc++ + ) + endif() + set(X_GCC_CUSTOM_WARNINGS_ "") if(X_GCC_CUSTOM_WARNINGS_TO_BE_SUPPRESSED) @@ -120,6 +134,16 @@ function(define_example_program program_name entry_point_source_name) ) endif() + # See define_automated_test_program: same MinGW PE loader mitigation. + if(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + + target_link_options(${program_name} + PRIVATE + -static-libgcc + -static-libstdc++ + ) + endif() + set(X_GCC_CUSTOM_WARNINGS_ "") if(X_GCC_CUSTOM_WARNINGS_TO_BE_SUPPRESSED) diff --git a/execute_performance_tests.sh b/execute_performance_tests.sh index 3f8763f6..00620fc9 100755 --- a/execute_performance_tests.sh +++ b/execute_performance_tests.sh @@ -152,17 +152,19 @@ if [ $status -eq 0 ]; then if [ $ExpandWidth -ne 0 ]; then $f | expand -t $ExpandWidth + child_ec=${PIPESTATUS[0]} else $f + child_ec=$? fi - if [ $? -eq 0 ]; then + if [ $child_ec -eq 0 ]; then : else - status=$? + status=$child_ec break 1 fi diff --git a/include/platformstl/filesystem/file_lines.hpp b/include/platformstl/filesystem/file_lines.hpp index b8574eab..7a8c0022 100644 --- a/include/platformstl/filesystem/file_lines.hpp +++ b/include/platformstl/filesystem/file_lines.hpp @@ -4,7 +4,7 @@ * Purpose: Platform header for the file_lines components. * * Created: 25th October 2007 - * Updated: 20th March 2025 + * Updated: 23rd September 2026 * * Home: http://stlsoft.org/ * @@ -48,8 +48,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_LINES_MAJOR 2 # define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_LINES_MINOR 1 -# define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_LINES_REVISION 1 -# define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_LINES_EDIT 52 +# define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_LINES_REVISION 4 +# define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_LINES_EDIT 55 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ /** \file platformstl/filesystem/file_lines.hpp @@ -106,6 +106,9 @@ #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING # include #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING */ +#ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_MINMAX +# include +#endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_MINMAX */ #ifndef STLSOFT_INCL_ALGORITHM # define STLSOFT_INCL_ALGORITHM @@ -196,7 +199,6 @@ class basic_file_lines /// Creates an empty instance basic_file_lines() : m_mmf() - , m_contents() , m_strings() {} /// Creates an instance from the (contents of) the given path @@ -204,7 +206,6 @@ class basic_file_lines ss_explicit_k basic_file_lines(S const& path) : m_mmf() - , m_contents() , m_strings() { create_(path); @@ -217,7 +218,6 @@ class basic_file_lines /// Move the basic_file_lines(class_type&& rhs) STLSOFT_NOEXCEPT : m_mmf(std::move(rhs.m_mmf)) - , m_contents(std::move(rhs.m_contents)) , m_strings(std::move(rhs.m_strings)) {} #endif /* STLSOFT_CF_RVALUE_REFERENCES_SUPPORT */ @@ -389,37 +389,26 @@ class basic_file_lines size_t cch = static_cast(cb / sizeof(char_type)); #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */ - // check if it looks like a binary file - if (base + cch != std::find(base, base + cch, '\0')) + if (0u == cb) { -#ifdef STLSOFT_CF_EXCEPTION_SUPPORT - STLSOFT_THROW_X(invalid_file_type_exception("file is binary (or unsupported text encoding)", 0, path)); -#else /* STLSOFT_CF_EXCEPTION_SUPPORT */ return; -#endif /* STLSOFT_CF_EXCEPTION_SUPPORT */ } - // 2. Create the contents string - - m_contents = base_string_type_(base, cch); - - STLSOFT_ASSERT(cch == m_contents.size()); + // 2. Parse the file, and populate the strings collection - // 3. Parse the file, and populate the strings collection + size_t const numReserved = maximum(static_cast(128), 1u + (cch / 10u)); - m_strings.reserve(1u + (cch / 10u)); + m_strings.reserve(numReserved); // This can work with EOL of CRLF or of LF, or a combination of the // two. - char_type const* const base1 = m_contents.data(); + char_type const* const base1 = base; char_type const* begin = base1; char_type const* const end = begin + cch; char_type const* s0 = begin; char_type prev = '\0'; -// bool const hasLF = (base + cch != std::find(base, base + cch, '\n')); -#if 1 { for (; begin != end; ++begin) { char_type const c = *begin; @@ -427,12 +416,29 @@ class basic_file_lines switch (c) { + case '\0': + + // reject if it looks like a binary file + +#ifdef STLSOFT_CF_EXCEPTION_SUPPORT + + STLSOFT_THROW_X(invalid_file_type_exception("file is binary (or unsupported text encoding)", 0, path)); +#else /* STLSOFT_CF_EXCEPTION_SUPPORT */ + + return; +#endif /* STLSOFT_CF_EXCEPTION_SUPPORT */ case '\r': if ('\r' == prev) { --eol; - m_strings.push_back(value_string_type_(s0, eol)); +#if __cplusplus >= 201103L + + m_strings.emplace_back(value_string_type_(s0, static_cast(eol - s0))); +#else /* ? C++ 11+ */ + + m_strings.push_back(value_string_type_(s0, static_cast(eol - s0))); +#endif /* C++ 11+ */ s0 = begin; } @@ -443,7 +449,13 @@ class basic_file_lines --eol; } - m_strings.push_back(value_string_type_(s0, eol)); +#if __cplusplus >= 201103L + + m_strings.emplace_back(value_string_type_(s0, static_cast(eol - s0))); +#else /* ? C++ 11+ */ + + m_strings.push_back(value_string_type_(s0, static_cast(eol - s0))); +#endif /* C++ 11+ */ s0 = begin + 1; break; @@ -452,7 +464,13 @@ class basic_file_lines { --eol; - m_strings.push_back(value_string_type_(s0, eol)); +#if __cplusplus >= 201103L + + m_strings.emplace_back(value_string_type_(s0, static_cast(eol - s0))); +#else /* ? C++ 11+ */ + + m_strings.push_back(value_string_type_(s0, static_cast(eol - s0))); +#endif /* C++ 11+ */ s0 = begin; } @@ -470,9 +488,14 @@ class basic_file_lines --eol; } - m_strings.push_back(value_string_type_(s0, eol)); +#if __cplusplus >= 201103L + + m_strings.emplace_back(value_string_type_(s0, static_cast(eol - s0))); +#else /* ? C++ 11+ */ + + m_strings.push_back(value_string_type_(s0, static_cast(eol - s0))); +#endif /* C++ 11+ */ } -#endif // Now determine whether we require the ongoing presence of the // underlying mapping. We can discard it if: @@ -514,9 +537,8 @@ class basic_file_lines } private: // fields - HRW_Ref_type m_mmf; - base_string_type_ m_contents; - strings_type_ m_strings; + HRW_Ref_type m_mmf; + strings_type_ m_strings; }; diff --git a/test/performance/platformstl/CMakeLists.txt b/test/performance/platformstl/CMakeLists.txt index 8a495afb..2001a39b 100644 --- a/test/performance/platformstl/CMakeLists.txt +++ b/test/performance/platformstl/CMakeLists.txt @@ -1,5 +1,3 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten add_subdirectory(diagnostics) - - -# ############################## end of file ############################# # - +add_subdirectory(filesystem) diff --git a/test/performance/platformstl/filesystem/CMakeLists.txt b/test/performance/platformstl/filesystem/CMakeLists.txt new file mode 100644 index 00000000..4df2b3ed --- /dev/null +++ b/test/performance/platformstl/filesystem/CMakeLists.txt @@ -0,0 +1,9 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) + + add_subdirectory(file_lines) +endif() + + +# ############################## end of file ############################# # + diff --git a/test/performance/platformstl/filesystem/file_lines/CMakeLists.txt b/test/performance/platformstl/filesystem/file_lines/CMakeLists.txt new file mode 100644 index 00000000..d76ef1eb --- /dev/null +++ b/test/performance/platformstl/filesystem/file_lines/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_example_program(test.performance.platformstl.file_lines main.cpp) diff --git a/test/performance/platformstl/filesystem/file_lines/main.cpp b/test/performance/platformstl/filesystem/file_lines/main.cpp new file mode 100644 index 00000000..a7f66195 --- /dev/null +++ b/test/performance/platformstl/filesystem/file_lines/main.cpp @@ -0,0 +1,433 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test.performance.platformstl.file_lines/main.cpp + * + * Purpose: Comparative perf-test for platformstl::file_lines and + * std::ifstream + std::getline. + * + * Created: 23rd September 2026 + * Updated: 30th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#if __cplusplus >= 201703L +# include +#endif /* C++17+ */ +#include +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * types + */ + +typedef stlsoft::std_chrono_hrc_stopwatch stopwatch_t; +typedef stopwatch_t::interval_type interval_t; + +typedef std::pair< + interval_t +, std::size_t +> result_t; + +typedef platformstl::basic_file_lines< + char +, std::string +> file_lines_std_string_t; +typedef platformstl::basic_file_lines< + char +, stlsoft::simple_string +> file_lines_stlsoft_simple_string_t; +typedef platformstl::basic_file_lines< + char +, stlsoft::string_view +> file_lines_stlsoft_string_view_t; +#if __cplusplus >= 201703L + +typedef platformstl::basic_file_lines< + char +, std::string_view +> file_lines_std_string_view_t; +#endif /* C++17+ */ + + +/* ///////////////////////////////////////////////////////////////////////// + * constants + */ + +namespace { + +char const TEST_FILE_NAME[] = "test.performance.platformstl.file_lines.txt"; + +std::size_t const COLUMN_WIDTH_ANCHOR = 12; +std::size_t const COLUMN_WIDTH_IMPLEMENTATION = 48; +std::size_t const COLUMN_WIDTH_ITERATIONS = 12; +std::size_t const COLUMN_WIDTH_NS_PER_OPERATION = 12; +std::size_t const COLUMN_WIDTH_SCENARIO = 24; +std::size_t const COLUMN_WIDTH_TOTAL_TIME = 16; +const std::size_t NUM_ITERATIONS = 1000; +const std::size_t NUM_WARMUPS = 2; + +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * helpers + */ + +enum line_ending_t +{ + line_ending_lf = 0 + , line_ending_crlf + , line_ending_cr +}; + +std::string +make_line( + std::size_t length +) +{ + std::string line(length, 'x'); + + for (std::size_t i = 0; length != i; ++i) + { + line[i] = static_cast('a' + (i % 26)); + } + + return line; +} + +char const* +line_ending_name_( + line_ending_t ending +) +{ + switch (ending) + { + case line_ending_cr: + + return "CR"; + case line_ending_crlf: + + return "CRLF"; + case line_ending_lf: + default: + + return "LF"; + } +} + +bool +write_test_file( + std::size_t num_lines +, std::size_t line_length +, line_ending_t ending +) +{ + char const* eol = "\n"; + std::size_t eol_len = 1u; + + switch (ending) + { + case line_ending_cr: + + eol = "\r"; + break; + case line_ending_crlf: + + eol = "\r\n"; + eol_len = 2u; + break; + case line_ending_lf: + default: + + break; + } + + std::string const line = make_line(line_length); + + FILE* stm = NULL; + + if (0 != STLSOFT_API_INTERNAL_stdio_fopen_m(TEST_FILE_NAME, "wb", &stm)) + { + return false; + } + + for (std::size_t i = 0; num_lines != i; ++i) + { + if (line.size() != fwrite(line.data(), 1u, line.size(), stm)) + { + fclose(stm); + return false; + } + if (eol_len != fwrite(eol, 1u, eol_len, stm)) + { + fclose(stm); + return false; + } + } + + return (0 == fclose(stm)); +} + +template +std::size_t +read_file_lines_() +{ + T_file_lines lines(TEST_FILE_NAME); + std::size_t anchor = lines.size(); + + for (typename T_file_lines::const_iterator i = lines.begin(); lines.end() != i; ++i) + { + anchor += (*i).size(); + } + + return anchor; +} + +template +result_t +time_( + std::size_t num_iterations +, F fn +) +{ + interval_t interval = 0; + std::size_t anchor = 0; + + for (std::size_t w = NUM_WARMUPS; 0 != w; --w) + { + stopwatch_t sw; + + anchor = 0; + sw.start(); + + for (std::size_t i = 0; num_iterations != i; ++i) + { + anchor += fn(); + } + + sw.stop(); + + if (1 == w) + { + interval = sw.get_nanoseconds(); + } + } + + return std::make_pair(interval, anchor); +} + +void +display_result( + char const* scenario +, char const* implementation +, std::size_t num_iterations +, result_t const& result +) +{ + std::cout + << std::left + << std::setw(COLUMN_WIDTH_SCENARIO) << scenario + << std::setw(COLUMN_WIDTH_IMPLEMENTATION) << implementation + << std::right + << std::setw(COLUMN_WIDTH_ITERATIONS) << num_iterations + << std::setw(COLUMN_WIDTH_TOTAL_TIME) << result.first + << std::setw(COLUMN_WIDTH_NS_PER_OPERATION) << std::fixed << std::setprecision(3) + << (static_cast(result.first) / num_iterations) + << std::setw(COLUMN_WIDTH_ANCHOR) << result.second + << std::endl; +} + +void +run_scenario( + std::size_t num_lines +, std::size_t line_length +, line_ending_t ending +) +{ + char scenario[64]; + + stlsoft::snprintf( + scenario + , sizeof(scenario) + , "%lu %s x %lu %s" + , static_cast(num_lines) + , (1u == num_lines) ? "line" : "lines" + , static_cast(line_length) + , line_ending_name_(ending) + ); + + if (!write_test_file(num_lines, line_length, ending)) + { + std::cerr + << "failed to write " + << TEST_FILE_NAME + << std::endl + ; + + return; + } + + result_t const getc = time_(NUM_ITERATIONS, []() -> std::size_t { + std::vector lines; + std::string line; + std::size_t anchor = 0; + FILE* stm = NULL; + + if (0 != STLSOFT_API_INTERNAL_stdio_fopen_m(TEST_FILE_NAME, "rb", &stm)) + { + return 0u; + } + + for (int ch = fgetc(stm); EOF != ch; ch = fgetc(stm)) + { + if ('\n' == ch) + { + anchor += line.size(); + lines.push_back(line); + line.clear(); + } + else + { + line.push_back(static_cast(ch)); + } + } + + if (0u != line.size()) + { + anchor += line.size(); + lines.push_back(line); + } + + fclose(stm); + + return lines.size() + anchor; + }); + + result_t const getline = time_(NUM_ITERATIONS, [ending]() -> std::size_t { + std::ifstream stm(TEST_FILE_NAME, std::ios::binary); + std::vector lines; + std::string line; + std::size_t anchor = 0; + char const delimiter = (line_ending_cr == ending) ? '\r' : '\n'; + + while (std::getline(stm, line, delimiter)) + { + if (line_ending_crlf == ending && !line.empty() && '\r' == line.back()) + { + line.pop_back(); + } + + anchor += line.size(); + lines.push_back(line); + } + + return lines.size() + anchor; + }); + + result_t const file_lines_std_string = time_(NUM_ITERATIONS, []() -> std::size_t { + return read_file_lines_(); + }); + + result_t const file_lines_stlsoft_simple_string = time_(NUM_ITERATIONS, []() -> std::size_t { + return read_file_lines_(); + }); + + result_t const file_lines_stlsoft_string_view = time_(NUM_ITERATIONS, []() -> std::size_t { + return read_file_lines_(); + }); + + display_result(scenario, "vector+getc", NUM_ITERATIONS, getc); + display_result(scenario, "vector+getline", NUM_ITERATIONS, getline); + display_result(scenario, "basic_file_lines", NUM_ITERATIONS, file_lines_std_string); + display_result(scenario, "basic_file_lines", NUM_ITERATIONS, file_lines_stlsoft_simple_string); + display_result(scenario, "basic_file_lines", NUM_ITERATIONS, file_lines_stlsoft_string_view); +#if __cplusplus >= 201703L + + result_t const file_lines_std_string_view = time_(NUM_ITERATIONS, []() -> std::size_t { + return read_file_lines_(); + }); + + display_result(scenario, "basic_file_lines", NUM_ITERATIONS, file_lines_std_string_view); +#endif /* C++17+ */ +} + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int /*argc*/, char* /*argv*/[]) +{ + std::cout + << std::left + << std::setw(COLUMN_WIDTH_SCENARIO) << "scenario" + << std::setw(COLUMN_WIDTH_IMPLEMENTATION) << "implementation" + << std::right + << std::setw(COLUMN_WIDTH_ITERATIONS) << "iterations" + << std::setw(COLUMN_WIDTH_TOTAL_TIME) << "total-ns" + << std::setw(COLUMN_WIDTH_NS_PER_OPERATION) << "ns/op" + << std::setw(COLUMN_WIDTH_ANCHOR) << "anchor" + << std::endl + ; + + struct scenario_t + { + std::size_t num_lines; + std::size_t line_length; + line_ending_t ending; + }; + + /* LF, then CRLF, then CR. The two large shapes match the original LF + * runs. The small shapes (one line, a handful of lines, about 2KB) are + * the fixed-cost region a later small-file path has to beat. + */ + scenario_t const scenarios[] = + { + { 1000, 64, line_ending_lf, }, + { 1000, 64, line_ending_crlf, }, + { 1000, 64, line_ending_cr, }, + { 5000, 80, line_ending_lf, }, + { 5000, 80, line_ending_crlf, }, + { 5000, 80, line_ending_cr, }, + { 1, 16, line_ending_lf, }, + { 1, 16, line_ending_crlf, }, + { 1, 16, line_ending_cr, }, + { 8, 32, line_ending_lf, }, + { 8, 32, line_ending_crlf, }, + { 8, 32, line_ending_cr, }, + { 32, 64, line_ending_lf, }, + { 32, 64, line_ending_crlf, }, + { 32, 64, line_ending_cr, }, + }; + + { for (std::size_t i = 0; STLSOFT_NUM_ELEMENTS(scenarios) != i; ++i) + { + run_scenario(scenarios[i].num_lines, scenarios[i].line_length, scenarios[i].ending); + }} + + std::remove(TEST_FILE_NAME); + + return EXIT_SUCCESS; +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + From 0287f1f0c7e5ae7c86163c2cf8234fa5a2d96c17 Mon Sep 17 00:00:00 2001 From: Matt Wilson <152443343+mwsis@users.noreply.github.com> Date: Wed, 30 Sep 2026 13:38:53 +1000 Subject: [PATCH 08/31] 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::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. --- CHANGES.md | 32 +- NEWS.md | 2 +- include/stlsoft/std/cstring.hpp | 16 +- include/stlsoft/string/char_traits.hpp | 15 +- include/stlsoft/string/functionals.hpp | 15 +- include/stlsoft/string/simple_string.hpp | 56 ++-- include/winstl/memory/netapi_allocator.hpp | 14 +- include/winstl/winstl.h | 9 +- .../comstl/string/BSTR_functions.C/entry.c | 59 ++++ .../string/BSTR_functions/CMakeLists.txt | 2 + .../comstl/string/BSTR_functions/entry.cpp | 240 +++++++++++++++ test/unit/comstl/string/CMakeLists.txt | 1 + test/unit/stlsoft/CMakeLists.txt | 1 + test/unit/stlsoft/std/CMakeLists.txt | 2 + test/unit/stlsoft/std/cstring/CMakeLists.txt | 2 + test/unit/stlsoft/std/cstring/entry.cpp | 219 +++++++++++++ test/unit/stlsoft/string/CMakeLists.txt | 6 + .../string/c_string.strnicmp.C/CMakeLists.txt | 2 + .../string/c_string.strnicmp.C/entry.c | 223 ++++++++++++++ .../string/c_string.strnicmp/CMakeLists.txt | 2 + .../string/c_string.strnicmp/entry.cpp | 245 +++++++++++++++ .../string/c_string_traits/CMakeLists.txt | 2 + .../stlsoft/string/c_string_traits/entry.cpp | 174 +++++++++++ .../stlsoft/string/char_traits/CMakeLists.txt | 2 + .../unit/stlsoft/string/char_traits/entry.cpp | 288 ++++++++++++++++++ .../CMakeLists.txt | 2 + .../functionals.string_begins_with/entry.cpp | 176 +++++++++++ .../stlsoft/string/simple_string/entry.cpp | 217 ++++++++++++- .../special_string_instance/CMakeLists.txt | 2 + .../string/special_string_instance/entry.cpp | 275 +++++++++++++++++ .../stlsoft/string/static_string/entry.cpp | 93 ++++++ .../stlsoft/string/string_slice/entry.cpp | 76 +++++ .../unit/stlsoft/string/string_view/entry.cpp | 91 ++++++ test/unit/versions/entry.cpp | 2 +- 34 files changed, 2476 insertions(+), 87 deletions(-) create mode 100644 test/unit/comstl/string/BSTR_functions/CMakeLists.txt create mode 100644 test/unit/comstl/string/BSTR_functions/entry.cpp create mode 100644 test/unit/stlsoft/std/CMakeLists.txt create mode 100644 test/unit/stlsoft/std/cstring/CMakeLists.txt create mode 100644 test/unit/stlsoft/std/cstring/entry.cpp create mode 100644 test/unit/stlsoft/string/c_string.strnicmp.C/CMakeLists.txt create mode 100644 test/unit/stlsoft/string/c_string.strnicmp.C/entry.c create mode 100644 test/unit/stlsoft/string/c_string.strnicmp/CMakeLists.txt create mode 100644 test/unit/stlsoft/string/c_string.strnicmp/entry.cpp create mode 100644 test/unit/stlsoft/string/c_string_traits/CMakeLists.txt create mode 100644 test/unit/stlsoft/string/c_string_traits/entry.cpp create mode 100644 test/unit/stlsoft/string/char_traits/CMakeLists.txt create mode 100644 test/unit/stlsoft/string/char_traits/entry.cpp create mode 100644 test/unit/stlsoft/string/functionals.string_begins_with/CMakeLists.txt create mode 100644 test/unit/stlsoft/string/functionals.string_begins_with/entry.cpp create mode 100644 test/unit/stlsoft/string/special_string_instance/CMakeLists.txt create mode 100644 test/unit/stlsoft/string/special_string_instance/entry.cpp diff --git a/CHANGES.md b/CHANGES.md index 44931d4e..c9fee270 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,28 +3,34 @@ ## 1.11.1-rc7 - 30th September 2026 +* **simple_string** — counted construction, `assign`, `append`, `push_back`, and concatenation keep an embedded NUL, including assignment of a single `'\0'`; +* **string_begins_with** — a `wchar_t` prefix compares with `char_traits::compare_max` (`wcsncmp`); +* **char_traits_safe** — a count of 0 compares equal; a non-zero count orders a null pointer before a live pointer; +* **platformstl::FILE_stream** — added `write_binary()` (writes every byte, including embedded NULs) and deprecated `write(void const*, size_t)` in its favour; +* `platformstl::basic_file_lines<>` — parse directly from the memory-mapped base (dropped the full-file `m_contents` heap copy); fold the binary/NUL reject into the parse loop; C++11+ `emplace_back`; floor line-reservation at 128; +* Approximate measured gains for `platformstl::basic_file_lines<>` on the new harness (1000×64 LF): view-based forms (~`stlsoft::string_view` / `std::string_view`) about **10–20×** faster than `fgetc` line accumulation and typically **comparable to or slightly ahead of** `std::getline` (~1.2× on MinGW CI); owning-string forms remain competitive with `std::getline` while avoiding the extra full-file copy; * Renamed `stlsoft_C_environment_variable_exists_a()` to `stlsoft_C_environment_variable_exists_m()`; the `_a` form remains as a deprecated forwarder; -* Component tests for `stlsoft::environment_variable_exists()` (**test/component/stlsoft/system/environment_variable_exists**), including `std::string` / `simple_string` shims and UNIX empty-value behaviour; * Added `count_bits_by_intrinsic()` and `find_highest_bit_by_intrinsic()` (unselected by default; `count_bits()` keeps the 8-bit table; `find_highest_bit()` keeps the scan); * Added **stlsoft/api/external/bitfns.h** and **stlsoft/api/internal/bitfns.h** — detection and adaptations for `popcount` / `clz` / `_BitScanReverse` intrinsics (GCC/Clang builtins preferred over MSVC when both are visible); * Clang cccap — `STLSOFT_CLANG_VER`; documented shared `STLSOFT_GCC_VER` (also noted in GCC cccap); * Fixed `count_bits()` overloads when `STLSOFT_BIT_COUNT_BY_Kernighan` is defined; -* Unit tests for intrinsic popcount / highest-bit helpers; broader width coverage for bit-function overloads; -* Performance suite **test/performance/stlsoft/util/bit_functions** (density patterns, intrinsic rows, median / ns-per-call reporting); * Strategy note **strategy/BIT_FUNCTIONS.md** — measurements and default choice (table for `count_bits()`; keep intrinsics unselected pending cross-toolchain evidence); -* CI — performance job exports **SIS_PERFTESTS_GROUPGAPS=1**; -* **platformstl::FILE_stream** — added `write_binary()` (writes every byte, including embedded NULs) and deprecated `write(void const*, size_t)` in its favour; -* Component tests for `platformstl::file_lines` (**test/component/platformstl/filesystem/file_lines**); -* `platformstl::basic_file_lines<>` — parse directly from the memory-mapped base (dropped the full-file `m_contents` heap copy); fold the binary/NUL reject into the parse loop; C++11+ `emplace_back`; floor line-reservation at 128; -* Approximate measured gains for `platformstl::basic_file_lines<>` on the new harness (1000×64 LF): view-based forms (~`stlsoft::string_view` / `std::string_view`) about **10–20×** faster than `fgetc` line accumulation and typically **comparable to or slightly ahead of** `std::getline` (~1.2× on MinGW CI); owning-string forms remain competitive with `std::getline` while avoiding the extra full-file copy; -* Performance suite **test/performance/platformstl/filesystem/file_lines** — comparative harness vs `fgetc` / `std::getline` (LF / CRLF / CR; mid-size and small-file shapes; C++11+); +* **winstl::netapi_allocator** — pass a `DWORD` byte count to `NetApiBufferAllocate`; the unit test links **netapi32**; +* **stlsoft/std/cstring.hpp** — suppress CRT deprecation around the `strcpy`, `strcat`, and `strdup` wrappers; +* **winstl** — **1.13.0 beta 3** (**_WINSTL_VER_1_13_0_B03**), with **STLSoft 1.11.1-rc7**; * CMake — Windows GNU (**MinGW**) test/example programs static-link **libgcc** / **libstdc++** so PE images load when runner **PATH** does not match the build toolchain; +* CI — performance job exports **SIS_PERFTESTS_GROUPGAPS=1**; * **execute_performance_tests.sh** — capture the child exit code after optional `expand` piping (was overwriting a failed status with `$?` from the success branch); -* Fixed `winstl::netapi_allocator` — pass a **DWORD** byte count to `NetApiBufferAllocate`; -* Unit tests — removed empty case functions; filled the nine allocator suites (round-trip sizes, `max_size()`, `std::list` / `std::vector`; `null_allocator` throws `out_of_memory_exception`); -* Test tree — leaf directories under **test/component**, **test/unit**, **test/scratch**, and **test/performance** renamed from `test..…` to the subject name (for example **glob_sequence**); executable target names unchanged; +* Test tree — leaf directories under **test/component**, **test/unit**, **test/scratch**, and **test/performance** renamed from `test..…` to the subject name (for example **glob_sequence**); executable names stay `test..*`; * **test/performance** — programs nested by sub-project and area (**platformstl/diagnostics**, **platformstl/filesystem**, **stlsoft/containers**, **stlsoft/conversion**, **stlsoft/diagnostics**, **stlsoft/memory**, **stlsoft/string**, **stlsoft/util**); -* **test.unit.versions** — aligned with **1.11.1-rc7** (**_STLSOFT_VER_1_11_1_RC7**); +* String-comparison units — `strnicmp` (C and C++), `c_string_traits`, `char_traits` / `char_traits_safe`, `strcmp` / `strncmp`, BSTR compare, `string_begins_with`, `special_string_instance::equal`, and compare edges on `simple_string`, `static_string`, `string_view`, and `string_slice`; +* Component tests for `stlsoft::environment_variable_exists()` (**test/component/stlsoft/system/environment_variable_exists**), including `std::string` / `simple_string` shims and UNIX empty-value behaviour; +* Component tests for `platformstl::file_lines` (**test/component/platformstl/filesystem/file_lines**) cover LF, CR, and CRLF splits, including an empty line, and reject an embedded NUL; +* Unit tests for intrinsic popcount / highest-bit helpers; broader width coverage for bit-function overloads; +* Performance suite **test/performance/stlsoft/util/bit_functions** (density patterns, intrinsic rows, median / ns-per-call reporting); +* Performance suite **test/performance/platformstl/filesystem/file_lines** — comparative harness vs `fgetc` / `std::getline` (LF / CRLF / CR; mid-size and small-file shapes; C++11+); +* Unit tests — removed empty placeholder cases; filled the nine allocator suites (**comstl::task_allocator**, **mfcstl::afx_allocator**, **malloc_allocator**, **new_allocator**, **null_allocator**, and WinSTL **global_allocator**, **netapi_allocator**, **processheap_allocator**, and **shell_allocator**) with round-trip sizes, `max_size()`, and `std::list` / `std::vector` use (`null_allocator` throws `out_of_memory_exception`); +* **test.unit.versions** — aligned with **1.11.1-rc7** (**_STLSOFT_VER_1_11_1_RC7**) and **WinSTL 1.13.0 beta 3** (**_WINSTL_VER_1_13_0_B03**); ## 1.11.1-rc6 - 21st September 2026 diff --git a/NEWS.md b/NEWS.md index b6ac5cb8..ade40c74 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,7 @@ | Date | News Item | Details | | ------------------- | ----------------------------------- | ------- | -| 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | bit-function intrinsics; `FILE_stream::write_binary()`; `basic_file_lines<>` mmap parse (~10–20× vs `fgetc`); **file_lines** perf; MinGW static runtime; nested **test/performance** | +| 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | counted NULs; `wchar_t` `string_begins_with`; bit intrinsics; `write_binary()`; `file_lines` mmap (~10–20× vs `fgetc`); compare and allocator units; MinGW static runtime; short test directories; nested **test/performance** | | 21st September 2026 | Release of [STLSoft 1.11.1-rc6](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc6) | ACE/ATL/MFC CI; Clang/macOS `stricmp` aliases | | 4th August 2026 | Release of [STLSoft 1.11.1-rc5](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc5) | `basic_simple_string<>#resize()`; **CHANGES.md**; docs | | 29th July 2026 | Release of [STLSoft 1.11.1-rc4](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc4) | GitHub Actions CI; VC++ 18.x; MinGW | diff --git a/include/stlsoft/std/cstring.hpp b/include/stlsoft/std/cstring.hpp index d6fcfcdc..5dccfea6 100644 --- a/include/stlsoft/std/cstring.hpp +++ b/include/stlsoft/std/cstring.hpp @@ -4,14 +4,14 @@ * Purpose: Mappings to std string functions * * Created: 2nd December 2004 - * Updated: 20th March 2025 + * Updated: 29th September 2026 * * Thanks: To Anton Sekeris for providing good advice on the naming scheme * for the stlsoft/std headers * * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2004-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -57,8 +57,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_STLSOFT_STD_HPP_CSTRING_MAJOR 1 # define STLSOFT_VER_STLSOFT_STD_HPP_CSTRING_MINOR 5 -# define STLSOFT_VER_STLSOFT_STD_HPP_CSTRING_REVISION 11 -# define STLSOFT_VER_STLSOFT_STD_HPP_CSTRING_EDIT 50 +# define STLSOFT_VER_STLSOFT_STD_HPP_CSTRING_REVISION 12 +# define STLSOFT_VER_STLSOFT_STD_HPP_CSTRING_EDIT 51 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -111,6 +111,8 @@ namespace stlsoft #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION +#include + #ifndef STLSOFT_NO_NAMESPACE namespace std_impl { @@ -187,6 +189,8 @@ namespace std_impl } // namespace std_impl #endif /* STLSOFT_NO_NAMESPACE */ +#include + #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ #ifdef STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT @@ -440,6 +444,8 @@ char * __cdecl strpbrk(char const*, char const*); #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION +#include + #ifndef STLSOFT_NO_NAMESPACE namespace std_impl { @@ -481,6 +487,8 @@ namespace std_impl } // namespace std_impl #endif /* STLSOFT_NO_NAMESPACE */ +#include + #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ diff --git a/include/stlsoft/string/char_traits.hpp b/include/stlsoft/string/char_traits.hpp index 731f07db..b7a81bbf 100644 --- a/include/stlsoft/string/char_traits.hpp +++ b/include/stlsoft/string/char_traits.hpp @@ -4,11 +4,11 @@ * Purpose: char_traits classes. * * Created: 19th November 1998 - * Updated: 20th March 2025 + * Updated: 29th September 2026 * * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 1998-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -54,8 +54,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_STLSOFT_STRING_HPP_CHAR_TRAITS_MAJOR 4 # define STLSOFT_VER_STLSOFT_STRING_HPP_CHAR_TRAITS_MINOR 3 -# define STLSOFT_VER_STLSOFT_STRING_HPP_CHAR_TRAITS_REVISION 2 -# define STLSOFT_VER_STLSOFT_STRING_HPP_CHAR_TRAITS_EDIT 101 +# define STLSOFT_VER_STLSOFT_STRING_HPP_CHAR_TRAITS_REVISION 3 +# define STLSOFT_VER_STLSOFT_STRING_HPP_CHAR_TRAITS_EDIT 102 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -678,7 +678,12 @@ struct stlsoft_char_traits_safe , size_type cch ) STLSOFT_NOEXCEPT { - return parent_class_type::compare(s1, s2, cch); + if (0 == cch) + { + return 0; + } + + return parent_class_type::compare_null(s1, s2, cch); } /// Compares, using compare_max(), \c s1 with \c s2, either or both of which may be \c nullptr diff --git a/include/stlsoft/string/functionals.hpp b/include/stlsoft/string/functionals.hpp index 526c7944..add7dfab 100644 --- a/include/stlsoft/string/functionals.hpp +++ b/include/stlsoft/string/functionals.hpp @@ -4,11 +4,11 @@ * Purpose: String function classes * * Created: 22nd April 2005 - * Updated: 20th March 2025 + * Updated: 29th September 2026 * * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2005-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -54,8 +54,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_STLSOFT_STRING_HPP_FUNCTIONALS_MAJOR 2 # define STLSOFT_VER_STLSOFT_STRING_HPP_FUNCTIONALS_MINOR 2 -# define STLSOFT_VER_STLSOFT_STRING_HPP_FUNCTIONALS_REVISION 11 -# define STLSOFT_VER_STLSOFT_STRING_HPP_FUNCTIONALS_EDIT 51 +# define STLSOFT_VER_STLSOFT_STRING_HPP_FUNCTIONALS_REVISION 12 +# define STLSOFT_VER_STLSOFT_STRING_HPP_FUNCTIONALS_EDIT 52 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -73,6 +73,9 @@ #ifndef STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING # include #endif /* !STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING */ +#ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_CHAR_TRAITS +# include +#endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_CHAR_TRAITS */ #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER # include #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */ @@ -160,7 +163,7 @@ struct string_begins_with_function #endif { public: - typedef char const* argument_type; + typedef C const* argument_type; typedef ss_bool_t result_type; public: @@ -172,7 +175,7 @@ struct string_begins_with_function public: ss_bool_t operator ()(C const* line) const { - return 0 == ::strncmp(line, m_prefix, m_prefixLen); + return 0 == char_traits::compare_max(line, m_prefix, m_prefixLen); } template ss_bool_t operator ()(S const& line) const diff --git a/include/stlsoft/string/simple_string.hpp b/include/stlsoft/string/simple_string.hpp index 8b74beb0..b9c2c132 100644 --- a/include/stlsoft/string/simple_string.hpp +++ b/include/stlsoft/string/simple_string.hpp @@ -4,11 +4,11 @@ * Purpose: basic_simple_string class template. * * Created: 19th March 1993 - * Updated: 31st July 2026 + * Updated: 29th September 2026 * * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 1993-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -52,10 +52,10 @@ #define STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION -# define STLSOFT_VER_STLSOFT_STRING_HPP_SIMPLE_STRING_MAJOR 4 -# define STLSOFT_VER_STLSOFT_STRING_HPP_SIMPLE_STRING_MINOR 8 -# define STLSOFT_VER_STLSOFT_STRING_HPP_SIMPLE_STRING_REVISION 4 -# define STLSOFT_VER_STLSOFT_STRING_HPP_SIMPLE_STRING_EDIT 285 +# define STLSOFT_VER_STLSOFT_STRING_HPP_SIMPLE_STRING_MAJOR 5 +# define STLSOFT_VER_STLSOFT_STRING_HPP_SIMPLE_STRING_MINOR 0 +# define STLSOFT_VER_STLSOFT_STRING_HPP_SIMPLE_STRING_REVISION 1 +# define STLSOFT_VER_STLSOFT_STRING_HPP_SIMPLE_STRING_EDIT 287 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -1747,9 +1747,9 @@ basic_simple_string::alloc_buffer_( ss_size_t const members = (STLSOFT_RAW_OFFSETOF(string_buffer, contents) + (sizeof(char_type) - 1)) / sizeof(char_type); - capacity += 1; // For null terminator - capacity += members; // Include the internal members. - capacity = (alloc_quantum + capacity) & ~alloc_quantum; // Round up to (alloc_quantum + 1) + capacity += 1; // for NUL-terminator + capacity += members; // include the internal members. + capacity = (alloc_quantum + capacity) & ~alloc_quantum; // round up to (alloc_quantum + 1) byte_ator_type byte_ator; # ifdef STLSOFT_LF_ALLOCATOR_ALLOCATE_HAS_HINT @@ -1798,17 +1798,10 @@ basic_simple_string::alloc_buffer_( , ss_typename_type_k basic_simple_string::size_type cch ) { - size_type length = traits_type::length_max_null(s, cch); - size_type capacity = cch; - - if (cch < length) - { - length = cch; - } - - return alloc_buffer_(s, capacity, length); + return alloc_buffer_(s, cch, cch); } + template < ss_typename_param_k C , ss_typename_param_k T @@ -2077,10 +2070,10 @@ template < > inline basic_simple_string::basic_simple_string( - ss_typename_type_k basic_simple_string::char_type const* s -, ss_typename_type_k basic_simple_string::size_type cch + ss_typename_type_k basic_simple_string::char_type const* s +, ss_typename_type_k basic_simple_string::size_type cch ) - : m_buffer(alloc_buffer_(s, cch)) + : m_buffer(alloc_buffer_(s, cch, cch)) { STLSOFT_ASSERT(is_valid()); } @@ -3043,7 +3036,7 @@ inline ss_typename_type_ret_k basic_simple_string::const_reference basic_simple_string::operator [](ss_typename_type_k basic_simple_string::size_type index) const STLSOFT_NOEXCEPT { - STLSOFT_MESSAGE_ASSERT("index access out of range in simple_string", index < size() + 1); // Valid to return (const) reference to nul-terminator + STLSOFT_MESSAGE_ASSERT("index access out of range in simple_string", index < size() + 1); // Valid to return (const) reference to NUL-terminator STLSOFT_ASSERT(is_valid()); @@ -3422,7 +3415,7 @@ basic_simple_string::assign( } else { - member_pointer const new_buffer = alloc_buffer_(s, cch, cch); + member_pointer const new_buffer = alloc_buffer_(s, cch); destroy_buffer_(m_buffer); @@ -3568,9 +3561,7 @@ inline ss_typename_type_ret_k basic_simple_string::class_type const& basic_simple_string::operator =(ss_typename_type_k basic_simple_string::char_type ch) { - char_type sz[2] = { ch, traits_type::to_char_type(0) }; - - return assign(sz); + return assign(&ch, 1); } @@ -3602,17 +3593,6 @@ basic_simple_string::append( } else { -#if 1 - // We're taking a length here, which may have been done already. - // This should be optimised out in a subsequent release - size_type len = traits_type::length_max(s, cch); - - if (len < cch) - { - cch = len; - } -#endif /* 0 */ - string_buffer* old_buffer = ss_nullptr_k; string_buffer* buffer = string_buffer_from_member_pointer_(m_buffer); size_type const buf_len = buffer->length; @@ -3620,7 +3600,7 @@ basic_simple_string::append( if (buffer->capacity - buf_len < 1 + cch) { // Allocate a new buffer of sufficient size - member_pointer const new_buffer = alloc_buffer_(buffer->contents, buf_len + cch); + member_pointer const new_buffer = alloc_buffer_(buffer->contents, buf_len + cch, buf_len); if (ss_nullptr_k == new_buffer) // Some allocators do not throw on failure! { diff --git a/include/winstl/memory/netapi_allocator.hpp b/include/winstl/memory/netapi_allocator.hpp index 476bb4c3..f7e60be9 100644 --- a/include/winstl/memory/netapi_allocator.hpp +++ b/include/winstl/memory/netapi_allocator.hpp @@ -1,12 +1,12 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: winstl/memory/netapi_allocator.hpp + * File: winstl/memory/netapi_allocator.hpp * - * Purpose: netapi_allocator class. + * Purpose: netapi_allocator class. * - * Created: 23rd March 2006 - * Updated: 30th September 2026 + * Created: 23rd March 2006 + * Updated: 30th September 2026 * - * Home: http://stlsoft.org/ + * Home: http://stlsoft.org/ * * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2006-2019, Matthew Wilson and Synesis Software @@ -53,8 +53,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define WINSTL_VER_WINSTL_MEMORY_HPP_NETAPI_ALLOCATOR_MAJOR 1 # define WINSTL_VER_WINSTL_MEMORY_HPP_NETAPI_ALLOCATOR_MINOR 1 -# define WINSTL_VER_WINSTL_MEMORY_HPP_NETAPI_ALLOCATOR_REVISION 9 -# define WINSTL_VER_WINSTL_MEMORY_HPP_NETAPI_ALLOCATOR_EDIT 32 +# define WINSTL_VER_WINSTL_MEMORY_HPP_NETAPI_ALLOCATOR_REVISION 10 +# define WINSTL_VER_WINSTL_MEMORY_HPP_NETAPI_ALLOCATOR_EDIT 33 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ diff --git a/include/winstl/winstl.h b/include/winstl/winstl.h index 2d358444..361f6292 100644 --- a/include/winstl/winstl.h +++ b/include/winstl/winstl.h @@ -5,7 +5,7 @@ * platform discriminations, and definitions of types. * * Created: 15th January 2002 - * Updated: 17th September 2026 + * Updated: 30th September 2026 * * Home: http://stlsoft.org/ * @@ -50,8 +50,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define WINSTL_VER_WINSTL_H_WINSTL_MAJOR 3 # define WINSTL_VER_WINSTL_H_WINSTL_MINOR 18 -# define WINSTL_VER_WINSTL_H_WINSTL_REVISION 13 -# define WINSTL_VER_WINSTL_H_WINSTL_EDIT 243 +# define WINSTL_VER_WINSTL_H_WINSTL_REVISION 14 +# define WINSTL_VER_WINSTL_H_WINSTL_EDIT 244 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ /** \file winstl/winstl.h @@ -183,12 +183,13 @@ # define _WINSTL_VER_1_13_0_A06 0x010d0046 /*!< Version 1.13.0 alpha 6 (with STLSoft 1.11.1 rc 2) */ # define _WINSTL_VER_1_13_0_B01 0x010d0081 /*!< Version 1.13.0 beta 1 (with STLSoft 1.11.1 rc 3) */ # define _WINSTL_VER_1_13_0_B02 0x010d0082 /*!< Version 1.13.0 beta 2 (with STLSoft 1.11.1 rc 4) */ +# define _WINSTL_VER_1_13_0_B03 0x010d0083 /*!< Version 1.13.0 beta 3 (with STLSoft 1.11.1 rc 7) */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ #define _WINSTL_VER_MAJOR 1 #define _WINSTL_VER_MINOR 13 #define _WINSTL_VER_PATCH 0 -#define _WINSTL_VER_ALPHABETA 0x82 +#define _WINSTL_VER_ALPHABETA 0x83 #define _WINSTL_VER \ (0\ diff --git a/test/unit/comstl/string/BSTR_functions.C/entry.c b/test/unit/comstl/string/BSTR_functions.C/entry.c index 7436ad43..b657d314 100644 --- a/test/unit/comstl/string/BSTR_functions.C/entry.c +++ b/test/unit/comstl/string/BSTR_functions.C/entry.c @@ -42,6 +42,9 @@ static void test_comstl_C_BSTR_create_a_2(void); static void test_comstl_C_BSTR_create_len_w(void); static void test_comstl_C_BSTR_create_len_a(void); static void test_comstl_C_BSTR_compare(void); +static void TEST_comstl_C_BSTR_compare_EMPTY(void); +static void TEST_comstl_C_BSTR_compare_EMBEDDED_NUL(void); +static void TEST_comstl_C_BSTR_compare_PREFIX_LENGTH(void); /* ///////////////////////////////////////////////////////////////////////// @@ -64,6 +67,9 @@ int main(int argc, char **argv) XTESTS_RUN_CASE(test_comstl_C_BSTR_create_len_w); XTESTS_RUN_CASE(test_comstl_C_BSTR_create_len_a); XTESTS_RUN_CASE(test_comstl_C_BSTR_compare); + XTESTS_RUN_CASE(TEST_comstl_C_BSTR_compare_EMPTY); + XTESTS_RUN_CASE(TEST_comstl_C_BSTR_compare_EMBEDDED_NUL); + XTESTS_RUN_CASE(TEST_comstl_C_BSTR_compare_PREFIX_LENGTH); XTESTS_PRINT_RESULTS(); @@ -231,5 +237,58 @@ static void test_comstl_C_BSTR_compare() comstl_C_BSTR_destroy(def); } +static void TEST_comstl_C_BSTR_compare_EMPTY() +{ + BSTR const empty = comstl_C_BSTR_create_w(L""); + BSTR const a = comstl_C_BSTR_create_w(L"a"); + + TEST_PTR_NE(NULL, empty); + TEST_INT_EQ(0u, SysStringLen(empty)); + + TEST_INT_EQ(0, comstl_C_BSTR_compare(empty, empty)); + TEST_INT_EQ(-1, comstl_C_BSTR_compare(NULL, empty)); + TEST_INT_EQ(1, comstl_C_BSTR_compare(empty, NULL)); + TEST_INT_LT(0, comstl_C_BSTR_compare(empty, a)); + TEST_INT_GT(0, comstl_C_BSTR_compare(a, empty)); + + comstl_C_BSTR_destroy(empty); + comstl_C_BSTR_destroy(a); +} + +static void TEST_comstl_C_BSTR_compare_EMBEDDED_NUL() +{ + wchar_t const ax[] = { L'a', L'\0', L'x' }; + wchar_t const ay[] = { L'a', L'\0', L'y' }; + wchar_t const bx[] = { L'b', L'\0', L'x' }; + BSTR const s_ax = comstl_C_BSTR_create_len_w(ax, 3); + BSTR const s_ay = comstl_C_BSTR_create_len_w(ay, 3); + BSTR const s_bx = comstl_C_BSTR_create_len_w(bx, 3); + + TEST_INT_EQ(3u, SysStringLen(s_ax)); + TEST_INT_EQ(0, comstl_C_BSTR_compare(s_ax, s_ay)); + TEST_INT_GT(0, comstl_C_BSTR_compare(s_bx, s_ax)); + + comstl_C_BSTR_destroy(s_ax); + comstl_C_BSTR_destroy(s_ay); + comstl_C_BSTR_destroy(s_bx); +} + +static void TEST_comstl_C_BSTR_compare_PREFIX_LENGTH() +{ + wchar_t const abc[] = L"abc"; + BSTR const ab = comstl_C_BSTR_create_len_w(abc, 2); + BSTR const ab_full = comstl_C_BSTR_create_w(L"ab"); + BSTR const abc_full = comstl_C_BSTR_create_w(L"abc"); + + TEST_INT_EQ(2u, SysStringLen(ab)); + TEST_INT_EQ(0, comstl_C_BSTR_compare(ab, ab_full)); + TEST_INT_LT(0, comstl_C_BSTR_compare(ab, abc_full)); + TEST_INT_GT(0, comstl_C_BSTR_compare(abc_full, ab)); + + comstl_C_BSTR_destroy(ab); + comstl_C_BSTR_destroy(ab_full); + comstl_C_BSTR_destroy(abc_full); +} + /* ///////////////////////////// end of file //////////////////////////// */ diff --git a/test/unit/comstl/string/BSTR_functions/CMakeLists.txt b/test/unit/comstl/string/BSTR_functions/CMakeLists.txt new file mode 100644 index 00000000..a50afa3b --- /dev/null +++ b/test/unit/comstl/string/BSTR_functions/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.unit.comstl.string.BSTR_functions entry.cpp) diff --git a/test/unit/comstl/string/BSTR_functions/entry.cpp b/test/unit/comstl/string/BSTR_functions/entry.cpp new file mode 100644 index 00000000..db231fec --- /dev/null +++ b/test/unit/comstl/string/BSTR_functions/entry.cpp @@ -0,0 +1,240 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: BSTR_functions/entry.cpp + * + * Purpose: Unit-tests for comstl BSTR comparison. + * + * Created: 29th September 2026 + * Updated: 29th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * test component header file include(s) + */ + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include +#include + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace +{ + + static void TEST_comstl_C_BSTR_compare_EMPTY(); + static void TEST_comstl_C_BSTR_compare_EMBEDDED_NUL(); + static void TEST_comstl_C_BSTR_compare_PREFIX_LENGTH(); + static void TEST_BSTR_compare_MATCHES_comstl_C_BSTR_compare(); + static void TEST_bstr_equal(); + static void TEST_comstl__bstr_compare_MATCHES_comstl_C_BSTR_compare(); + +} /* anonymous namespace */ + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.comstl.string.BSTR_functions", verbosity)) + { + XTESTS_RUN_CASE(TEST_comstl_C_BSTR_compare_EMPTY); + XTESTS_RUN_CASE(TEST_comstl_C_BSTR_compare_EMBEDDED_NUL); + XTESTS_RUN_CASE(TEST_comstl_C_BSTR_compare_PREFIX_LENGTH); + XTESTS_RUN_CASE(TEST_BSTR_compare_MATCHES_comstl_C_BSTR_compare); + XTESTS_RUN_CASE(TEST_bstr_equal); + XTESTS_RUN_CASE(TEST_comstl__bstr_compare_MATCHES_comstl_C_BSTR_compare); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace +{ + +static void expect_match_(BSTR s1, BSTR s2, int sign) +{ + int const cpp = comstl::BSTR_compare(s1, s2); + int const c = comstl::comstl_C_BSTR_compare(s1, s2); + + TEST_INT_EQ(c, cpp); + + if (sign < 0) + { + TEST_INT_LT(0, cpp); + } + else if (sign > 0) + { + TEST_INT_GT(0, cpp); + } + else + { + TEST_INT_EQ(0, cpp); + } +} + +static void TEST_comstl_C_BSTR_compare_EMPTY() +{ + BSTR const empty = comstl::comstl_C_BSTR_create_w(L""); + BSTR const a = comstl::comstl_C_BSTR_create_w(L"a"); + + TEST_PTR_NE(NULL, empty); + TEST_INT_EQ(0u, SysStringLen(empty)); + + TEST_INT_EQ(0, comstl::BSTR_compare(empty, empty)); + TEST_INT_EQ(-1, comstl::BSTR_compare(NULL, empty)); + TEST_INT_EQ(1, comstl::BSTR_compare(empty, NULL)); + TEST_INT_LT(0, comstl::BSTR_compare(empty, a)); + TEST_INT_GT(0, comstl::BSTR_compare(a, empty)); + + comstl::comstl_C_BSTR_destroy(empty); + comstl::comstl_C_BSTR_destroy(a); +} + +static void TEST_comstl_C_BSTR_compare_EMBEDDED_NUL() +{ + wchar_t const ax[] = { L'a', L'\0', L'x' }; + wchar_t const ay[] = { L'a', L'\0', L'y' }; + wchar_t const bx[] = { L'b', L'\0', L'x' }; + BSTR const s_ax = comstl::comstl_C_BSTR_create_len_w(ax, 3); + BSTR const s_ay = comstl::comstl_C_BSTR_create_len_w(ay, 3); + BSTR const s_bx = comstl::comstl_C_BSTR_create_len_w(bx, 3); + + TEST_INT_EQ(3u, SysStringLen(s_ax)); + TEST_INT_EQ(0, comstl::BSTR_compare(s_ax, s_ay)); + TEST_INT_GT(0, comstl::BSTR_compare(s_bx, s_ax)); + + comstl::comstl_C_BSTR_destroy(s_ax); + comstl::comstl_C_BSTR_destroy(s_ay); + comstl::comstl_C_BSTR_destroy(s_bx); +} + +static void TEST_comstl_C_BSTR_compare_PREFIX_LENGTH() +{ + wchar_t const abc[] = L"abc"; + BSTR const ab = comstl::comstl_C_BSTR_create_len_w(abc, 2); + BSTR const ab_full = comstl::comstl_C_BSTR_create_w(L"ab"); + BSTR const abc_full = comstl::comstl_C_BSTR_create_w(L"abc"); + + TEST_INT_EQ(2u, SysStringLen(ab)); + TEST_INT_EQ(0, comstl::BSTR_compare(ab, ab_full)); + TEST_INT_LT(0, comstl::BSTR_compare(ab, abc_full)); + TEST_INT_GT(0, comstl::BSTR_compare(abc_full, ab)); + + comstl::comstl_C_BSTR_destroy(ab); + comstl::comstl_C_BSTR_destroy(ab_full); + comstl::comstl_C_BSTR_destroy(abc_full); +} + +static void TEST_BSTR_compare_MATCHES_comstl_C_BSTR_compare() +{ + wchar_t const ax[] = { L'a', L'\0', L'x' }; + wchar_t const ay[] = { L'a', L'\0', L'y' }; + BSTR const empty = comstl::comstl_C_BSTR_create_w(L""); + BSTR const abc = comstl::comstl_C_BSTR_create_w(L"abc"); + BSTR const def = comstl::comstl_C_BSTR_create_w(L"def"); + BSTR const ab = comstl::comstl_C_BSTR_create_len_w(L"abc", 2); + BSTR const s_ax = comstl::comstl_C_BSTR_create_len_w(ax, 3); + BSTR const s_ay = comstl::comstl_C_BSTR_create_len_w(ay, 3); + + expect_match_(NULL, NULL, 0); + expect_match_(NULL, abc, -1); + expect_match_(abc, NULL, +1); + expect_match_(abc, abc, 0); + expect_match_(abc, def, -1); + expect_match_(def, abc, +1); + expect_match_(empty, empty, 0); + expect_match_(empty, abc, -1); + expect_match_(ab, abc, -1); + expect_match_(s_ax, s_ay, 0); + + comstl::comstl_C_BSTR_destroy(empty); + comstl::comstl_C_BSTR_destroy(abc); + comstl::comstl_C_BSTR_destroy(def); + comstl::comstl_C_BSTR_destroy(ab); + comstl::comstl_C_BSTR_destroy(s_ax); + comstl::comstl_C_BSTR_destroy(s_ay); +} + +static void TEST_bstr_equal() +{ + comstl::bstr const abc(L"abc"); + comstl::bstr const abc2(L"abc"); + comstl::bstr const abd(L"abd"); + comstl::bstr const empty; + BSTR const raw = comstl::comstl_C_BSTR_create_w(L"abc"); + + TEST_BOOLEAN_TRUE(abc.equal(abc)); + TEST_BOOLEAN_TRUE(abc.equal(abc2)); + TEST_BOOLEAN_FALSE(abc.equal(abd)); + TEST_BOOLEAN_TRUE(empty.equal(empty)); + TEST_BOOLEAN_FALSE(empty.equal(abc)); + TEST_BOOLEAN_TRUE(abc.equal(raw)); + TEST_BOOLEAN_FALSE(abc.equal(static_cast(NULL))); + + comstl::comstl_C_BSTR_destroy(raw); +} + +static void TEST_comstl__bstr_compare_MATCHES_comstl_C_BSTR_compare() +{ + BSTR const abc = comstl::comstl_C_BSTR_create_w(L"abc"); + BSTR const def = comstl::comstl_C_BSTR_create_w(L"def"); + + /* One call of the deprecated name, with the warning suppressed. */ +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4996) +#endif +#if defined(__clang__) || defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + + int const compared = comstl::comstl__bstr_compare(abc, def); + +#if defined(__clang__) || defined(__GNUC__) +# pragma GCC diagnostic pop +#endif +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + + TEST_INT_EQ(comstl::comstl_C_BSTR_compare(abc, def), compared); + TEST_INT_LT(0, compared); + + comstl::comstl_C_BSTR_destroy(abc); + comstl::comstl_C_BSTR_destroy(def); +} + +} /* anonymous namespace */ + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/comstl/string/CMakeLists.txt b/test/unit/comstl/string/CMakeLists.txt index 1c649c5c..36475e5f 100644 --- a/test/unit/comstl/string/CMakeLists.txt +++ b/test/unit/comstl/string/CMakeLists.txt @@ -1,2 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(BSTR_functions) add_subdirectory(BSTR_functions.C) diff --git a/test/unit/stlsoft/CMakeLists.txt b/test/unit/stlsoft/CMakeLists.txt index f3e515a6..b0f17e17 100644 --- a/test/unit/stlsoft/CMakeLists.txt +++ b/test/unit/stlsoft/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(iterator) add_subdirectory(limits) add_subdirectory(memory) add_subdirectory(smartptr) +add_subdirectory(std) add_subdirectory(string) add_subdirectory(system) add_subdirectory(traits) diff --git a/test/unit/stlsoft/std/CMakeLists.txt b/test/unit/stlsoft/std/CMakeLists.txt new file mode 100644 index 00000000..f631ba27 --- /dev/null +++ b/test/unit/stlsoft/std/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(cstring) diff --git a/test/unit/stlsoft/std/cstring/CMakeLists.txt b/test/unit/stlsoft/std/cstring/CMakeLists.txt new file mode 100644 index 00000000..a7698dbc --- /dev/null +++ b/test/unit/stlsoft/std/cstring/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.unit.stlsoft.std.cstring entry.cpp) diff --git a/test/unit/stlsoft/std/cstring/entry.cpp b/test/unit/stlsoft/std/cstring/entry.cpp new file mode 100644 index 00000000..0ac2fd44 --- /dev/null +++ b/test/unit/stlsoft/std/cstring/entry.cpp @@ -0,0 +1,219 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: cstring/entry.cpp + * + * Purpose: Unit-tests for stlsoft::strcmp and stlsoft::strncmp. + * + * Created: 29th September 2026 + * Updated: 29th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* string_view's c_str_ptr exists only when this is defined. The string + * headers precede cstring.hpp so those overloads are visible to the + * qualified call in the S const& templates. + */ +#define STLSOFT_STRING_VIEW_PROVIDE_c_str +#include +#include +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include +#include + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace +{ + + static void TEST_strcmp_CHAR(); + static void TEST_strcmp_WCHAR(); + static void TEST_strncmp_n_0(); + static void TEST_strncmp_STOPS_AT_NUL(); + static void TEST_strcmp_SHIM_simple_string(); + static void TEST_strcmp_SHIM_string_view(); + static void TEST_strncmp_SHIM(); + +} /* anonymous namespace */ + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.stlsoft.std.cstring", verbosity)) + { + XTESTS_RUN_CASE(TEST_strcmp_CHAR); + XTESTS_RUN_CASE(TEST_strcmp_WCHAR); + XTESTS_RUN_CASE(TEST_strncmp_n_0); + XTESTS_RUN_CASE(TEST_strncmp_STOPS_AT_NUL); + XTESTS_RUN_CASE(TEST_strcmp_SHIM_simple_string); + XTESTS_RUN_CASE(TEST_strcmp_SHIM_string_view); + XTESTS_RUN_CASE(TEST_strncmp_SHIM); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace +{ + +static void TEST_strcmp_CHAR() +{ + unsigned char const below_u[] = { 0x01, 0 }; + unsigned char const above_u[] = { 0xFF, 0 }; + char const* const below = reinterpret_cast(below_u); + char const* const above = reinterpret_cast(above_u); + + TEST_INT_EQ(0, stlsoft::strcmp("abc", "abc")); + TEST_INT_EQ(0, stlsoft::strcmp("", "")); + TEST_INT_LT(0, stlsoft::strcmp("abc", "abd")); + TEST_INT_LT(0, stlsoft::strcmp("", "a")); + TEST_INT_GT(0, stlsoft::strcmp("abd", "abc")); + TEST_INT_GT(0, stlsoft::strcmp("a", "")); + TEST_INT_LT(0, stlsoft::strcmp("A", "a")); + TEST_INT_LT(0, stlsoft::strcmp(below, above)); +} + +static void TEST_strcmp_WCHAR() +{ + TEST_INT_EQ(0, stlsoft::strcmp(L"abc", L"abc")); + TEST_INT_EQ(0, stlsoft::strcmp(L"", L"")); + TEST_INT_LT(0, stlsoft::strcmp(L"abc", L"abd")); + TEST_INT_LT(0, stlsoft::strcmp(L"", L"a")); + TEST_INT_GT(0, stlsoft::strcmp(L"abd", L"abc")); + TEST_INT_GT(0, stlsoft::strcmp(L"a", L"")); + TEST_INT_LT(0, stlsoft::strcmp(L"A", L"a")); +} + +static void TEST_strncmp_n_0() +{ + TEST_INT_EQ(0, stlsoft::strncmp("abc", "xyz", 0)); + TEST_INT_EQ(0, stlsoft::strncmp("", "abc", 0)); + TEST_INT_EQ(0, stlsoft::strncmp("abX", "abY", 2)); + TEST_INT_LT(0, stlsoft::strncmp("abX", "abY", 3)); + + TEST_INT_EQ(0, stlsoft::strncmp(L"abc", L"xyz", 0)); + TEST_INT_EQ(0, stlsoft::strncmp(L"", L"abc", 0)); + TEST_INT_EQ(0, stlsoft::strncmp(L"abX", L"abY", 2)); + TEST_INT_LT(0, stlsoft::strncmp(L"abX", L"abY", 3)); +} + +static void TEST_strncmp_STOPS_AT_NUL() +{ + char const a1[] = { 'a', '\0', 'x' }; + char const a2[] = { 'a', '\0', 'y' }; + wchar_t const w1[] = { L'a', L'\0', L'x' }; + wchar_t const w2[] = { L'a', L'\0', L'y' }; + + TEST_INT_EQ(0, stlsoft::strncmp(a1, a2, 3)); + TEST_INT_EQ(0, stlsoft::strncmp(w1, w2, 3)); +} + +static void TEST_strcmp_SHIM_simple_string() +{ + stlsoft::simple_string const abc("abc"); + stlsoft::simple_string const abd("abd"); + stlsoft::simple_string const empty; + stlsoft::simple_wstring const wabc(L"abc"); + stlsoft::simple_wstring const wabd(L"abd"); + stlsoft::simple_wstring const wempty; + + TEST_INT_EQ(0, stlsoft::strcmp(abc, abc)); + TEST_INT_EQ(0, stlsoft::strcmp(empty, empty)); + TEST_INT_LT(0, stlsoft::strcmp(abc, abd)); + TEST_INT_LT(0, stlsoft::strcmp(empty, abc)); + TEST_INT_GT(0, stlsoft::strcmp(abd, abc)); + + TEST_INT_EQ(0, stlsoft::strcmp(wabc, wabc)); + TEST_INT_EQ(0, stlsoft::strcmp(wempty, wempty)); + TEST_INT_LT(0, stlsoft::strcmp(wabc, wabd)); + TEST_INT_GT(0, stlsoft::strcmp(wabd, wabc)); +} + +static void TEST_strcmp_SHIM_string_view() +{ + stlsoft::string_view const abc("abc"); + stlsoft::string_view const abd("abd"); + stlsoft::string_view const empty; + stlsoft::wstring_view const wabc(L"abc"); + stlsoft::wstring_view const wabd(L"abd"); + stlsoft::wstring_view const wempty; + + TEST_INT_EQ(0, stlsoft::strcmp(abc, abc)); + TEST_INT_EQ(0, stlsoft::strcmp(empty, empty)); + TEST_INT_LT(0, stlsoft::strcmp(abc, abd)); + TEST_INT_LT(0, stlsoft::strcmp(empty, abc)); + TEST_INT_GT(0, stlsoft::strcmp(abd, abc)); + + TEST_INT_EQ(0, stlsoft::strcmp(wabc, wabc)); + TEST_INT_EQ(0, stlsoft::strcmp(wempty, wempty)); + TEST_INT_LT(0, stlsoft::strcmp(wabc, wabd)); + TEST_INT_GT(0, stlsoft::strcmp(wabd, wabc)); +} + +static void TEST_strncmp_SHIM() +{ + char const a1[] = { 'a', '\0', 'x' }; + char const a2[] = { 'a', '\0', 'y' }; + wchar_t const w1[] = { L'a', L'\0', L'x' }; + wchar_t const w2[] = { L'a', L'\0', L'y' }; + + stlsoft::simple_string const abX("abX"); + stlsoft::simple_string const abY("abY"); + stlsoft::simple_string const embedded1(a1, 3); + stlsoft::simple_string const embedded2(a2, 3); + stlsoft::string_view const v1(a1, 3); + stlsoft::string_view const v2(a2, 3); + + stlsoft::simple_wstring const wabX(L"abX"); + stlsoft::simple_wstring const wabY(L"abY"); + stlsoft::simple_wstring const wembedded1(w1, 3); + stlsoft::simple_wstring const wembedded2(w2, 3); + stlsoft::wstring_view const wv1(w1, 3); + stlsoft::wstring_view const wv2(w2, 3); + + TEST_INT_EQ(0, stlsoft::strncmp(abX, abY, 0)); + TEST_INT_EQ(0, stlsoft::strncmp(abX, abY, 2)); + TEST_INT_LT(0, stlsoft::strncmp(abX, abY, 3)); + TEST_INT_EQ(0, stlsoft::strncmp(embedded1, embedded2, 3)); + TEST_INT_EQ(0, stlsoft::strncmp(v1, v2, 3)); + + TEST_INT_EQ(0, stlsoft::strncmp(wabX, wabY, 0)); + TEST_INT_EQ(0, stlsoft::strncmp(wabX, wabY, 2)); + TEST_INT_LT(0, stlsoft::strncmp(wabX, wabY, 3)); + TEST_INT_EQ(0, stlsoft::strncmp(wembedded1, wembedded2, 3)); + TEST_INT_EQ(0, stlsoft::strncmp(wv1, wv2, 3)); +} + +} /* anonymous namespace */ + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/stlsoft/string/CMakeLists.txt b/test/unit/stlsoft/string/CMakeLists.txt index 682c6f42..cff73bc9 100644 --- a/test/unit/stlsoft/string/CMakeLists.txt +++ b/test/unit/stlsoft/string/CMakeLists.txt @@ -1,8 +1,14 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(c_string.strnicmp) +add_subdirectory(c_string.strnicmp.C) +add_subdirectory(c_string_traits) +add_subdirectory(char_traits) add_subdirectory(copy_functions) add_subdirectory(exception_string) +add_subdirectory(functionals.string_begins_with) add_subdirectory(shim_string) add_subdirectory(simple_string) +add_subdirectory(special_string_instance) add_subdirectory(static_string) add_subdirectory(string_slice) add_subdirectory(string_view) diff --git a/test/unit/stlsoft/string/c_string.strnicmp.C/CMakeLists.txt b/test/unit/stlsoft/string/c_string.strnicmp.C/CMakeLists.txt new file mode 100644 index 00000000..bc97fbb7 --- /dev/null +++ b/test/unit/stlsoft/string/c_string.strnicmp.C/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.unit.stlsoft.string.c_string.strnicmp.C entry.c) diff --git a/test/unit/stlsoft/string/c_string.strnicmp.C/entry.c b/test/unit/stlsoft/string/c_string.strnicmp.C/entry.c new file mode 100644 index 00000000..3184f3ab --- /dev/null +++ b/test/unit/stlsoft/string/c_string.strnicmp.C/entry.c @@ -0,0 +1,223 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: c_string.strnicmp.C/entry.c + * + * Purpose: Unit-tests for stlsoft_C_strnicmp() and stlsoft_C_wcsnicmp(). + * + * Created: 29th September 2026 + * Updated: 29th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * test component header file include(s) + */ + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include +#include + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +static void TEST_stlsoft_C_strnicmp_EQUAL(void); +static void TEST_stlsoft_C_strnicmp_LESS(void); +static void TEST_stlsoft_C_strnicmp_GREATER(void); +static void TEST_stlsoft_C_strnicmp_n_0(void); +static void TEST_stlsoft_C_strnicmp_STOPS_AT_NUL(void); +static void TEST_stlsoft_C_strnicmp_IGNORES_BYTE_PAST_n(void); +static void TEST_stlsoft_C_strnicmp_ASCII_CASE_FOLD(void); +static void TEST_stlsoft_C_strnicmp_HIGH_BIT(void); +static void TEST_stlsoft_C_wcsnicmp_EQUAL(void); +static void TEST_stlsoft_C_wcsnicmp_LESS(void); +static void TEST_stlsoft_C_wcsnicmp_GREATER(void); +static void TEST_stlsoft_C_wcsnicmp_n_0(void); +static void TEST_stlsoft_C_wcsnicmp_STOPS_AT_NUL(void); +static void TEST_stlsoft_C_wcsnicmp_IGNORES_BYTE_PAST_n(void); +static void TEST_stlsoft_C_wcsnicmp_ASCII_CASE_FOLD(void); +static void TEST_stlsoft_C_wcsnicmp_HIGH_BIT(void); + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.stlsoft.string.c_string.strnicmp.C", verbosity)) + { + XTESTS_RUN_CASE(TEST_stlsoft_C_strnicmp_EQUAL); + XTESTS_RUN_CASE(TEST_stlsoft_C_strnicmp_LESS); + XTESTS_RUN_CASE(TEST_stlsoft_C_strnicmp_GREATER); + XTESTS_RUN_CASE(TEST_stlsoft_C_strnicmp_n_0); + XTESTS_RUN_CASE(TEST_stlsoft_C_strnicmp_STOPS_AT_NUL); + XTESTS_RUN_CASE(TEST_stlsoft_C_strnicmp_IGNORES_BYTE_PAST_n); + XTESTS_RUN_CASE(TEST_stlsoft_C_strnicmp_ASCII_CASE_FOLD); + XTESTS_RUN_CASE(TEST_stlsoft_C_strnicmp_HIGH_BIT); + XTESTS_RUN_CASE(TEST_stlsoft_C_wcsnicmp_EQUAL); + XTESTS_RUN_CASE(TEST_stlsoft_C_wcsnicmp_LESS); + XTESTS_RUN_CASE(TEST_stlsoft_C_wcsnicmp_GREATER); + XTESTS_RUN_CASE(TEST_stlsoft_C_wcsnicmp_n_0); + XTESTS_RUN_CASE(TEST_stlsoft_C_wcsnicmp_STOPS_AT_NUL); + XTESTS_RUN_CASE(TEST_stlsoft_C_wcsnicmp_IGNORES_BYTE_PAST_n); + XTESTS_RUN_CASE(TEST_stlsoft_C_wcsnicmp_ASCII_CASE_FOLD); + XTESTS_RUN_CASE(TEST_stlsoft_C_wcsnicmp_HIGH_BIT); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +static void TEST_stlsoft_C_strnicmp_EQUAL(void) +{ + TEST_INT_EQ(0, stlsoft_C_strnicmp("abc", "abc", 3)); + TEST_INT_EQ(0, stlsoft_C_strnicmp("abc", "abc", 10)); + TEST_INT_EQ(0, stlsoft_C_strnicmp("", "", 1)); +} + +static void TEST_stlsoft_C_strnicmp_LESS(void) +{ + TEST_INT_LT(0, stlsoft_C_strnicmp("abc", "abd", 3)); + TEST_INT_LT(0, stlsoft_C_strnicmp("ab", "abc", 3)); +} + +static void TEST_stlsoft_C_strnicmp_GREATER(void) +{ + TEST_INT_GT(0, stlsoft_C_strnicmp("abd", "abc", 3)); + TEST_INT_GT(0, stlsoft_C_strnicmp("abc", "ab", 3)); +} + +static void TEST_stlsoft_C_strnicmp_n_0(void) +{ + TEST_INT_EQ(0, stlsoft_C_strnicmp("abc", "xyz", 0)); + TEST_INT_EQ(0, stlsoft_C_strnicmp("", "abc", 0)); +} + +static void TEST_stlsoft_C_strnicmp_STOPS_AT_NUL(void) +{ + char const s1[] = { 'a', '\0', 'x' }; + char const s2[] = { 'a', '\0', 'y' }; + + TEST_INT_EQ(0, stlsoft_C_strnicmp(s1, s2, 3)); +} + +static void TEST_stlsoft_C_strnicmp_IGNORES_BYTE_PAST_n(void) +{ + TEST_INT_EQ(0, stlsoft_C_strnicmp("abX", "abY", 2)); + TEST_INT_LT(0, stlsoft_C_strnicmp("abX", "abY", 3)); +} + +static void TEST_stlsoft_C_strnicmp_ASCII_CASE_FOLD(void) +{ + TEST_INT_EQ(0, stlsoft_C_strnicmp("AbC", "aBc", 3)); + TEST_INT_EQ(0, stlsoft_C_strnicmp("AbC", "aBc", 10)); + TEST_INT_LT(0, stlsoft_C_strnicmp("abC", "aBd", 3)); + TEST_INT_GT(0, stlsoft_C_strnicmp("B", "a", 1)); +} + +static void TEST_stlsoft_C_strnicmp_HIGH_BIT(void) +{ + unsigned char const same1_u[] = { 0xE9, 'A', 0 }; + unsigned char const same2_u[] = { 0xE9, 'a', 0 }; + unsigned char const later_u[] = { 0xE9, 'B', 0 }; + unsigned char const lo_u[] = { 0xE1, 0 }; + unsigned char const hi_u[] = { 0xE2, 0 }; + char const* const same1 = (char const*)same1_u; + char const* const same2 = (char const*)same2_u; + char const* const later = (char const*)later_u; + char const* const lo = (char const*)lo_u; + char const* const hi = (char const*)hi_u; + + TEST_INT_EQ(0, stlsoft_C_strnicmp(same1, same2, 2)); + TEST_INT_LT(0, stlsoft_C_strnicmp(same1, later, 2)); + TEST_INT_LT(0, stlsoft_C_strnicmp(lo, hi, 1)); + TEST_INT_GT(0, stlsoft_C_strnicmp(hi, lo, 1)); +} + +static void TEST_stlsoft_C_wcsnicmp_EQUAL(void) +{ + TEST_INT_EQ(0, stlsoft_C_wcsnicmp(L"abc", L"abc", 3)); + TEST_INT_EQ(0, stlsoft_C_wcsnicmp(L"abc", L"abc", 10)); + TEST_INT_EQ(0, stlsoft_C_wcsnicmp(L"", L"", 1)); +} + +static void TEST_stlsoft_C_wcsnicmp_LESS(void) +{ + TEST_INT_LT(0, stlsoft_C_wcsnicmp(L"abc", L"abd", 3)); + TEST_INT_LT(0, stlsoft_C_wcsnicmp(L"ab", L"abc", 3)); +} + +static void TEST_stlsoft_C_wcsnicmp_GREATER(void) +{ + TEST_INT_GT(0, stlsoft_C_wcsnicmp(L"abd", L"abc", 3)); + TEST_INT_GT(0, stlsoft_C_wcsnicmp(L"abc", L"ab", 3)); +} + +static void TEST_stlsoft_C_wcsnicmp_n_0(void) +{ + TEST_INT_EQ(0, stlsoft_C_wcsnicmp(L"abc", L"xyz", 0)); + TEST_INT_EQ(0, stlsoft_C_wcsnicmp(L"", L"abc", 0)); +} + +static void TEST_stlsoft_C_wcsnicmp_STOPS_AT_NUL(void) +{ + wchar_t const s1[] = { L'a', L'\0', L'x' }; + wchar_t const s2[] = { L'a', L'\0', L'y' }; + + TEST_INT_EQ(0, stlsoft_C_wcsnicmp(s1, s2, 3)); +} + +static void TEST_stlsoft_C_wcsnicmp_IGNORES_BYTE_PAST_n(void) +{ + TEST_INT_EQ(0, stlsoft_C_wcsnicmp(L"abX", L"abY", 2)); + TEST_INT_LT(0, stlsoft_C_wcsnicmp(L"abX", L"abY", 3)); +} + +static void TEST_stlsoft_C_wcsnicmp_ASCII_CASE_FOLD(void) +{ + TEST_INT_EQ(0, stlsoft_C_wcsnicmp(L"AbC", L"aBc", 3)); + TEST_INT_EQ(0, stlsoft_C_wcsnicmp(L"AbC", L"aBc", 10)); + TEST_INT_LT(0, stlsoft_C_wcsnicmp(L"abC", L"aBd", 3)); + TEST_INT_GT(0, stlsoft_C_wcsnicmp(L"B", L"a", 1)); +} + +static void TEST_stlsoft_C_wcsnicmp_HIGH_BIT(void) +{ + wchar_t const same1[] = { L'\x00E9', L'A', L'\0' }; + wchar_t const same2[] = { L'\x00E9', L'a', L'\0' }; + wchar_t const later[] = { L'\x00E9', L'B', L'\0' }; + wchar_t const lo[] = { L'\x00E1', L'\0' }; + wchar_t const hi[] = { L'\x00E2', L'\0' }; + + TEST_INT_EQ(0, stlsoft_C_wcsnicmp(same1, same2, 2)); + TEST_INT_LT(0, stlsoft_C_wcsnicmp(same1, later, 2)); + TEST_INT_LT(0, stlsoft_C_wcsnicmp(lo, hi, 1)); + TEST_INT_GT(0, stlsoft_C_wcsnicmp(hi, lo, 1)); +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/stlsoft/string/c_string.strnicmp/CMakeLists.txt b/test/unit/stlsoft/string/c_string.strnicmp/CMakeLists.txt new file mode 100644 index 00000000..bb0bc58b --- /dev/null +++ b/test/unit/stlsoft/string/c_string.strnicmp/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.unit.stlsoft.string.c_string.strnicmp entry.cpp) diff --git a/test/unit/stlsoft/string/c_string.strnicmp/entry.cpp b/test/unit/stlsoft/string/c_string.strnicmp/entry.cpp new file mode 100644 index 00000000..35c7108a --- /dev/null +++ b/test/unit/stlsoft/string/c_string.strnicmp/entry.cpp @@ -0,0 +1,245 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: c_string.strnicmp/entry.cpp + * + * Purpose: Unit-tests for stlsoft::c_string::strnicmp() and wcsnicmp(). + * + * Created: 29th September 2026 + * Updated: 29th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * test component header file include(s) + */ + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include +#include + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace +{ + + static void TEST_c_string_strnicmp_EQUAL(); + static void TEST_c_string_strnicmp_LESS(); + static void TEST_c_string_strnicmp_GREATER(); + static void TEST_c_string_strnicmp_n_0(); + static void TEST_c_string_strnicmp_STOPS_AT_NUL(); + static void TEST_c_string_strnicmp_IGNORES_BYTE_PAST_n(); + static void TEST_c_string_strnicmp_ASCII_CASE_FOLD(); + static void TEST_c_string_strnicmp_HIGH_BIT(); + static void TEST_c_string_wcsnicmp_EQUAL(); + static void TEST_c_string_wcsnicmp_LESS(); + static void TEST_c_string_wcsnicmp_GREATER(); + static void TEST_c_string_wcsnicmp_n_0(); + static void TEST_c_string_wcsnicmp_STOPS_AT_NUL(); + static void TEST_c_string_wcsnicmp_IGNORES_BYTE_PAST_n(); + static void TEST_c_string_wcsnicmp_ASCII_CASE_FOLD(); + static void TEST_c_string_wcsnicmp_HIGH_BIT(); + + static int wcsnicmp_both_(wchar_t const* s1, wchar_t const* s2, size_t n); + +} /* anonymous namespace */ + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.stlsoft.string.c_string.strnicmp", verbosity)) + { + XTESTS_RUN_CASE(TEST_c_string_strnicmp_EQUAL); + XTESTS_RUN_CASE(TEST_c_string_strnicmp_LESS); + XTESTS_RUN_CASE(TEST_c_string_strnicmp_GREATER); + XTESTS_RUN_CASE(TEST_c_string_strnicmp_n_0); + XTESTS_RUN_CASE(TEST_c_string_strnicmp_STOPS_AT_NUL); + XTESTS_RUN_CASE(TEST_c_string_strnicmp_IGNORES_BYTE_PAST_n); + XTESTS_RUN_CASE(TEST_c_string_strnicmp_ASCII_CASE_FOLD); + XTESTS_RUN_CASE(TEST_c_string_strnicmp_HIGH_BIT); + XTESTS_RUN_CASE(TEST_c_string_wcsnicmp_EQUAL); + XTESTS_RUN_CASE(TEST_c_string_wcsnicmp_LESS); + XTESTS_RUN_CASE(TEST_c_string_wcsnicmp_GREATER); + XTESTS_RUN_CASE(TEST_c_string_wcsnicmp_n_0); + XTESTS_RUN_CASE(TEST_c_string_wcsnicmp_STOPS_AT_NUL); + XTESTS_RUN_CASE(TEST_c_string_wcsnicmp_IGNORES_BYTE_PAST_n); + XTESTS_RUN_CASE(TEST_c_string_wcsnicmp_ASCII_CASE_FOLD); + XTESTS_RUN_CASE(TEST_c_string_wcsnicmp_HIGH_BIT); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace +{ + +static int wcsnicmp_both_(wchar_t const* s1, wchar_t const* s2, size_t n) +{ + int const via_str = stlsoft::c_string::strnicmp(s1, s2, n); + int const via_wcs = stlsoft::c_string::wcsnicmp(s1, s2, n); + + TEST_INT_EQ(via_wcs, via_str); + + return via_wcs; +} + +static void TEST_c_string_strnicmp_EQUAL() +{ + TEST_INT_EQ(0, stlsoft::c_string::strnicmp("abc", "abc", 3)); + TEST_INT_EQ(0, stlsoft::c_string::strnicmp("abc", "abc", 10)); + TEST_INT_EQ(0, stlsoft::c_string::strnicmp("", "", 1)); +} + +static void TEST_c_string_strnicmp_LESS() +{ + TEST_INT_LT(0, stlsoft::c_string::strnicmp("abc", "abd", 3)); + TEST_INT_LT(0, stlsoft::c_string::strnicmp("ab", "abc", 3)); +} + +static void TEST_c_string_strnicmp_GREATER() +{ + TEST_INT_GT(0, stlsoft::c_string::strnicmp("abd", "abc", 3)); + TEST_INT_GT(0, stlsoft::c_string::strnicmp("abc", "ab", 3)); +} + +static void TEST_c_string_strnicmp_n_0() +{ + TEST_INT_EQ(0, stlsoft::c_string::strnicmp("abc", "xyz", 0)); + TEST_INT_EQ(0, stlsoft::c_string::strnicmp("", "abc", 0)); +} + +static void TEST_c_string_strnicmp_STOPS_AT_NUL() +{ + char const s1[] = { 'a', '\0', 'x' }; + char const s2[] = { 'a', '\0', 'y' }; + + TEST_INT_EQ(0, stlsoft::c_string::strnicmp(s1, s2, 3)); +} + +static void TEST_c_string_strnicmp_IGNORES_BYTE_PAST_n() +{ + TEST_INT_EQ(0, stlsoft::c_string::strnicmp("abX", "abY", 2)); + TEST_INT_LT(0, stlsoft::c_string::strnicmp("abX", "abY", 3)); +} + +static void TEST_c_string_strnicmp_ASCII_CASE_FOLD() +{ + TEST_INT_EQ(0, stlsoft::c_string::strnicmp("AbC", "aBc", 3)); + TEST_INT_EQ(0, stlsoft::c_string::strnicmp("AbC", "aBc", 10)); + TEST_INT_LT(0, stlsoft::c_string::strnicmp("abC", "aBd", 3)); + TEST_INT_GT(0, stlsoft::c_string::strnicmp("B", "a", 1)); +} + +static void TEST_c_string_strnicmp_HIGH_BIT() +{ + unsigned char const same1_u[] = { 0xE9, 'A', 0 }; + unsigned char const same2_u[] = { 0xE9, 'a', 0 }; + unsigned char const later_u[] = { 0xE9, 'B', 0 }; + unsigned char const lo_u[] = { 0xE1, 0 }; + unsigned char const hi_u[] = { 0xE2, 0 }; + char const* const same1 = reinterpret_cast(same1_u); + char const* const same2 = reinterpret_cast(same2_u); + char const* const later = reinterpret_cast(later_u); + char const* const lo = reinterpret_cast(lo_u); + char const* const hi = reinterpret_cast(hi_u); + + TEST_INT_EQ(0, stlsoft::c_string::strnicmp(same1, same2, 2)); + TEST_INT_LT(0, stlsoft::c_string::strnicmp(same1, later, 2)); + TEST_INT_LT(0, stlsoft::c_string::strnicmp(lo, hi, 1)); + TEST_INT_GT(0, stlsoft::c_string::strnicmp(hi, lo, 1)); +} + +static void TEST_c_string_wcsnicmp_EQUAL() +{ + TEST_INT_EQ(0, wcsnicmp_both_(L"abc", L"abc", 3)); + TEST_INT_EQ(0, wcsnicmp_both_(L"abc", L"abc", 10)); + TEST_INT_EQ(0, wcsnicmp_both_(L"", L"", 1)); +} + +static void TEST_c_string_wcsnicmp_LESS() +{ + TEST_INT_LT(0, wcsnicmp_both_(L"abc", L"abd", 3)); + TEST_INT_LT(0, wcsnicmp_both_(L"ab", L"abc", 3)); +} + +static void TEST_c_string_wcsnicmp_GREATER() +{ + TEST_INT_GT(0, wcsnicmp_both_(L"abd", L"abc", 3)); + TEST_INT_GT(0, wcsnicmp_both_(L"abc", L"ab", 3)); +} + +static void TEST_c_string_wcsnicmp_n_0() +{ + TEST_INT_EQ(0, wcsnicmp_both_(L"abc", L"xyz", 0)); + TEST_INT_EQ(0, wcsnicmp_both_(L"", L"abc", 0)); +} + +static void TEST_c_string_wcsnicmp_STOPS_AT_NUL() +{ + wchar_t const s1[] = { L'a', L'\0', L'x' }; + wchar_t const s2[] = { L'a', L'\0', L'y' }; + + TEST_INT_EQ(0, wcsnicmp_both_(s1, s2, 3)); +} + +static void TEST_c_string_wcsnicmp_IGNORES_BYTE_PAST_n() +{ + TEST_INT_EQ(0, wcsnicmp_both_(L"abX", L"abY", 2)); + TEST_INT_LT(0, wcsnicmp_both_(L"abX", L"abY", 3)); +} + +static void TEST_c_string_wcsnicmp_ASCII_CASE_FOLD() +{ + TEST_INT_EQ(0, wcsnicmp_both_(L"AbC", L"aBc", 3)); + TEST_INT_EQ(0, wcsnicmp_both_(L"AbC", L"aBc", 10)); + TEST_INT_LT(0, wcsnicmp_both_(L"abC", L"aBd", 3)); + TEST_INT_GT(0, wcsnicmp_both_(L"B", L"a", 1)); +} + +static void TEST_c_string_wcsnicmp_HIGH_BIT() +{ + wchar_t const same1[] = { L'\x00E9', L'A', L'\0' }; + wchar_t const same2[] = { L'\x00E9', L'a', L'\0' }; + wchar_t const later[] = { L'\x00E9', L'B', L'\0' }; + wchar_t const lo[] = { L'\x00E1', L'\0' }; + wchar_t const hi[] = { L'\x00E2', L'\0' }; + + TEST_INT_EQ(0, wcsnicmp_both_(same1, same2, 2)); + TEST_INT_LT(0, wcsnicmp_both_(same1, later, 2)); + TEST_INT_LT(0, wcsnicmp_both_(lo, hi, 1)); + TEST_INT_GT(0, wcsnicmp_both_(hi, lo, 1)); +} + +} /* anonymous namespace */ + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/stlsoft/string/c_string_traits/CMakeLists.txt b/test/unit/stlsoft/string/c_string_traits/CMakeLists.txt new file mode 100644 index 00000000..9da8587e --- /dev/null +++ b/test/unit/stlsoft/string/c_string_traits/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.unit.stlsoft.string.c_string_traits entry.cpp) diff --git a/test/unit/stlsoft/string/c_string_traits/entry.cpp b/test/unit/stlsoft/string/c_string_traits/entry.cpp new file mode 100644 index 00000000..67fef21d --- /dev/null +++ b/test/unit/stlsoft/string/c_string_traits/entry.cpp @@ -0,0 +1,174 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: c_string_traits/entry.cpp + * + * Purpose: Unit-tests for stlsoft::c_string_traits compare functions. + * + * Created: 29th September 2026 + * Updated: 29th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * test component header file include(s) + */ + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include +#include + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace +{ + + static void TEST_str_compare_CHAR(); + static void TEST_str_compare_WCHAR(); + static void TEST_str_n_compare_n_0(); + static void TEST_str_n_compare_STOPS_AT_NUL(); + static void TEST_str_n_compare_IGNORES_BYTE_PAST_n(); + static void TEST_str_compare_no_case_ASCII(); + static void TEST_str_n_compare_no_case_ASCII(); + +} /* anonymous namespace */ + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.stlsoft.string.c_string_traits", verbosity)) + { + XTESTS_RUN_CASE(TEST_str_compare_CHAR); + XTESTS_RUN_CASE(TEST_str_compare_WCHAR); + XTESTS_RUN_CASE(TEST_str_n_compare_n_0); + XTESTS_RUN_CASE(TEST_str_n_compare_STOPS_AT_NUL); + XTESTS_RUN_CASE(TEST_str_n_compare_IGNORES_BYTE_PAST_n); + XTESTS_RUN_CASE(TEST_str_compare_no_case_ASCII); + XTESTS_RUN_CASE(TEST_str_n_compare_no_case_ASCII); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace +{ + +typedef stlsoft::c_string_traits a_traits_t; +typedef stlsoft::c_string_traits w_traits_t; + +static void TEST_str_compare_CHAR() +{ + TEST_INT_EQ(0, a_traits_t::str_compare("abc", "abc")); + TEST_INT_EQ(0, a_traits_t::str_compare("", "")); + TEST_INT_LT(0, a_traits_t::str_compare("abc", "abd")); + TEST_INT_LT(0, a_traits_t::str_compare("", "a")); + TEST_INT_GT(0, a_traits_t::str_compare("abd", "abc")); + TEST_INT_GT(0, a_traits_t::str_compare("abc", "ab")); + TEST_INT_LT(0, a_traits_t::str_compare("A", "a")); + TEST_INT_NE(0, a_traits_t::str_compare("AbC", "aBc")); +} + +static void TEST_str_compare_WCHAR() +{ + TEST_INT_EQ(0, w_traits_t::str_compare(L"abc", L"abc")); + TEST_INT_EQ(0, w_traits_t::str_compare(L"", L"")); + TEST_INT_LT(0, w_traits_t::str_compare(L"abc", L"abd")); + TEST_INT_LT(0, w_traits_t::str_compare(L"", L"a")); + TEST_INT_GT(0, w_traits_t::str_compare(L"abd", L"abc")); + TEST_INT_GT(0, w_traits_t::str_compare(L"abc", L"ab")); + TEST_INT_LT(0, w_traits_t::str_compare(L"A", L"a")); + TEST_INT_NE(0, w_traits_t::str_compare(L"AbC", L"aBc")); +} + +static void TEST_str_n_compare_n_0() +{ + TEST_INT_EQ(0, a_traits_t::str_n_compare("abc", "xyz", 0)); + TEST_INT_EQ(0, a_traits_t::str_n_compare("", "abc", 0)); + TEST_INT_EQ(0, w_traits_t::str_n_compare(L"abc", L"xyz", 0)); + TEST_INT_EQ(0, w_traits_t::str_n_compare(L"", L"abc", 0)); +} + +static void TEST_str_n_compare_STOPS_AT_NUL() +{ + char const a1[] = { 'a', '\0', 'x' }; + char const a2[] = { 'a', '\0', 'y' }; + wchar_t const w1[] = { L'a', L'\0', L'x' }; + wchar_t const w2[] = { L'a', L'\0', L'y' }; + + TEST_INT_EQ(0, a_traits_t::str_n_compare(a1, a2, 3)); + TEST_INT_EQ(0, w_traits_t::str_n_compare(w1, w2, 3)); +} + +static void TEST_str_n_compare_IGNORES_BYTE_PAST_n() +{ + TEST_INT_EQ(0, a_traits_t::str_n_compare("abX", "abY", 2)); + TEST_INT_LT(0, a_traits_t::str_n_compare("abX", "abY", 3)); + TEST_INT_EQ(0, w_traits_t::str_n_compare(L"abX", L"abY", 2)); + TEST_INT_LT(0, w_traits_t::str_n_compare(L"abX", L"abY", 3)); +} + +static void TEST_str_compare_no_case_ASCII() +{ + TEST_INT_EQ(0, a_traits_t::str_compare_no_case("AbC", "aBc")); + TEST_INT_EQ(0, a_traits_t::str_compare_no_case("", "")); + TEST_INT_LT(0, a_traits_t::str_compare_no_case("abC", "aBd")); + TEST_INT_GT(0, a_traits_t::str_compare_no_case("B", "a")); + TEST_INT_EQ(0, w_traits_t::str_compare_no_case(L"AbC", L"aBc")); + TEST_INT_EQ(0, w_traits_t::str_compare_no_case(L"", L"")); + TEST_INT_LT(0, w_traits_t::str_compare_no_case(L"abC", L"aBd")); + TEST_INT_GT(0, w_traits_t::str_compare_no_case(L"B", L"a")); +} + +static void TEST_str_n_compare_no_case_ASCII() +{ + char const a1[] = { 'A', '\0', 'x' }; + char const a2[] = { 'a', '\0', 'y' }; + wchar_t const w1[] = { L'A', L'\0', L'x' }; + wchar_t const w2[] = { L'a', L'\0', L'y' }; + + TEST_INT_EQ(0, a_traits_t::str_n_compare_no_case("abc", "XYZ", 0)); + TEST_INT_EQ(0, a_traits_t::str_n_compare_no_case("AbC", "aBc", 3)); + TEST_INT_EQ(0, a_traits_t::str_n_compare_no_case("abX", "ABY", 2)); + TEST_INT_LT(0, a_traits_t::str_n_compare_no_case("abC", "aBd", 3)); + TEST_INT_EQ(0, a_traits_t::str_n_compare_no_case(a1, a2, 3)); + + TEST_INT_EQ(0, w_traits_t::str_n_compare_no_case(L"abc", L"XYZ", 0)); + TEST_INT_EQ(0, w_traits_t::str_n_compare_no_case(L"AbC", L"aBc", 3)); + TEST_INT_EQ(0, w_traits_t::str_n_compare_no_case(L"abX", L"ABY", 2)); + TEST_INT_LT(0, w_traits_t::str_n_compare_no_case(L"abC", L"aBd", 3)); + TEST_INT_EQ(0, w_traits_t::str_n_compare_no_case(w1, w2, 3)); +} + +} /* anonymous namespace */ + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/stlsoft/string/char_traits/CMakeLists.txt b/test/unit/stlsoft/string/char_traits/CMakeLists.txt new file mode 100644 index 00000000..219ec893 --- /dev/null +++ b/test/unit/stlsoft/string/char_traits/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.unit.stlsoft.string.char_traits entry.cpp) diff --git a/test/unit/stlsoft/string/char_traits/entry.cpp b/test/unit/stlsoft/string/char_traits/entry.cpp new file mode 100644 index 00000000..4fd98757 --- /dev/null +++ b/test/unit/stlsoft/string/char_traits/entry.cpp @@ -0,0 +1,288 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: char_traits/entry.cpp + * + * Purpose: Unit-tests for stlsoft::char_traits and char_traits_safe. + * + * Created: 29th September 2026 + * Updated: 29th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * test component header file include(s) + */ + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include +#include + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace +{ + + static void TEST_eq_AND_lt(); + static void TEST_compare_EQUAL(); + static void TEST_compare_LESS(); + static void TEST_compare_GREATER(); + static void TEST_compare_n_0(); + static void TEST_compare_EXACT_n_SEES_BYTE_AFTER_NUL(); + static void TEST_compare_max_STOPS_AT_NUL(); + static void TEST_compare_null_BOTH_NULL(); + static void TEST_compare_null_ONE_NULL(); + static void TEST_compare_HIGH_BIT_UNSIGNED_ORDER(); + static void TEST_char_traits_safe_compare(); + static void TEST_char_traits_safe_compare_NULL(); + +} /* anonymous namespace */ + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.stlsoft.string.char_traits", verbosity)) + { + XTESTS_RUN_CASE(TEST_eq_AND_lt); + XTESTS_RUN_CASE(TEST_compare_EQUAL); + XTESTS_RUN_CASE(TEST_compare_LESS); + XTESTS_RUN_CASE(TEST_compare_GREATER); + XTESTS_RUN_CASE(TEST_compare_n_0); + XTESTS_RUN_CASE(TEST_compare_EXACT_n_SEES_BYTE_AFTER_NUL); + XTESTS_RUN_CASE(TEST_compare_max_STOPS_AT_NUL); + XTESTS_RUN_CASE(TEST_compare_null_BOTH_NULL); + XTESTS_RUN_CASE(TEST_compare_null_ONE_NULL); + XTESTS_RUN_CASE(TEST_compare_HIGH_BIT_UNSIGNED_ORDER); + XTESTS_RUN_CASE(TEST_char_traits_safe_compare); + XTESTS_RUN_CASE(TEST_char_traits_safe_compare_NULL); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace +{ + +typedef stlsoft::char_traits a_traits_t; +typedef stlsoft::char_traits w_traits_t; +typedef stlsoft::char_traits_safe a_safe_t; +typedef stlsoft::char_traits_safe w_safe_t; + +static void TEST_eq_AND_lt() +{ + TEST_BOOLEAN_TRUE(a_traits_t::eq('a', 'a')); + TEST_BOOLEAN_FALSE(a_traits_t::eq('a', 'b')); + TEST_BOOLEAN_TRUE(a_traits_t::lt('a', 'b')); + TEST_BOOLEAN_FALSE(a_traits_t::lt('b', 'a')); + TEST_BOOLEAN_FALSE(a_traits_t::lt('a', 'a')); + + TEST_BOOLEAN_TRUE(w_traits_t::eq(L'a', L'a')); + TEST_BOOLEAN_FALSE(w_traits_t::eq(L'a', L'b')); + TEST_BOOLEAN_TRUE(w_traits_t::lt(L'a', L'b')); + TEST_BOOLEAN_FALSE(w_traits_t::lt(L'b', L'a')); + TEST_BOOLEAN_FALSE(w_traits_t::lt(L'a', L'a')); +} + +static void TEST_compare_EQUAL() +{ + TEST_INT_EQ(0, a_traits_t::compare("abc", "abc", 3)); + TEST_INT_EQ(0, a_traits_t::compare("abcd", "abce", 3)); + TEST_INT_EQ(0, a_traits_t::compare("", "", 1)); + + TEST_INT_EQ(0, w_traits_t::compare(L"abc", L"abc", 3)); + TEST_INT_EQ(0, w_traits_t::compare(L"abcd", L"abce", 3)); + TEST_INT_EQ(0, w_traits_t::compare(L"", L"", 1)); +} + +static void TEST_compare_LESS() +{ + TEST_INT_LT(0, a_traits_t::compare("abc", "abd", 3)); + TEST_INT_LT(0, a_traits_t::compare("ab", "abc", 3)); + + TEST_INT_LT(0, w_traits_t::compare(L"abc", L"abd", 3)); + TEST_INT_LT(0, w_traits_t::compare(L"ab", L"abc", 3)); +} + +static void TEST_compare_GREATER() +{ + TEST_INT_GT(0, a_traits_t::compare("abd", "abc", 3)); + TEST_INT_GT(0, a_traits_t::compare("abc", "ab", 3)); + + TEST_INT_GT(0, w_traits_t::compare(L"abd", L"abc", 3)); + TEST_INT_GT(0, w_traits_t::compare(L"abc", L"ab", 3)); +} + +static void TEST_compare_n_0() +{ + TEST_INT_EQ(0, a_traits_t::compare("abc", "xyz", 0)); + TEST_INT_EQ(0, a_traits_t::compare(NULL, NULL, 0)); + TEST_INT_EQ(0, a_traits_t::compare_max("abc", "xyz", 0)); + + TEST_INT_EQ(0, w_traits_t::compare(L"abc", L"xyz", 0)); + TEST_INT_EQ(0, w_traits_t::compare(NULL, NULL, 0)); + TEST_INT_EQ(0, w_traits_t::compare_max(L"abc", L"xyz", 0)); +} + +static void TEST_compare_EXACT_n_SEES_BYTE_AFTER_NUL() +{ + char const a1[] = { 'a', '\0', 'd' }; + char const a2[] = { 'a', '\0', 'e' }; + wchar_t const w1[] = { L'a', L'\0', L'd' }; + wchar_t const w2[] = { L'a', L'\0', L'e' }; + + TEST_INT_LT(0, a_traits_t::compare(a1, a2, 3)); + TEST_INT_LT(0, w_traits_t::compare(w1, w2, 3)); +} + +static void TEST_compare_max_STOPS_AT_NUL() +{ + char const a1[] = { 'a', '\0', 'd' }; + char const a2[] = { 'a', '\0', 'e' }; + wchar_t const w1[] = { L'a', L'\0', L'd' }; + wchar_t const w2[] = { L'a', L'\0', L'e' }; + + TEST_INT_EQ(0, a_traits_t::compare_max(a1, a2, 3)); + TEST_INT_EQ(0, a_traits_t::compare_max("abc", "abc", 3)); + TEST_INT_LT(0, a_traits_t::compare_max("abc", "abd", 3)); + + TEST_INT_EQ(0, w_traits_t::compare_max(w1, w2, 3)); + TEST_INT_EQ(0, w_traits_t::compare_max(L"abc", L"abc", 3)); + TEST_INT_LT(0, w_traits_t::compare_max(L"abc", L"abd", 3)); +} + +static void TEST_compare_null_BOTH_NULL() +{ + TEST_INT_EQ(0, a_traits_t::compare_null(NULL, NULL, 0)); + TEST_INT_EQ(0, a_traits_t::compare_null(NULL, NULL, 4)); + TEST_INT_EQ(0, w_traits_t::compare_null(NULL, NULL, 0)); + TEST_INT_EQ(0, w_traits_t::compare_null(NULL, NULL, 4)); +} + +static void TEST_compare_null_ONE_NULL() +{ + TEST_INT_EQ(-1, a_traits_t::compare_null(NULL, "a", 0)); + TEST_INT_EQ(-1, a_traits_t::compare_null(NULL, "a", 1)); + TEST_INT_EQ(1, a_traits_t::compare_null("a", NULL, 0)); + TEST_INT_EQ(1, a_traits_t::compare_null("a", NULL, 1)); + TEST_INT_LT(0, a_traits_t::compare_null("abc", "abd", 3)); + + TEST_INT_EQ(-1, w_traits_t::compare_null(NULL, L"a", 0)); + TEST_INT_EQ(-1, w_traits_t::compare_null(NULL, L"a", 1)); + TEST_INT_EQ(1, w_traits_t::compare_null(L"a", NULL, 0)); + TEST_INT_EQ(1, w_traits_t::compare_null(L"a", NULL, 1)); + TEST_INT_LT(0, w_traits_t::compare_null(L"abc", L"abd", 3)); +} + +static void TEST_compare_HIGH_BIT_UNSIGNED_ORDER() +{ + unsigned char const below_u[] = { 0x01 }; + unsigned char const above_u[] = { 0xFF }; + char const* const s_below = reinterpret_cast(below_u); + char const* const s_above = reinterpret_cast(above_u); + char const below = s_below[0]; + char const above = s_above[0]; + + TEST_BOOLEAN_TRUE(a_traits_t::eq(above, above)); + TEST_BOOLEAN_FALSE(a_traits_t::eq(below, above)); + + if (below < above) + { + TEST_BOOLEAN_TRUE(a_traits_t::lt(below, above)); + } + else + { + TEST_BOOLEAN_FALSE(a_traits_t::lt(below, above)); + TEST_BOOLEAN_TRUE(a_traits_t::lt(above, below)); + } + + TEST_INT_LT(0, a_traits_t::compare(s_below, s_above, 1)); + TEST_INT_GT(0, a_traits_t::compare(s_above, s_below, 1)); + + wchar_t const w_small[] = { 0x0001 }; + wchar_t const w_large[] = { 0x00FF }; + + TEST_BOOLEAN_TRUE(w_traits_t::lt(w_small[0], w_large[0])); + TEST_INT_LT(0, w_traits_t::compare(w_small, w_large, 1)); + TEST_INT_GT(0, w_traits_t::compare(w_large, w_small, 1)); +} + +static void TEST_char_traits_safe_compare() +{ + char const a1[] = { 'a', '\0', 'd' }; + char const a2[] = { 'a', '\0', 'e' }; + wchar_t const w1[] = { L'a', L'\0', L'd' }; + wchar_t const w2[] = { L'a', L'\0', L'e' }; + + TEST_INT_EQ(0, a_safe_t::compare("abc", "abc", 3)); + TEST_INT_LT(0, a_safe_t::compare("abc", "abd", 3)); + TEST_INT_LT(0, a_safe_t::compare(a1, a2, 3)); + TEST_INT_EQ(0, a_safe_t::compare_max(a1, a2, 3)); + + TEST_INT_EQ(0, w_safe_t::compare(L"abc", L"abc", 3)); + TEST_INT_LT(0, w_safe_t::compare(L"abc", L"abd", 3)); + TEST_INT_LT(0, w_safe_t::compare(w1, w2, 3)); + TEST_INT_EQ(0, w_safe_t::compare_max(w1, w2, 3)); +} + +static void TEST_char_traits_safe_compare_NULL() +{ + /* A count of 0 compares no characters, so a null pointer and a live + * pointer are equal. A non-zero count orders a null pointer before a + * live pointer, and two null pointers compare equal. + */ + TEST_INT_EQ(0, a_safe_t::compare(NULL, NULL, 0)); + TEST_INT_EQ(0, a_safe_t::compare(NULL, NULL, 4)); + TEST_INT_EQ(0, a_safe_t::compare(NULL, "a", 0)); + TEST_INT_EQ(-1, a_safe_t::compare(NULL, "a", 1)); + TEST_INT_EQ(0, a_safe_t::compare("a", NULL, 0)); + TEST_INT_EQ(1, a_safe_t::compare("a", NULL, 1)); + + TEST_INT_EQ(0, w_safe_t::compare(NULL, NULL, 0)); + TEST_INT_EQ(0, w_safe_t::compare(NULL, NULL, 4)); + TEST_INT_EQ(0, w_safe_t::compare(NULL, L"a", 0)); + TEST_INT_EQ(-1, w_safe_t::compare(NULL, L"a", 1)); + TEST_INT_EQ(0, w_safe_t::compare(L"a", NULL, 0)); + TEST_INT_EQ(1, w_safe_t::compare(L"a", NULL, 1)); + + TEST_INT_EQ(0, a_safe_t::compare_max(NULL, NULL, 4)); + TEST_INT_EQ(-1, a_safe_t::compare_max(NULL, "a", 1)); + TEST_INT_EQ(1, a_safe_t::compare_max("a", NULL, 1)); + + TEST_INT_EQ(0, w_safe_t::compare_max(NULL, NULL, 4)); + TEST_INT_EQ(-1, w_safe_t::compare_max(NULL, L"a", 1)); + TEST_INT_EQ(1, w_safe_t::compare_max(L"a", NULL, 1)); +} + +} /* anonymous namespace */ + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/stlsoft/string/functionals.string_begins_with/CMakeLists.txt b/test/unit/stlsoft/string/functionals.string_begins_with/CMakeLists.txt new file mode 100644 index 00000000..897f02cc --- /dev/null +++ b/test/unit/stlsoft/string/functionals.string_begins_with/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.unit.stlsoft.string.functionals.string_begins_with entry.cpp) diff --git a/test/unit/stlsoft/string/functionals.string_begins_with/entry.cpp b/test/unit/stlsoft/string/functionals.string_begins_with/entry.cpp new file mode 100644 index 00000000..687c6b12 --- /dev/null +++ b/test/unit/stlsoft/string/functionals.string_begins_with/entry.cpp @@ -0,0 +1,176 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: functionals.string_begins_with/entry.cpp + * + * Purpose: Unit-tests for stlsoft::string_begins_with. + * + * Created: 29th September 2026 + * Updated: 29th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * test component header file include(s) + */ + +#include +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include +#include + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace +{ + + static void TEST_string_begins_with_MATCH(); + static void TEST_string_begins_with_REJECT(); + static void TEST_string_begins_with_EMPTY_PREFIX(); + static void TEST_string_begins_with_LONGER_PREFIX(); + static void TEST_string_begins_with_CASE_SENSITIVE(); + static void TEST_string_begins_with_WCHAR(); + +} /* anonymous namespace */ + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.stlsoft.string.functionals.string_begins_with", verbosity)) + { + XTESTS_RUN_CASE(TEST_string_begins_with_MATCH); + XTESTS_RUN_CASE(TEST_string_begins_with_REJECT); + XTESTS_RUN_CASE(TEST_string_begins_with_EMPTY_PREFIX); + XTESTS_RUN_CASE(TEST_string_begins_with_LONGER_PREFIX); + XTESTS_RUN_CASE(TEST_string_begins_with_CASE_SENSITIVE); + XTESTS_RUN_CASE(TEST_string_begins_with_WCHAR); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace +{ + +static void TEST_string_begins_with_MATCH() +{ + stlsoft::string_begins_with_function const begins = stlsoft::string_begins_with("ab"); + stlsoft::simple_string const abc("abc"); + char const embedded[] = { 'a', '\0', 'x' }; + stlsoft::string_begins_with_function const begins_n(embedded); + + TEST_BOOLEAN_TRUE(begins("abc")); + TEST_BOOLEAN_TRUE(begins("ab")); + TEST_BOOLEAN_TRUE(begins("abcd")); + TEST_BOOLEAN_TRUE(begins(abc)); + + TEST_BOOLEAN_TRUE(begins_n("abc")); + TEST_BOOLEAN_FALSE(begins_n("xbc")); +} + +static void TEST_string_begins_with_REJECT() +{ + stlsoft::string_begins_with_function const begins = stlsoft::string_begins_with("abc"); + stlsoft::simple_string const abd("abd"); + + TEST_BOOLEAN_FALSE(begins("abd")); + TEST_BOOLEAN_FALSE(begins("xbc")); + TEST_BOOLEAN_FALSE(begins("ab")); + TEST_BOOLEAN_FALSE(begins("")); + TEST_BOOLEAN_FALSE(begins(abd)); +} + +static void TEST_string_begins_with_EMPTY_PREFIX() +{ + stlsoft::string_begins_with_function const begins = stlsoft::string_begins_with(""); + + TEST_BOOLEAN_TRUE(begins("abc")); + TEST_BOOLEAN_TRUE(begins("")); +} + +static void TEST_string_begins_with_LONGER_PREFIX() +{ + stlsoft::string_begins_with_function const begins = stlsoft::string_begins_with("abcd"); + + TEST_BOOLEAN_FALSE(begins("abc")); + TEST_BOOLEAN_FALSE(begins("")); + TEST_BOOLEAN_TRUE(begins("abcd")); + TEST_BOOLEAN_TRUE(begins("abcde")); +} + +static void TEST_string_begins_with_CASE_SENSITIVE() +{ + stlsoft::string_begins_with_function const begins = stlsoft::string_begins_with("Ab"); + + TEST_BOOLEAN_FALSE(begins("abc")); + TEST_BOOLEAN_FALSE(begins("aBc")); + TEST_BOOLEAN_TRUE(begins("Abc")); + TEST_BOOLEAN_TRUE(begins("Ab")); +} + +static void TEST_string_begins_with_WCHAR() +{ + stlsoft::string_begins_with_function const begins = stlsoft::string_begins_with(L"ab"); + stlsoft::simple_wstring const abc(L"abc"); + wchar_t const embedded[] = { L'a', L'\0', L'x' }; + stlsoft::string_begins_with_function const begins_n(embedded); + stlsoft::string_begins_with_function const begins_abc = stlsoft::string_begins_with(L"abc"); + stlsoft::string_begins_with_function const begins_empty = stlsoft::string_begins_with(L""); + stlsoft::string_begins_with_function const begins_long = stlsoft::string_begins_with(L"abcd"); + stlsoft::string_begins_with_function const begins_case = stlsoft::string_begins_with(L"Ab"); + + TEST_BOOLEAN_TRUE(begins(L"abc")); + TEST_BOOLEAN_TRUE(begins(L"ab")); + TEST_BOOLEAN_TRUE(begins(L"abcd")); + TEST_BOOLEAN_TRUE(begins(abc)); + + TEST_BOOLEAN_TRUE(begins_n(L"abc")); + TEST_BOOLEAN_FALSE(begins_n(L"xbc")); + + TEST_BOOLEAN_FALSE(begins_abc(L"abd")); + TEST_BOOLEAN_FALSE(begins_abc(L"ab")); + TEST_BOOLEAN_FALSE(begins_abc(L"")); + + TEST_BOOLEAN_TRUE(begins_empty(L"abc")); + TEST_BOOLEAN_TRUE(begins_empty(L"")); + + TEST_BOOLEAN_FALSE(begins_long(L"abc")); + TEST_BOOLEAN_TRUE(begins_long(L"abcd")); + + TEST_BOOLEAN_FALSE(begins_case(L"abc")); + TEST_BOOLEAN_TRUE(begins_case(L"Abc")); +} + +} /* anonymous namespace */ + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/stlsoft/string/simple_string/entry.cpp b/test/unit/stlsoft/string/simple_string/entry.cpp index 3b7230ff..bd1c22eb 100644 --- a/test/unit/stlsoft/string/simple_string/entry.cpp +++ b/test/unit/stlsoft/string/simple_string/entry.cpp @@ -127,6 +127,12 @@ namespace { static void test_compare_2(); static void test_compare_3(); static void test_compare_4(); + static void TEST_compare_EMPTY(); + static void TEST_ctor_EMBEDDED_NUL(); + static void TEST_append_EMBEDDED_NUL(); + static void TEST_assign_EMBEDDED_NUL(); + static void TEST_compare_EMBEDDED_NUL(); + static void TEST_compare_WCHAR(); static void test_equality_operators_1(); #ifndef USE_std_string static void test_equal_p_n_ccs_n(); @@ -295,6 +301,12 @@ int main(int argc, char* argv[]) XTESTS_RUN_CASE(test_compare_2); XTESTS_RUN_CASE(test_compare_3); XTESTS_RUN_CASE(test_compare_4); + XTESTS_RUN_CASE(TEST_compare_EMPTY); + XTESTS_RUN_CASE(TEST_ctor_EMBEDDED_NUL); + XTESTS_RUN_CASE(TEST_append_EMBEDDED_NUL); + XTESTS_RUN_CASE(TEST_assign_EMBEDDED_NUL); + XTESTS_RUN_CASE(TEST_compare_EMBEDDED_NUL); + XTESTS_RUN_CASE(TEST_compare_WCHAR); XTESTS_RUN_CASE(test_equality_operators_1); #ifndef USE_std_string XTESTS_RUN_CASE(test_equal_p_n_ccs_n); @@ -462,8 +474,8 @@ namespace { #endif - static char const alphabet[] = "abcdefghijklmnopqrstuvwxyz"; - static wchar_t const alphabet_w[] = L"abcdefghijklmnopqrstuvwxyz"; + static char const alphabet[] = "abcdefghijklmnopqrstuvwxyz"; + static wchar_t const alphabet_w[] = L"abcdefghijklmnopqrstuvwxyz"; // construction @@ -1471,6 +1483,175 @@ static void test_compare_4() } } +static void TEST_compare_EMPTY() +{ + string_t const empty; + string_t const empty2; + string_t const a("a"); + + TEST_INT_EQ(0, empty.compare(empty2)); + TEST_INT_EQ(0, empty.compare("")); + TEST_INT_LT(0, empty.compare(a)); + TEST_INT_LT(0, empty.compare("a")); + TEST_INT_GT(0, a.compare(empty)); + TEST_INT_GT(0, a.compare("")); +} + +static void expect_embedded_char_(string_t const& s) +{ + TEST_INT_EQ(3u, s.size()); + TEST_INT_EQ(int('a'), int(s.data()[0])); + TEST_INT_EQ(0, int(s.data()[1])); + TEST_INT_EQ(int('x'), int(s.data()[2])); +} + +static void expect_embedded_wchar_(wstring_t const& s) +{ + TEST_INT_EQ(3u, s.size()); + TEST_INT_EQ(int(L'a'), int(s.data()[0])); + TEST_INT_EQ(0, int(s.data()[1])); + TEST_INT_EQ(int(L'x'), int(s.data()[2])); +} + +static void TEST_ctor_EMBEDDED_NUL() +{ + char const src[] = { 'a', '\0', 'x' }; + wchar_t const wsrc[] = { L'a', L'\0', L'x' }; + + expect_embedded_char_(string_t(src, 3)); + expect_embedded_wchar_(wstring_t(wsrc, 3)); +} + +static void TEST_append_EMBEDDED_NUL() +{ + char const src[] = { 'a', '\0', 'x' }; + char const tail[] = { '\0', 'x' }; + wchar_t const wsrc[] = { L'a', L'\0', L'x' }; + wchar_t const wtail[] = { L'\0', L'x' }; + string_t s; + string_t prefixed("q"); + string_t pushed; + wstring_t ws; + wstring_t wprefixed(L"q"); + wstring_t wpushed; + + s.append(src, 3); + prefixed.append(tail, 2); + pushed.push_back('a'); + pushed.push_back('\0'); + pushed.push_back('x'); + ws.append(wsrc, 3); + wprefixed.append(wtail, 2); + wpushed.push_back(L'a'); + wpushed.push_back(L'\0'); + wpushed.push_back(L'x'); + + expect_embedded_char_(s); + expect_embedded_char_(pushed); + TEST_INT_EQ(3u, prefixed.size()); + TEST_INT_EQ(int('q'), int(prefixed.data()[0])); + TEST_INT_EQ(0, int(prefixed.data()[1])); + TEST_INT_EQ(int('x'), int(prefixed.data()[2])); + + expect_embedded_wchar_(ws); + expect_embedded_wchar_(wpushed); + TEST_INT_EQ(3u, wprefixed.size()); + TEST_INT_EQ(int(L'q'), int(wprefixed.data()[0])); + TEST_INT_EQ(0, int(wprefixed.data()[1])); + TEST_INT_EQ(int(L'x'), int(wprefixed.data()[2])); +} + +static void TEST_assign_EMBEDDED_NUL() +{ + char const src[] = { 'a', '\0', 'x' }; + wchar_t const wsrc[] = { L'a', L'\0', L'x' }; + string_t empty; + string_t existing("z"); + string_t filled("abc"); + wstring_t wempty; + wstring_t wexisting(L"z"); + wstring_t wfilled(L"abc"); + + empty.assign(src, 3); + existing.reserve(32); + existing.assign(src, 3); + filled.assign(3, '\0'); + wempty.assign(wsrc, 3); + wexisting.reserve(32); + wexisting.assign(wsrc, 3); + wfilled.assign(3, L'\0'); + + expect_embedded_char_(empty); + expect_embedded_char_(existing); + expect_embedded_char_(string_t(existing)); + TEST_INT_EQ(3u, filled.size()); + TEST_INT_EQ(0, int(filled.data()[0])); + TEST_INT_EQ(0, int(filled.data()[1])); + TEST_INT_EQ(0, int(filled.data()[2])); + + string_t nul_ch; + wstring_t wnul_ch; + + nul_ch = '\0'; + wnul_ch = L'\0'; + + expect_embedded_wchar_(wempty); + expect_embedded_wchar_(wexisting); + expect_embedded_wchar_(wstring_t(wexisting)); + TEST_INT_EQ(1u, nul_ch.size()); + TEST_INT_EQ(0, int(nul_ch.data()[0])); + TEST_INT_EQ(1u, wnul_ch.size()); + TEST_INT_EQ(0, int(wnul_ch.data()[0])); + TEST_INT_EQ(3u, wfilled.size()); + TEST_INT_EQ(0, int(wfilled.data()[0])); + TEST_INT_EQ(0, int(wfilled.data()[1])); + TEST_INT_EQ(0, int(wfilled.data()[2])); +} + +static void TEST_compare_EMBEDDED_NUL() +{ + char const src_x[] = { 'a', '\0', 'x' }; + char const src_y[] = { 'a', '\0', 'y' }; + char const src_b[] = { 'b', '\0', 'x' }; + string_t const s_ax(src_x, 3); + string_t const s_ay(src_y, 3); + string_t const s_bx(src_b, 3); + string_t const s_ax2(src_x, 3); + + expect_embedded_char_(s_ax); + TEST_INT_EQ(0, s_ax.compare(s_ax2)); + TEST_INT_LT(0, s_ax.compare("ax")); + TEST_INT_LT(0, s_ax.compare(s_ay)); + TEST_INT_GT(0, s_bx.compare(s_ax)); + TEST_INT_LT(0, string_t("a").compare(s_ax)); +} + +static void TEST_compare_WCHAR() +{ + wstring_t const abc(L"abc"); + wstring_t const abd(L"abd"); + wstring_t const empty; + wstring_t w_ax; + wstring_t w_ay; + + w_ax.push_back(L'a'); + w_ax.push_back(L'\0'); + w_ax.push_back(L'x'); + w_ay.push_back(L'a'); + w_ay.push_back(L'\0'); + w_ay.push_back(L'y'); + + TEST_INT_EQ(0, abc.compare(wstring_t(L"abc"))); + TEST_INT_LT(0, abc.compare(abd)); + TEST_INT_GT(0, abd.compare(abc)); + TEST_INT_EQ(0, empty.compare(wstring_t())); + TEST_INT_EQ(0, empty.compare(L"")); + TEST_INT_LT(0, empty.compare(abc)); + expect_embedded_wchar_(w_ax); + TEST_INT_LT(0, w_ax.compare(L"ax")); + TEST_INT_LT(0, w_ax.compare(w_ay)); +} + static void test_equality_operators_1() { string_t s1("abc"); @@ -3688,13 +3869,33 @@ static void test_string_traits() static void test_concatenation_1() { - string_t s1(alphabet); - string_t s2(s1, 0, 10); - string_t s3(s1, 10, 10); - string_t s4(s1, 20, 6); - string_t s5 = s2 + s3 + s4; + { + string_t s1(alphabet); + string_t s2(s1, 0, 10); + string_t s3(s1, 10, 10); + string_t s4(s1, 20, 6); + string_t s5 = s2 + s3 + s4; - TEST_MS_EQ(s1, s5); + TEST_MS_EQ(s1, s5); + } + + { + static char const alphabet_with_NUL_vowels[] = "\0bcd\0fgh\0jklmn\0pqrst\0vwxyz"; + + string_t s1(alphabet_with_NUL_vowels, 26); + + TEST_INT_EQ(26, s1.length()); + + string_t s2(s1, 0, 10); + string_t s3(s1, 10, 10); + string_t s4(s1, 20, 6); + string_t s5 = s2 + s3 + s4; + + TEST_MS_EQ(s1, s5); + TEST_INT_EQ(26, s5.length()); + + TEST_EQ(0, memcmp(alphabet_with_NUL_vowels, s5.data(), sizeof(char) * s5.length())); + } } static void test_concatenation_2() diff --git a/test/unit/stlsoft/string/special_string_instance/CMakeLists.txt b/test/unit/stlsoft/string/special_string_instance/CMakeLists.txt new file mode 100644 index 00000000..266d4ce2 --- /dev/null +++ b/test/unit/stlsoft/string/special_string_instance/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.unit.stlsoft.string.special_string_instance entry.cpp) diff --git a/test/unit/stlsoft/string/special_string_instance/entry.cpp b/test/unit/stlsoft/string/special_string_instance/entry.cpp new file mode 100644 index 00000000..112d6cd1 --- /dev/null +++ b/test/unit/stlsoft/string/special_string_instance/entry.cpp @@ -0,0 +1,275 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: special_string_instance/entry.cpp + * + * Purpose: Unit-tests for special_string_instance::equal. + * + * Created: 29th September 2026 + * Updated: 29th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* simple_string's c_str_data / c_str_len must be declared before + * special_string_instance.hpp parses equal(), which calls them by + * qualified name. + */ +#include + +/* counted_chars reports a length that may include a NUL. + * simple_string's (pointer, count) constructor stops at NUL. + */ +struct counted_chars +{ + char const* p; + size_t n; +}; + +namespace stlsoft +{ +inline char const* c_str_data(counted_chars const& s) +{ + return s.p; +} +inline size_t c_str_len(counted_chars const& s) +{ + return s.n; +} +} /* namespace stlsoft */ + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include +#include + +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace +{ + + static void TEST_equal_CASE_SENSITIVE(); + static void TEST_equal_CASE_INSENSITIVE_ASCII(); + static void TEST_equal_LENGTH_MISMATCH(); + static void TEST_equal_EMBEDDED_NUL(); + static void TEST_equal_WCHAR(); + +} /* anonymous namespace */ + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.stlsoft.string.special_string_instance", verbosity)) + { + XTESTS_RUN_CASE(TEST_equal_CASE_SENSITIVE); + XTESTS_RUN_CASE(TEST_equal_CASE_INSENSITIVE_ASCII); + XTESTS_RUN_CASE(TEST_equal_LENGTH_MISMATCH); + XTESTS_RUN_CASE(TEST_equal_EMBEDDED_NUL); + XTESTS_RUN_CASE(TEST_equal_WCHAR); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace +{ + +struct content_abc {}; +struct content_empty {}; +struct content_embedded {}; + +template < + ss_typename_param_k C +, int V_caseSensitive +, ss_typename_param_k T_content +> +struct fixed_ssi_policy +{ + typedef C char_type; + typedef size_t size_type; + typedef size_type (*pfn_type)(char_type*, size_type); + typedef ss_typename_type_k stlsoft::allocator_selector< + char_type + >::allocator_type allocator_type; + + enum { internalBufferSize = 32 }; + enum { allowImplicitConversion = 0 }; + enum { caseSensitive = V_caseSensitive }; + enum { sharedState = 0 }; + + static size_type get_value(char_type* buffer, size_type cch) + { + char_type const* const src = content_chars(static_cast(0), static_cast(0)); + size_type const n = content_length(static_cast(0)); + + if (cch <= n) + { + return n; + } + + { size_type i; for (i = 0; i != n; ++i) + { + buffer[i] = src[i]; + }} + + return n; + } + + static pfn_type get_fn() + { + return &get_value; + } +}; + +inline char const* content_chars(content_abc const*, char const*) +{ + return "abc"; +} +inline wchar_t const* content_chars(content_abc const*, wchar_t const*) +{ + return L"abc"; +} +inline size_t content_length(content_abc const*) +{ + return 3; +} + +inline char const* content_chars(content_empty const*, char const*) +{ + return ""; +} +inline size_t content_length(content_empty const*) +{ + return 0; +} + +inline char const* content_chars(content_embedded const*, char const*) +{ + static char const s[] = { 'a', '\0', 'x' }; + + return s; +} +inline size_t content_length(content_embedded const*) +{ + return 3; +} + +typedef stlsoft::special_string_instance_0< + fixed_ssi_policy +> abc_t; +typedef stlsoft::special_string_instance_0< + fixed_ssi_policy +> abc_nocase_t; +typedef stlsoft::special_string_instance_0< + fixed_ssi_policy +> empty_t; +typedef stlsoft::special_string_instance_0< + fixed_ssi_policy +> embedded_t; +typedef stlsoft::special_string_instance_0< + fixed_ssi_policy +> wabc_t; +typedef stlsoft::special_string_instance_0< + fixed_ssi_policy +> wabc_nocase_t; + +static void TEST_equal_CASE_SENSITIVE() +{ + abc_t const abc; + empty_t const empty; + stlsoft::simple_string const same("abc"); + + TEST_BOOLEAN_TRUE(abc.equal("abc")); + TEST_BOOLEAN_TRUE(abc.equal(same)); + TEST_BOOLEAN_FALSE(abc.equal("abC")); + TEST_BOOLEAN_FALSE(abc.equal("xyz")); + TEST_BOOLEAN_TRUE(empty.equal("")); +} + +static void TEST_equal_CASE_INSENSITIVE_ASCII() +{ + abc_nocase_t const abc; + wabc_nocase_t const wabc; + + TEST_BOOLEAN_TRUE(abc.equal("abc")); + TEST_BOOLEAN_TRUE(abc.equal("ABC")); + TEST_BOOLEAN_TRUE(abc.equal("AbC")); + TEST_BOOLEAN_FALSE(abc.equal("ABD")); + TEST_BOOLEAN_FALSE(abc.equal("AB")); + + TEST_BOOLEAN_TRUE(wabc.equal(L"abc")); + TEST_BOOLEAN_TRUE(wabc.equal(L"ABC")); + TEST_BOOLEAN_FALSE(wabc.equal(L"ABD")); +} + +static void TEST_equal_LENGTH_MISMATCH() +{ + abc_t const abc; + empty_t const empty; + + TEST_BOOLEAN_FALSE(abc.equal("ab")); + TEST_BOOLEAN_FALSE(abc.equal("abcd")); + TEST_BOOLEAN_FALSE(abc.equal("")); + TEST_BOOLEAN_FALSE(empty.equal("a")); +} + +static void TEST_equal_EMBEDDED_NUL() +{ + embedded_t const embedded; + char const same[] = { 'a', '\0', 'x' }; + char const diff[] = { 'a', '\0', 'y' }; + char const other[] = { 'b', '\0', 'x' }; + counted_chars const s_same = { same, 3 }; + counted_chars const s_diff = { diff, 3 }; + counted_chars const s_other = { other, 3 }; + + TEST_INT_EQ(3u, embedded.size()); + TEST_BOOLEAN_TRUE(embedded.equal(s_same)); + TEST_BOOLEAN_TRUE(embedded.equal(s_diff)); + TEST_BOOLEAN_FALSE(embedded.equal(s_other)); + TEST_BOOLEAN_FALSE(embedded.equal("a")); +} + +static void TEST_equal_WCHAR() +{ + wabc_t const wabc; + stlsoft::simple_wstring const same(L"abc"); + + TEST_BOOLEAN_TRUE(wabc.equal(L"abc")); + TEST_BOOLEAN_TRUE(wabc.equal(same)); + TEST_BOOLEAN_FALSE(wabc.equal(L"abC")); + TEST_BOOLEAN_FALSE(wabc.equal(L"ab")); + TEST_BOOLEAN_FALSE(wabc.equal(L"abcd")); +} + +} /* anonymous namespace */ + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/stlsoft/string/static_string/entry.cpp b/test/unit/stlsoft/string/static_string/entry.cpp index f6c00d8a..45ab3632 100644 --- a/test/unit/stlsoft/string/static_string/entry.cpp +++ b/test/unit/stlsoft/string/static_string/entry.cpp @@ -123,6 +123,10 @@ namespace { // comparison + static void TEST_compare_CHAR(); + static void TEST_compare_EMPTY(); + static void TEST_compare_EMBEDDED_NUL(); + static void TEST_compare_WCHAR(); static void test_contains_1(); static void test_contains_2(); static void test_contains_3(); @@ -254,6 +258,10 @@ int main(int argc, char* argv[]) // comparison + XTESTS_RUN_CASE(TEST_compare_CHAR); + XTESTS_RUN_CASE(TEST_compare_EMPTY); + XTESTS_RUN_CASE(TEST_compare_EMBEDDED_NUL); + XTESTS_RUN_CASE(TEST_compare_WCHAR); XTESTS_RUN_CASE(test_contains_1); XTESTS_RUN_CASE(test_contains_2); XTESTS_RUN_CASE(test_contains_3); @@ -1476,6 +1484,91 @@ static void test_capacity() // comparison +static void TEST_compare_CHAR() +{ + typedef string_10_t string_t; + + string_t const abc("abc"); + string_t const abd("abd"); + unsigned char const below_u[] = { 0x01, 0 }; + unsigned char const above_u[] = { 0xFF, 0 }; + char const* const below = reinterpret_cast(below_u); + char const* const above = reinterpret_cast(above_u); + + TEST_INT_EQ(0, abc.compare(string_t("abc"))); + TEST_INT_EQ(0, abc.compare("abc")); + TEST_INT_LT(0, abc.compare(abd)); + TEST_INT_LT(0, abc.compare("abd")); + TEST_INT_GT(0, abd.compare(abc)); + TEST_INT_GT(0, abd.compare("abc")); + TEST_INT_LT(0, string_t(below).compare(above)); +} + +static void TEST_compare_EMPTY() +{ + typedef string_10_t string_t; + + string_t const empty; + string_t const empty2; + string_t const a("a"); + + TEST_INT_EQ(0, empty.compare(empty2)); + TEST_INT_EQ(0, empty.compare("")); + TEST_INT_LT(0, empty.compare(a)); + TEST_INT_LT(0, empty.compare("a")); + TEST_INT_GT(0, a.compare(empty)); + TEST_INT_GT(0, a.compare("")); +} + +static void TEST_compare_EMBEDDED_NUL() +{ + typedef string_10_t string_t; + + char const src_x[] = { 'a', '\0', 'x' }; + char const src_y[] = { 'a', '\0', 'y' }; + char const src_b[] = { 'b', '\0', 'x' }; + string_t const s_ax(src_x, 3); + string_t const s_ay(src_y, 3); + string_t const s_bx(src_b, 3); + string_t const s_ax2(src_x, 3); + + TEST_INT_EQ(3u, s_ax.size()); + TEST_INT_EQ(int('a'), int(s_ax.data()[0])); + TEST_INT_EQ(0, int(s_ax.data()[1])); + TEST_INT_EQ(int('x'), int(s_ax.data()[2])); + TEST_INT_EQ(0, s_ax.compare(s_ax2)); + TEST_INT_LT(0, s_ax.compare("ax")); + TEST_INT_LT(0, s_ax.compare(s_ay)); + TEST_INT_GT(0, s_bx.compare(s_ax)); + TEST_INT_LT(0, string_t("a").compare(s_ax)); +} + +static void TEST_compare_WCHAR() +{ + typedef wstring_10_t string_t; + + string_t const abc(L"abc"); + string_t const abd(L"abd"); + string_t const empty; + wchar_t const src_x[] = { L'a', L'\0', L'x' }; + wchar_t const src_y[] = { L'a', L'\0', L'y' }; + string_t const w_ax(src_x, 3); + string_t const w_ay(src_y, 3); + + TEST_INT_EQ(0, abc.compare(string_t(L"abc"))); + TEST_INT_LT(0, abc.compare(abd)); + TEST_INT_GT(0, abd.compare(abc)); + TEST_INT_EQ(0, empty.compare(string_t())); + TEST_INT_EQ(0, empty.compare(L"")); + TEST_INT_LT(0, empty.compare(abc)); + TEST_INT_EQ(3u, w_ax.size()); + TEST_INT_EQ(int(L'a'), int(w_ax.data()[0])); + TEST_INT_EQ(0, int(w_ax.data()[1])); + TEST_INT_EQ(int(L'x'), int(w_ax.data()[2])); + TEST_INT_LT(0, w_ax.compare(L"ax")); + TEST_INT_LT(0, w_ax.compare(w_ay)); +} + static void test_contains_1() { typedef string_30_t string_t; diff --git a/test/unit/stlsoft/string/string_slice/entry.cpp b/test/unit/stlsoft/string/string_slice/entry.cpp index de01c365..2560d697 100644 --- a/test/unit/stlsoft/string/string_slice/entry.cpp +++ b/test/unit/stlsoft/string/string_slice/entry.cpp @@ -57,6 +57,9 @@ namespace { static void test_greater_than_operator_1(); static void test_lessgreaterequal_operators_1(); static void test_lessgreaterequal_operators_2(); + static void TEST_compare_EMPTY(); + static void TEST_compare_EMBEDDED_NUL(); + static void TEST_compare_HIGH_BIT(); static void test_insertion_1(); static void test_insertion_2(); static void test_insertion_3(); @@ -94,6 +97,9 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_greater_than_operator_1); XTESTS_RUN_CASE(test_lessgreaterequal_operators_1); XTESTS_RUN_CASE(test_lessgreaterequal_operators_2); + XTESTS_RUN_CASE(TEST_compare_EMPTY); + XTESTS_RUN_CASE(TEST_compare_EMBEDDED_NUL); + XTESTS_RUN_CASE(TEST_compare_HIGH_BIT); XTESTS_RUN_CASE(test_insertion_1); XTESTS_RUN_CASE(test_insertion_2); XTESTS_RUN_CASE(test_insertion_3); @@ -406,6 +412,76 @@ static void test_lessgreaterequal_operators_2() TEST_BOOLEAN_TRUE(slice1_w <= slice2_w); } +static void TEST_compare_EMPTY() +{ + stlsoft::string_slice const empty; + stlsoft::string_slice const empty2; + stlsoft::string_slice const a("a"); + stlsoft::string_slice const wempty; + stlsoft::string_slice const wempty2; + stlsoft::string_slice const wa(L"a"); + + TEST_INT_EQ(0, empty.compare(empty2)); + TEST_INT_EQ(0, empty.compare("")); + TEST_INT_LT(0, empty.compare(a)); + TEST_INT_LT(0, empty.compare("a")); + TEST_INT_GT(0, a.compare(empty)); + TEST_INT_GT(0, a.compare("")); + + TEST_INT_EQ(0, wempty.compare(wempty2)); + TEST_INT_EQ(0, wempty.compare(L"")); + TEST_INT_LT(0, wempty.compare(wa)); + TEST_INT_LT(0, wempty.compare(L"a")); + TEST_INT_GT(0, wa.compare(wempty)); + TEST_INT_GT(0, wa.compare(L"")); +} + +static void TEST_compare_EMBEDDED_NUL() +{ + char const src_x[] = { 'a', '\0', 'x' }; + char const src_y[] = { 'a', '\0', 'y' }; + char const src_b[] = { 'b', '\0', 'x' }; + wchar_t const wsrc_x[] = { L'a', L'\0', L'x' }; + wchar_t const wsrc_y[] = { L'a', L'\0', L'y' }; + + stlsoft::string_slice const s_ax(src_x, 3); + stlsoft::string_slice const s_ay(src_y, 3); + stlsoft::string_slice const s_bx(src_b, 3); + stlsoft::string_slice const s_ax2(src_x, 3); + stlsoft::string_slice const w_ax(wsrc_x, 3); + stlsoft::string_slice const w_ay(wsrc_y, 3); + + TEST_INT_EQ(3u, s_ax.size()); + TEST_INT_EQ(int('a'), int(s_ax.data()[0])); + TEST_INT_EQ(0, int(s_ax.data()[1])); + TEST_INT_EQ(int('x'), int(s_ax.data()[2])); + TEST_INT_EQ(0, s_ax.compare(s_ax2)); + TEST_INT_LT(0, s_ax.compare("ax")); + TEST_INT_LT(0, s_ax.compare(s_ay)); + TEST_INT_GT(0, s_bx.compare(s_ax)); + TEST_INT_LT(0, stlsoft::string_slice("a").compare(s_ax)); + + TEST_INT_EQ(3u, w_ax.size()); + TEST_INT_EQ(int(L'a'), int(w_ax.data()[0])); + TEST_INT_EQ(0, int(w_ax.data()[1])); + TEST_INT_EQ(int(L'x'), int(w_ax.data()[2])); + TEST_INT_LT(0, w_ax.compare(L"ax")); + TEST_INT_LT(0, w_ax.compare(w_ay)); +} + +static void TEST_compare_HIGH_BIT() +{ + unsigned char const below_u[] = { 0x01 }; + unsigned char const above_u[] = { 0xFF }; + char const* const below = reinterpret_cast(below_u); + char const* const above = reinterpret_cast(above_u); + stlsoft::string_slice const lo(below, 1); + stlsoft::string_slice const hi(above, 1); + + TEST_INT_LT(0, lo.compare(hi)); + TEST_INT_GT(0, hi.compare(lo)); +} + static void test_insertion_1() { stlsoft::string_slice const s1; diff --git a/test/unit/stlsoft/string/string_view/entry.cpp b/test/unit/stlsoft/string/string_view/entry.cpp index bc6ce4f0..0f731cb5 100644 --- a/test/unit/stlsoft/string/string_view/entry.cpp +++ b/test/unit/stlsoft/string/string_view/entry.cpp @@ -95,6 +95,10 @@ namespace { static void test_compare_2(); static void test_compare_3(); static void test_compare_4(); + static void TEST_compare_EMPTY(); + static void TEST_compare_EMBEDDED_NUL(); + static void TEST_compare_WCHAR(); + static void TEST_compare_char_traits_safe(); static void test_at_1(); static void test_at_2(); static void test_at_3(); @@ -153,6 +157,10 @@ int main(int argc, char *argv[]) XTESTS_RUN_CASE(test_compare_2); XTESTS_RUN_CASE(test_compare_3); XTESTS_RUN_CASE(test_compare_4); + XTESTS_RUN_CASE(TEST_compare_EMPTY); + XTESTS_RUN_CASE(TEST_compare_EMBEDDED_NUL); + XTESTS_RUN_CASE(TEST_compare_WCHAR); + XTESTS_RUN_CASE(TEST_compare_char_traits_safe); XTESTS_RUN_CASE(test_at_1); XTESTS_RUN_CASE(test_at_2); XTESTS_RUN_CASE_THAT_THROWS(test_at_3, std::out_of_range); @@ -783,6 +791,89 @@ static void test_compare_4() } } +static void TEST_compare_EMPTY() +{ + string_v_t const empty; + string_v_t const empty2; + string_v_t const a("a"); + + TEST_INT_EQ(0, empty.compare(empty2)); + TEST_INT_EQ(0, empty.compare("")); + TEST_INT_LT(0, empty.compare(a)); + TEST_INT_LT(0, empty.compare("a")); + TEST_INT_GT(0, a.compare(empty)); + TEST_INT_GT(0, a.compare("")); +} + +static void TEST_compare_EMBEDDED_NUL() +{ + char const src_x[] = { 'a', '\0', 'x' }; + char const src_y[] = { 'a', '\0', 'y' }; + char const src_b[] = { 'b', '\0', 'x' }; + string_v_t const s_ax(src_x, 3); + string_v_t const s_ay(src_y, 3); + string_v_t const s_bx(src_b, 3); + string_v_t const s_ax2(src_x, 3); + + TEST_INT_EQ(3u, s_ax.size()); + TEST_CHAR_EQ('a', s_ax.data()[0]); + TEST_CHAR_EQ('\0', s_ax.data()[1]); + TEST_CHAR_EQ('x', s_ax.data()[2]); + TEST_INT_EQ(0, s_ax.compare(s_ax2)); + TEST_INT_LT(0, s_ax.compare("ax")); + TEST_INT_LT(0, s_ax.compare(s_ay)); + TEST_INT_GT(0, s_bx.compare(s_ax)); + TEST_INT_LT(0, string_v_t("a").compare(s_ax)); +} + +static void TEST_compare_WCHAR() +{ + wchar_t const src_x[] = { L'a', L'\0', L'x' }; + wchar_t const src_y[] = { L'a', L'\0', L'y' }; + wstring_v_t const abc(L"abc"); + wstring_v_t const abd(L"abd"); + wstring_v_t const empty; + wstring_v_t const w_ax(src_x, 3); + wstring_v_t const w_ay(src_y, 3); + + TEST_INT_EQ(0, abc.compare(wstring_v_t(L"abc"))); + TEST_INT_LT(0, abc.compare(abd)); + TEST_INT_GT(0, abd.compare(abc)); + TEST_INT_EQ(0, empty.compare(wstring_v_t())); + TEST_INT_EQ(0, empty.compare(L"")); + TEST_INT_LT(0, empty.compare(abc)); + TEST_INT_EQ(3u, w_ax.size()); + TEST_INT_EQ(int(L'a'), int(w_ax.data()[0])); + TEST_INT_EQ(0, int(w_ax.data()[1])); + TEST_INT_EQ(int(L'x'), int(w_ax.data()[2])); + TEST_INT_LT(0, w_ax.compare(L"ax")); + TEST_INT_LT(0, w_ax.compare(w_ay)); +} + +static void TEST_compare_char_traits_safe() +{ + char const src_x[] = { 'a', '\0', 'x' }; + char const src_y[] = { 'a', '\0', 'y' }; + string_v_null_t const abc("abc"); + string_v_null_t const abd("abd"); + string_v_null_t const empty; + string_v_null_t const s_ax(src_x, 3); + string_v_null_t const s_ay(src_y, 3); + + TEST_INT_EQ(0, abc.compare(string_v_null_t("abc"))); + TEST_INT_LT(0, abc.compare(abd)); + TEST_INT_GT(0, abd.compare(abc)); + TEST_INT_EQ(0, empty.compare(string_v_null_t())); + TEST_INT_EQ(0, empty.compare("")); + TEST_INT_LT(0, empty.compare(abc)); + TEST_INT_EQ(3u, s_ax.size()); + TEST_CHAR_EQ('a', s_ax.data()[0]); + TEST_CHAR_EQ('\0', s_ax.data()[1]); + TEST_CHAR_EQ('x', s_ax.data()[2]); + TEST_INT_LT(0, s_ax.compare("ax")); + TEST_INT_LT(0, s_ax.compare(s_ay)); +} + static void test_at_1() { diff --git a/test/unit/versions/entry.cpp b/test/unit/versions/entry.cpp index a08232d5..b18bd6a3 100644 --- a/test/unit/versions/entry.cpp +++ b/test/unit/versions/entry.cpp @@ -171,7 +171,7 @@ static void TEST__COMSTL_VER() static void TEST__WINSTL_VER() { - TEST_INT_EQ(_WINSTL_VER_1_13_0_B02, _WINSTL_VER); + TEST_INT_EQ(_WINSTL_VER_1_13_0_B03, _WINSTL_VER); } #endif #ifdef STLSOFT_HAS_MFC From ec095eb9101f1b820d51a6271eec2b5c1b1dd29e Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Wed, 30 Sep 2026 13:39:42 +1000 Subject: [PATCH 09/31] `platformstl::basic_file_lines<>` perf-tests improvements: gap-groups (#30) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 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. --- .github/workflows/ci-cell.yml | 6 +- .gitignore | 1 + execute_performance_tests.cmd | 32 ++- execute_performance_tests.sh | 23 +- test/performance/CMakeLists.txt | 9 +- test/performance/perf_group_gaps.hpp | 212 ++++++++++++++++++ .../diagnostics/stopwatch/main.cpp | 10 +- .../filesystem/file_lines/main.cpp | 7 + .../stlsoft/containers/frequency_map/main.cpp | 9 +- .../conversion/integer_to_string/main.cpp | 33 ++- .../stlsoft/diagnostics/doomgram/main.cpp | 9 +- .../stlsoft/diagnostics/gram_utils/main.cpp | 6 +- .../stlsoft/memory/auto_buffer/main.cpp | 20 +- .../string/simple_string.compare/main.cpp | 18 +- .../string/simple_string.op_eq/main.cpp | 10 +- .../stlsoft/util/bit_functions/main.cpp | 65 +----- .../stlsoft/util/count_digits/main.cpp | 10 +- 17 files changed, 395 insertions(+), 85 deletions(-) create mode 100644 test/performance/perf_group_gaps.hpp diff --git a/.github/workflows/ci-cell.yml b/.github/workflows/ci-cell.yml index 2214d999..acac2798 100644 --- a/.github/workflows/ci-cell.yml +++ b/.github/workflows/ci-cell.yml @@ -606,6 +606,6 @@ jobs: if [ "${{ inputs.c-compiler }}" = "mingw" ]; then export PATH="/mingw64/bin:$PATH" fi - # Gaps between pattern groups in the bit-functions harness. - export SIS_PERFTESTS_GROUPGAPS=1 - SIS_CMAKE_BUILD_DIR="${{ github.workspace }}/build" ./execute_performance_tests.sh -M + # --gap-groups sets SIS_PERFTESTS_GROUPGAPS=1 for blank lines + # between pattern / scenario groups in performance output. + SIS_CMAKE_BUILD_DIR="${{ github.workspace }}/build" ./execute_performance_tests.sh -M --gap-groups diff --git a/.gitignore b/.gitignore index 226c1608..44e39b19 100644 --- a/.gitignore +++ b/.gitignore @@ -118,6 +118,7 @@ list_changes.cmd logging-bailout.txt prepare.cmd sh.exe.stackdump +test.performance.platformstl.file_lines.txt test/testpatterns.orj test/tests-plan.txt tidydir.cmd diff --git a/execute_performance_tests.cmd b/execute_performance_tests.cmd index bed0a0f9..7c0954ab 100644 --- a/execute_performance_tests.cmd +++ b/execute_performance_tests.cmd @@ -14,6 +14,7 @@ IF DEFINED SIS_CMAKE_BUILD_DIR ( ) SET ExpandWidth=0 +SET GapGroups=0 SET ListOnly=0 SET RunMake=1 @@ -28,6 +29,19 @@ IF DEFINED CMAKE_BUILD_TYPE SET BuildConfig=%CMAKE_BUILD_TYPE% IF "%~1"=="" GOTO args_done IF /I "%~1"=="--help" GOTO show_help +IF /I "%~1"=="--expand-width" ( + SHIFT + IF "%~1"=="" ( + ECHO %ScriptPath%: --expand-width requires an argument 1>&2 + EXIT /B 1 + ) + SET ExpandWidth=%~1 + GOTO next_arg +) +IF /I "%~1"=="--gap-groups" ( + SET GapGroups=1 + GOTO next_arg +) IF /I "%~1"=="-l" ( SET ListOnly=1 GOTO next_arg @@ -44,15 +58,6 @@ IF /I "%~1"=="--no-make" ( SET RunMake=0 GOTO next_arg ) -IF /I "%~1"=="--expand-width" ( - SHIFT - IF "%~1"=="" ( - ECHO %ScriptPath%: --expand-width requires an argument 1>&2 - EXIT /B 1 - ) - SET ExpandWidth=%~1 - GOTO next_arg -) ECHO %ScriptPath%: unrecognised argument '%~1'; use --help for usage 1>&2 EXIT /B 1 @@ -67,6 +72,10 @@ GOTO parse_args :: ######################################################### :: main() +IF %GapGroups% NEQ 0 ( + SET SIS_PERFTESTS_GROUPGAPS=1 +) + SET status=0 IF %RunMake% NEQ 0 ( @@ -159,6 +168,11 @@ ECHO --expand-width ^ ECHO subjects each performance test program's output to tab expansion ECHO with the given width (Unix shell script only) ECHO. +ECHO --gap-groups +ECHO sets SIS_PERFTESTS_GROUPGAPS=1 so performance programs emit a +ECHO blank line between scenario groups on a TTY, or a visible +ECHO tab+hyphen rule when stdout is not a TTY (e.g. CI) +ECHO. ECHO -l ECHO --list-only ECHO lists the target programs but does not execute them diff --git a/execute_performance_tests.sh b/execute_performance_tests.sh index 00620fc9..e15fbc44 100755 --- a/execute_performance_tests.sh +++ b/execute_performance_tests.sh @@ -10,6 +10,7 @@ ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") ExpandWidth=0 +GapGroups=0 ListOnly=0 RunMake=1 @@ -38,15 +39,19 @@ fi while [[ $# -gt 0 ]]; do case $1 in - --list-only|-l) - - ListOnly=1 - ;; --expand-width) shift ExpandWidth=$1 ;; + --gap-groups) + + GapGroups=1 + ;; + --list-only|-l) + + ListOnly=1 + ;; --no-make|-M) RunMake=0 @@ -67,6 +72,11 @@ Flags/options: subjects each performance test program's output to expand with the given + --gap-groups + sets SIS_PERFTESTS_GROUPGAPS=1 so performance programs emit a blank + line between scenario groups on a TTY, or a visible `\t----------` + rule when stdout is not a TTY (e.g. CI) + -l --list-only lists the target programs but does not execute them @@ -100,6 +110,11 @@ done # ########################################################## # main() +if [ $GapGroups -ne 0 ]; then + + export SIS_PERFTESTS_GROUPGAPS=1 +fi + status=0 if [ $RunMake -ne 0 ]; then diff --git a/test/performance/CMakeLists.txt b/test/performance/CMakeLists.txt index 6845234f..63b12caf 100644 --- a/test/performance/CMakeLists.txt +++ b/test/performance/CMakeLists.txt @@ -1,3 +1,10 @@ -# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +# Performance tests (human attention; not CTest-gated) + + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + add_subdirectory(platformstl) add_subdirectory(stlsoft) + + +# ############################## end of file ############################# # diff --git a/test/performance/perf_group_gaps.hpp b/test/performance/perf_group_gaps.hpp new file mode 100644 index 00000000..0cdde581 --- /dev/null +++ b/test/performance/perf_group_gaps.hpp @@ -0,0 +1,212 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test/performance/perf_group_gaps.hpp + * + * Purpose: Shared helpers for optional separators between logical groups + * in performance-test output (SIS_PERFTESTS_GROUPGAPS). TTY emits + * a blank line; non-TTY / CI emits a visible `\t----------` rule. + * + * Created: 30th September 2026 + * Updated: 30th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +#ifndef STLSOFT_INCL_TEST_PERFORMANCE_HPP_PERF_GROUP_GAPS +#define STLSOFT_INCL_TEST_PERFORMANCE_HPP_PERF_GROUP_GAPS + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include + +#include +#include +#include + +#include +#include +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * functions + */ + +/** Returns true when the named environment variable is a recognised truey + * form (`1` / `ok` / `on` / `true` / `yes` / `y`, and uppercase forms). + */ +inline +bool +perf_env_is_truey( + char const* name +) +{ +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4996) +#endif + char const* const env = ::getenv(name); +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + + if (NULL == env || '\0' == *env) + { + return false; + } + + if (0 == ::strcmp(env, "1") || + 0 == ::strcmp(env, "ok") || + 0 == ::strcmp(env, "on") || + 0 == ::strcmp(env, "true") || + 0 == ::strcmp(env, "yes") || + 0 == ::strcmp(env, "y") || + 0 == ::strcmp(env, "OK") || + 0 == ::strcmp(env, "ON") || + 0 == ::strcmp(env, "TRUE") || + 0 == ::strcmp(env, "YES") || + 0 == ::strcmp(env, "Y")) + { + return true; + } + + return false; +} + +/** Emit a group separator on `stm`: blank line on a TTY; `\t----------` + * otherwise (GitHub Actions strips bare blank lines from log UI). + */ +inline +void +perf_emit_group_separator( + std::ostream& stm +) +{ + // Bare blank lines are stripped by GitHub Actions log UI; use a + // visible rule when stdout is not a TTY (CI / redirected logs). + if (platformstl::isatty(stdout)) + { + stm << std::endl; + } + else + { + stm << "\t----------" << std::endl; + } +} + +/** FILE* overload of the group separator. */ +inline +void +perf_emit_group_separator( + FILE* fp +) +{ + if (platformstl::isatty(fp)) + { + std::fputc('\n', fp); + } + else + { + std::fputs("\t----------\n", fp); + } +} + +/** When `SIS_PERFTESTS_GROUPGAPS` is truey, emit a group separator on + * `stm` when `group_key` differs from the previous call (not before the + * first). + */ +inline +void +perf_maybe_emit_group_gap( + std::ostream& stm +, char const* group_key +) +{ + static bool have_prev = false; + static char prev_key[128] = ""; + + if (!perf_env_is_truey("SIS_PERFTESTS_GROUPGAPS")) + { + return; + } + + if (NULL == group_key) + { + group_key = ""; + } + + if (have_prev && 0 != ::strcmp(prev_key, group_key)) + { + perf_emit_group_separator(stm); + } + + ::snprintf(prev_key, sizeof(prev_key), "%s", group_key); + have_prev = true; +} + +/** FILE* overload for harnesses that print via `fprintf(stdout, ...)`. */ +inline +void +perf_maybe_emit_group_gap( + FILE* fp +, char const* group_key +) +{ + static bool have_prev = false; + static char prev_key[128] = ""; + + if (!perf_env_is_truey("SIS_PERFTESTS_GROUPGAPS")) + { + return; + } + + if (NULL == group_key) + { + group_key = ""; + } + + if (have_prev && 0 != ::strcmp(prev_key, group_key)) + { + perf_emit_group_separator(fp); + } + + ::snprintf(prev_key, sizeof(prev_key), "%s", group_key); + have_prev = true; +} + +/** When `SIS_PERFTESTS_GROUPGAPS` is truey, print the one-line Env banner. */ +inline +void +perf_maybe_emit_groupgaps_banner( + std::ostream& stm +) +{ + if (perf_env_is_truey("SIS_PERFTESTS_GROUPGAPS")) + { + stm + << "Env: SIS_PERFTESTS_GROUPGAPS=1" + << std::endl; + } +} + +/** FILE* overload of the Env banner. */ +inline +void +perf_maybe_emit_groupgaps_banner( + FILE* fp +) +{ + if (perf_env_is_truey("SIS_PERFTESTS_GROUPGAPS")) + { + std::fputs("Env: SIS_PERFTESTS_GROUPGAPS=1\n", fp); + } +} + + +/* ////////////////////////////////////////////////////////////////////// */ + +#endif /* !STLSOFT_INCL_TEST_PERFORMANCE_HPP_PERF_GROUP_GAPS */ + +/* ///////////////////////////// end of file //////////////////////////// */ diff --git a/test/performance/platformstl/diagnostics/stopwatch/main.cpp b/test/performance/platformstl/diagnostics/stopwatch/main.cpp index b448478b..a63718c6 100644 --- a/test/performance/platformstl/diagnostics/stopwatch/main.cpp +++ b/test/performance/platformstl/diagnostics/stopwatch/main.cpp @@ -4,7 +4,7 @@ * Purpose: Perf-test for stopwatch types. * * Created: 15th March 2024 - * Updated: 29th September 2026 + * Updated: 30th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -33,6 +33,8 @@ #include #include +#include "perf_group_gaps.hpp" + #include #include #include @@ -280,6 +282,8 @@ int main(int /* argc */, char* /* argv */[]) #define DEFINE_TYPE_AND_NAME(t) char const* const type_name = #t; typedef t sw_t + perf_maybe_emit_groupgaps_banner(std::cout); + std::cout << '\t' << "type" @@ -300,6 +304,8 @@ int main(int /* argc */, char* /* argv */[]) // start-stop { + /* Gap between stopwatch cost/scenario sections. */ + perf_maybe_emit_group_gap(std::cout, "start-stop"); std::cout << "`start()` - `stop()`(cost):" << std::endl; { @@ -340,6 +346,8 @@ int main(int /* argc */, char* /* argv */[]) // pause-unpause { + /* Gap between stopwatch cost/scenario sections. */ + perf_maybe_emit_group_gap(std::cout, "pause-unpause"); std::cout << "`pause()` - `unpause()` (cost):" << std::endl; { diff --git a/test/performance/platformstl/filesystem/file_lines/main.cpp b/test/performance/platformstl/filesystem/file_lines/main.cpp index a7f66195..cd42891b 100644 --- a/test/performance/platformstl/filesystem/file_lines/main.cpp +++ b/test/performance/platformstl/filesystem/file_lines/main.cpp @@ -20,6 +20,8 @@ #include #include +#include "perf_group_gaps.hpp" + #include #include #include @@ -242,6 +244,9 @@ display_result( , result_t const& result ) { + /* Gap when the scenario label changes, not between implementations. */ + perf_maybe_emit_group_gap(std::cout, scenario); + std::cout << std::left << std::setw(COLUMN_WIDTH_SCENARIO) << scenario @@ -376,6 +381,8 @@ run_scenario( int main(int /*argc*/, char* /*argv*/[]) { + perf_maybe_emit_groupgaps_banner(std::cout); + std::cout << std::left << std::setw(COLUMN_WIDTH_SCENARIO) << "scenario" diff --git a/test/performance/stlsoft/containers/frequency_map/main.cpp b/test/performance/stlsoft/containers/frequency_map/main.cpp index 7471d7da..938a0c71 100644 --- a/test/performance/stlsoft/containers/frequency_map/main.cpp +++ b/test/performance/stlsoft/containers/frequency_map/main.cpp @@ -4,7 +4,7 @@ * Purpose: Perf-test for `stlsoft::frequency_map<>`. * * Created: 5th October 2024 - * Updated: 29th September 2026 + * Updated: 30th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -36,6 +36,8 @@ # include #endif /* C++11+ */ +#include "perf_group_gaps.hpp" + /* Standard header files */ #if __cplusplus >= 201103L @@ -157,6 +159,9 @@ display_results( > const& r ) { + /* Gap when the ordering group (O / U) changes. */ + perf_maybe_emit_group_gap(stm, ordering_label); + stm << '\t' << ordering_label << ": " << test_name @@ -708,6 +713,8 @@ int main(int /* argc */, char* /* argv */[]) { // pipe to expand: `test.performance.stlsoft.frequency_map | expand -t 8,64,80,96,112,128,160` + perf_maybe_emit_groupgaps_banner(std::cout); + std::cout << std::endl; intervals_t const intervals_o = run_tests("O").first; #if __cplusplus >= 201103L diff --git a/test/performance/stlsoft/conversion/integer_to_string/main.cpp b/test/performance/stlsoft/conversion/integer_to_string/main.cpp index f0e74748..d49505f3 100644 --- a/test/performance/stlsoft/conversion/integer_to_string/main.cpp +++ b/test/performance/stlsoft/conversion/integer_to_string/main.cpp @@ -4,7 +4,7 @@ * Purpose: Perf-test for `stlsoft::integer_to_string<>`. * * Created: 29th October 2016 - * Updated: 29th September 2026 + * Updated: 30th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -23,6 +23,8 @@ #include +#include "perf_group_gaps.hpp" + #include #include #include @@ -410,7 +412,10 @@ int main(int argc, char* argv[]) size_t total = 0; + perf_maybe_emit_groupgaps_banner(stdout); + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "std::to_string() - base 0"); fprintf(stdout, "std::to_string() - base 0\n"); { @@ -431,6 +436,8 @@ int main(int argc, char* argv[]) total += execute_xtos< signed long long>(warmups, loops, iterations, stopwatch, 0); } + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "std::to_string() - base max() - N"); fprintf(stdout, "std::to_string() - base max() - N\n"); { @@ -454,6 +461,8 @@ int main(int argc, char* argv[]) } + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "snprintf() - base 0"); fprintf(stdout, "snprintf() - base 0\n"); { @@ -474,6 +483,8 @@ int main(int argc, char* argv[]) total += execute_printf< signed long long>(warmups, loops, iterations, stopwatch, 0); } + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "snprintf() - base max() - N"); fprintf(stdout, "snprintf() - base max() - N\n"); { @@ -497,6 +508,8 @@ int main(int argc, char* argv[]) } + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "integer_to_decimal_string() - base 0"); fprintf(stdout, "integer_to_decimal_string() - base 0\n"); { @@ -520,6 +533,8 @@ int main(int argc, char* argv[]) total += execute_dec< signed long long>(warmups, loops, iterations, stopwatch, 0); } + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "integer_to_decimal_string() - base max() - N"); fprintf(stdout, "integer_to_decimal_string() - base max() - N\n"); { @@ -543,6 +558,8 @@ int main(int argc, char* argv[]) } + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "integer_to_octal_string() - base 0"); fprintf(stdout, "integer_to_octal_string() - base 0\n"); { @@ -566,6 +583,8 @@ int main(int argc, char* argv[]) total += execute_oct< signed long long>(warmups, loops, iterations, stopwatch, 0); } + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "integer_to_octal_string() - base max() - N"); fprintf(stdout, "integer_to_octal_string() - base max() - N\n"); @@ -589,6 +608,8 @@ int main(int argc, char* argv[]) #undef N } + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "integer_to_hexadecimal_string() - base 0"); fprintf(stdout, "integer_to_hexadecimal_string() - base 0\n"); { @@ -612,6 +633,8 @@ int main(int argc, char* argv[]) total += execute_hex< signed long long>(warmups, loops, iterations, stopwatch, 0); } + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "integer_to_hexadecimal_string() - base max() - N"); fprintf(stdout, "integer_to_hexadecimal_string() - base max() - N\n"); { @@ -635,6 +658,8 @@ int main(int argc, char* argv[]) } + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "integer_to_base32_string() - base 0"); fprintf(stdout, "integer_to_base32_string() - base 0\n"); { @@ -658,6 +683,8 @@ int main(int argc, char* argv[]) total += execute_b32< signed long long>(warmups, loops, iterations, stopwatch, 0); } + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "integer_to_base32_string() - base max() - N"); fprintf(stdout, "integer_to_base32_string() - base max() - N\n"); { @@ -681,6 +708,8 @@ int main(int argc, char* argv[]) } + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "integer_to_base36_string() - base 0"); fprintf(stdout, "integer_to_base36_string() - base 0\n"); { @@ -704,6 +733,8 @@ int main(int argc, char* argv[]) total += execute_b36< signed long long>(warmups, loops, iterations, stopwatch, 0); } + /* Gap between API / base-family sections. */ + perf_maybe_emit_group_gap(stdout, "integer_to_base36_string() - base max() - N"); fprintf(stdout, "integer_to_base36_string() - base max() - N\n"); { diff --git a/test/performance/stlsoft/diagnostics/doomgram/main.cpp b/test/performance/stlsoft/diagnostics/doomgram/main.cpp index 58077af3..8a305129 100644 --- a/test/performance/stlsoft/diagnostics/doomgram/main.cpp +++ b/test/performance/stlsoft/diagnostics/doomgram/main.cpp @@ -4,7 +4,7 @@ * Purpose: Perf-test for `stlsoft::doomgram<>`. * * Created: 11th December 2024 - * Updated: 29th September 2026 + * Updated: 30th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -36,6 +36,8 @@ # include #endif /* C++11+ */ +#include "perf_group_gaps.hpp" + /* Standard header files */ #include @@ -147,6 +149,9 @@ display_results( > const& r ) { + /* Gap when the ordering / type group label changes. */ + perf_maybe_emit_group_gap(stm, ordering_label); + stm << '\t' << ordering_label << ": " << test_name @@ -411,6 +416,8 @@ int main(int /* argc */, char* /* argv */[]) { // pipe to expand: `test.performance.stlsoft.doomgram | expand -t 8,64,80,96,112,128,160` + perf_maybe_emit_groupgaps_banner(std::cout); + std::cout << std::endl; intervals_t const intervals_o = run_tests().first; diff --git a/test/performance/stlsoft/diagnostics/gram_utils/main.cpp b/test/performance/stlsoft/diagnostics/gram_utils/main.cpp index 90cab694..a6cc1447 100644 --- a/test/performance/stlsoft/diagnostics/gram_utils/main.cpp +++ b/test/performance/stlsoft/diagnostics/gram_utils/main.cpp @@ -4,7 +4,7 @@ * Purpose: Perf-test for gram_utils * * Created: 17th December 2024 - * Updated: 29th September 2026 + * Updated: 30th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -37,6 +37,8 @@ #endif /* C++11+ */ #include +#include "perf_group_gaps.hpp" + /* Standard header files */ #include @@ -94,6 +96,8 @@ thousands( int main(int /*argc*/, char* /*argv*/[]) { + perf_maybe_emit_groupgaps_banner(std::cout); + stopwatch_t sw; for (int W = 2; 0 != W; --W) diff --git a/test/performance/stlsoft/memory/auto_buffer/main.cpp b/test/performance/stlsoft/memory/auto_buffer/main.cpp index 40d5354b..fca69412 100644 --- a/test/performance/stlsoft/memory/auto_buffer/main.cpp +++ b/test/performance/stlsoft/memory/auto_buffer/main.cpp @@ -4,7 +4,7 @@ * Purpose: Perf-test for `stlsoft::auto_buffer<>`. * * Created: ... mid 2010s ... - * Updated: 29th September 2026 + * Updated: 30th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -29,6 +29,8 @@ #include #include +#include "perf_group_gaps.hpp" + #include #include #include @@ -192,6 +194,8 @@ int main(int argc, char* argv[]) char const* casename; + perf_maybe_emit_groupgaps_banner(std::cout); + std::cout << "creating array(s)" << std::endl; auto arrays_of_integers = create_integers_arrays( @@ -230,6 +234,8 @@ int main(int argc, char* argv[]) { char const* const grpname = "reserve"; + /* Gap between named auto_buffer operation groups. */ + perf_maybe_emit_group_gap(stdout, grpname); fprintf(stdout, "%s:\n", grpname); platformstl::stopwatch::interval_type tm_vec = 0; @@ -354,6 +360,8 @@ int main(int argc, char* argv[]) { char const* const grpname = "ctor(n, v)"; + /* Gap between named auto_buffer operation groups. */ + perf_maybe_emit_group_gap(stdout, grpname); fprintf(stdout, "%s:\n", grpname); platformstl::stopwatch::interval_type tm_vec = 0; @@ -487,6 +495,8 @@ int main(int argc, char* argv[]) { char const* const grpname = "copy construction"; + /* Gap between named auto_buffer operation groups. */ + perf_maybe_emit_group_gap(stdout, grpname); fprintf(stdout, "%s:\n", grpname); platformstl::stopwatch::interval_type tm_vec = 0; @@ -626,6 +636,8 @@ int main(int argc, char* argv[]) { char const* const grpname = "range construction"; + /* Gap between named auto_buffer operation groups. */ + perf_maybe_emit_group_gap(stdout, grpname); fprintf(stdout, "%s:\n", grpname); platformstl::stopwatch::interval_type tm_vec = 0; @@ -768,6 +780,8 @@ int main(int argc, char* argv[]) { char const* const grpname = "range construction (from list)"; + /* Gap between named auto_buffer operation groups. */ + perf_maybe_emit_group_gap(stdout, grpname); fprintf(stdout, "%s:\n", grpname); platformstl::stopwatch::interval_type tm_vec = 0; @@ -914,6 +928,8 @@ int main(int argc, char* argv[]) { char const* const grpname = "range construction (from input-iterator)"; + /* Gap between named auto_buffer operation groups. */ + perf_maybe_emit_group_gap(stdout, grpname); fprintf(stdout, "%s:\n", grpname); platformstl::stopwatch::interval_type tm_vec = 0; @@ -1049,6 +1065,8 @@ int main(int argc, char* argv[]) { char const* const grpname = "move ctor"; + /* Gap between named auto_buffer operation groups. */ + perf_maybe_emit_group_gap(stdout, grpname); fprintf(stdout, "%s:\n", grpname); platformstl::stopwatch::interval_type tm_vec = 0; diff --git a/test/performance/stlsoft/string/simple_string.compare/main.cpp b/test/performance/stlsoft/string/simple_string.compare/main.cpp index d3d4e212..a43848ec 100644 --- a/test/performance/stlsoft/string/simple_string.compare/main.cpp +++ b/test/performance/stlsoft/string/simple_string.compare/main.cpp @@ -4,7 +4,7 @@ * Purpose: Perf-test for `stlsoft::basic_simple_string#compare()`. * * Created: 15th March 2024 - * Updated: 29th September 2026 + * Updated: 30th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -50,6 +50,8 @@ #include #include +#include "perf_group_gaps.hpp" + #include #include #include @@ -334,6 +336,8 @@ int main(int argc, char* argv[]) { stlsoft::string_slice_m_t const program_name = platformstl::get_executable_name_from_path(argv[0]); + perf_maybe_emit_groupgaps_banner(std::cout); + // FOOLING THE OPTIMISER: // // - load the scenarios (from `SCENARIOS`); @@ -395,6 +399,8 @@ large (unequal lengths)|abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd // sc& <=> cc* { + /* Gap between compare-form sections. */ + perf_maybe_emit_group_gap(std::cout, "sc& <=> cc*"); std::cout << "sc& <=> cc*:" << std::endl; for (auto i : line_tokeniser) @@ -446,6 +452,8 @@ large (unequal lengths)|abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd // sc& <=> p, n, cc* { + /* Gap between compare-form sections. */ + perf_maybe_emit_group_gap(std::cout, "sc& <=> p, n, cc*"); std::cout << "sc& <=> p, n, cc*:" << std::endl; for (auto i : line_tokeniser) @@ -497,6 +505,8 @@ large (unequal lengths)|abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd // sc& <=> p, n, cc*, n { + /* Gap between compare-form sections. */ + perf_maybe_emit_group_gap(std::cout, "sc& <=> p, n, cc*, n"); std::cout << "sc& <=> p, n, cc*, n:" << std::endl; for (auto i : line_tokeniser) @@ -548,6 +558,8 @@ large (unequal lengths)|abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd // sc& <=> sc& { + /* Gap between compare-form sections. */ + perf_maybe_emit_group_gap(std::cout, "sc& <=> sc&"); std::cout << "sc& <=> sc&:" << std::endl; for (auto i : line_tokeniser) @@ -598,6 +610,8 @@ large (unequal lengths)|abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd // sc& <=> p, n, sc& { + /* Gap between compare-form sections. */ + perf_maybe_emit_group_gap(std::cout, "sc& <=> p/n/sc&"); std::cout << "sc& <=> p/n/sc&:" << std::endl; for (auto i : line_tokeniser) @@ -649,6 +663,8 @@ large (unequal lengths)|abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd // sc& <=> p, n, sc&, p, n { + /* Gap between compare-form sections. */ + perf_maybe_emit_group_gap(std::cout, "sc& <=> p/n/sc&/p/n"); std::cout << "sc& <=> p/n/sc&/p/n:" << std::endl; for (auto i : line_tokeniser) diff --git a/test/performance/stlsoft/string/simple_string.op_eq/main.cpp b/test/performance/stlsoft/string/simple_string.op_eq/main.cpp index 8ca3222d..b77fce21 100644 --- a/test/performance/stlsoft/string/simple_string.op_eq/main.cpp +++ b/test/performance/stlsoft/string/simple_string.op_eq/main.cpp @@ -4,7 +4,7 @@ * Purpose: Perf-test for `stlsoft::basic_simple_string#operator ==()`. * * Created: 15th March 2024 - * Updated: 29th September 2026 + * Updated: 30th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -50,6 +50,8 @@ #include #include +#include "perf_group_gaps.hpp" + #include #include #include @@ -207,6 +209,8 @@ int main(int argc, char* argv[]) { stlsoft::string_slice_m_t const program_name = platformstl::get_executable_name_from_path(argv[0]); + perf_maybe_emit_groupgaps_banner(std::cout); + // FOOLING THE OPTIMISER: // // - load the scenarios (from `SCENARIOS`); @@ -268,6 +272,8 @@ large (unequal lengths)|abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd // sc& <=> cc* { + /* Gap between compare-form sections. */ + perf_maybe_emit_group_gap(std::cout, "sc& <=> cc*"); std::cout << "sc& <=> cc*:" << std::endl; for (auto i : line_tokeniser) @@ -318,6 +324,8 @@ large (unequal lengths)|abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd // sc& <=> sc& { + /* Gap between compare-form sections. */ + perf_maybe_emit_group_gap(std::cout, "sc& <=> sc&"); std::cout << "sc& <=> sc&:" << std::endl; for (auto i : line_tokeniser) diff --git a/test/performance/stlsoft/util/bit_functions/main.cpp b/test/performance/stlsoft/util/bit_functions/main.cpp index b19331e8..7bf43064 100644 --- a/test/performance/stlsoft/util/bit_functions/main.cpp +++ b/test/performance/stlsoft/util/bit_functions/main.cpp @@ -4,7 +4,7 @@ * Purpose: Perf-test for bit functions. * * Created: 24th September 2026 - * Updated: 25th September 2026 + * Updated: 30th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -37,6 +37,8 @@ #endif /* C++11+ */ #include +#include "perf_group_gaps.hpp" + #include #include #include @@ -297,56 +299,12 @@ emit_header_row() std::cout << std::endl; } -bool -env_is_truey( - char const* name -) -{ -#if defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable : 4996) -#endif - char const* const env = ::getenv(name); -#if defined(_MSC_VER) -# pragma warning(pop) -#endif - - if (NULL == env || '\0' == *env) - { - return false; - } - - if (0 == ::strcmp(env, "1") || - 0 == ::strcmp(env, "ok") || - 0 == ::strcmp(env, "on") || - 0 == ::strcmp(env, "true") || - 0 == ::strcmp(env, "yes") || - 0 == ::strcmp(env, "y") || - 0 == ::strcmp(env, "OK") || - 0 == ::strcmp(env, "ON") || - 0 == ::strcmp(env, "TRUE") || - 0 == ::strcmp(env, "YES") || - 0 == ::strcmp(env, "Y")) - { - return true; - } - - return false; -} - void maybe_emit_group_gap( char const* function_name ) { - static bool have_prev = false; - static char prev_key[64] = ""; - - if (!env_is_truey("SIS_PERFTESTS_GROUPGAPS")) - { - return; - } - + /* Gap when bit-function family + pattern group changes. */ char const* const slash = ::strrchr(function_name, '/'); char const* const pattern = (NULL == slash) ? "" : slash; char const* family = "other"; @@ -368,13 +326,7 @@ maybe_emit_group_gap( snprintf(key, sizeof(key), "%s%s", family, pattern); - if (have_prev && 0 != ::strcmp(prev_key, key)) - { - std::cout << std::endl; - } - - snprintf(prev_key, sizeof(prev_key), "%s", key); - have_prev = true; + perf_maybe_emit_group_gap(std::cout, key); } void @@ -525,12 +477,7 @@ emit_build_banner() std::cout << "width columns are loop ns; ns columns are ns/call; el columns are ns/element" << std::endl; - if (env_is_truey("SIS_PERFTESTS_GROUPGAPS")) - { - std::cout - << "Env: SIS_PERFTESTS_GROUPGAPS=1" - << std::endl; - } + perf_maybe_emit_groupgaps_banner(std::cout); } diff --git a/test/performance/stlsoft/util/count_digits/main.cpp b/test/performance/stlsoft/util/count_digits/main.cpp index 72f2fa81..dda4fa3d 100644 --- a/test/performance/stlsoft/util/count_digits/main.cpp +++ b/test/performance/stlsoft/util/count_digits/main.cpp @@ -4,7 +4,7 @@ * Purpose: Perf-test for digit-counting functions. * * Created: 18th December 2024 - * Updated: 29th September 2026 + * Updated: 30th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -37,6 +37,8 @@ #endif /* C++11+ */ #include +#include "perf_group_gaps.hpp" + #include #include @@ -90,7 +92,11 @@ thousands( int main(int /*argc*/, char* /*argv*/[]) { + perf_maybe_emit_groupgaps_banner(std::cout); + // count_decimal_digits + /* Gap between digit-count function families. */ + perf_maybe_emit_group_gap(std::cout, "count_decimal_digits"); for (int W = 2; 0 != W; --W) { stopwatch_t sw; @@ -181,6 +187,8 @@ int main(int /*argc*/, char* /*argv*/[]) // count_hexadecimal_digits + /* Gap between digit-count function families. */ + perf_maybe_emit_group_gap(std::cout, "count_hexadecimal_digits"); for (int W = 2; 0 != W; --W) { stopwatch_t sw; From c0135ce646404833b8467d12130e0f0c6cfc6eb7 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Wed, 30 Sep 2026 13:56:55 +1000 Subject: [PATCH 10/31] 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**. --- CMakeLists.txt | 4 ++-- TODO.md | 2 +- strategy/BIT_FUNCTIONS.md | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 02f1f520..93f51914 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ # Purpose: Top-level CMake lists file for STLSoft # # Created: 31st March 2021 -# Updated: 7th August 2026 +# Updated: 30th September 2026 # # ######################################################################## # @@ -112,7 +112,7 @@ if(MFC_FOUND) # static CRT (**MSVC_USE_MT**), in which case static MFC is required. # # **CMAKE_MFC_FLAG** / **_AFXDLL** are applied only to MFC-consuming - # targets (see **test/unit/mfcstl** and **test.unit.versions**). Setting + # targets (see **test/unit/mfcstl** and **test/unit/versions**). Setting # them project-wide would force every subsequent MSVC executable to link # MFC. Without them on those targets, `find_package(MFC)` can succeed # while mfcstl tests fail to link — the historical GHA failure mode. diff --git a/TODO.md b/TODO.md index b1564d42..fae197b5 100644 --- a/TODO.md +++ b/TODO.md @@ -51,7 +51,7 @@ Dedicated increment: **test analysis and coverage only** — no other product ch * [ ] `invalid_integral_range_policy::operator()` — implement in terms of `stlsoft_C_snprintf()` (replace `::sprintf`); * [ ] Canonicalise exception messages (consistency, lower-case, etc.); * [ ] Rename HAS files under **include/stlsoft/internal/std/has/** to remove the trailing `_` (and disambiguate further if needed); -* [ ] Add **test.performance.stlsoft.util.bit_functions**; +* [x] ~~~Add **test.performance.stlsoft.util.bit_functions**~~~ - ✅; * [ ] Take down https://github.com/synesissoftware/STLSoft-1.10-delta; diff --git a/strategy/BIT_FUNCTIONS.md b/strategy/BIT_FUNCTIONS.md index f736d0ed..d757cec4 100644 --- a/strategy/BIT_FUNCTIONS.md +++ b/strategy/BIT_FUNCTIONS.md @@ -1,6 +1,6 @@ -# STLSoft.b - Bit Functions +# STLSoft - Bit Functions -Strategy note for **STLSoft.b** bit utilities. Measurements are of the performance program **test/performance/stlsoft/bit_functions/main.cpp**. Library sources are **include/stlsoft/util/bits/count_functions.h**, **include/stlsoft/util/bits/test_functions.h**, and **include/stlsoft/util/bits/xor_functions.h**. Intrinsic detection and naming live in **include/stlsoft/api/external/bitfns.h** and **include/stlsoft/api/internal/bitfns.h**. +Strategy note for **STLSoft** bit utilities. Measurements are of the performance program **test/performance/stlsoft/util/bit_functions/main.cpp**. Library sources are **include/stlsoft/util/bits/count_functions.h**, **include/stlsoft/util/bits/test_functions.h**, and **include/stlsoft/util/bits/xor_functions.h**. Intrinsic detection and naming live in **include/stlsoft/api/external/bitfns.h** and **include/stlsoft/api/internal/bitfns.h**. ## Question From 085f4f957ce1bcdf0bb93685acb15e433d0e5d40 Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Thu, 8 Oct 2026 19:35:45 +1100 Subject: [PATCH 11/31] Boilerplate, CI (#53) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * .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 (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 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::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 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> --- .gitattributes | 27 +++ build_cmake.sh | 188 +++++++++++++++------ clean_cmake.sh | 160 ++++++++++++++---- ctest_cmake.sh | 171 ++++++++++++++++--- dev/bin/batch_compile_check | 2 +- execute_performance_tests.sh | 2 +- generate_doxygen.sh | 83 ++++++++++ prepare_cmake.sh | 280 ++++++++++++++++++++----------- remove_cmake_artefacts.sh | 146 ++++++++++++----- run_all_automated_tests.cmd | 106 ++++++++++++ run_all_automated_tests.sh | 180 ++++++++++++++++++++ run_all_component_tests.cmd | 94 +++++++++++ run_all_component_tests.sh | 300 ++++++++++++++++++++++++++++++++++ run_all_examples.cmd | 225 +++++++------------------ run_all_examples.sh | 273 +++++++++++++++---------------- run_all_performance_tests.cmd | 96 +++++++++++ run_all_performance_tests.sh | 290 ++++++++++++++++++++++++++++++++ run_all_scratch_tests.cmd | 190 ++++++--------------- run_all_scratch_tests.sh | 204 +++++++++++++++++------ run_all_unit_tests.cmd | 231 +++++++------------------- run_all_unit_tests.sh | 246 +++++++++++++++++----------- 21 files changed, 2489 insertions(+), 1005 deletions(-) create mode 100755 generate_doxygen.sh create mode 100644 run_all_automated_tests.cmd create mode 100755 run_all_automated_tests.sh create mode 100644 run_all_component_tests.cmd create mode 100755 run_all_component_tests.sh create mode 100644 run_all_performance_tests.cmd create mode 100755 run_all_performance_tests.sh diff --git a/.gitattributes b/.gitattributes index 76a2f865..1ad0590c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,6 +3,11 @@ # Sources: GitHub Docs (line endings), git-scm gitattributes (diff=cpp), # gitattributes/gitattributes C++.gitattributes + Common.gitattributes, # github-linguist overrides. +# +# Linguist language-bar policy (Synesis): classify public C API headers as C +# and *.cmake as CMake scripts; keep helper scripts, IDE project files, and +# CMakeLists.txt config out of the advertised language mix. Prefer +# -linguist-detectable over linguist-detectable=false. # Default: detect text, normalize to LF in the repository * text=auto @@ -97,3 +102,25 @@ TODO text # --- GitHub Linguist --- **/build/** linguist-generated **/cmake-build-*/** linguist-generated + +# Classification (C-primary / C API with C++ tests; *.cmake as CMake scripts) +*.c linguist-language=C +*.cmake linguist-language=CMake +*.cpp linguist-language=C++ +*.cxx linguist-language=C++ +*.h linguist-language=C +*.hpp linguist-language=C++ +*.hxx linguist-language=C++ + +# Keep the bar on library languages (helpers / legacy IDE / docs / +# CMakeLists.txt config; leave *.cmake detectable as CMake) +*.cmd -linguist-detectable +*.dsp -linguist-detectable +*.dsw -linguist-detectable +*.html -linguist-detectable +*.sh -linguist-detectable +*.sln -linguist-detectable +*.vcxproj -linguist-detectable +*.vimrc -linguist-detectable +CMakeLists.txt -linguist-detectable +makefile -linguist-detectable diff --git a/build_cmake.sh b/build_cmake.sh index 55e6c4ac..a675a9da 100755 --- a/build_cmake.sh +++ b/build_cmake.sh @@ -1,22 +1,119 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) -Basename=$(basename "$ScriptPath") +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} IgnoreRemainingFlagsAndOptions=0 +SisUseColours=0 Targets=() # ########################################################## -# functions +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { -function join_by { local IFS="$1"; shift; echo "$*"; } + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} # ########################################################## @@ -26,21 +123,16 @@ while [[ $# -gt 0 ]]; do if [ $IgnoreRemainingFlagsAndOptions -ne 0 ]; then - Targets+=($1) - + Targets+=("$1") shift - continue - else - - if [ ! ${1:0:1} = '-' ]; then - - Targets+=($1) + fi - shift + if [ "${1:0:1}" != '-' ]; then - continue - fi + Targets+=("$1") + shift + continue fi case $1 in @@ -48,18 +140,33 @@ while [[ $# -gt 0 ]]; do IgnoreRemainingFlagsAndOptions=1 ;; + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --help) [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" cat << EOF Executes CMake-generated artefacts to (re)build project -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + (no arguments) + builds all default targets + + ... + builds one or more specific targets + + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + standard flags: @@ -72,7 +179,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -85,41 +192,26 @@ done # ########################################################## # main() -if [ ! -d "$CMakeDir" ]; then +if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + >&2 echo "${ScriptPathClr}: CMake build directory '${CMakeDirClr}' not found or not configured; use script 'prepare_cmake.sh' first" exit 1 -else - - cd $CMakeDir - - if [ ! -f "$CMakeDir/Makefile" ]; then - - >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' does not contain expected file 'Makefile', so a build cannot be performed. It is recommended that you remove all CMake artefacts using script 'remove_cmake_artefacts.sh' followed by regeneration via 'prepare_cmake.sh'" - - cd ->/dev/null - - exit 1 - else - - if [ -z "$Targets" ]; then - - echo "Executing build for ${ProjectName} (via command \`$MakeCmd\`)" - else - - echo "Executing build for ${ProjectName} (via command \`$MakeCmd\`) with specific target(s) $(join_by , "${Targets[@]}")" - fi +fi - $MakeCmd ${Targets[*]} - status=$? +if [ ${#Targets[@]} -eq 0 ]; then - cd ->/dev/null + echo "Executing build of ${ProjectNameClr} (via cmake --build)" + sis_cmake_build + status=$? +else - exit $status - fi + echo "Executing build of ${ProjectNameClr} (via cmake --build) with specific target(s): ${Targets[*]}" + sis_cmake_build "${Targets[@]}" + status=$? fi +exit $status -# ############################## end of file ############################# # +# ############################## end of file ############################# # diff --git a/clean_cmake.sh b/clean_cmake.sh index ead9c205..733afbdd 100755 --- a/clean_cmake.sh +++ b/clean_cmake.sh @@ -1,13 +1,117 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) -Basename=$(basename "$ScriptPath") +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 + +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} +SisUseColours=0 + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} # ########################################################## @@ -16,18 +120,27 @@ ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --help) [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" cat << EOF -Executes CMake-generated artefacts to clean project +Cleans CMake-generated build artefacts via cmake --build --target clean -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + standard flags: @@ -40,7 +153,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -53,35 +166,16 @@ done # ########################################################## # main() -if [ ! -d "$CMakeDir" ]; then +if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + >&2 echo "${ScriptPathClr}: CMake build directory '${CMakeDirClr}' not found or not configured; nothing to clean" exit 1 -else - - cd $CMakeDir - - if [ ! -f "$CMakeDir/Makefile" ]; then - - >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' does not contain expected file 'Makefile', so a clean cannot be performed. It is recommended that you remove all CMake artefacts using script 'remove_cmake_artefacts.sh' followed by regeneration via 'prepare_cmake.sh'" - - cd ->/dev/null - - exit 1 - else - - echo "Cleaning ${ProjectName} build (via command \`$MakeCmd clean\`)" - - $MakeCmd clean - status=$? - - cd ->/dev/null - - exit $status - fi fi +echo "Executing clean of ${ProjectNameClr} (via cmake --build --target clean)" +sis_cmake_build clean +exit $? -# ############################## end of file ############################# # +# ############################## end of file ############################# # diff --git a/ctest_cmake.sh b/ctest_cmake.sh index 24c21723..4e09ee21 100755 --- a/ctest_cmake.sh +++ b/ctest_cmake.sh @@ -1,16 +1,119 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) -Basename=$(basename "$ScriptPath") +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 -CMakeVerbose= +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} +CTestVerbose= RunMake=1 +SisUseColours=0 + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} # ########################################################## @@ -19,13 +122,17 @@ RunMake=1 while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --no-make|-M) RunMake=0 ;; --verbose|-V) - CMakeVerbose=--verbose + CTestVerbose=--verbose ;; --help) @@ -33,15 +140,20 @@ while [[ $# -gt 0 ]]; do cat << EOF Runs CMake's CTest test program(s) -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + -M --no-make - does not execute CMake and make before running tests + does not execute a build before running tests -V --verbose @@ -59,7 +171,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -76,29 +188,48 @@ status=0 if [ $RunMake -ne 0 ]; then - echo "Executing build for ${ProjectName} (via command \`$MakeCmd\`) and then running all component and unit test programs" + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build) and then running CTest" - mkdir -p $CMakeDir || exit 1 + mkdir -p "$CMakeDir" || exit 1 - cd $CMakeDir + if [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - $MakeCmd - status=$? + >&2 echo "${ScriptPathClr}: '${CMakeDirClr}' is not configured; use prepare_cmake.sh first" + + exit 1 + fi - cd ->/dev/null + sis_cmake_build + status=$? else - if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ] || [ ! -d "$CMakeDir/CMakeFiles" ]; then + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then + + >&2 echo "${ScriptPathClr}: cannot run in '--no-make' mode without a previous successful configure/build" - >&2 echo "$ScriptPath: cannot run in '--no-make' mode without a previous successful build step" + exit 1 fi fi if [ $status -eq 0 ]; then - echo "Running CMake tests" + echo + echo "Running ${ProjectNameClr} CMake tests" + + # Multi-config generators (e.g. Visual Studio) need -C ; + # mirror sis_cmake_build's CMAKE_CONFIGURATION_TYPES detection. + ctest_args=(--test-dir "$CMakeDir" --output-on-failure) + if [ -n "$CTestVerbose" ]; then + + ctest_args+=("$CTestVerbose") + fi + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + ctest_args+=(-C "${SIS_CMAKE_CONFIG:-Release}") + fi - ctest --test-dir $CMakeDir $CMakeVerbose + ctest "${ctest_args[@]}" status=$? fi diff --git a/dev/bin/batch_compile_check b/dev/bin/batch_compile_check index b5274772..2bd4c0a6 100755 --- a/dev/bin/batch_compile_check +++ b/dev/bin/batch_compile_check @@ -14,7 +14,7 @@ ScriptPath=$0 -ProjectDir=$(cd $(dirname "$ScriptPath"); pwd) +ProjectDir=$(cd "$(dirname "$ScriptPath")" && pwd) Basename=$(basename "$ScriptPath") IncludeDir="$ProjectDir/../../include" ScratchDir="$ProjectDir/../../scratch" diff --git a/execute_performance_tests.sh b/execute_performance_tests.sh index e15fbc44..b26b638c 100755 --- a/execute_performance_tests.sh +++ b/execute_performance_tests.sh @@ -1,7 +1,7 @@ #! /bin/bash ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) Basename=$(basename "$ScriptPath") CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} [[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make diff --git a/generate_doxygen.sh b/generate_doxygen.sh new file mode 100755 index 00000000..504b6619 --- /dev/null +++ b/generate_doxygen.sh @@ -0,0 +1,83 @@ +#! /bin/bash + +############################################################################# +# File: generate_doxygen.sh +# +# Purpose: Generates HTML API documentation from public headers via Doxygen +# +############################################################################# + +ScriptPath=$0 +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) +Basename=$(basename "$ScriptPath") +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Generates HTML API documentation from public headers via Doxygen + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + standard flags: + + --help + displays this help and terminates + +Environment: + + SIS_CMAKE_BUILD_DIR + CMake build directory (default: /_build); documentation is + written to /doxygen/html/ + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +cd "$Dir" || exit 1 + +if ! command -v doxygen >/dev/null 2>&1; then + >&2 echo "$ScriptPath: doxygen not found on PATH" + exit 1 +fi + +mkdir -p "${CMakeDir}/doxygen" + +{ + cat Doxyfile + echo "" + echo "# Output directory (overridden by ${Basename})" + echo "OUTPUT_DIRECTORY = ${CMakeDir}/doxygen" +} | doxygen - + +echo "${ProjectName} API documentation written to ${CMakeDir}/doxygen/html/index.html" + + +# ############################## end of file ############################# # diff --git a/prepare_cmake.sh b/prepare_cmake.sh index b1f2da31..1738fafd 100755 --- a/prepare_cmake.sh +++ b/prepare_cmake.sh @@ -1,41 +1,143 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) -Basename=$(basename "$ScriptPath") -CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -if [[ -n "$MSYSTEM" ]]; then +# ########################################################## +# functions - 1 - DefaultMakeCmd=mingw32-make.exe - MinGW=1 -else +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in - DefaultMakeCmd=make -fi -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 - +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} +BuildSharedLibs=0 Configuration=Release ExamplesDisabled=0 +MinGW=$(sis_cmake_is_truey "${SIS_CMAKE_MINGW:-}" && echo 1 || echo 0) MSVC_MT=0 -MinGW="${MinGW:=0}" -NO_ACE=0 -NO_cstring=0 NO_shwild=0 RunMake=0 +SisUseColours=0 +STLSoftDirGiven= TestingDisabled=0 -USE_UNIXem=0 VerboseMakefile=0 +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} + + # ########################################################## # command-line handling while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; + --build-shared-libs) + + BuildSharedLibs=1 + ;; --cmake-verbose-makefile|-v) VerboseMakefile=1 @@ -60,14 +162,6 @@ while [[ $# -gt 0 ]]; do MSVC_MT=1 ;; - --no-ace) - - NO_ACE=1 - ;; - --no-cstring) - - NO_cstring=1 - ;; --no-shwild) NO_shwild=1 @@ -76,9 +170,10 @@ while [[ $# -gt 0 ]]; do RunMake=1 ;; - --use-unixem) + --stlsoft-root-dir|-s) - USE_UNIXem=1 + shift + STLSoftDirGiven=$1 ;; --help) @@ -86,60 +181,57 @@ while [[ $# -gt 0 ]]; do cat << EOF Creates/reinitialises the CMake build script(s) -$ScriptPath [ ... flags/options ... ] - -IMPORTANT: If you have not previously performed a CMake installation of xTests, the library that STLSoft uses for its own tests, you MUST specify the -E and -T flags. Once you have installed STLSoft, you can then configure/build/install STLSoft, and then come back and prepare STLSoft without -E/-T and exercise its examples and tests. +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + + --build-shared-libs + builds ${ProjectName} as a shared library (BUILD_SHARED_LIBS=ON) + -v --cmake-verbose-makefile - configures CMake to run verbosely (by setting CMAKE_VERBOSE_MAKEFILE - to be ON) + configures CMake to run verbosely (CMAKE_VERBOSE_MAKEFILE=ON) -d --debug-configuration - use Debug configuration (by setting CMAKE_BUILD_TYPE=Debug). Default - is to use Release + use Debug configuration (CMAKE_BUILD_TYPE=Debug). Default is Release -E --disable-examples - disables building of examples (by setting BUILD_EXAMPLES=OFF) + disables building of examples (BUILD_EXAMPLES=OFF) -T --disable-testing - disables building of tests (by setting BUILD_TESTING=OFF). This is - necessary, for example, when installing on a system that does not - (yet) have xTests - which itself depends on STLSOFT - installed + disables building of tests (BUILD_TESTING=OFF). Unless testing is + disabled the STLSoft and xTests libraries will be required to be + available to CMake --mingw uses explicitly the "MinGW Makefiles" generator --msvc-mt - when using Visual C++ (MSVC), the static runtime library will be - selected; the default is the dynamic runtime library. Has no effect - when not using Visual C++ - - --no-ace - suppresses discovery of ACE (ACESTL examples/tests will not be built) - - --no-cstring - suppresses discovery of cstring package + when using Visual C++ (MSVC), select the static runtime library --no-shwild - suppresses discovery of shwild package + prevents recognising shwild library (NO_SHWILD=ON); xTests + pattern-match assertions are then unavailable -m --run-make - executes make after a successful running of CMake + executes a build via cmake --build after a successful configure - --use-unixem - when building on Windows, use the UNIXem library and define the - preprocessor symbol _STLSOFT_FORCE_ANY_COMPILER so as to emulate and - exercise UNIXSTL, not WinSTL (or COMSTL, etc.). Has no effect when not - executing on Windows + -s + --stlsoft-root-dir + specifies the STLSoft root-directory, which will be passed to CMake + as the variable STLSOFT, and which will override the environment + variable STLSOFT (if present) standard flags: @@ -147,15 +239,13 @@ Flags/options: --help displays this help and terminates -IMPORTANT: If you have not previously performed a CMake installation of xTests, the library that STLSoft uses for its own tests, you MUST specify the -E and -T flags. Once you have installed STLSoft, you can then configure/build/install STLSoft, and then come back and prepare STLSoft without -E/-T and exercise its examples and tests. - EOF exit 0 ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -168,72 +258,68 @@ done # ########################################################## # main() -mkdir -p $CMakeDir || exit 1 - -cd $CMakeDir +mkdir -p "$CMakeDir" || exit 1 -echo "Executing CMake for ${ProjectName} (in ${CMakeDir})" +echo +echo "Executing CMake for ${ProjectNameClr} (in ${CMakeDirClr})" +if [ $BuildSharedLibs -eq 0 ]; then CMakeBuildSharedLibsFlag="OFF" ; else CMakeBuildSharedLibsFlag="ON" ; fi if [ $ExamplesDisabled -eq 0 ]; then CMakeBuildExamplesFlag="ON" ; else CMakeBuildExamplesFlag="OFF" ; fi if [ $MSVC_MT -eq 0 ]; then CMakeMsvcMtFlag="OFF" ; else CMakeMsvcMtFlag="ON" ; fi -if [ $NO_ACE -eq 0 ]; then CMakeNoACE="OFF" ; else CMakeNoACE="ON" ; fi -if [ $NO_cstring -eq 0 ]; then CMakeNoCstring="OFF" ; else CMakeNoCstring="ON" ; fi if [ $NO_shwild -eq 0 ]; then CMakeNoShwild="OFF" ; else CMakeNoShwild="ON" ; fi +if [ -z "$STLSoftDirGiven" ]; then CMakeSTLSoftVariable="" ; else CMakeSTLSoftVariable="-DSTLSOFT=$STLSoftDirGiven/" ; fi if [ $TestingDisabled -eq 0 ]; then CMakeBuildTestingFlag="ON" ; else CMakeBuildTestingFlag="OFF" ; fi -if [ $USE_UNIXem -ne 0 ]; then CMakeUSE_UNIXem="ON" ; else CMakeUSE_UNIXem="OFF" ; fi if [ $VerboseMakefile -eq 0 ]; then CMakeVerboseMakefileFlag="OFF" ; else CMakeVerboseMakefileFlag="ON" ; fi +# NOTE: the generator is the *only* thing that may differ between the MinGW +# and the default paths; every -D option is passed in both cases, so that no +# flag can be silently ignored according to the generator selected. + +CMakeGeneratorArgs=() + +if [ -n "${SIS_CMAKE_GENERATOR:-}" ] && [ $MinGW -eq 0 ]; then + + CMakeGeneratorArgs=(-G "$SIS_CMAKE_GENERATOR") +fi + if [ $MinGW -ne 0 ]; then - cmake \ - -DBUILD_EXAMPLES:BOOL=$CMakeBuildExamplesFlag \ - -DBUILD_TESTING:BOOL=$CMakeBuildTestingFlag \ - -DCMAKE_BUILD_TYPE=$Configuration \ - -DNO_ACE:BOOL=$CMakeNoACE \ - -DNO_CSTRING:BOOL=$CMakeNoCstring \ - -DNO_SHWILD:BOOL=$CMakeNoShwild \ - -DUSE_UNIXEM:BOOL=$CMakeUSE_UNIXem \ - -G "MinGW Makefiles" \ - -S $Dir \ - -B $CMakeDir \ - || (cd ->/dev/null ; exit 1) -else - - cmake \ - -DBUILD_EXAMPLES:BOOL=$CMakeBuildExamplesFlag \ - -DBUILD_TESTING:BOOL=$CMakeBuildTestingFlag \ - -DCMAKE_BUILD_TYPE=$Configuration \ - -DCMAKE_VERBOSE_MAKEFILE:BOOL=$CMakeVerboseMakefileFlag \ - -DMSVC_USE_MT:BOOL=$CMakeMsvcMtFlag \ - -DNO_ACE:BOOL=$CMakeNoACE \ - -DNO_CSTRING:BOOL=$CMakeNoCstring \ - -DNO_SHWILD:BOOL=$CMakeNoShwild \ - -DUSE_UNIXEM:BOOL=$CMakeUSE_UNIXem \ - -S $Dir \ - -B $CMakeDir \ - || (cd ->/dev/null ; exit 1) + CMakeGeneratorArgs=(-G "MinGW Makefiles") fi +cmake \ + -DBUILD_EXAMPLES:BOOL=$CMakeBuildExamplesFlag \ + -DBUILD_SHARED_LIBS:BOOL=$CMakeBuildSharedLibsFlag \ + -DBUILD_TESTING:BOOL=$CMakeBuildTestingFlag \ + -DCMAKE_BUILD_TYPE=$Configuration \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=$CMakeVerboseMakefileFlag \ + -DMSVC_USE_MT:BOOL=$CMakeMsvcMtFlag \ + -DNO_SHWILD:BOOL=$CMakeNoShwild \ + $CMakeSTLSoftVariable \ + "${CMakeGeneratorArgs[@]}" \ + -B "$CMakeDir" \ + -S "$Dir" \ + || exit 1 + status=0 if [ $RunMake -ne 0 ]; then - echo "Executing build for ${ProjectName} (via command \`$MakeCmd\`)" + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build)" - $MakeCmd + sis_cmake_build status=$? fi -cd ->/dev/null - if [ $VerboseMakefile -ne 0 ]; then - echo -e "contents of $CMakeDir:" - ls -al $CMakeDir + echo + echo -e "contents of ${CMakeDirClr}:" + ls -al "$CMakeDir" fi exit $status # ############################## end of file ############################# # - diff --git a/remove_cmake_artefacts.sh b/remove_cmake_artefacts.sh index 97c1bc00..377d3ab8 100755 --- a/remove_cmake_artefacts.sh +++ b/remove_cmake_artefacts.sh @@ -1,17 +1,20 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) -Basename=$(basename "$ScriptPath") +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} Directories=( CMakeFiles Testing cmake - docs examples projects src @@ -21,19 +24,77 @@ Files=( CMakeCache.txt CTestTestfile.cmake DartConfiguration.tcl - Doxyfile Makefile cmake_install.cmake install_manifest.txt ) +SisUseColours=0 + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" # ########################################################## # operating environment detection -OsName="$(uname -s)" +OsName="$(uname -s 2>/dev/null || echo Unknown)" case "${OsName}" in - CYGWIN*|MINGW*|MSYS_NT*) + CYGWIN*|MINGW*|MSYS_NT*|Windows_NT) Directories+=( ARM64 @@ -45,9 +106,6 @@ case "${OsName}" in "*.sln" "*.vcxproj" ) - ;; - *) - ;; esac @@ -58,18 +116,27 @@ esac while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --help) [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" cat << EOF Removes all known CMake artefacts -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + standard flags: @@ -82,7 +149,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -97,59 +164,50 @@ done if [ ! -d "$CMakeDir" ]; then - echo "$ScriptPath: CMake build directory '$CMakeDir' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + echo "${ScriptPathClr}: CMake build directory '${CMakeDirClr}' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" exit 0 -else - - echo "Removing all ${ProjectName} cmake artefacts in '$CMakeDir'" +fi - num_dirs_removed=0 - num_files_removed=0 +echo "Removing all ${ProjectNameClr} cmake artefacts in '${CMakeDirClr}'" - for d in ${Directories[@]} - do +num_dirs_removed=0 +num_files_removed=0 - fq_dir_path="$CMakeDir/$d" +for d in "${Directories[@]}"; do - [ -d "$fq_dir_path" ] || continue + fq_dir_path="$CMakeDir/$d" - echo "removing directory '$d'" + [ -d "$fq_dir_path" ] || continue - rm -dfr "$fq_dir_path" + echo "removing directory '$d'" - num_dirs_removed=$((num_dirs_removed+1)) - done + rm -dfr "$fq_dir_path" - cd "$CMakeDir" + num_dirs_removed=$((num_dirs_removed+1)) +done - for f in ${Files[@]} - do +for f in "${Files[@]}"; do - for fq_file_path in $f - do + for fq_file_path in "$CMakeDir"/$f; do - [ -f "$fq_file_path" ] || continue + [ -f "$fq_file_path" ] || continue - echo "removing file '$fq_file_path'" + echo "removing file '$fq_file_path'" - rm -f "$fq_file_path" + rm -f "$fq_file_path" - num_files_removed=$((num_files_removed+1)) - done + num_files_removed=$((num_files_removed+1)) done +done - cd ->/dev/null - - if [ 0 -eq $num_dirs_removed ] && [ 0 -eq $num_files_removed ]; then +if [ 0 -eq $num_dirs_removed ] && [ 0 -eq $num_files_removed ]; then - echo "nothing to do" - else + echo "nothing to do" +else - echo "removed $num_dirs_removed directories and $num_files_removed files" - fi + echo "removed $num_dirs_removed directories and $num_files_removed files" fi # ############################## end of file ############################# # - diff --git a/run_all_automated_tests.cmd b/run_all_automated_tests.cmd new file mode 100644 index 00000000..b6dd937d --- /dev/null +++ b/run_all_automated_tests.cmd @@ -0,0 +1,106 @@ +@echo off + +SETLOCAL + +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] + +SET UnitOnly=0 +SET ComponentOnly=0 + +FOR %%a IN (%*) DO ( + + IF /I {--help}=={%%a} ( + + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( + + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ + +Runs all ^(matching^) automated test programs ^(unit and component^) ^ + +^ + +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ + +^ + +Flags/options: ^ + + behaviour: ^ + +^ + + --unit-only ^ + + runs only unit-test programs ^ + +^ + + --component-only ^ + + runs only component-test programs ^ + +^ + + standard flags: ^ + +^ + + --help ^ + + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE IF /I {--unit-only}=={%%a} ( + + SET UnitOnly=1 + ) ELSE IF /I {--component-only}=={%%a} ( + + SET ComponentOnly=1 + ) ELSE ( + + ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 + + EXIT /B 1 + ) +) + +IF %UnitOnly% NEQ 0 IF %ComponentOnly% NEQ 0 ( + + ECHO %SCRIPT_PATH_DOC%: --unit-only and --component-only are mutually exclusive 1>&2 + + EXIT /B 1 +) + +IF %UnitOnly% NEQ 0 ( + CALL "%SCRIPT_DIRECTORY%run_all_unit_tests.cmd" + EXIT /B %ERRORLEVEL% +) + +IF %ComponentOnly% NEQ 0 ( + CALL "%SCRIPT_DIRECTORY%run_all_component_tests.cmd" + EXIT /B %ERRORLEVEL% +) + +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" + +IF NOT DEFINED ProjectName ( + + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 +) + +ECHO Running all %ProjectName% automated test programs ^(unit and component^) + +CALL "%SCRIPT_DIRECTORY%run_all_unit_tests.cmd" +IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% + +CALL "%SCRIPT_DIRECTORY%run_all_component_tests.cmd" +EXIT /B %ERRORLEVEL% + +ENDLOCAL diff --git a/run_all_automated_tests.sh b/run_all_automated_tests.sh new file mode 100755 index 00000000..2c13b16e --- /dev/null +++ b/run_all_automated_tests.sh @@ -0,0 +1,180 @@ +#! /bin/bash + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 + +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} +ComponentOnly=0 +ForwardedArgs=() +SisUseColours=0 +UnitOnly=0 + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - handled above; forward so category runners see it + ForwardedArgs+=("$1") + ;; + --unit-only) + + UnitOnly=1 + ;; + --component-only) + + ComponentOnly=1 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Runs all (matching) automated test programs (unit and component) + +${ScriptPath} [ ... flags/options ... ] + +Flags/options: + + behaviour: + + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + + --component-only + runs only component-test programs + + --unit-only + runs only unit-test programs + + (all other flags are forwarded to the category runner script) + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + ForwardedArgs+=("$1") + ;; + esac + + shift +done + +if [ $UnitOnly -ne 0 ] && [ $ComponentOnly -ne 0 ]; then + + >&2 echo "${ScriptPathClr}: ${SisClr_Red}${SisClr_Bold}--unit-only${SisClr_None} and ${SisClr_Red}${SisClr_Bold}--component-only${SisClr_None} are mutually exclusive" + + exit 1 +fi + + +# ########################################################## +# main() + +status=0 + +if [ $UnitOnly -ne 0 ]; then + + "$Dir/run_all_unit_tests.sh" "${ForwardedArgs[@]}" + exit $? +fi + +if [ $ComponentOnly -ne 0 ]; then + + "$Dir/run_all_component_tests.sh" "${ForwardedArgs[@]}" + exit $? +fi + +echo +echo "Running all ${ProjectNameClr} automated test programs (unit and component)" + +"$Dir/run_all_unit_tests.sh" "${ForwardedArgs[@]}" +status=$? + +if [ $status -eq 0 ]; then + + "$Dir/run_all_component_tests.sh" "${ForwardedArgs[@]}" + status=$? +fi + +exit $status + + +# ############################## end of file ############################# # diff --git a/run_all_component_tests.cmd b/run_all_component_tests.cmd new file mode 100644 index 00000000..970c9bab --- /dev/null +++ b/run_all_component_tests.cmd @@ -0,0 +1,94 @@ +@echo off + +SETLOCAL + +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] + +IF DEFINED SIS_CMAKE_BUILD_DIR ( + + SET CMAKE_DIR=%SIS_CMAKE_BUILD_DIR% +) ELSE ( + + SET CMAKE_DIR=%SCRIPT_DIRECTORY%_build +) + +FOR %%a IN (%*) DO ( + + IF /I {--help}=={%%a} ( + + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( + + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ + +Runs all ^(matching^) component-test programs ^ + +^ + +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ + +^ + +Flags/options: ^ + + behaviour: ^ + +^ + + --component-only ^ + + accepted for compatibility; this script always runs component tests only ^ + +^ + + standard flags: ^ + +^ + + --help ^ + + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE IF /I {--component-only}=={%%a} ( + + REM Benign: this script is already component-only + ) ELSE ( + + ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 + + EXIT /B 1 + ) +) + +if NOT EXIST "%CMAKE_DIR%" ( + + ECHO "CMake build directory '%CMAKE_DIR%' does not exist" + + EXIT /B 1 +) + +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" + +IF NOT DEFINED ProjectName ( + + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 +) + +ECHO Running all %ProjectName% component-test programs + +FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I test.*component.*\.exe$`) DO ( + + ECHO . + ECHO executing %%f + %%f + IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% +) + +ENDLOCAL diff --git a/run_all_component_tests.sh b/run_all_component_tests.sh new file mode 100755 index 00000000..c0bd27ef --- /dev/null +++ b/run_all_component_tests.sh @@ -0,0 +1,300 @@ +#! /bin/bash + +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 + +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} +ListOnly=0 +RunMake=1 +SisUseColours=0 +Verbosity=${XTESTS_VERBOSITY:-${TEST_VERBOSITY:-3}} + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; + --component-only) + + # Benign: this script is already component-only (aggregate / CI may + # pass it) + ;; + --list-only|-l) + + ListOnly=1 + ;; + --no-make|-M) + + RunMake=0 + ;; + --verbosity) + + shift + Verbosity=$1 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Runs all (matching) component-test programs + +${ScriptPath} [ ... flags/options ... ] + +Flags/options: + + behaviour: + + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + + --component-only + accepted for compatibility; this script always runs component tests + only + + -l + --list-only + lists the target programs but does not execute them + + -M + --no-make + does not execute a build before running programs + + --verbosity + specifies an explicit verbosity, forwarded to each program + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +status=0 + +if [ $RunMake -ne 0 ]; then + + if [ $ListOnly -eq 0 ]; then + + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build) and then running all component-test programs" + + mkdir -p "$CMakeDir" || exit 1 + + if [ ! -f "$CMakeDir/CMakeCache.txt" ]; then + + >&2 echo "${ScriptPathClr}: '${CMakeDirClr}' is not configured; use prepare_cmake.sh first" + + exit 1 + fi + + sis_cmake_build + status=$? + fi +else + + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then + + >&2 echo "${ScriptPathClr}: cannot run in '--no-make' mode without a previous successful configure/build" + + exit 1 + fi +fi + +if [ $status -eq 0 ]; then + + if [ $ListOnly -ne 0 ]; then + + echo + echo "Listing all ${ProjectNameClr} component-test programs" + else + + echo + echo "Running all ${ProjectNameClr} component-test programs" + fi + + NumPrograms=0 + + while IFS= read -r -d '' f; do + + case "$f" in + *.pdb|*.ilk|*.log|*.obj|*.o) + continue + ;; + esac + + NumPrograms=$((NumPrograms + 1)) + + fClr="${SisClr_Blue}${SisClr_Bold}${f}${SisClr_None}" + + if [ $ListOnly -ne 0 ]; then + + echo "would execute ${fClr}:" + + continue + fi + + if [ $Verbosity -ge 3 ]; then + + echo + fi + if [ $Verbosity -ge 2 ]; then + + echo "executing ${fClr}:" + fi + + if "$f" --verbosity="$Verbosity"; then + + : + else + + status=$? + + break 1 + fi + done < <(find "$CMakeDir" -type f \( -name 'test_component*' -o -name 'test.component.*' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) + + if [ $NumPrograms -eq 0 ]; then + + echo "${ScriptPathClr}: found no component-test programs under '${CMakeDirClr}' (none found)" + + exit 0 + fi +fi + +exit $status + + +# ############################## end of file ############################# # diff --git a/run_all_examples.cmd b/run_all_examples.cmd index 34f62e5d..11273cb0 100644 --- a/run_all_examples.cmd +++ b/run_all_examples.cmd @@ -1,196 +1,89 @@ -@ECHO OFF +@echo off -SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS +SETLOCAL -SET ScriptPath=%~n0[%~x0] -SET ScriptDir=%~dp0 +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] IF DEFINED SIS_CMAKE_BUILD_DIR ( - SET CMakeDir=%SIS_CMAKE_BUILD_DIR% + SET CMAKE_DIR=%SIS_CMAKE_BUILD_DIR% ) ELSE ( - SET CMakeDir=%ScriptDir%_build + SET CMAKE_DIR=%SCRIPT_DIRECTORY%_build ) -SET ListOnly=0 -SET RunMake=1 -SET SkipInteractive=0 +FOR %%a IN (%*) DO ( -SET BuildConfig=Release -IF DEFINED CMAKE_BUILD_TYPE SET BuildConfig=%CMAKE_BUILD_TYPE% + IF /I {--help}=={%%a} ( + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( -:: ######################################################### -:: command-line handling + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ -:parse_args -IF "%~1"=="" GOTO args_done +Runs all ^(matching^) example programs ^ -IF /I "%~1"=="--help" GOTO show_help -IF /I "%~1"=="-l" ( - SET ListOnly=1 - GOTO next_arg -) -IF /I "%~1"=="--list-only" ( - SET ListOnly=1 - GOTO next_arg -) -IF /I "%~1"=="-M" ( - SET RunMake=0 - GOTO next_arg -) -IF /I "%~1"=="--no-make" ( - SET RunMake=0 - GOTO next_arg -) -IF /I "%~1"=="--skip-interactive" ( - SET SkipInteractive=1 - GOTO next_arg -) +^ -ECHO %ScriptPath%: unrecognised argument '%~1'; use --help for usage 1>&2 -EXIT /B 1 +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ -:next_arg -SHIFT -GOTO parse_args +^ -:args_done +Flags/options: ^ + behaviour: ^ -:: ######################################################### -:: main() +^ -SET status=0 + standard flags: ^ -IF %RunMake% NEQ 0 ( - IF %ListOnly% EQU 0 ( - ECHO Executing build and then running all example programs - CALL :do_build - IF ERRORLEVEL 1 SET status=1 - ) -) ELSE ( - IF NOT EXIST "%CMakeDir%\CMakeCache.txt" ( - ECHO %ScriptPath%: cannot run in '--no-make' mode without a previous successful build step 1>&2 - EXIT /B 1 - ) -) +^ -IF %status% EQU 0 ( - IF NOT EXIST "%CMakeDir%\examples" ( - ECHO %ScriptPath%: examples build tree not found at '%CMakeDir%\examples' 1>&2 - ENDLOCAL - EXIT /B 1 - ) - - IF %ListOnly% NEQ 0 ( - ECHO Listing all example programs - ) ELSE ( - ECHO Running all example programs - ) - - FOR /F "usebackq delims=" %%f IN (`DIR /A:-D /B /S "%CMakeDir%\examples\*.exe" 2^>NUL`) DO ( - CALL :is_skipped_interactive "%%~nxf" - IF !skip_example! EQU 1 ( - IF !ListOnly! NEQ 0 ( - ECHO would skip %%f: (interactive; --skip-interactive) - ) ELSE ( - ECHO. - ECHO skipping %%f: (interactive; --skip-interactive) - ) - ) ELSE IF !ListOnly! NEQ 0 ( - ECHO would execute %%f: - ) ELSE ( - ECHO. - ECHO executing %%f: - CALL "%%f" - IF ERRORLEVEL 1 ( - SET status=1 - GOTO examples_done - ) - ) - ) + --help ^ + + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE ( + + ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 + + EXIT /B 1 + ) ) -:examples_done -IF !status! NEQ 0 ( - ENDLOCAL +if NOT EXIST "%CMAKE_DIR%" ( + + ECHO "CMake build directory '%CMAKE_DIR%' does not exist" + EXIT /B 1 ) -ENDLOCAL -EXIT /B 0 - - -:: ######################################################### -:: helpers - -:is_skipped_interactive -SET skip_example=0 -IF %SkipInteractive% EQU 0 EXIT /B 0 -IF NOT EXIST "%ScriptDir%.github\ci_skip_interactive_examples.txt" EXIT /B 0 -SET "exe_name=%~n1" -FOR /F "usebackq eol=# tokens=1" %%s IN ("%ScriptDir%.github\ci_skip_interactive_examples.txt") DO ( - SET "skip_name=%%s" - SET "skip_name=!skip_name: =!" - IF /I "!skip_name!"=="%exe_name%" SET skip_example=1 - IF /I "!skip_name!"=="%~nx1" SET skip_example=1 -) -EXIT /B 0 - -:do_build -IF DEFINED SIS_CMAKE_MAKE_COMMAND ( - PUSHd "%CMakeDir%" - CALL %SIS_CMAKE_MAKE_COMMAND% - SET build_status=!ERRORLEVEL! - POPD - EXIT /B !build_status! -) -IF EXIST "%CMakeDir%\Makefile" ( - PUSHd "%CMakeDir%" - IF DEFINED MSYSTEM ( - mingw32-make.exe - ) ELSE ( - make - ) - SET build_status=!ERRORLEVEL! - POPD - EXIT /B !build_status! + +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" + +IF NOT DEFINED ProjectName ( + + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 ) -cmake --build "%CMakeDir%" --config %BuildConfig% -EXIT /B %ERRORLEVEL% +REM Examples that require human input may honour SIS_EXAMPLE_SMOKE for a +REM no-arg built-in tmpfile demo (see example.c.cstring_vector). +SET SIS_EXAMPLE_SMOKE=1 + +ECHO Running all %ProjectName% example programs -:show_help -IF EXIST "%ScriptDir%.sis\script_info_lines.txt" ( - type "%ScriptDir%.sis\script_info_lines.txt" +FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I example.*\.exe$`) DO ( + + ECHO . + ECHO executing %%f + %%f + IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% ) -ECHO. -ECHO Runs all (matching) example programs -ECHO. -ECHO %ScriptPath% [ ... flags/options ... ] -ECHO. -ECHO Flags/options: -ECHO. -ECHO behaviour: -ECHO. -ECHO -l -ECHO --list-only -ECHO lists the target programs but does not execute them -ECHO. -ECHO -M -ECHO --no-make -ECHO does not execute CMake and make before running examples -ECHO. -ECHO --skip-interactive -ECHO skips examples listed in .github/ci_skip_interactive_examples.txt -ECHO (GUI / desktop-interactive programs unsuitable for headless CI) -ECHO. -ECHO standard flags: -ECHO. -ECHO --help -ECHO displays this help and terminates -EXIT /B 0 - - -:: ############################# end of file ############################ :: + +ENDLOCAL diff --git a/run_all_examples.sh b/run_all_examples.sh index 09362e68..967f82cc 100755 --- a/run_all_examples.sh +++ b/run_all_examples.sh @@ -1,96 +1,118 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) -Basename=$(basename "$ScriptPath") -CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} -ProjectNameFile="$Dir/.sis/project_name.txt" -ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") - -ListOnly=0 -RunMake=1 -SkipInteractive=0 - - # ########################################################## -# colours +# functions - 1 -if command -v tput > /dev/null; then +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in - SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} - SisClr_Red=${FG_BLUE:-$(tput setaf 1)} - SisClr_Bold=${FD_BOLD:-$(tput bold)} - SisClr_None=${FD_NONE:-$(tput sgr0)} -else + 1|ok|on|true|yes|y) - SisClr_Blue= - SisClr_Red= - SisClr_Bold= - SisClr_None= -fi + return 0 + ;; + *) + + return 1 + ;; + esac +} # ########################################################## -# helpers +# constants and variables -example_stem() -{ - local p="${1//\\//}" +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 - p="${p##*/}" +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} +ListOnly=0 +RunMake=1 +SisUseColours=0 - case "$p" in - *.exe|*.EXE) p="${p%.*}" ;; + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; esac +done - echo "$p" -} +if command -v tput >/dev/null 2>&1; then -names_match() -{ - local a b + if [ $AlwaysUseColours -ne 0 ]; then - a=$(echo "$1" | tr '[:upper:]' '[:lower:]') - b=$(echo "$2" | tr '[:upper:]' '[:lower:]') + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then - [ "$a" = "$b" ] -} + TERM=xterm-256color + fi -is_skipped_interactive_example() -{ - local name f_norm line line_stem skip_file="$Dir/.github/ci_skip_interactive_examples.txt" + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then - [ $SkipInteractive -ne 0 ] || return 1 + SisUseColours=1 + fi +fi - if [ ! -f "$skip_file" ]; then +if [ $SisUseColours -ne 0 ]; then - >&2 echo "$ScriptPath: --skip-interactive: skip list not found at '$skip_file'" + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi - return 1 - fi +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" - f_norm="${1//\\//}" - name=$(example_stem "$f_norm") - while IFS= read -r line || [ -n "$line" ]; do +# ########################################################## +# functions - 2 - line="${line//$'\r'/}" +sis_cmake_build() { - case "$line" in - ''|\#*) continue ;; - esac + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then - line_stem=$(example_stem "$line") + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then - if names_match "$name" "$line_stem"; then + local t + for t in "$@"; do - return 0 - fi - done < "$skip_file" + args+=(--target "$t") + done + fi - return 1 + cmake "${args[@]}" } @@ -100,6 +122,10 @@ is_skipped_interactive_example() while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --list-only|-l) ListOnly=1 @@ -108,34 +134,30 @@ while [[ $# -gt 0 ]]; do RunMake=0 ;; - --skip-interactive) - - SkipInteractive=1 - ;; --help) [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" cat << EOF Runs all (matching) example programs -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + -l --list-only lists the target programs but does not execute them -M --no-make - does not execute CMake and make before running examples - - --skip-interactive - skips examples listed in .github/ci_skip_interactive_examples.txt - (GUI / desktop-interactive programs unsuitable for headless CI; - list stems or names, e.g. shell_functions or shell_functions.exe) + does not execute a build before running programs standard flags: @@ -149,7 +171,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -168,22 +190,26 @@ if [ $RunMake -ne 0 ]; then if [ $ListOnly -eq 0 ]; then - echo "Executing build (via command \`$MakeCmd\`) and then running all ${ProjectName} example programs" + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build) and then running all example programs" - mkdir -p $CMakeDir || exit 1 + mkdir -p "$CMakeDir" || exit 1 - cd $CMakeDir + if [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - $MakeCmd - status=$? + >&2 echo "${ScriptPathClr}: '${CMakeDirClr}' is not configured; use prepare_cmake.sh first" + + exit 1 + fi - cd ->/dev/null + sis_cmake_build + status=$? fi else - if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ] || [ ! -d "$CMakeDir/CMakeFiles" ]; then + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - >&2 echo "$ScriptPath: cannot run in '--no-make' mode without a previous successful build step" + >&2 echo "${ScriptPathClr}: cannot run in '--no-make' mode without a previous successful configure/build" exit 1 fi @@ -191,79 +217,45 @@ fi if [ $status -eq 0 ]; then - if [ ! -d "$CMakeDir/examples" ]; then - - >&2 echo "$ScriptPath: examples build tree not found at '$CMakeDir/examples'" - - exit 1 - fi - if [ $ListOnly -ne 0 ]; then - echo "Listing all ${ProjectName} example programs" + echo + echo "Listing all ${ProjectNameClr} example programs" else - echo "Running all ${ProjectName} example programs" - fi - - # Exclude CMake / build artefacts that can become +x after artifact restore. - ExamplePrograms=( $(find "$CMakeDir/examples" -type f \ - ! -path '*/CMakeFiles/*' \ - ! -name '*.a' \ - ! -name '*.cmake' \ - ! -name '*.d' \ - ! -name '*.lib' \ - ! -name '*.log' \ - ! -name '*.o' \ - ! -name '*.obj' \ - ! -name '*.pdb' \ - ! -name 'CMakeLists.txt' \ - ! -name 'CTestTestfile.cmake' \ - ! -name 'Makefile' \ - ! -name 'cmake_install.cmake' \ - -exec test -x {} \; -print | sort) ) - - echo "discovered ${#ExamplePrograms[@]} example program(s)" - - if [ ${#ExamplePrograms[@]} -eq 0 ]; then - - >&2 echo "$ScriptPath: no matching executable example programs under '$CMakeDir/examples' (execute bits missing after artifact download?)" - - if [ $ListOnly -eq 0 ]; then - - status=1 - fi + echo + echo "Running all ${ProjectNameClr} example programs" fi - for f in "${ExamplePrograms[@]}" - do - - if is_skipped_interactive_example "$f"; then + # Examples that require human input may honour SIS_EXAMPLE_SMOKE for a + # no-arg built-in tmpfile demo (see example.c.cstring_vector). + export SIS_EXAMPLE_SMOKE=1 - if [ $ListOnly -ne 0 ]; then + NumPrograms=0 - echo "would skip $SisClr_Blue$SisClr_Bold$f$SisClr_None (interactive; --skip-interactive)" + while IFS= read -r -d '' f; do - else + case "$f" in + *.pdb|*.ilk|*.log|*.obj|*.o) + continue + ;; + esac - echo - echo "skipping $SisClr_Blue$SisClr_Bold$f$SisClr_None (interactive; --skip-interactive)" - fi + NumPrograms=$((NumPrograms + 1)) - continue - fi + fClr="${SisClr_Blue}${SisClr_Bold}${f}${SisClr_None}" if [ $ListOnly -ne 0 ]; then - echo "would execute $SisClr_Blue$SisClr_Bold$f$SisClr_None:" + echo "would execute ${fClr}:" continue fi echo - echo "executing $SisClr_Blue$SisClr_Bold$f$SisClr_None:" + echo "executing ${fClr}:" - if $f; then + if "$f"; then : else @@ -272,7 +264,14 @@ if [ $status -eq 0 ]; then break 1 fi - done + done < <(find "$CMakeDir" -type f \( -name 'example*' ! -name '*.md' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) + + if [ $NumPrograms -eq 0 ]; then + + echo "${ScriptPathClr}: found no example programs under '${CMakeDirClr}' (none found)" + + exit 0 + fi fi exit $status diff --git a/run_all_performance_tests.cmd b/run_all_performance_tests.cmd new file mode 100644 index 00000000..adb8746f --- /dev/null +++ b/run_all_performance_tests.cmd @@ -0,0 +1,96 @@ +@echo off + +SETLOCAL + +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] + +IF DEFINED SIS_CMAKE_BUILD_DIR ( + + SET CMAKE_DIR=%SIS_CMAKE_BUILD_DIR% +) ELSE ( + + SET CMAKE_DIR=%SCRIPT_DIRECTORY%_build +) + +FOR %%a IN (%*) DO ( + + IF /I {--help}=={%%a} ( + + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( + + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ + +Runs all ^(matching^) performance-test programs ^ + +^ + +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ + +^ + +Flags/options: ^ + + behaviour: ^ + +^ + + --gap-groups ^ + + sets SIS_PERFTESTS_GROUPGAPS=1 so performance programs emit a ^ + + blank line between scenario groups ^ + +^ + + standard flags: ^ + +^ + + --help ^ + + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE IF /I {--gap-groups}=={%%a} ( + + SET SIS_PERFTESTS_GROUPGAPS=1 + ) ELSE ( + + ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 + + EXIT /B 1 + ) +) + +if NOT EXIST "%CMAKE_DIR%" ( + + ECHO "CMake build directory '%CMAKE_DIR%' does not exist" + + EXIT /B 1 +) + +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" + +IF NOT DEFINED ProjectName ( + + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 +) + +ECHO Running all %ProjectName% performance-test programs + +FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I test.*performance.*\.exe$`) DO ( + + ECHO . + ECHO executing %%f + %%f + IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% +) + +ENDLOCAL diff --git a/run_all_performance_tests.sh b/run_all_performance_tests.sh new file mode 100755 index 00000000..6f3c3739 --- /dev/null +++ b/run_all_performance_tests.sh @@ -0,0 +1,290 @@ +#! /bin/bash + +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 + +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} +GapGroups=0 +ListOnly=0 +RunMake=1 +SisUseColours=0 + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; + --gap-groups) + + GapGroups=1 + ;; + --list-only|-l) + + ListOnly=1 + ;; + --no-make|-M) + + RunMake=0 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Runs all (matching) performance-test programs + +${ScriptPath} [ ... flags/options ... ] + +Flags/options: + + behaviour: + + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + + --gap-groups + sets SIS_PERFTESTS_GROUPGAPS=1 so performance programs emit a blank + line between scenario groups + + -l + --list-only + lists the target programs but does not execute them + + -M + --no-make + does not execute a build before running programs + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +if [ $GapGroups -ne 0 ]; then + + export SIS_PERFTESTS_GROUPGAPS=1 +fi + +status=0 + +if [ $RunMake -ne 0 ]; then + + if [ $ListOnly -eq 0 ]; then + + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build) and then running all performance-test programs" + + mkdir -p "$CMakeDir" || exit 1 + + if [ ! -f "$CMakeDir/CMakeCache.txt" ]; then + + >&2 echo "${ScriptPathClr}: '${CMakeDirClr}' is not configured; use prepare_cmake.sh first" + + exit 1 + fi + + sis_cmake_build + status=$? + fi +else + + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then + + >&2 echo "${ScriptPathClr}: cannot run in '--no-make' mode without a previous successful configure/build" + + exit 1 + fi +fi + +if [ $status -eq 0 ]; then + + if [ $ListOnly -ne 0 ]; then + + echo + echo "Listing all ${ProjectNameClr} performance-test programs" + else + + echo + echo "Running all ${ProjectNameClr} performance-test programs" + fi + + NumPrograms=0 + + while IFS= read -r -d '' f; do + + case "$f" in + *.pdb|*.ilk|*.log|*.obj|*.o) + continue + ;; + esac + + NumPrograms=$((NumPrograms + 1)) + + fClr="${SisClr_Blue}${SisClr_Bold}${f}${SisClr_None}" + + if [ $ListOnly -ne 0 ]; then + + echo "would execute ${fClr}:" + + continue + fi + + echo + echo "executing ${fClr}:" + + if "$f"; then + + : + else + + status=$? + + break 1 + fi + done < <(find "$CMakeDir" -type f \( -name 'test_performance*' -o -name 'test.performance.*' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) + + if [ $NumPrograms -eq 0 ]; then + + echo "${ScriptPathClr}: found no performance-test programs under '${CMakeDirClr}' (none found)" + + exit 0 + fi +fi + +exit $status + + +# ############################## end of file ############################# # diff --git a/run_all_scratch_tests.cmd b/run_all_scratch_tests.cmd index 4b18544b..9b05623f 100644 --- a/run_all_scratch_tests.cmd +++ b/run_all_scratch_tests.cmd @@ -1,173 +1,85 @@ -@ECHO OFF +@echo off -SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS +SETLOCAL -SET ScriptPath=%~n0[%~x0] -SET ScriptDir=%~dp0 +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] IF DEFINED SIS_CMAKE_BUILD_DIR ( - SET CMakeDir=%SIS_CMAKE_BUILD_DIR% + SET CMAKE_DIR=%SIS_CMAKE_BUILD_DIR% ) ELSE ( - SET CMakeDir=%ScriptDir%_build + SET CMAKE_DIR=%SCRIPT_DIRECTORY%_build ) -SET ListOnly=0 -SET RunMake=1 -SET TestVerbosityDefault=3 -SET TestVerbosity=%TEST_VERBOSITY% +FOR %%a IN (%*) DO ( -IF NOT DEFINED TestVerbosity SET TestVerbosity=%TestVerbosityDefault% -IF DEFINED XTESTS_VERBOSITY SET TestVerbosity=%XTESTS_VERBOSITY% + IF /I {--help}=={%%a} ( -SET BuildConfig=Release -IF DEFINED CMAKE_BUILD_TYPE SET BuildConfig=%CMAKE_BUILD_TYPE% + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ -:: ######################################################### -:: command-line handling +Runs all ^(matching^) scratch-test programs ^ -:parse_args -IF "%~1"=="" GOTO args_done +^ -IF /I "%~1"=="--help" GOTO show_help -IF /I "%~1"=="-l" ( - SET ListOnly=1 - GOTO next_arg -) -IF /I "%~1"=="--list-only" ( - SET ListOnly=1 - GOTO next_arg -) -IF /I "%~1"=="-M" ( - SET RunMake=0 - GOTO next_arg -) -IF /I "%~1"=="--no-make" ( - SET RunMake=0 - GOTO next_arg -) -IF /I "%~1"=="--verbosity" ( - SHIFT - IF "%~1"=="" ( - ECHO %ScriptPath%: --verbosity requires an argument 1>&2 - EXIT /B 1 - ) - SET TestVerbosity=%~1 - GOTO next_arg -) +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ -ECHO %ScriptPath%: unrecognised argument '%~1'; use --help for usage 1>&2 -EXIT /B 1 +^ -:next_arg -SHIFT -GOTO parse_args +Flags/options: ^ -:args_done + behaviour: ^ +^ -:: ######################################################### -:: main() + standard flags: ^ -SET status=0 +^ -IF %RunMake% NEQ 0 ( - IF %ListOnly% EQU 0 ( - ECHO Executing build and then running all scratch test programs - CALL :do_build - IF ERRORLEVEL 1 SET status=1 - ) -) ELSE ( - IF NOT EXIST "%CMakeDir%\CMakeCache.txt" ( - ECHO %ScriptPath%: cannot run in '--no-make' mode without a previous successful build step 1>&2 - EXIT /B 1 - ) -) + --help ^ + + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE ( -IF %status% EQU 0 ( - IF %ListOnly% NEQ 0 ( - ECHO Listing all scratch test programs - ) ELSE ( - ECHO Running all scratch test programs - ) - - FOR /F "usebackq delims=" %%f IN (`DIR /A:-D /B /S "%CMakeDir%" 2^>NUL ^| FINDSTR /I /R "test[._]scratch[._].*\.exe$"`) DO ( - IF !ListOnly! NEQ 0 ( - ECHO would execute %%f: - ) ELSE ( - IF !TestVerbosity! GEQ 3 ECHO. - IF !TestVerbosity! GEQ 2 ECHO executing %%f: - CALL "%%f" - IF ERRORLEVEL 1 SET status=1 - ) - ) + ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 + + EXIT /B 1 + ) ) -IF !status! NEQ 0 ( - ENDLOCAL +if NOT EXIST "%CMAKE_DIR%" ( + + ECHO "CMake build directory '%CMAKE_DIR%' does not exist" + EXIT /B 1 ) -ENDLOCAL -EXIT /B 0 +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" -:: ######################################################### -:: helpers +IF NOT DEFINED ProjectName ( -:do_build -IF DEFINED SIS_CMAKE_MAKE_COMMAND ( - PUSHd "%CMakeDir%" - CALL %SIS_CMAKE_MAKE_COMMAND% - SET build_status=!ERRORLEVEL! - POPD - EXIT /B !build_status! -) -IF EXIST "%CMakeDir%\Makefile" ( - PUSHd "%CMakeDir%" - IF DEFINED MSYSTEM ( - mingw32-make.exe - ) ELSE ( - make - ) - SET build_status=!ERRORLEVEL! - POPD - EXIT /B !build_status! + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 ) -cmake --build "%CMakeDir%" --config %BuildConfig% -EXIT /B %ERRORLEVEL% +ECHO Running all %ProjectName% scratch-test programs + +FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I test.*scratch.*\.exe$`) DO ( -:show_help -IF EXIST "%ScriptDir%.sis\script_info_lines.txt" ( - type "%ScriptDir%.sis\script_info_lines.txt" + ECHO . + ECHO executing %%f + %%f + IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% ) -ECHO. -ECHO Runs all (matching) scratch-test programs -ECHO. -ECHO %ScriptPath% [ ... flags/options ... ] -ECHO. -ECHO Flags/options: -ECHO. -ECHO behaviour: -ECHO. -ECHO -l -ECHO --list-only -ECHO lists the target programs but does not execute them -ECHO. -ECHO -M -ECHO --no-make -ECHO does not execute CMake and make before running tests -ECHO. -ECHO --verbosity ^ -ECHO reserved for output control; scratch programs are invoked without xTests verbosity flags -ECHO. -ECHO standard flags: -ECHO. -ECHO --help -ECHO displays this help and terminates -EXIT /B 0 - - -:: ############################# end of file ############################ :: + +ENDLOCAL diff --git a/run_all_scratch_tests.sh b/run_all_scratch_tests.sh index 14626b2e..5e6659a8 100755 --- a/run_all_scratch_tests.sh +++ b/run_all_scratch_tests.sh @@ -1,36 +1,120 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) -Basename=$(basename "$ScriptPath") +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} ListOnly=0 RunMake=1 -Verbosity=${XTESTS_VERBOSITY:-${TEST_VERBOSITY:-3}} +SisUseColours=0 # ########################################################## # colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done -if command -v tput > /dev/null; then +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} - SisClr_Red=${FG_BLUE:-$(tput setaf 1)} SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} SisClr_None=${FD_NONE:-$(tput sgr0)} -else - - SisClr_Blue= - SisClr_Red= - SisClr_Bold= - SisClr_None= + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} fi +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} + # ########################################################## # command-line handling @@ -38,6 +122,10 @@ fi while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --list-only|-l) ListOnly=1 @@ -46,34 +134,30 @@ while [[ $# -gt 0 ]]; do RunMake=0 ;; - --verbosity) - - shift - Verbosity=$1 - ;; --help) [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" cat << EOF Runs all (matching) scratch-test programs -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + -l --list-only lists the target programs but does not execute them -M --no-make - does not execute CMake and make before running tests - - --verbosity - specifies an explicit verbosity (reserved; scratch programs are - invoked without xTests verbosity flags) + does not execute a build before running programs standard flags: @@ -87,7 +171,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -105,22 +189,27 @@ status=0 if [ $RunMake -ne 0 ]; then if [ $ListOnly -eq 0 ]; then - echo "Executing build (via command \`$MakeCmd\`) and then running all ${ProjectName} scratch test programs" - mkdir -p $CMakeDir || exit 1 + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build) and then running all scratch-test programs" - cd $CMakeDir + mkdir -p "$CMakeDir" || exit 1 - $MakeCmd - status=$? + if [ ! -f "$CMakeDir/CMakeCache.txt" ]; then + + >&2 echo "${ScriptPathClr}: '${CMakeDirClr}' is not configured; use prepare_cmake.sh first" - cd ->/dev/null + exit 1 + fi + + sis_cmake_build + status=$? fi else - if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ] || [ ! -d "$CMakeDir/CMakeFiles" ]; then + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - >&2 echo "$ScriptPath: cannot run in '--no-make' mode without a previous successful build step" + >&2 echo "${ScriptPathClr}: cannot run in '--no-make' mode without a previous successful configure/build" exit 1 fi @@ -130,43 +219,58 @@ if [ $status -eq 0 ]; then if [ $ListOnly -ne 0 ]; then - echo "Listing all ${ProjectName} scratch test programs" + echo + echo "Listing all ${ProjectNameClr} scratch-test programs" else - echo "Running all ${ProjectName} scratch test programs" + echo + echo "Running all ${ProjectNameClr} scratch-test programs" fi - for f in $(find "$CMakeDir" -type f '(' -name 'test_scratch*' -o -name 'test.scratch.*' ')' -exec test -x {} \; -print | sort) - do + NumPrograms=0 - if [ $ListOnly -ne 0 ]; then + while IFS= read -r -d '' f; do - echo "would execute $SisClr_Blue$SisClr_Bold$f$SisClr_None:" + case "$f" in + *.pdb|*.ilk|*.log|*.obj|*.o) + continue + ;; + esac - continue - fi + NumPrograms=$((NumPrograms + 1)) - if [ $Verbosity -ge 3 ]; then + fClr="${SisClr_Blue}${SisClr_Bold}${f}${SisClr_None}" - echo - fi - if [ $Verbosity -ge 2 ]; then + if [ $ListOnly -ne 0 ]; then + + echo "would execute ${fClr}:" - echo "executing $SisClr_Blue$SisClr_Bold$f$SisClr_None:" + continue fi - if $f; then + echo + echo "executing ${fClr}:" + + if "$f"; then : else status=$? + + break 1 fi - done + done < <(find "$CMakeDir" -type f \( -name 'test_scratch*' -o -name 'test.scratch.*' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) + + if [ $NumPrograms -eq 0 ]; then + + echo "${ScriptPathClr}: found no scratch-test programs under '${CMakeDirClr}' (none found)" + + exit 0 + fi fi exit $status # ############################## end of file ############################# # - diff --git a/run_all_unit_tests.cmd b/run_all_unit_tests.cmd index de418c98..18b040a8 100644 --- a/run_all_unit_tests.cmd +++ b/run_all_unit_tests.cmd @@ -1,209 +1,94 @@ -@ECHO OFF +@echo off -SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS +SETLOCAL -SET ScriptPath=%~n0[%~x0] -SET ScriptDir=%~dp0 +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] IF DEFINED SIS_CMAKE_BUILD_DIR ( - SET CMakeDir=%SIS_CMAKE_BUILD_DIR% + SET CMAKE_DIR=%SIS_CMAKE_BUILD_DIR% ) ELSE ( - SET CMakeDir=%ScriptDir%_build + SET CMAKE_DIR=%SCRIPT_DIRECTORY%_build ) -SET ListOnly=0 -SET RunMake=1 -SET UnitOnly=0 -SET ComponentOnly=0 -SET TestVerbosityDefault=3 -SET TestVerbosity=%TEST_VERBOSITY% +FOR %%a IN (%*) DO ( -IF NOT DEFINED TestVerbosity SET TestVerbosity=%TestVerbosityDefault% -IF DEFINED XTESTS_VERBOSITY SET TestVerbosity=%XTESTS_VERBOSITY% + IF /I {--help}=={%%a} ( -SET BuildConfig=Release -IF DEFINED CMAKE_BUILD_TYPE SET BuildConfig=%CMAKE_BUILD_TYPE% + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ -:: ######################################################### -:: command-line handling +Runs all ^(matching^) unit-test programs ^ -:parse_args -IF "%~1"=="" GOTO args_done +^ -IF /I "%~1"=="--help" GOTO show_help -IF /I "%~1"=="-l" ( - SET ListOnly=1 - GOTO next_arg -) -IF /I "%~1"=="--list-only" ( - SET ListOnly=1 - GOTO next_arg -) -IF /I "%~1"=="-M" ( - SET RunMake=0 - GOTO next_arg -) -IF /I "%~1"=="--no-make" ( - SET RunMake=0 - GOTO next_arg -) -IF /I "%~1"=="--unit-only" ( - SET UnitOnly=1 - GOTO next_arg -) -IF /I "%~1"=="--component-only" ( - SET ComponentOnly=1 - GOTO next_arg -) -IF /I "%~1"=="--verbosity" ( - SHIFT - IF "%~1"=="" ( - ECHO %ScriptPath%: --verbosity requires an argument 1>&2 - EXIT /B 1 - ) - SET TestVerbosity=%~1 - GOTO next_arg -) +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ -ECHO %ScriptPath%: unrecognised argument '%~1'; use --help for usage 1>&2 -EXIT /B 1 +^ -:next_arg -SHIFT -GOTO parse_args +Flags/options: ^ -:args_done + behaviour: ^ -IF %UnitOnly% NEQ 0 IF %ComponentOnly% NEQ 0 ( - ECHO %ScriptPath%: --unit-only and --component-only are mutually exclusive 1>&2 - EXIT /B 1 -) +^ -IF %UnitOnly% NEQ 0 ( - SET TestKindDescription=unit test - SET FindPattern=test[._]unit[._].*\.exe$ -) ELSE IF %ComponentOnly% NEQ 0 ( - SET TestKindDescription=component test - SET FindPattern=test[._]component[._].*\.exe$ -) ELSE ( - SET TestKindDescription=component and unit test - SET FindPattern=test[._]unit[._].*\.exe$ test[._]component[._].*\.exe$ -) + --unit-only ^ + accepted for compatibility; this script always runs unit tests only ^ -:: ######################################################### -:: main() +^ -SET status=0 + standard flags: ^ -IF %RunMake% NEQ 0 ( - IF %ListOnly% EQU 0 ( - ECHO Executing build and then running all !TestKindDescription! programs - CALL :do_build - IF ERRORLEVEL 1 SET status=1 - ) -) ELSE ( - IF NOT EXIST "%CMakeDir%\CMakeCache.txt" ( - ECHO %ScriptPath%: cannot run in '--no-make' mode without a previous successful build step 1>&2 - EXIT /B 1 - ) -) +^ + + --help ^ -IF %status% EQU 0 ( - IF %ListOnly% NEQ 0 ( - ECHO Listing all !TestKindDescription! programs - ) ELSE ( - ECHO Running all !TestKindDescription! programs - ) - - FOR /F "usebackq delims=" %%f IN (`DIR /A:-D /B /S "%CMakeDir%" 2^>NUL ^| FINDSTR /I /R "%FindPattern%"`) DO ( - IF !ListOnly! NEQ 0 ( - ECHO would execute %%f: - ) ELSE ( - ECHO. - ECHO executing %%f: - CALL "%%f" --verbosity=!TestVerbosity! - IF ERRORLEVEL 1 ( - SET status=1 - GOTO tests_done - ) - ) - ) + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE IF /I {--unit-only}=={%%a} ( + + REM Benign: this script is already unit-only + ) ELSE ( + + ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 + + EXIT /B 1 + ) ) -:tests_done -IF !status! NEQ 0 ( - ENDLOCAL +if NOT EXIST "%CMAKE_DIR%" ( + + ECHO "CMake build directory '%CMAKE_DIR%' does not exist" + EXIT /B 1 ) -ENDLOCAL -EXIT /B 0 +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" -:: ######################################################### -:: helpers +IF NOT DEFINED ProjectName ( -:do_build -IF DEFINED SIS_CMAKE_MAKE_COMMAND ( - PUSHd "%CMakeDir%" - CALL %SIS_CMAKE_MAKE_COMMAND% - SET build_status=!ERRORLEVEL! - POPD - EXIT /B !build_status! -) -IF EXIST "%CMakeDir%\Makefile" ( - PUSHd "%CMakeDir%" - IF DEFINED MSYSTEM ( - mingw32-make.exe - ) ELSE ( - make - ) - SET build_status=!ERRORLEVEL! - POPD - EXIT /B !build_status! + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 ) -cmake --build "%CMakeDir%" --config %BuildConfig% -EXIT /B %ERRORLEVEL% +ECHO Running all %ProjectName% unit-test programs -:show_help -IF EXIST "%ScriptDir%.sis\script_info_lines.txt" ( - type "%ScriptDir%.sis\script_info_lines.txt" +FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I test.*unit.*\.exe$`) DO ( + + ECHO . + ECHO executing %%f + %%f + IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% ) -ECHO. -ECHO Runs all (matching) unit-test and/or component-test programs -ECHO. -ECHO %ScriptPath% [ ... flags/options ... ] -ECHO. -ECHO Flags/options: -ECHO. -ECHO behaviour: -ECHO. -ECHO -l -ECHO --list-only -ECHO lists the target programs but does not execute them -ECHO. -ECHO -M -ECHO --no-make -ECHO does not execute CMake and make before running tests -ECHO. -ECHO --unit-only -ECHO runs only unit-test programs (test.unit.* / test_unit*) -ECHO. -ECHO --component-only -ECHO runs only component-test programs (test.component.* / test_component*) -ECHO. -ECHO --verbosity ^ -ECHO specifies an explicit verbosity for the unit-test(s) -ECHO. -ECHO standard flags: -ECHO. -ECHO --help -ECHO displays this help and terminates -EXIT /B 0 - - -:: ############################# end of file ############################ :: + +ENDLOCAL diff --git a/run_all_unit_tests.sh b/run_all_unit_tests.sh index 0d7e147d..301ccae2 100755 --- a/run_all_unit_tests.sh +++ b/run_all_unit_tests.sh @@ -1,38 +1,121 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) -Basename=$(basename "$ScriptPath") +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} ListOnly=0 RunMake=1 -UnitOnly=0 -ComponentOnly=0 +SisUseColours=0 Verbosity=${XTESTS_VERBOSITY:-${TEST_VERBOSITY:-3}} # ########################################################## # colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then -if command -v tput > /dev/null; then + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} - SisClr_Red=${FG_BLUE:-$(tput setaf 1)} SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} SisClr_None=${FD_NONE:-$(tput sgr0)} -else - - SisClr_Blue= - SisClr_Red= - SisClr_Bold= - SisClr_None= + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} fi +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} + # ########################################################## # command-line handling @@ -40,6 +123,10 @@ fi while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --list-only|-l) ListOnly=1 @@ -50,11 +137,7 @@ while [[ $# -gt 0 ]]; do ;; --unit-only) - UnitOnly=1 - ;; - --component-only) - - ComponentOnly=1 + # Benign: this script is already unit-only (aggregate / CI may pass it) ;; --verbosity) @@ -65,30 +148,32 @@ while [[ $# -gt 0 ]]; do [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" cat << EOF -Runs all (matching) unit-test and/or component-test programs +Runs all (matching) unit-test programs -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + -l --list-only lists the target programs but does not execute them -M --no-make - does not execute CMake and make before running tests + does not execute a build before running programs --unit-only - runs only unit-test programs (test.unit.* / test_unit*) - - --component-only - runs only component-test programs (test.component.* / test_component*) + accepted for compatibility; this script always runs unit tests only --verbosity - specifies an explicit verbosity for the unit-test(s) + specifies an explicit verbosity, forwarded to each program standard flags: @@ -102,7 +187,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -111,50 +196,36 @@ EOF shift done -if [ $UnitOnly -ne 0 ] && [ $ComponentOnly -ne 0 ]; then - - >&2 echo "$ScriptPath: --unit-only and --component-only are mutually exclusive" - - exit 1 -fi - # ########################################################## # main() status=0 -if [ $UnitOnly -ne 0 ]; then - - TestKindDescription='unit test' -elif [ $ComponentOnly -ne 0 ]; then - - TestKindDescription='component test' -else - - TestKindDescription='component and unit test' -fi - if [ $RunMake -ne 0 ]; then if [ $ListOnly -eq 0 ]; then - echo "Executing build (via command \`$MakeCmd\`) and then running all ${ProjectName} ${TestKindDescription} programs" + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build) and then running all unit-test programs" - mkdir -p $CMakeDir || exit 1 + mkdir -p "$CMakeDir" || exit 1 - cd $CMakeDir + if [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - $MakeCmd - status=$? + >&2 echo "${ScriptPathClr}: '${CMakeDirClr}' is not configured; use prepare_cmake.sh first" - cd ->/dev/null + exit 1 + fi + + sis_cmake_build + status=$? fi else - if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ] || [ ! -d "$CMakeDir/CMakeFiles" ]; then + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - >&2 echo "$ScriptPath: cannot run in '--no-make' mode without a previous successful build step" + >&2 echo "${ScriptPathClr}: cannot run in '--no-make' mode without a previous successful configure/build" exit 1 fi @@ -164,54 +235,31 @@ if [ $status -eq 0 ]; then if [ $ListOnly -ne 0 ]; then - echo "Listing all ${ProjectName} ${TestKindDescription} programs" - else - - echo "Running all ${ProjectName} ${TestKindDescription} programs" - fi - - if [ $UnitOnly -ne 0 ]; then - - find_name_expr=( \( -name 'test_unit*' -o -name 'test.unit.*' \) ) - elif [ $ComponentOnly -ne 0 ]; then - - find_name_expr=( \( -name 'test_component*' -o -name 'test.component.*' \) ) + echo + echo "Listing all ${ProjectNameClr} unit-test programs" else - find_name_expr=( \( -name 'test_unit*' -o -name 'test.unit.*' -o -name 'test_component*' -o -name 'test.component.*' \) ) + echo + echo "Running all ${ProjectNameClr} unit-test programs" fi - # Exclude build artefacts that can match suite name globs (CMake object - # files under CMakeFiles/, etc.). - TestPrograms=( $(find "$CMakeDir" -type f "${find_name_expr[@]}" \ - ! -path '*/CMakeFiles/*' \ - ! -name '*.a' \ - ! -name '*.d' \ - ! -name '*.lib' \ - ! -name '*.log' \ - ! -name '*.o' \ - ! -name '*.obj' \ - ! -name '*.pdb' \ - -exec test -x {} \; -print | sort) ) + NumPrograms=0 - echo "discovered ${#TestPrograms[@]} ${TestKindDescription} program(s)" + while IFS= read -r -d '' f; do - if [ ${#TestPrograms[@]} -eq 0 ]; then + case "$f" in + *.pdb|*.ilk|*.log|*.obj|*.o) + continue + ;; + esac - >&2 echo "$ScriptPath: no matching executable ${TestKindDescription} programs under '$CMakeDir' (execute bits missing after artifact download?)" + NumPrograms=$((NumPrograms + 1)) - if [ $ListOnly -eq 0 ]; then - - status=1 - fi - fi - - for f in "${TestPrograms[@]}" - do + fClr="${SisClr_Blue}${SisClr_Bold}${f}${SisClr_None}" if [ $ListOnly -ne 0 ]; then - echo "would execute $SisClr_Blue$SisClr_Bold$f$SisClr_None:" + echo "would execute ${fClr}:" continue fi @@ -222,10 +270,10 @@ if [ $status -eq 0 ]; then fi if [ $Verbosity -ge 2 ]; then - echo "executing $SisClr_Blue$SisClr_Bold$f$SisClr_None:" + echo "executing ${fClr}:" fi - if $f --verbosity=$Verbosity; then + if "$f" --verbosity="$Verbosity"; then : else @@ -234,11 +282,17 @@ if [ $status -eq 0 ]; then break 1 fi - done + done < <(find "$CMakeDir" -type f \( -name 'test_unit*' -o -name 'test.unit.*' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) + + if [ $NumPrograms -eq 0 ]; then + + echo "${ScriptPathClr}: found no unit-test programs under '${CMakeDirClr}' (none found)" + + exit 0 + fi fi exit $status # ############################## end of file ############################# # - From f0157ecbe3b06ba8b03d78425c917bc747861fbc Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 8 Oct 2026 20:17:46 +1100 Subject: [PATCH 12/31] 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**; --- .github/workflows/ci-cell.yml | 2 +- CHANGES.md | 16 +++ CMakeLists.txt | 2 +- Doxyfile | 72 +++++++++++ INSTALL.md | 23 ++-- NEWS.md | 1 + doc/mainpage.md | 71 +++++++++++ include/stlsoft/stlsoft.h | 9 +- prepare_cmake.sh | 33 +++++ run_all_component_tests.sh | 7 +- run_all_examples.cmd | 225 +++++++++++++++++++++++++--------- run_all_examples.sh | 136 +++++++++++++++++--- run_all_unit_tests.sh | 7 +- test/unit/versions/entry.cpp | 4 +- 14 files changed, 511 insertions(+), 97 deletions(-) create mode 100644 Doxyfile create mode 100644 doc/mainpage.md diff --git a/.github/workflows/ci-cell.yml b/.github/workflows/ci-cell.yml index acac2798..0a9c3979 100644 --- a/.github/workflows/ci-cell.yml +++ b/.github/workflows/ci-cell.yml @@ -478,7 +478,7 @@ jobs: if [ "${{ inputs.c-compiler }}" = "mingw" ]; then export PATH="/mingw64/bin:$PATH" fi - SIS_CMAKE_BUILD_DIR="${{ github.workspace }}/build" ./run_all_unit_tests.sh -M --component-only + SIS_CMAKE_BUILD_DIR="${{ github.workspace }}/build" ./run_all_component_tests.sh -M test-scratch: name: Scratch tests (${{ inputs.cell-id }}) diff --git a/CHANGES.md b/CHANGES.md index c9fee270..23372961 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,22 @@ # STLSoft - CHANGES +## 1.11.1-rc8 - 10th October 2026 + +* Scripts — **build_cmake.sh**, **clean_cmake.sh**, **ctest_cmake.sh**, **prepare_cmake.sh**, **remove_cmake_artefacts.sh**, **run_all_examples.sh**, and **run_all_scratch_tests.sh** rewritten to the common Synesis helper-script layout: builds go through `cmake --build` (with `--config` selected from `SIS_CMAKE_CONFIG` for multi-config generators) rather than `make` / `mingw32-make`; coloured output (`-A` / `--always-use-colours`, `SIS_CMAKE_ALWAYS_USE_COLOURS`, `NO_COLOR`); quoted paths and arguments; `.sis/project_name.txt` used in all status messages; +* **prepare_cmake.sh** — added `--build-shared-libs` and `-s` / `--stlsoft-root-dir`; honours `SIS_CMAKE_GENERATOR` and `SIS_CMAKE_MINGW`; every `-D` option is passed on all generator paths; +* **run_all_unit_tests.sh** / **.cmd** — now run unit-test programs only (`--unit-only` accepted for compatibility; `--component-only` removed); +* Added **run_all_component_tests.sh** / **.cmd**, **run_all_performance_tests.sh** / **.cmd** (with `--gap-groups`), and **run_all_automated_tests.sh** / **.cmd** (unit then component; `--unit-only` / `--component-only`); +* **run_all_examples.sh** — retains `--skip-interactive` (**.github/ci_skip_interactive_examples.txt**, which prevents headless CI hanging on GUI examples) and its discovery of every executable under the **examples** tree, and now exports `SIS_EXAMPLE_SMOKE=1`; **run_all_scratch_tests.sh** / **.cmd** — removed `--verbosity`; +* **remove_cmake_artefacts.sh** — no longer removes **docs** or **Doxyfile**; iterates arrays safely; +* Added **generate_doxygen.sh**, **Doxyfile**, and **doc/mainpage.md** — HTML API documentation generated from the public headers into **_build/doxygen/html**; +* **batch_compile_check**, **execute_performance_tests.sh** — quote the `$(dirname ...)` directory resolution; +* **.gitattributes** — Linguist language-bar policy: public C headers and sources are classified as C, C++ headers and sources as C++, and `*.cmake` as CMake; helper scripts, IDE project files, **CMakeLists.txt**, and **makefile** are excluded from the advertised language mix (`-linguist-detectable`); +* CI — **ci-cell.yml** runs component tests via **run_all_component_tests.sh**; +* **INSTALL.md** — documented **run_all_component_tests.sh**, **run_all_automated_tests.sh**, and **generate_doxygen.sh**; corrected the unit-test discovery patterns; +* **test.unit.versions** — aligned with **1.11.1-rc8** (**_STLSOFT_VER_1_11_1_RC8**); + + ## 1.11.1-rc7 - 30th September 2026 * **simple_string** — counted construction, `assign`, `append`, `push_back`, and concatenation keep an embedded NUL, including assignment of a single `'\0'`; diff --git a/CMakeLists.txt b/CMakeLists.txt index 93f51914..f8d841ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ # Purpose: Top-level CMake lists file for STLSoft # # Created: 31st March 2021 -# Updated: 30th September 2026 +# Updated: 10th October 2026 # # ######################################################################## # diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 00000000..2b908973 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,72 @@ +# Doxyfile for STLSoft (C/C++ API; 100% header-only) + +PROJECT_NAME = "STLSoft" +PROJECT_BRIEF = "Robust, lightweight, cross-platform, template software" +PROJECT_NUMBER = 1.11.1-rc8 + +# Overridden at generation time by generate_doxygen.sh (respects +# SIS_CMAKE_BUILD_DIR). +OUTPUT_DIRECTORY = _build/doxygen +CREATE_SUBDIRS = NO + +OUTPUT_LANGUAGE = English +TAB_SIZE = 4 +# Many header names recur across sub-projects (e.g. **functions.h**), so +# retain the path relative to include/. +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = include +STRIP_FROM_INC_PATH = include +TIMESTAMP = NO + +INPUT = include \ + doc +FILE_PATTERNS = *.h \ + *.hpp \ + *.md +RECURSIVE = YES + +USE_MDFILE_AS_MAINPAGE = doc/mainpage.md + +EXAMPLE_PATH = examples +EXAMPLE_RECURSIVE = YES + +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO + +GENERATE_HTML = YES +GENERATE_LATEX = NO +HTML_OUTPUT = html + +GENERATE_TREEVIEW = YES +DISABLE_INDEX = NO +SEARCHENGINE = YES +SOURCE_BROWSER = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES + +MARKDOWN_SUPPORT = YES +JAVADOC_AUTOBRIEF = YES +QUIET = YES + +# Undocumented-member and parameter warnings are disabled (unlike the +# smaller C libraries) because the very large template corpus would bury +# genuine documentation errors. +WARN_IF_UNDOCUMENTED = NO +WARN_NO_PARAMDOC = NO +WARN_IF_DOC_ERROR = YES + +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SKIP_FUNCTION_MACROS = YES +# Skip internal version/edit noise. +PREDEFINED = STLSOFT_DOCUMENTATION_SKIP_SECTION + +HAVE_DOT = NO + + +# ########################### end of file ########################### # diff --git a/INSTALL.md b/INSTALL.md index dcb57aaa..13e5c0ee 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -23,17 +23,17 @@ There are three options for installing **STLSoft**, depending on how you obtain If you obtain the latest release as an archive from the [**STLSoft** GitHub Releases](https://github.com/synesissoftware/STLSoft/releases) page (legacy archives may also still appear on [SourceForge](https://sourceforge.net/projects/stlsoft/)): -1. Download the latest distribution, e.g. [**STLSoft-1.11.1-rc7.zip**](https://github.com/synesissoftware/STLSoft/archive/refs/tags/1.11.1-rc7.zip); +1. Download the latest distribution, e.g. [**STLSoft-1.11.1-rc8.zip**](https://github.com/synesissoftware/STLSoft/archive/refs/tags/1.11.1-rc8.zip); 2. Unzip it to a directory of your choice, as in: ```bash $ mkdir -p ~/open-source $ cd ~/open-source -$ unzip STLSoft-1.11.1-rc7.zip +$ unzip STLSoft-1.11.1-rc8.zip ``` -3. Define an environment variable `STLSOFT`, whose value is the directory in which you unzipped it, e.g. `STLSOFT=~/open-source/STLSoft-1.11.1-rc7`, and then specify `$(STLSOFT)/include` (**UNIX**) or `%STLSOFT%\include` (**Windows**) in your project files and makefiles; +3. Define an environment variable `STLSOFT`, whose value is the directory in which you unzipped it, e.g. `STLSOFT=~/open-source/STLSoft-1.11.1-rc8`, and then specify `$(STLSOFT)/include` (**UNIX**) or `%STLSOFT%\include` (**Windows**) in your project files and makefiles; ### Cloning project, using environment variables @@ -100,16 +100,16 @@ $ sudo cmake --install ${SIS_CMAKE_BUILD_DIR:-./_build} --config Release Unless you are certain that your projects, and all the projects upon which they depend, all use **STLSoft** via **CMake** then it is recommended that you define an `STLSOFT` environment variable. For example, if you're using **UNIX** and you install to -**/usr/local/stlsoft/STLSoft-1.11.1-rc7** +**/usr/local/stlsoft/STLSoft-1.11.1-rc8** then you should set the environment variable `STLSOFT` to -**/usr/local/stlsoft/STLSoft-1.11.1-rc7** -in which case the file `stlsoft/stlsoft.h`, for example, will be located in `/usr/local/stlsoft/STLSoft-1.11.1-rc7/include/stlsoft/stlsoft.h`. +**/usr/local/stlsoft/STLSoft-1.11.1-rc8** +in which case the file `stlsoft/stlsoft.h`, for example, will be located in `/usr/local/stlsoft/STLSoft-1.11.1-rc8/include/stlsoft/stlsoft.h`. Conversely, if you're using **Windows** and you install to -**C:\3pty\STLSoft\STLSoft-1.11.1-rc7** +**C:\3pty\STLSoft\STLSoft-1.11.1-rc8** then you should set the environment variable `STLSOFT` to -**C:\3pty\STLSoft\STLSoft-1.11.1-rc7** -in which case the file `stlsoft/stlsoft.h`, for example, will be located in `C:\3pty\STLSoft\STLSoft-1.11.1-rc7\include\stlsoft\stlsoft.h`. +**C:\3pty\STLSoft\STLSoft-1.11.1-rc8** +in which case the file `stlsoft/stlsoft.h`, for example, will be located in `C:\3pty\STLSoft\STLSoft-1.11.1-rc8\include\stlsoft\stlsoft.h`. The makefiles / project files of several other open-source projects expect this symbol, including: @@ -143,7 +143,10 @@ This project comes with a number of scripts useful for building with **CMake**, | **build_cmake.sh** | Executes **CMake**-generated artefacts to (re)build the project.

Meaningful only once `prepare_cmake.sh` has been run to generate the **CMake** build artefacts.

Use `./build_cmake.sh --help` for further information. | | **clean_cmake.sh** | Executes **CMake**-generated artefacts to clean the project.

Meaningful only once `prepare_cmake.sh` has been run and a build has been run.

Use `./clean_cmake.sh --help` for further information. | | **run_all_examples.sh** | Runs all (matching) example programs.

Performs a build and then recursively runs executables under the examples tree. See also [**EXAMPLES.md**](./EXAMPLES.md).

Use `./run_all_examples.sh --help` for further information. | -| **run_all_unit_tests.sh** | Runs all (matching) unit-test programs.

Performs a build and then recursively runs executable programs matching the shell patterns `test_*` and `test.*`.

Use `./run_all_unit_tests.sh --help` for further information. | +| **run_all_unit_tests.sh** | Runs all (matching) unit-test programs.

Performs a build and then recursively runs executable programs matching the shell patterns `test_unit*` and `test.unit.*`.

Use `./run_all_unit_tests.sh --help` for further information. | +| **run_all_component_tests.sh** | Runs all (matching) component-test programs.

Performs a build and then recursively runs executable programs matching the shell patterns `test_component*` and `test.component.*`.

Use `./run_all_component_tests.sh --help` for further information. | +| **run_all_automated_tests.sh** | Runs all (matching) automated test programs: unit tests followed by component tests.

Use `./run_all_automated_tests.sh --help` for further information. | +| **generate_doxygen.sh** | Generates HTML API documentation from the public headers via **Doxygen**.

Writes to `./_build/doxygen/html/` (see **SIS_CMAKE_BUILD_DIR**); requires `doxygen` on the `PATH`.

Use `./generate_doxygen.sh --help` for further information. | | **remove_cmake_artefacts.sh** | Removes all known **CMake** artefacts.

Removes known **CMake** build artefacts from the build directory (currently `./_build`) to prepare for complete regeneration using `prepare_cmake.sh`.

Use `./remove_cmake_artefacts.sh --help` for further information. | diff --git a/NEWS.md b/NEWS.md index ade40c74..bd5928f7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ | Date | News Item | Details | | ------------------- | ----------------------------------- | ------- | +| 10th October 2026 | Release of [STLSoft 1.11.1-rc8](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc8) | `cmake --build` helper scripts; **run_all_component_tests.sh** / **run_all_automated_tests.sh**; **generate_doxygen.sh**; Linguist classification | | 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | counted NULs; `wchar_t` `string_begins_with`; bit intrinsics; `write_binary()`; `file_lines` mmap (~10–20× vs `fgetc`); compare and allocator units; MinGW static runtime; short test directories; nested **test/performance** | | 21st September 2026 | Release of [STLSoft 1.11.1-rc6](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc6) | ACE/ATL/MFC CI; Clang/macOS `stricmp` aliases | | 4th August 2026 | Release of [STLSoft 1.11.1-rc5](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc5) | `basic_simple_string<>#resize()`; **CHANGES.md**; docs | diff --git a/doc/mainpage.md b/doc/mainpage.md new file mode 100644 index 00000000..1ed8959d --- /dev/null +++ b/doc/mainpage.md @@ -0,0 +1,71 @@ +# STLSoft {#mainpage} + +**STLSoft** is a suite of **C** and **C++** libraries that provides STL extensions, general-purpose utility components, and facades over operating-system and technology-specific APIs. It is robust, lightweight, and cross-platform. + +The overarching characteristic of **STLSoft** is that it is *lightweight*. The libraries are **100% header-only**: all components are defined entirely within header files, so users need only `#include` the requisite files to access the functionality. **STLSoft** is *not* a framework; each component is as thin as possible for its given function, intended as a building block for higher-level software. + + +## Components + +The components are organised as *sub-projects* (technology / platform facets), each rooted at its own header directory: + +| Sub-project | Header | Summary | +| ----------- | ------ | ------- | +| **ACESTL** | `` | Components for the **ACE** framework | +| **ATLSTL** | `` | Components for the **Active Template Library (ATL)** | +| **COMSTL** | `` | Components for the **Component Object Model (COM)** | +| **InetSTL** | `` | Components for internet APIs | +| **MFCSTL** | `` | Components for the **Microsoft Foundation Classes (MFC)** | +| **PlatformSTL** | `` | Platform-selected facades over **UnixSTL** or **WinSTL** | +| **STLSoft** | `` | General-purpose components and base-level features | +| **UnixSTL** | `` | Components for **Unix** operating-system APIs | +| **WinSTL** | `` | Components for **Windows** operating-system APIs | + +Many functional areas (for example **filesystem**, **dl**, and **memory**) appear in more than one sub-project with *intersecting conformance*: similar components are structurally compatible, without being related by type, only to the degree of the intersection of their functionality. + + +## Quick start + +Include the requisite header(s) and use the component; there is nothing to link: + +```cpp +#include + +#include +#include + +int main() +{ + // up to 128 chars on the stack; beyond that, on the heap + stlsoft::auto_buffer buff(10); + + ::memset(&buff[0], '1', buff.size()); + + buff.resize(1000, '2'); + + return EXIT_SUCCESS; +} +``` + +Consumer **CMake** projects may use `find_package(STLSoft)` and link +`STLSoft::STLSoft`. Otherwise, define an environment variable `STLSOFT` and +add `$(STLSOFT)/include` to the include path. See +[INSTALL.md](https://github.com/synesissoftware/STLSoft/blob/master/INSTALL.md) +for build and install instructions, and +[EXAMPLES.md](https://github.com/synesissoftware/STLSoft/blob/master/EXAMPLES.md) +for the catalogue of example programs. + + +## Related projects + +Projects that depend on **STLSoft**: + +| Project | Use | +| ------- | --- | +| [b64](https://github.com/synesissoftware/b64) | C++ API is implemented in terms of **STLSoft** | +| [Pantheios](https://github.com/synesissoftware/Pantheios) | Logging API library | +| [shwild](https://github.com/synesissoftware/shwild) | Optional dependency (`USE_STLSOFT_PKG`) | +| [xTests](https://github.com/synesissoftware/xTests) | Testing library; used for the **STLSoft** unit and component tests | + + + diff --git a/include/stlsoft/stlsoft.h b/include/stlsoft/stlsoft.h index 1293605b..9eac5c46 100644 --- a/include/stlsoft/stlsoft.h +++ b/include/stlsoft/stlsoft.h @@ -5,7 +5,7 @@ * and platform discriminations, and definitions of types. * * Created: 15th January 2002 - * Updated: 30th September 2026 + * Updated: 10th October 2026 * * Home: http://stlsoft.org/ * @@ -55,8 +55,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_STLSOFT_H_STLSOFT_MAJOR 3 # define STLSOFT_VER_STLSOFT_H_STLSOFT_MINOR 57 -# define STLSOFT_VER_STLSOFT_H_STLSOFT_REVISION 19 -# define STLSOFT_VER_STLSOFT_H_STLSOFT_EDIT 607 +# define STLSOFT_VER_STLSOFT_H_STLSOFT_REVISION 20 +# define STLSOFT_VER_STLSOFT_H_STLSOFT_EDIT 608 #else /* ? STLSOFT_DOCUMENTATION_SKIP_SECTION */ /* # include "./internal/doxygen_defs.h" */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -422,12 +422,13 @@ # define _STLSOFT_VER_1_11_1_RC5 0x010b01c5 /*!< Version 1.11.1 rc 5 (4th August 2026) */ # define _STLSOFT_VER_1_11_1_RC6 0x010b01c6 /*!< Version 1.11.1 rc 6 (21st September 2026) */ # define _STLSOFT_VER_1_11_1_RC7 0x010b01c7 /*!< Version 1.11.1 rc 7 (30th September 2026) */ +# define _STLSOFT_VER_1_11_1_RC8 0x010b01c8 /*!< Version 1.11.1 rc 8 (10th October 2026) */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ #define _STLSOFT_VER_MAJOR 1 #define _STLSOFT_VER_MINOR 11 #define _STLSOFT_VER_PATCH 1 -#define _STLSOFT_VER_ALPHABETA 0xc7 +#define _STLSOFT_VER_ALPHABETA 0xc8 #define _STLSOFT_VER \ (0\ diff --git a/prepare_cmake.sh b/prepare_cmake.sh index 1738fafd..6852f32c 100755 --- a/prepare_cmake.sh +++ b/prepare_cmake.sh @@ -34,11 +34,14 @@ Configuration=Release ExamplesDisabled=0 MinGW=$(sis_cmake_is_truey "${SIS_CMAKE_MINGW:-}" && echo 1 || echo 0) MSVC_MT=0 +NO_ACE=0 +NO_cstring=0 NO_shwild=0 RunMake=0 SisUseColours=0 STLSoftDirGiven= TestingDisabled=0 +USE_UNIXem=0 VerboseMakefile=0 @@ -162,6 +165,14 @@ while [[ $# -gt 0 ]]; do MSVC_MT=1 ;; + --no-ace) + + NO_ACE=1 + ;; + --no-cstring) + + NO_cstring=1 + ;; --no-shwild) NO_shwild=1 @@ -175,6 +186,10 @@ while [[ $# -gt 0 ]]; do shift STLSoftDirGiven=$1 ;; + --use-unixem) + + USE_UNIXem=1 + ;; --help) [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" @@ -219,6 +234,12 @@ Flags/options: --msvc-mt when using Visual C++ (MSVC), select the static runtime library + --no-ace + suppresses discovery of ACE (ACESTL examples/tests will not be built) + + --no-cstring + suppresses discovery of cstring package + --no-shwild prevents recognising shwild library (NO_SHWILD=ON); xTests pattern-match assertions are then unavailable @@ -233,6 +254,12 @@ Flags/options: as the variable STLSOFT, and which will override the environment variable STLSOFT (if present) + --use-unixem + when building on Windows, use the UNIXem library and define the + preprocessor symbol _STLSOFT_FORCE_ANY_COMPILER so as to emulate and + exercise UNIXSTL, not WinSTL (or COMSTL, etc.). Has no effect when + not executing on Windows + standard flags: @@ -266,9 +293,12 @@ echo "Executing CMake for ${ProjectNameClr} (in ${CMakeDirClr})" if [ $BuildSharedLibs -eq 0 ]; then CMakeBuildSharedLibsFlag="OFF" ; else CMakeBuildSharedLibsFlag="ON" ; fi if [ $ExamplesDisabled -eq 0 ]; then CMakeBuildExamplesFlag="ON" ; else CMakeBuildExamplesFlag="OFF" ; fi if [ $MSVC_MT -eq 0 ]; then CMakeMsvcMtFlag="OFF" ; else CMakeMsvcMtFlag="ON" ; fi +if [ $NO_ACE -eq 0 ]; then CMakeNoACE="OFF" ; else CMakeNoACE="ON" ; fi +if [ $NO_cstring -eq 0 ]; then CMakeNoCstring="OFF" ; else CMakeNoCstring="ON" ; fi if [ $NO_shwild -eq 0 ]; then CMakeNoShwild="OFF" ; else CMakeNoShwild="ON" ; fi if [ -z "$STLSoftDirGiven" ]; then CMakeSTLSoftVariable="" ; else CMakeSTLSoftVariable="-DSTLSOFT=$STLSoftDirGiven/" ; fi if [ $TestingDisabled -eq 0 ]; then CMakeBuildTestingFlag="ON" ; else CMakeBuildTestingFlag="OFF" ; fi +if [ $USE_UNIXem -ne 0 ]; then CMakeUSE_UNIXem="ON" ; else CMakeUSE_UNIXem="OFF" ; fi if [ $VerboseMakefile -eq 0 ]; then CMakeVerboseMakefileFlag="OFF" ; else CMakeVerboseMakefileFlag="ON" ; fi # NOTE: the generator is the *only* thing that may differ between the MinGW @@ -294,7 +324,10 @@ cmake \ -DCMAKE_BUILD_TYPE=$Configuration \ -DCMAKE_VERBOSE_MAKEFILE:BOOL=$CMakeVerboseMakefileFlag \ -DMSVC_USE_MT:BOOL=$CMakeMsvcMtFlag \ + -DNO_ACE:BOOL=$CMakeNoACE \ + -DNO_CSTRING:BOOL=$CMakeNoCstring \ -DNO_SHWILD:BOOL=$CMakeNoShwild \ + -DUSE_UNIXEM:BOOL=$CMakeUSE_UNIXem \ $CMakeSTLSoftVariable \ "${CMakeGeneratorArgs[@]}" \ -B "$CMakeDir" \ diff --git a/run_all_component_tests.sh b/run_all_component_tests.sh index c0bd27ef..7473fc54 100755 --- a/run_all_component_tests.sh +++ b/run_all_component_tests.sh @@ -288,9 +288,12 @@ if [ $status -eq 0 ]; then if [ $NumPrograms -eq 0 ]; then - echo "${ScriptPathClr}: found no component-test programs under '${CMakeDirClr}' (none found)" + >&2 echo "${ScriptPathClr}: no matching executable component-test programs under '${CMakeDirClr}' (execute bits missing after artifact download?)" - exit 0 + if [ $ListOnly -eq 0 ]; then + + exit 1 + fi fi fi diff --git a/run_all_examples.cmd b/run_all_examples.cmd index 11273cb0..34f62e5d 100644 --- a/run_all_examples.cmd +++ b/run_all_examples.cmd @@ -1,89 +1,196 @@ -@echo off +@ECHO OFF -SETLOCAL +SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS -SET SCRIPT_DIRECTORY=%~dp0 -SET SCRIPT_PATH_DOC=%~n0[%~x0] +SET ScriptPath=%~n0[%~x0] +SET ScriptDir=%~dp0 IF DEFINED SIS_CMAKE_BUILD_DIR ( - SET CMAKE_DIR=%SIS_CMAKE_BUILD_DIR% + SET CMakeDir=%SIS_CMAKE_BUILD_DIR% ) ELSE ( - SET CMAKE_DIR=%SCRIPT_DIRECTORY%_build + SET CMakeDir=%ScriptDir%_build ) -FOR %%a IN (%*) DO ( +SET ListOnly=0 +SET RunMake=1 +SET SkipInteractive=0 - IF /I {--help}=={%%a} ( +SET BuildConfig=Release +IF DEFINED CMAKE_BUILD_TYPE SET BuildConfig=%CMAKE_BUILD_TYPE% - IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( - type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" - ) - ECHO ^ +:: ######################################################### +:: command-line handling -Runs all ^(matching^) example programs ^ +:parse_args +IF "%~1"=="" GOTO args_done -^ - -%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ - -^ - -Flags/options: ^ - - behaviour: ^ - -^ - - standard flags: ^ +IF /I "%~1"=="--help" GOTO show_help +IF /I "%~1"=="-l" ( + SET ListOnly=1 + GOTO next_arg +) +IF /I "%~1"=="--list-only" ( + SET ListOnly=1 + GOTO next_arg +) +IF /I "%~1"=="-M" ( + SET RunMake=0 + GOTO next_arg +) +IF /I "%~1"=="--no-make" ( + SET RunMake=0 + GOTO next_arg +) +IF /I "%~1"=="--skip-interactive" ( + SET SkipInteractive=1 + GOTO next_arg +) -^ +ECHO %ScriptPath%: unrecognised argument '%~1'; use --help for usage 1>&2 +EXIT /B 1 - --help ^ +:next_arg +SHIFT +GOTO parse_args - displays this help and terminates ^ +:args_done - EXIT /B 0 - ) ELSE ( +:: ######################################################### +:: main() - ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 +SET status=0 - EXIT /B 1 - ) +IF %RunMake% NEQ 0 ( + IF %ListOnly% EQU 0 ( + ECHO Executing build and then running all example programs + CALL :do_build + IF ERRORLEVEL 1 SET status=1 + ) +) ELSE ( + IF NOT EXIST "%CMakeDir%\CMakeCache.txt" ( + ECHO %ScriptPath%: cannot run in '--no-make' mode without a previous successful build step 1>&2 + EXIT /B 1 + ) ) -if NOT EXIST "%CMAKE_DIR%" ( - - ECHO "CMake build directory '%CMAKE_DIR%' does not exist" - - EXIT /B 1 +IF %status% EQU 0 ( + IF NOT EXIST "%CMakeDir%\examples" ( + ECHO %ScriptPath%: examples build tree not found at '%CMakeDir%\examples' 1>&2 + ENDLOCAL + EXIT /B 1 + ) + + IF %ListOnly% NEQ 0 ( + ECHO Listing all example programs + ) ELSE ( + ECHO Running all example programs + ) + + FOR /F "usebackq delims=" %%f IN (`DIR /A:-D /B /S "%CMakeDir%\examples\*.exe" 2^>NUL`) DO ( + CALL :is_skipped_interactive "%%~nxf" + IF !skip_example! EQU 1 ( + IF !ListOnly! NEQ 0 ( + ECHO would skip %%f: (interactive; --skip-interactive) + ) ELSE ( + ECHO. + ECHO skipping %%f: (interactive; --skip-interactive) + ) + ) ELSE IF !ListOnly! NEQ 0 ( + ECHO would execute %%f: + ) ELSE ( + ECHO. + ECHO executing %%f: + CALL "%%f" + IF ERRORLEVEL 1 ( + SET status=1 + GOTO examples_done + ) + ) + ) ) -SET "ProjectName=" -FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" - -IF NOT DEFINED ProjectName ( - - ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 - +:examples_done +IF !status! NEQ 0 ( + ENDLOCAL EXIT /B 1 ) +ENDLOCAL +EXIT /B 0 + + +:: ######################################################### +:: helpers + +:is_skipped_interactive +SET skip_example=0 +IF %SkipInteractive% EQU 0 EXIT /B 0 +IF NOT EXIST "%ScriptDir%.github\ci_skip_interactive_examples.txt" EXIT /B 0 +SET "exe_name=%~n1" +FOR /F "usebackq eol=# tokens=1" %%s IN ("%ScriptDir%.github\ci_skip_interactive_examples.txt") DO ( + SET "skip_name=%%s" + SET "skip_name=!skip_name: =!" + IF /I "!skip_name!"=="%exe_name%" SET skip_example=1 + IF /I "!skip_name!"=="%~nx1" SET skip_example=1 +) +EXIT /B 0 + +:do_build +IF DEFINED SIS_CMAKE_MAKE_COMMAND ( + PUSHd "%CMakeDir%" + CALL %SIS_CMAKE_MAKE_COMMAND% + SET build_status=!ERRORLEVEL! + POPD + EXIT /B !build_status! +) +IF EXIST "%CMakeDir%\Makefile" ( + PUSHd "%CMakeDir%" + IF DEFINED MSYSTEM ( + mingw32-make.exe + ) ELSE ( + make + ) + SET build_status=!ERRORLEVEL! + POPD + EXIT /B !build_status! +) +cmake --build "%CMakeDir%" --config %BuildConfig% +EXIT /B %ERRORLEVEL% -REM Examples that require human input may honour SIS_EXAMPLE_SMOKE for a -REM no-arg built-in tmpfile demo (see example.c.cstring_vector). -SET SIS_EXAMPLE_SMOKE=1 - -ECHO Running all %ProjectName% example programs - -FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I example.*\.exe$`) DO ( - ECHO . - ECHO executing %%f - %%f - IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% +:show_help +IF EXIST "%ScriptDir%.sis\script_info_lines.txt" ( + type "%ScriptDir%.sis\script_info_lines.txt" ) - -ENDLOCAL +ECHO. +ECHO Runs all (matching) example programs +ECHO. +ECHO %ScriptPath% [ ... flags/options ... ] +ECHO. +ECHO Flags/options: +ECHO. +ECHO behaviour: +ECHO. +ECHO -l +ECHO --list-only +ECHO lists the target programs but does not execute them +ECHO. +ECHO -M +ECHO --no-make +ECHO does not execute CMake and make before running examples +ECHO. +ECHO --skip-interactive +ECHO skips examples listed in .github/ci_skip_interactive_examples.txt +ECHO (GUI / desktop-interactive programs unsuitable for headless CI) +ECHO. +ECHO standard flags: +ECHO. +ECHO --help +ECHO displays this help and terminates +EXIT /B 0 + + +:: ############################# end of file ############################ :: diff --git a/run_all_examples.sh b/run_all_examples.sh index 967f82cc..8744843c 100755 --- a/run_all_examples.sh +++ b/run_all_examples.sh @@ -32,6 +32,7 @@ AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} ListOnly=0 RunMake=1 SisUseColours=0 +SkipInteractive=0 # ########################################################## @@ -115,6 +116,66 @@ sis_cmake_build() { cmake "${args[@]}" } +example_stem() +{ + local p="${1//\\//}" + + p="${p##*/}" + + case "$p" in + *.exe|*.EXE) p="${p%.*}" ;; + esac + + echo "$p" +} + +names_match() +{ + local a b + + a=$(echo "$1" | tr '[:upper:]' '[:lower:]') + b=$(echo "$2" | tr '[:upper:]' '[:lower:]') + + [ "$a" = "$b" ] +} + +# Examples listed in .github/ci_skip_interactive_examples.txt require an +# interactive desktop (GUI dialogs, etc.) and would hang a headless CI run. +is_skipped_interactive_example() +{ + local name f_norm line line_stem skip_file="$Dir/.github/ci_skip_interactive_examples.txt" + + [ $SkipInteractive -ne 0 ] || return 1 + + if [ ! -f "$skip_file" ]; then + + >&2 echo "${ScriptPathClr}: --skip-interactive: skip list not found at '$skip_file'" + + return 1 + fi + + f_norm="${1//\\//}" + name=$(example_stem "$f_norm") + + while IFS= read -r line || [ -n "$line" ]; do + + line="${line//$'\r'/}" + + case "$line" in + ''|\#*) continue ;; + esac + + line_stem=$(example_stem "$line") + + if names_match "$name" "$line_stem"; then + + return 0 + fi + done < "$skip_file" + + return 1 +} + # ########################################################## # command-line handling @@ -134,6 +195,10 @@ while [[ $# -gt 0 ]]; do RunMake=0 ;; + --skip-interactive) + + SkipInteractive=1 + ;; --help) [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" @@ -159,6 +224,11 @@ Flags/options: --no-make does not execute a build before running programs + --skip-interactive + skips examples listed in .github/ci_skip_interactive_examples.txt + (GUI / desktop-interactive programs unsuitable for headless CI; + list stems or names, e.g. shell_functions or shell_functions.exe) + standard flags: @@ -231,20 +301,61 @@ if [ $status -eq 0 ]; then # no-arg built-in tmpfile demo (see example.c.cstring_vector). export SIS_EXAMPLE_SMOKE=1 - NumPrograms=0 + if [ ! -d "$CMakeDir/examples" ]; then - while IFS= read -r -d '' f; do + >&2 echo "${ScriptPathClr}: examples build tree not found at '${CMakeDirClr}/examples'" - case "$f" in - *.pdb|*.ilk|*.log|*.obj|*.o) - continue - ;; - esac + exit 1 + fi + + # Exclude CMake / build artefacts that can become +x after artifact restore. + ExamplePrograms=( $(find "$CMakeDir/examples" -type f \ + ! -path '*/CMakeFiles/*' \ + ! -name '*.a' \ + ! -name '*.cmake' \ + ! -name '*.d' \ + ! -name '*.lib' \ + ! -name '*.log' \ + ! -name '*.o' \ + ! -name '*.obj' \ + ! -name '*.pdb' \ + ! -name 'CMakeLists.txt' \ + ! -name 'CTestTestfile.cmake' \ + ! -name 'Makefile' \ + ! -name 'cmake_install.cmake' \ + -exec test -x {} \; -print | sort) ) + + echo "discovered ${#ExamplePrograms[@]} example program(s)" + + if [ ${#ExamplePrograms[@]} -eq 0 ]; then + + >&2 echo "${ScriptPathClr}: no matching executable example programs under '${CMakeDirClr}/examples' (execute bits missing after artifact download?)" + + if [ $ListOnly -eq 0 ]; then + + status=1 + fi + fi - NumPrograms=$((NumPrograms + 1)) + for f in "${ExamplePrograms[@]}" + do fClr="${SisClr_Blue}${SisClr_Bold}${f}${SisClr_None}" + if is_skipped_interactive_example "$f"; then + + if [ $ListOnly -ne 0 ]; then + + echo "would skip ${fClr} (interactive; --skip-interactive)" + else + + echo + echo "skipping ${fClr} (interactive; --skip-interactive)" + fi + + continue + fi + if [ $ListOnly -ne 0 ]; then echo "would execute ${fClr}:" @@ -264,14 +375,7 @@ if [ $status -eq 0 ]; then break 1 fi - done < <(find "$CMakeDir" -type f \( -name 'example*' ! -name '*.md' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) - - if [ $NumPrograms -eq 0 ]; then - - echo "${ScriptPathClr}: found no example programs under '${CMakeDirClr}' (none found)" - - exit 0 - fi + done fi exit $status diff --git a/run_all_unit_tests.sh b/run_all_unit_tests.sh index 301ccae2..56003827 100755 --- a/run_all_unit_tests.sh +++ b/run_all_unit_tests.sh @@ -286,9 +286,12 @@ if [ $status -eq 0 ]; then if [ $NumPrograms -eq 0 ]; then - echo "${ScriptPathClr}: found no unit-test programs under '${CMakeDirClr}' (none found)" + >&2 echo "${ScriptPathClr}: no matching executable unit-test programs under '${CMakeDirClr}' (execute bits missing after artifact download?)" - exit 0 + if [ $ListOnly -eq 0 ]; then + + exit 1 + fi fi fi diff --git a/test/unit/versions/entry.cpp b/test/unit/versions/entry.cpp index b18bd6a3..7c14db25 100644 --- a/test/unit/versions/entry.cpp +++ b/test/unit/versions/entry.cpp @@ -4,7 +4,7 @@ * Purpose: Unit-tests for versions * * Created: 23rd August 2025 - * Updated: 30th September 2026 + * Updated: 10th October 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -133,7 +133,7 @@ namespace { static void TEST__STLSOFT_VER() { - TEST_INT_EQ(_STLSOFT_VER_1_11_1_RC7, _STLSOFT_VER); + TEST_INT_EQ(_STLSOFT_VER_1_11_1_RC8, _STLSOFT_VER); } #ifdef STLSOFT_HAS_ACE From eb47ae26e992bdb2a68f1215d68faa64271eac6c Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Thu, 8 Oct 2026 21:30:00 +1100 Subject: [PATCH 13/31] 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; --- CHANGES.md | 1 + NEWS.md | 2 +- include/stlsoft/stlsoft.h | 6 +- .../stlsoft/system/environment/functions.h | 8 +- .../environment_variable_exists/entry.cpp | 46 +++- .../CMakeLists.txt | 2 + .../entry.cpp | 259 ++++++++++++++++++ 7 files changed, 307 insertions(+), 17 deletions(-) create mode 100644 test/component/stlsoft/system/test.component.stlsoft.system.environment_variable_exists/CMakeLists.txt create mode 100644 test/component/stlsoft/system/test.component.stlsoft.system.environment_variable_exists/entry.cpp diff --git a/CHANGES.md b/CHANGES.md index 23372961..9df2b2ac 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,7 @@ ## 1.11.1-rc8 - 10th October 2026 +* Fixed `stlsoft_C_environment_variable_exists_m()` when `getenv_s()` reports an existing empty variable; added component tests for `stlsoft::environment_variable_exists()`; * Scripts — **build_cmake.sh**, **clean_cmake.sh**, **ctest_cmake.sh**, **prepare_cmake.sh**, **remove_cmake_artefacts.sh**, **run_all_examples.sh**, and **run_all_scratch_tests.sh** rewritten to the common Synesis helper-script layout: builds go through `cmake --build` (with `--config` selected from `SIS_CMAKE_CONFIG` for multi-config generators) rather than `make` / `mingw32-make`; coloured output (`-A` / `--always-use-colours`, `SIS_CMAKE_ALWAYS_USE_COLOURS`, `NO_COLOR`); quoted paths and arguments; `.sis/project_name.txt` used in all status messages; * **prepare_cmake.sh** — added `--build-shared-libs` and `-s` / `--stlsoft-root-dir`; honours `SIS_CMAKE_GENERATOR` and `SIS_CMAKE_MINGW`; every `-D` option is passed on all generator paths; * **run_all_unit_tests.sh** / **.cmd** — now run unit-test programs only (`--unit-only` accepted for compatibility; `--component-only` removed); diff --git a/NEWS.md b/NEWS.md index bd5928f7..6dbaeec5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,7 @@ | Date | News Item | Details | | ------------------- | ----------------------------------- | ------- | -| 10th October 2026 | Release of [STLSoft 1.11.1-rc8](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc8) | `cmake --build` helper scripts; **run_all_component_tests.sh** / **run_all_automated_tests.sh**; **generate_doxygen.sh**; Linguist classification | +| 10th October 2026 | Release of [STLSoft 1.11.1-rc8](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc8) | `getenv_s()` empty-variable fix; component tests; `cmake --build` helper scripts; **run_all_component_tests.sh** / **run_all_automated_tests.sh**; **generate_doxygen.sh**; Linguist classification | | 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | counted NULs; `wchar_t` `string_begins_with`; bit intrinsics; `write_binary()`; `file_lines` mmap (~10–20× vs `fgetc`); compare and allocator units; MinGW static runtime; short test directories; nested **test/performance** | | 21st September 2026 | Release of [STLSoft 1.11.1-rc6](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc6) | ACE/ATL/MFC CI; Clang/macOS `stricmp` aliases | | 4th August 2026 | Release of [STLSoft 1.11.1-rc5](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc5) | `basic_simple_string<>#resize()`; **CHANGES.md**; docs | diff --git a/include/stlsoft/stlsoft.h b/include/stlsoft/stlsoft.h index 9eac5c46..51d82f0c 100644 --- a/include/stlsoft/stlsoft.h +++ b/include/stlsoft/stlsoft.h @@ -421,14 +421,14 @@ # define _STLSOFT_VER_1_11_1_RC4 0x010b01c4 /*!< Version 1.11.1 rc 4 (1st July 2026) */ # define _STLSOFT_VER_1_11_1_RC5 0x010b01c5 /*!< Version 1.11.1 rc 5 (4th August 2026) */ # define _STLSOFT_VER_1_11_1_RC6 0x010b01c6 /*!< Version 1.11.1 rc 6 (21st September 2026) */ -# define _STLSOFT_VER_1_11_1_RC7 0x010b01c7 /*!< Version 1.11.1 rc 7 (30th September 2026) */ -# define _STLSOFT_VER_1_11_1_RC8 0x010b01c8 /*!< Version 1.11.1 rc 8 (10th October 2026) */ +# define _STLSOFT_VER_1_11_1_RC7 0x010B01C7 /*!< Version 1.11.1 rc 7 (30th September 2026) */ +# define _STLSOFT_VER_1_11_1_RC8 0x010B01C8 /*!< Version 1.11.1 rc 8 (10th October 2026) */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ #define _STLSOFT_VER_MAJOR 1 #define _STLSOFT_VER_MINOR 11 #define _STLSOFT_VER_PATCH 1 -#define _STLSOFT_VER_ALPHABETA 0xc8 +#define _STLSOFT_VER_ALPHABETA 0xC8 #define _STLSOFT_VER \ (0\ diff --git a/include/stlsoft/system/environment/functions.h b/include/stlsoft/system/environment/functions.h index 5b81b824..e3492e7c 100644 --- a/include/stlsoft/system/environment/functions.h +++ b/include/stlsoft/system/environment/functions.h @@ -4,7 +4,7 @@ * Purpose: Environment functions. * * Created: 4th March 2011 - * Updated: 28th September 2026 + * Updated: 8th October 2026 * * Home: http://stlsoft.org/ * @@ -53,8 +53,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_MAJOR 1 # define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_MINOR 0 -# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_REVISION 3 -# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_EDIT 15 +# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_REVISION 4 +# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_EDIT 16 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -119,7 +119,7 @@ stlsoft_C_environment_variable_exists_m( if (0 == e) { - if ('\0' == buff[0]) + if (0 == n) { // variable doesn't exist return 0; diff --git a/test/component/stlsoft/system/environment_variable_exists/entry.cpp b/test/component/stlsoft/system/environment_variable_exists/entry.cpp index 93e4506a..6fbb2d09 100644 --- a/test/component/stlsoft/system/environment_variable_exists/entry.cpp +++ b/test/component/stlsoft/system/environment_variable_exists/entry.cpp @@ -4,7 +4,7 @@ * Purpose: Component-tests for `stlsoft::environment_variable_exists()`. * * Created: 28th September 2026 - * Updated: 30th September 2026 + * Updated: 8th October 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -218,21 +218,49 @@ static void TEST_environment_variable_exists_WITH_simple_string() } #ifndef _WIN32 -/* An empty value is a defined variable on UNIX. The Windows CRT treats an - * empty assignment as erasure, so this case is UNIX-only. +/* An empty value is a defined variable on UNIX: getenv() returns "". + * Existence is true for the C function and the C++ overloads. The Windows + * CRT treats an empty assignment as erasure, so this case is UNIX-only. */ static void TEST_environment_variable_exists_WHEN_EMPTY() { - environment_variable_scope const empty(VAR_NAME, ""); + char const* const name = VAR_NAME; - char const* const value = ::getenv(VAR_NAME); + { + environment_variable_scope const empty(VAR_NAME, ""); - XTESTS_REQUIRE(TEST_PTR_NE(NULL, value)); - TEST_MS_EQ("", value); + char const* const value = ::getenv(name); - char const* const name = VAR_NAME; + XTESTS_REQUIRE(TEST_PTR_NE(NULL, value)); + TEST_MS_EQ("", value); - TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); + TEST_BOOLEAN_TRUE(stlsoft::stlsoft_C_environment_variable_exists_m(name)); + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(std::string(name))); + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(stlsoft::simple_string(name))); + TEST_BOOLEAN_FALSE(stlsoft::stlsoft_C_environment_variable_exists_m("STLSOFT_CT_ENV_VAR_EXISTS_NO_SUCH")); + } + + { + environment_variable_scope const present(VAR_NAME, "present"); + + TEST_BOOLEAN_TRUE(stlsoft::stlsoft_C_environment_variable_exists_m(name)); + + environment_variable_scope const emptied(VAR_NAME, ""); + + char const* const value = ::getenv(name); + + XTESTS_REQUIRE(TEST_PTR_NE(NULL, value)); + TEST_MS_EQ("", value); + + TEST_BOOLEAN_TRUE(stlsoft::stlsoft_C_environment_variable_exists_m(name)); + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); + } + + environment_variable_scope const erased(VAR_NAME, ss_nullptr_k); + + TEST_BOOLEAN_FALSE(stlsoft::stlsoft_C_environment_variable_exists_m(name)); + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(name)); } #endif /* !_WIN32 */ diff --git a/test/component/stlsoft/system/test.component.stlsoft.system.environment_variable_exists/CMakeLists.txt b/test/component/stlsoft/system/test.component.stlsoft.system.environment_variable_exists/CMakeLists.txt new file mode 100644 index 00000000..9107eda8 --- /dev/null +++ b/test/component/stlsoft/system/test.component.stlsoft.system.environment_variable_exists/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.component.stlsoft.system.environment_variable_exists entry.cpp) diff --git a/test/component/stlsoft/system/test.component.stlsoft.system.environment_variable_exists/entry.cpp b/test/component/stlsoft/system/test.component.stlsoft.system.environment_variable_exists/entry.cpp new file mode 100644 index 00000000..7f7bbca0 --- /dev/null +++ b/test/component/stlsoft/system/test.component.stlsoft.system.environment_variable_exists/entry.cpp @@ -0,0 +1,259 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test.component.stlsoft.system.environment_variable_exists/entry.cpp + * + * Purpose: Component-tests for `stlsoft::environment_variable_exists()`. + * + * Created: 28th September 2026 + * Updated: 28th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +/* ///////////////////////////////////// + * test component header file include(s) + */ + +/* String-access shims must be visible before functions.hpp so the template + * overload can bind c_str_ptr() for these types. + */ +#include +#include +#include + +/* ///////////////////////////////////// + * general includes + */ + +/* xTests header files */ +#include +#include + +/* STLSoft header files */ +#include +#include + +/* Standard C++ header files */ +#include + +/* Standard C header files */ +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace { + + static void TEST_environment_variable_exists_WHEN_ABSENT(); + static void TEST_environment_variable_exists_WHEN_PRESENT(); + static void TEST_environment_variable_exists_WHEN_ERASED(); + static void TEST_environment_variable_exists_WHEN_VALUE_REPLACED(); + static void TEST_environment_variable_exists_EXACT_NAME(); + static void TEST_environment_variable_exists_WITH_std_string(); + static void TEST_environment_variable_exists_WITH_simple_string(); +#ifndef _WIN32 + static void TEST_environment_variable_exists_WHEN_EMPTY(); +#endif /* !_WIN32 */ + static void TEST_environment_variable_exists_CASE_SENSITIVITY(); +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.component.stlsoft.system.environment_variable_exists", verbosity)) + { + XTESTS_RUN_CASE(TEST_environment_variable_exists_WHEN_ABSENT); + XTESTS_RUN_CASE(TEST_environment_variable_exists_WHEN_PRESENT); + XTESTS_RUN_CASE(TEST_environment_variable_exists_WHEN_ERASED); + XTESTS_RUN_CASE(TEST_environment_variable_exists_WHEN_VALUE_REPLACED); + XTESTS_RUN_CASE(TEST_environment_variable_exists_EXACT_NAME); + XTESTS_RUN_CASE(TEST_environment_variable_exists_WITH_std_string); + XTESTS_RUN_CASE(TEST_environment_variable_exists_WITH_simple_string); +#ifndef _WIN32 + XTESTS_RUN_CASE(TEST_environment_variable_exists_WHEN_EMPTY); +#endif /* !_WIN32 */ + XTESTS_RUN_CASE(TEST_environment_variable_exists_CASE_SENSITIVITY); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * constants + */ + +namespace { + + using platformstl::environment_variable_scope; + + char const VAR_NAME[] = "STLSOFT_CT_ENV_VAR_EXISTS"; + char const VAR_NAME_EXTRA[] = "STLSOFT_CT_ENV_VAR_EXISTS_EXTRA"; + char const VAR_NAME_PREFIX[] = "STLSOFT_CT_ENV_VAR"; + char const VAR_NAME_UPPER[] = "STLSOFT_CT_ENV_VAR_EXISTS_CASE"; + char const VAR_NAME_LOWER[] = "stlsoft_ct_env_var_exists_case"; +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace { + +static void TEST_environment_variable_exists_WHEN_ABSENT() +{ + environment_variable_scope const absent(VAR_NAME, ss_nullptr_k); + + char const* const name = VAR_NAME; + + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(name)); + TEST_BOOLEAN_FALSE(stlsoft::stlsoft_C_environment_variable_exists_m(name)); + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists("STLSOFT_CT_ENV_VAR_EXISTS_NO_SUCH")); +} + +static void TEST_environment_variable_exists_WHEN_PRESENT() +{ + environment_variable_scope const present(VAR_NAME, "present"); + + char const* const name = VAR_NAME; + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); + TEST_BOOLEAN_TRUE(stlsoft::stlsoft_C_environment_variable_exists_m(name)); +} + +static void TEST_environment_variable_exists_WHEN_ERASED() +{ + environment_variable_scope const present(VAR_NAME, "present"); + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(VAR_NAME)); + + environment_variable_scope const erased(VAR_NAME, ss_nullptr_k); + + char const* const name = VAR_NAME; + + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(name)); +} + +static void TEST_environment_variable_exists_WHEN_VALUE_REPLACED() +{ + environment_variable_scope const first(VAR_NAME, "one"); + + char const* const name = VAR_NAME; + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); + + environment_variable_scope const second(VAR_NAME, "two"); + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); +} + +static void TEST_environment_variable_exists_EXACT_NAME() +{ + environment_variable_scope const extra_absent(VAR_NAME_EXTRA, ss_nullptr_k); + environment_variable_scope const prefix_absent(VAR_NAME_PREFIX, ss_nullptr_k); + environment_variable_scope const present(VAR_NAME, "value"); + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(VAR_NAME)); + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(VAR_NAME_EXTRA)); + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(VAR_NAME_PREFIX)); + + environment_variable_scope const erased(VAR_NAME, ss_nullptr_k); + environment_variable_scope const extra(VAR_NAME_EXTRA, "extra"); + + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(VAR_NAME)); + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(VAR_NAME_EXTRA)); +} + +static void TEST_environment_variable_exists_WITH_std_string() +{ + { + environment_variable_scope const absent(VAR_NAME, ss_nullptr_k); + + std::string const name(VAR_NAME); + + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(name)); + } + + environment_variable_scope const present(VAR_NAME, "present"); + + std::string const name(VAR_NAME); + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); +} + +static void TEST_environment_variable_exists_WITH_simple_string() +{ + { + environment_variable_scope const absent(VAR_NAME, ss_nullptr_k); + + stlsoft::simple_string const name(VAR_NAME); + + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(name)); + } + + environment_variable_scope const present(VAR_NAME, "present"); + + stlsoft::simple_string const name(VAR_NAME); + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); +} +#ifndef _WIN32 + +/* An empty value is a defined variable on UNIX. The Windows CRT treats an + * empty assignment as erasure, so this case is UNIX-only. + */ +static void TEST_environment_variable_exists_WHEN_EMPTY() +{ + environment_variable_scope const empty(VAR_NAME, ""); + + char const* const value = ::getenv(VAR_NAME); + + XTESTS_REQUIRE(TEST_PTR_NE(NULL, value)); + TEST_MS_EQ("", value); + + char const* const name = VAR_NAME; + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(name)); +} +#endif /* !_WIN32 */ + +/* UNIX names are case-sensitive; the Windows CRT folds case. + */ +static void TEST_environment_variable_exists_CASE_SENSITIVITY() +{ + environment_variable_scope const lower(VAR_NAME_LOWER, ss_nullptr_k); + environment_variable_scope const upper(VAR_NAME_UPPER, "1"); + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(VAR_NAME_UPPER)); +#ifdef _WIN32 + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_exists(VAR_NAME_LOWER)); +#else + + TEST_BOOLEAN_FALSE(stlsoft::environment_variable_exists(VAR_NAME_LOWER)); +#endif +} +} // anonymous namespace + + +/* ///////////////////////////// end of file //////////////////////////// */ + From 59cd3eb017c206dbfc234dc8a82183f2ca673838 Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Fri, 9 Oct 2026 04:44:41 +1100 Subject: [PATCH 14/31] Traits conformance (#51) * chore(layout): trivial whitespace changes to InetSTL component(s) * versions * fix(unixstl): define class_type in terms of char_type in traits Correct the definition of class_type in both filesystem_traits and system_traits for narrow and wide characters under unixstl. Previously, the wide-character specialisations erroneously defined class_type as the narrow specialisation (using us_char_a_t instead of us_char_w_t) due to copy-paste errors. Defining class_type as traits fixes this bug and ensures both specialisations are correct and consistent. - In filesystem_traits, define class_type as filesystem_traits; - In system_traits, define class_type as system_traits; - Bump file revision and edit numbers for both header files; - Update header file metadata banners to current date and copyright year; * versions * versions * refactor(unixstl,winstl): canonicalise preprocessor guards in *_traits Reshape conditional-compilation guards in the UNIXSTL and WinSTL **system_traits** and **filesystem_traits** headers so that future edits to the condition sets are single-line diffs, per **revisibility**. No behavioural change is intended: - Prefix affected guards with `#if 0` so that each real condition is an `#elif` and every condition term sits on its own line; - Add `0 ||` / `|| 0` and `1 &&` / `&& 1` sentinel terms to multi-term conditions so that the first and last terms can be edited in isolation; - Label `#endif` and `#else` comments with the `_WIN32` condition they close, replacing `OS` and unlabelled forms; - Remove the blank line that preceded `#ifdef _WIN32` blocks in the UNIXSTL **system_traits** and **filesystem_traits** path and compare functions; - Change the `buffer` parameter of **get_full_path_name_impl2()** from `char_type*` to `char_type buffer[]` in UNIXSTL **filesystem_traits**, matching sibling overloads (signature-equivalent); - Adjust blank lines around the WinSTL MSVC < 1200 **get_full_path_name()** shim and in UNIXSTL **call_getcwd_()**; --- .../inetstl/filesystem/filesystem_traits.hpp | 66 ++++----- include/inetstl/inetstl.h | 13 +- .../unixstl/filesystem/filesystem_traits.hpp | 140 ++++++++++-------- include/unixstl/system/system_traits.hpp | 33 +++-- include/unixstl/unixstl.h | 13 +- .../winstl/filesystem/filesystem_traits.hpp | 5 +- include/winstl/system/system_traits.hpp | 5 +- include/winstl/winstl.h | 13 +- test/unit/versions/entry.cpp | 4 +- 9 files changed, 159 insertions(+), 133 deletions(-) diff --git a/include/inetstl/filesystem/filesystem_traits.hpp b/include/inetstl/filesystem/filesystem_traits.hpp index 74fe9d1c..e8a2ffa6 100644 --- a/include/inetstl/filesystem/filesystem_traits.hpp +++ b/include/inetstl/filesystem/filesystem_traits.hpp @@ -5,11 +5,11 @@ * Unicode specialisations thereof. * * Created: 30th April 1999 - * Updated: 20th March 2025 + * Updated: 8th October 2026 * * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 1999-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -53,10 +53,10 @@ #define INETSTL_INCL_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION -# define INETSTL_VER_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MAJOR 5 -# define INETSTL_VER_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MINOR 0 -# define INETSTL_VER_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_REVISION 2 -# define INETSTL_VER_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_EDIT 98 +# define INETSTL_VER_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MAJOR 5 +# define INETSTL_VER_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MINOR 0 +# define INETSTL_VER_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_REVISION 2 +# define INETSTL_VER_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_EDIT 99 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -135,23 +135,23 @@ struct filesystem_traits /// @{ public: /// The character type - typedef C char_type; + typedef C char_type; /// The size type - typedef is_size_t size_type; + typedef is_size_t size_type; /// The difference type - typedef is_ptrdiff_t difference_type; + typedef is_ptrdiff_t difference_type; /// The find data type - typedef WIN32_FIND_DATA find_data_type; + typedef WIN32_FIND_DATA find_data_type; /// The stat data type - typedef WIN32_FIND_DATA stat_data_type; + typedef WIN32_FIND_DATA stat_data_type; /// The current instantion of the type - typedef filesystem_traits class_type; + typedef filesystem_traits class_type; /// The (signed) integer type - typedef is_int_t int_type; + typedef is_int_t int_type; /// The Boolean type - typedef is_bool_t bool_type; + typedef is_bool_t bool_type; /// The type of system error codes - typedef DWORD error_type; + typedef DWORD error_type; /// @} /// \name File-system entry names @@ -274,15 +274,15 @@ struct filesystem_traits : public STLSOFT_NS_QUAL(c_string_traits) { public: - typedef is_char_a_t char_type; - typedef is_size_t size_type; - typedef is_ptrdiff_t difference_type; - typedef WIN32_FIND_DATAA find_data_type; - typedef WIN32_FIND_DATAA stat_data_type; - typedef filesystem_traits class_type; - typedef is_int_t int_type; - typedef is_bool_t bool_type; - typedef DWORD error_type; + typedef is_char_a_t char_type; + typedef is_size_t size_type; + typedef is_ptrdiff_t difference_type; + typedef WIN32_FIND_DATAA find_data_type; + typedef WIN32_FIND_DATAA stat_data_type; + typedef filesystem_traits class_type; + typedef is_int_t int_type; + typedef is_bool_t bool_type; + typedef DWORD error_type; public: // File-system entry names @@ -553,15 +553,15 @@ struct filesystem_traits : public STLSOFT_NS_QUAL(c_string_traits) { public: - typedef is_char_w_t char_type; - typedef is_size_t size_type; - typedef is_ptrdiff_t difference_type; - typedef WIN32_FIND_DATAW find_data_type; - typedef WIN32_FIND_DATAW stat_data_type; - typedef filesystem_traits class_type; - typedef is_int_t int_type; - typedef is_bool_t bool_type; - typedef DWORD error_type; + typedef is_char_w_t char_type; + typedef is_size_t size_type; + typedef is_ptrdiff_t difference_type; + typedef WIN32_FIND_DATAW find_data_type; + typedef WIN32_FIND_DATAW stat_data_type; + typedef filesystem_traits class_type; + typedef is_int_t int_type; + typedef is_bool_t bool_type; + typedef DWORD error_type; public: diff --git a/include/inetstl/inetstl.h b/include/inetstl/inetstl.h index db1fe52e..aca3309d 100644 --- a/include/inetstl/inetstl.h +++ b/include/inetstl/inetstl.h @@ -5,7 +5,7 @@ * platform discriminations, and definitions of types. * * Created: 24th April 2004 - * Updated: 17th September 2026 + * Updated: 8th October 2026 * * Home: http://stlsoft.org/ * @@ -50,8 +50,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define INETSTL_VER_INETSTL_H_INETSTL_MAJOR 3 # define INETSTL_VER_INETSTL_H_INETSTL_MINOR 11 -# define INETSTL_VER_INETSTL_H_INETSTL_REVISION 3 -# define INETSTL_VER_INETSTL_H_INETSTL_EDIT 578 +# define INETSTL_VER_INETSTL_H_INETSTL_REVISION 4 +# define INETSTL_VER_INETSTL_H_INETSTL_EDIT 579 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ /** \file inetstl/inetstl.h @@ -145,12 +145,13 @@ # define _INETSTL_VER_1_4_2 0x010402ff /*!< Version 1.4.2 (with STLSoft 1.11.1 alpha 8) */ # define _INETSTL_VER_1_5_0_A01 0x01050041 /*!< Version 1.5.0 alpha 1 (with STLSoft 1.11.1 beta 2) */ # define _INETSTL_VER_1_5_0_A02 0x01050042 /*!< Version 1.5.0 alpha 2 (with STLSoft 1.11.1 rc 2) */ +# define _INETSTL_VER_1_5_0_A03 0x01050043 /*!< Version 1.5.0 alpha 3 (with STLSoft 1.11.1 rc 8) */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ #define _INETSTL_VER_MAJOR 1 #define _INETSTL_VER_MINOR 5 #define _INETSTL_VER_PATCH 0 -#define _INETSTL_VER_ALPHABETA 0x42 +#define _INETSTL_VER_ALPHABETA 0x43 #define _INETSTL_VER \ (0\ @@ -194,8 +195,8 @@ * STLSoft version compatibility check(s) */ -#if _STLSOFT_VER < 0x010b0182 -# error This version of the InetSTL libraries requires STLSoft version 1.11.1 beta 2, or later +#if _STLSOFT_VER < 0x010B01C8 +# error This version of the InetSTL libraries requires STLSoft version 1.11.1 rc 8, or later #endif /* _STLSOFT_VER */ diff --git a/include/unixstl/filesystem/filesystem_traits.hpp b/include/unixstl/filesystem/filesystem_traits.hpp index b8aab10e..c276159b 100644 --- a/include/unixstl/filesystem/filesystem_traits.hpp +++ b/include/unixstl/filesystem/filesystem_traits.hpp @@ -5,7 +5,7 @@ * Unicode specialisations thereof. * * Created: 15th November 2002 - * Updated: 6th May 2025 + * Updated: 8th October 2026 * * Thanks: To Sergey Nikulov, for spotting a preprocessor typo that broke * GCC -pedantic; to Michal Makowski and Zar Eindl for reporting @@ -14,7 +14,7 @@ * * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2002-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -60,8 +60,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MAJOR 4 # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MINOR 16 -# define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_REVISION 1 -# define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_EDIT 188 +# define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_REVISION 2 +# define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_EDIT 189 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -791,7 +791,7 @@ struct filesystem_traits static bool_type is_device(char_type const* path); /// Returns whether the given path represents a socket static bool_type is_socket(char_type const* path); -#endif /* OS */ +#endif /* _WIN32 */ /// Returns whether the given path represents a link static bool_type is_link(char_type const* path); @@ -811,7 +811,7 @@ struct filesystem_traits static bool_type is_device(stat_data_type const* stat_data); /// Returns whether the given stat info represents a socket static bool_type is_socket(stat_data_type const* stat_data); -#endif /* OS */ +#endif /* _WIN32 */ /// Returns whether the given stat info represents a link static bool_type is_link(stat_data_type const* stat_data); @@ -900,7 +900,8 @@ struct filesystem_traits_ public: // path classification and analysis static size_type path_max() { -#if defined(PATH_MAX) +#if 0 +#elif defined(PATH_MAX) return PATH_MAX; #else /* ? PATH_MAX */ @@ -924,7 +925,7 @@ struct filesystem_traits typedef us_ptrdiff_t difference_type; typedef struct stat stat_data_type; typedef struct stat fstat_data_type; - typedef filesystem_traits class_type; + typedef filesystem_traits class_type; typedef path_classification_t path_classification_type; typedef unixstl_C_path_classification_results_m_t path_classification_results_type; typedef stlsoft_C_string_slice_m_t path_classification_string_slice_type; @@ -1356,7 +1357,6 @@ struct filesystem_traits static bool_type is_path_rooted(char_type const* path) { UNIXSTL_ASSERT(NULL != path); - #ifdef _WIN32 // It might be a UNC path. This is handled by the second test below, but @@ -1389,7 +1389,6 @@ struct filesystem_traits ) { UNIXSTL_ASSERT(NULL != path); - #ifdef _WIN32 if (len >= 2) @@ -1426,7 +1425,6 @@ struct filesystem_traits static bool_type is_path_absolute(char_type const* path) { UNIXSTL_ASSERT(NULL != path); - #ifdef _WIN32 // If it's really on Windows, then it can only be absolute if ... @@ -1460,7 +1458,6 @@ struct filesystem_traits { return false; } - #ifdef _WIN32 // If it's really on Windows, then it can only be absolute if ... @@ -1491,7 +1488,6 @@ struct filesystem_traits static bool_type is_path_UNC(char_type const* path) { UNIXSTL_ASSERT(NULL != path); - #ifdef _WIN32 size_type const len = str_len(path); @@ -1674,7 +1670,6 @@ struct filesystem_traits { return true; } - #ifdef _WIN32 if (is_root_drive_(path, cchPath)) @@ -1686,7 +1681,7 @@ struct filesystem_traits { return true; } -#endif +#endif /* _WIN32 */ return false; } @@ -1763,9 +1758,9 @@ struct filesystem_traits if (NULL == slash2) { -#if 0 +# if 0 WINSTL_API_EXTERNAL_ErrorHandling_SetLastError(ERROR_INVALID_ARGUMENT); -#endif /* 0 */ +# endif /* 0 */ return 0; } @@ -1798,7 +1793,7 @@ struct filesystem_traits get_full_path_name_impl2( char_type const* fileName , size_type const len - , char_type* buffer + , char_type buffer[] , size_type cchBuffer ) { @@ -1828,7 +1823,7 @@ struct filesystem_traits return get_full_path_name_impl2(cwd.data(), n2 + len, buffer, cchBuffer); } -#endif +#endif /* _WIN32 */ // The next thing to so is determine whether the path is absolute, in // which case we'll just copy it into the buffer @@ -1836,10 +1831,10 @@ struct filesystem_traits #ifdef _WIN32 if (is_path_absolute(fileName)) -#else +#else /* ? _WIN32 */ if (is_path_rooted(fileName)) -#endif +#endif /* _WIN32 */ { // Given path is absolute, so simply copy into buffer if (NULL == buffer) @@ -1952,9 +1947,12 @@ struct filesystem_traits } // For some reason OS-X's GCC needs this : it's confused. -#if defined(STLSOFT_COMPILER_IS_GCC) && \ - STLSOFT_GCC_VER >= 40200 && \ - STLSOFT_GCC_VER < 40300 +#if 0 +#elif 1 &&\ + defined(STLSOFT_COMPILER_IS_GCC) &&\ + STLSOFT_GCC_VER >= 40200 &&\ + STLSOFT_GCC_VER < 40300 &&\ + 1 UNIXSTL_ASSERT(0); // should never get here return 0; #endif @@ -2197,9 +2195,12 @@ return 0; char_type const* dir ) { -#if defined(_WIN32) && \ - ( defined(STLSOFT_COMPILER_IS_MSVC) || \ - defined(STLSOFT_COMPILER_IS_INTEL)) +#if 0 +#elif defined(_WIN32) &&\ + ( 0 ||\ + defined(STLSOFT_COMPILER_IS_MSVC) ||\ + defined(STLSOFT_COMPILER_IS_INTEL) ||\ + 0) return 0 == ::_chdir(dir); #else /* ? _WIN32 */ @@ -2240,10 +2241,15 @@ return 0; private: static char_type const* call_getcwd_(char_type buffer[], size_type cchBuffer) { -#if defined(STLSOFT_COMPILER_IS_INTEL) || \ - defined(STLSOFT_COMPILER_IS_MSVC) +#if 0 +#elif 0 ||\ + defined(STLSOFT_COMPILER_IS_INTEL) ||\ + defined(STLSOFT_COMPILER_IS_MSVC) ||\ + 0 + return ::_getcwd(buffer, int(cchBuffer)); #else /* ? compiler */ + return ::getcwd(buffer, int(cchBuffer)); #endif /* compiler */ } @@ -2256,7 +2262,8 @@ return 0; , size_type cchBuffer ) { -#if defined(_WIN32) +#if 0 +#elif defined(_WIN32) char_type local[1 + _MAX_PATH]; size_type const cchLocal = STLSOFT_NUM_ELEMENTS(local); @@ -2373,7 +2380,7 @@ return 0; return class_type::stat(path, &sd) && class_type::is_socket(&sd); } -#endif /* OS */ +#endif /* _WIN32 */ static bool_type is_link(char_type const* path) { #ifdef _WIN32 @@ -2393,7 +2400,6 @@ return 0; { UNIXSTL_ASSERT(NULL != path); UNIXSTL_ASSERT(NULL != stat_data); - #ifdef _WIN32 if (NULL != class_type::str_pbrk(path, "*?")) @@ -2477,42 +2483,42 @@ return 0; static bool_type is_device(stat_data_type const* stat_data) { -#if 1 +# if 1 switch (stat_data->st_mode & S_IFMT) { -#ifdef S_IFBLK +# ifdef S_IFBLK case S_IFBLK: -#endif // S_IFBLK -#ifdef S_IFCHR +# endif // S_IFBLK +# ifdef S_IFCHR case S_IFCHR: -#endif // S_IFCHR -#ifdef S_IFIFO +# endif // S_IFCHR +# ifdef S_IFIFO case S_IFIFO: -#endif // S_IFIFO -#ifdef S_IFWHT +# endif // S_IFIFO +# ifdef S_IFWHT case S_IFWHT: -#endif // S_IFWHT +# endif // S_IFWHT return true; default: return false; } -#else /* ? 0 */ +# else /* ? 0 */ return false; -#endif /* 0 */ +# endif /* 0 */ } static bool_type is_socket(stat_data_type const* stat_data) { -#if 1 +# if 1 return S_IFSOCK == (stat_data->st_mode & S_IFMT); -#else /* ? 0 */ +# else /* ? 0 */ return filesystem_traits_util_::is_file_type_(stat_data, S_IFSOCK); -#endif /* 0 */ +# endif /* 0 */ } -#endif /* OS */ +#endif /* _WIN32 */ static bool_type is_link(stat_data_type const* stat_data) { #ifdef _WIN32 @@ -2558,10 +2564,13 @@ return 0; static bool_type create_directory(char_type const* dir, mode_type permissions) { -#if defined(_WIN32) && \ - ( defined(STLSOFT_COMPILER_IS_INTEL) || \ - defined(STLSOFT_COMPILER_IS_GCC) || \ - defined(STLSOFT_COMPILER_IS_MSVC)) +#if 0 +#elif defined(_WIN32) &&\ + ( 0 ||\ + defined(STLSOFT_COMPILER_IS_INTEL) ||\ + defined(STLSOFT_COMPILER_IS_GCC) ||\ + defined(STLSOFT_COMPILER_IS_MSVC) ||\ + 0) STLSOFT_SUPPRESS_UNUSED(permissions); @@ -2580,9 +2589,12 @@ return 0; static bool_type remove_directory(char_type const* dir) { -#if defined(_WIN32) && \ - ( defined(STLSOFT_COMPILER_IS_INTEL) || \ - defined(STLSOFT_COMPILER_IS_MSVC)) +#if 0 +#elif defined(_WIN32) &&\ + ( 0 ||\ + defined(STLSOFT_COMPILER_IS_INTEL) ||\ + defined(STLSOFT_COMPILER_IS_MSVC) ||\ + 0) return 0 == ::_rmdir(dir); #else /* ? _WIN32 */ @@ -2615,9 +2627,12 @@ return 0; static file_handle_type open_file(char_type const* fileName, int oflag, int pmode) { -#if defined(_WIN32) && \ - ( defined(STLSOFT_COMPILER_IS_INTEL) || \ - defined(STLSOFT_COMPILER_IS_MSVC)) +#if 0 +#elif defined(_WIN32) && \ + ( 0 ||\ + defined(STLSOFT_COMPILER_IS_INTEL) ||\ + defined(STLSOFT_COMPILER_IS_MSVC) ||\ + 0) return ::_open(fileName, oflag, pmode); #else /* ? _WIN32 */ @@ -2630,9 +2645,12 @@ return 0; static bool_type close_file(file_handle_type h) { -#if defined(_WIN32) && \ - ( defined(STLSOFT_COMPILER_IS_INTEL) || \ - defined(STLSOFT_COMPILER_IS_MSVC)) +#if 0 +#elif defined(_WIN32) && \ + ( 0 ||\ + defined(STLSOFT_COMPILER_IS_INTEL) ||\ + defined(STLSOFT_COMPILER_IS_MSVC) ||\ + 0) return 0 == ::_close(h); #else /* ? _WIN32 */ @@ -2685,7 +2703,7 @@ struct filesystem_traits typedef us_ptrdiff_t difference_type; typedef struct stat stat_data_type; typedef struct stat fstat_data_type; - typedef filesystem_traits class_type; + typedef filesystem_traits class_type; typedef us_int_t int_type; typedef us_bool_t bool_type; typedef int file_handle_type; diff --git a/include/unixstl/system/system_traits.hpp b/include/unixstl/system/system_traits.hpp index 1dd668ff..fa1543a5 100644 --- a/include/unixstl/system/system_traits.hpp +++ b/include/unixstl/system/system_traits.hpp @@ -5,11 +5,11 @@ * Unicode specialisations thereof. * * Created: 15th November 2002 - * Updated: 20th March 2025 + * Updated: 8th October 2026 * * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2002-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -55,8 +55,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_MAJOR 6 # define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_MINOR 2 -# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 2 -# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 140 +# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 3 +# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 141 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -86,8 +86,9 @@ # include #endif /* !STLSOFT_INCL_STLSOFT_API_external_h_string */ -#if defined(_WIN32) || \ - defined(_WIN64) +#if 0 +#elif defined(_WIN32) || \ + defined(_WIN64) # include #endif /* Windows */ #ifndef STLSOFT_INCL_H_ERRNO @@ -98,8 +99,9 @@ # define STLSOFT_INCL_H_FCNTL # include #endif /* !STLSOFT_INCL_H_FCNTL */ -#if defined(_WIN32) || \ - defined(_WIN64) +#if 0 +#elif defined(_WIN32) || \ + defined(_WIN64) # include # if defined(STLSOFT_COMPILER_IS_INTEL) || \ defined(STLSOFT_COMPILER_IS_MSVC) @@ -408,9 +410,12 @@ struct system_traits_ public: static bool_type close_handle(handle_type h) { -#if defined(_WIN32) && \ - ( defined(STLSOFT_COMPILER_IS_MSVC) || \ - defined(STLSOFT_COMPILER_IS_INTEL)) +#if 0 +#elif defined(_WIN32) &&\ + ( 0 ||\ + defined(STLSOFT_COMPILER_IS_MSVC) ||\ + defined(STLSOFT_COMPILER_IS_INTEL) ||\ + 0) return 0 == ::_close(h); #else /* ? _WIN32 */ @@ -462,7 +467,7 @@ struct system_traits typedef us_char_a_t char_type; typedef us_size_t size_type; typedef us_ptrdiff_t difference_type; - typedef system_traits class_type; + typedef system_traits class_type; typedef us_int_t int_type; typedef us_bool_t bool_type; typedef void* module_type; @@ -484,7 +489,6 @@ struct system_traits for (;; ++ps1, ++ps2) { int_type d = int_type(*ps1) - int_type(*ps2); - #ifdef _WIN32 if (0 != d) @@ -540,7 +544,6 @@ struct system_traits for (; 0 != cch; ++ps1, ++ps2, --cch) { int_type d = int_type(*ps1) - int_type(*ps2); - #ifdef _WIN32 if (0 != d) @@ -743,7 +746,7 @@ struct system_traits typedef us_char_w_t char_type; typedef us_size_t size_type; typedef us_ptrdiff_t difference_type; - typedef system_traits class_type; + typedef system_traits class_type; typedef us_int_t int_type; typedef us_bool_t bool_type; typedef void* module_type; diff --git a/include/unixstl/unixstl.h b/include/unixstl/unixstl.h index 390583b5..76874ced 100644 --- a/include/unixstl/unixstl.h +++ b/include/unixstl/unixstl.h @@ -5,7 +5,7 @@ * platform discriminations, and definitions of types. * * Created: 15th January 2002 - * Updated: 17th September 2026 + * Updated: 8th October 2026 * * Home: http://stlsoft.org/ * @@ -50,8 +50,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_MAJOR 3 # define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_MINOR 11 -# define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_REVISION 3 -# define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_EDIT 130 +# define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_REVISION 4 +# define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_EDIT 131 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ /** \file unixstl/unixstl.h @@ -163,12 +163,13 @@ # define _UNIXSTL_VER_1_8_6_B04 0x01080684 /*!< Version 1.8.8 beta 4 (with STLSoft 1.11.1 beta 8) */ # define _UNIXSTL_VER_1_8_6_B05 0x01080685 /*!< Version 1.8.8 beta 5 (with STLSoft 1.11.1 rc 2) */ # define _UNIXSTL_VER_1_8_6_B06 0x01080686 /*!< Version 1.8.8 beta 6 (with STLSoft 1.11.1 rc 3) */ +# define _UNIXSTL_VER_1_8_6_B07 0x01080687 /*!< Version 1.8.8 beta 7 (with STLSoft 1.11.1 rc 8) */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ #define _UNIXSTL_VER_MAJOR 1 #define _UNIXSTL_VER_MINOR 8 #define _UNIXSTL_VER_PATCH 6 -#define _UNIXSTL_VER_ALPHABETA 0x86 +#define _UNIXSTL_VER_ALPHABETA 0x87 #define _UNIXSTL_VER \ (0\ @@ -199,8 +200,8 @@ * STLSoft version compatibility check(s) */ -#if _STLSOFT_VER < 0x010b0187 -# error This version of the UNIXSTL libraries requires STLSoft version 1.11.1 beta 7, or later +#if _STLSOFT_VER < 0x010B01C8 +# error This version of the UNIXSTL libraries requires STLSoft version 1.11.1 rc 8, or later #endif /* _STLSOFT_VER */ diff --git a/include/winstl/filesystem/filesystem_traits.hpp b/include/winstl/filesystem/filesystem_traits.hpp index fa1f9f8a..431f0d4e 100644 --- a/include/winstl/filesystem/filesystem_traits.hpp +++ b/include/winstl/filesystem/filesystem_traits.hpp @@ -1696,9 +1696,10 @@ struct filesystem_traits { return WINSTL_CONST_MAX_PATH; } +#if 0 +#elif defined(STLSOFT_COMPILER_IS_MSVC) &&\ + _MSC_VER < 1200 -#if defined(STLSOFT_COMPILER_IS_MSVC) && \ - _MSC_VER < 1200 static size_type get_full_path_name( diff --git a/include/winstl/system/system_traits.hpp b/include/winstl/system/system_traits.hpp index 74b0bc17..0f1aaeb2 100644 --- a/include/winstl/system/system_traits.hpp +++ b/include/winstl/system/system_traits.hpp @@ -82,8 +82,9 @@ # include #endif /* !STLSOFT_INCL_STLSOFT_INTERNAL_H_SAFESTR */ -#if defined(WINSTL_OS_IS_WIN64) || \ - defined(_Wp64) +#if 0 +#elif defined(WINSTL_OS_IS_WIN64) || \ + defined(_Wp64) # define _WINSTL_SYSTEM_TRAITS_USE_TRUNCATION_TESTING #endif /* _WIN64 || _M_IA64 */ diff --git a/include/winstl/winstl.h b/include/winstl/winstl.h index 361f6292..592659ec 100644 --- a/include/winstl/winstl.h +++ b/include/winstl/winstl.h @@ -5,7 +5,7 @@ * platform discriminations, and definitions of types. * * Created: 15th January 2002 - * Updated: 30th September 2026 + * Updated: 8th October 2026 * * Home: http://stlsoft.org/ * @@ -50,8 +50,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define WINSTL_VER_WINSTL_H_WINSTL_MAJOR 3 # define WINSTL_VER_WINSTL_H_WINSTL_MINOR 18 -# define WINSTL_VER_WINSTL_H_WINSTL_REVISION 14 -# define WINSTL_VER_WINSTL_H_WINSTL_EDIT 244 +# define WINSTL_VER_WINSTL_H_WINSTL_REVISION 15 +# define WINSTL_VER_WINSTL_H_WINSTL_EDIT 245 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ /** \file winstl/winstl.h @@ -184,12 +184,13 @@ # define _WINSTL_VER_1_13_0_B01 0x010d0081 /*!< Version 1.13.0 beta 1 (with STLSoft 1.11.1 rc 3) */ # define _WINSTL_VER_1_13_0_B02 0x010d0082 /*!< Version 1.13.0 beta 2 (with STLSoft 1.11.1 rc 4) */ # define _WINSTL_VER_1_13_0_B03 0x010d0083 /*!< Version 1.13.0 beta 3 (with STLSoft 1.11.1 rc 7) */ +# define _WINSTL_VER_1_13_0_B04 0x010d0084 /*!< Version 1.13.0 beta 4 (with STLSoft 1.11.1 rc 8) */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ #define _WINSTL_VER_MAJOR 1 #define _WINSTL_VER_MINOR 13 #define _WINSTL_VER_PATCH 0 -#define _WINSTL_VER_ALPHABETA 0x83 +#define _WINSTL_VER_ALPHABETA 0x84 #define _WINSTL_VER \ (0\ @@ -290,8 +291,8 @@ * STLSoft version compatibility check(s) */ -#if _STLSOFT_VER < 0x010b0151 -# error This version of the WinSTL libraries requires STLSoft version 1.11.1 alpha 17, or later +#if _STLSOFT_VER < 0x010B01C8 +# error This version of the WinSTL libraries requires STLSoft version 1.11.1 rc 8, or later #endif /* _STLSOFT_VER */ diff --git a/test/unit/versions/entry.cpp b/test/unit/versions/entry.cpp index 7c14db25..8b1cddeb 100644 --- a/test/unit/versions/entry.cpp +++ b/test/unit/versions/entry.cpp @@ -160,7 +160,7 @@ static void TEST__PLATFORMSTL_VER() static void TEST__UNIXSTL_VER() { - TEST_INT_EQ(_UNIXSTL_VER_1_8_6_B06, _UNIXSTL_VER); + TEST_INT_EQ(_UNIXSTL_VER_1_8_6_B07, _UNIXSTL_VER); } #elif defined(PLATFORMSTL_OS_IS_WINDOWS) @@ -171,7 +171,7 @@ static void TEST__COMSTL_VER() static void TEST__WINSTL_VER() { - TEST_INT_EQ(_WINSTL_VER_1_13_0_B03, _WINSTL_VER); + TEST_INT_EQ(_WINSTL_VER_1_13_0_B04, _WINSTL_VER); } #endif #ifdef STLSOFT_HAS_MFC From 4de00a928cb1df34bd04b2349d774f6633ce5676 Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Fri, 9 Oct 2026 07:19:39 +1100 Subject: [PATCH 15/31] feat(process): add current-process-id C accessors (#33) * tidying * feat(process): add current-process-id C accessors Add `unixstl_C_get_current_process_id()` and `winstl_C_get_current_process_id()` plus `platformstl_C_get_current_process_id()` around `getpid()` / `_getpid()`; Wire unit tests and generated `CMakeLists.txt` entries for the new `process` subtrees across UNIXSTL, PlatformSTL, and WinSTL; Refresh the 1.11.1-rc8 changelog, news, and version markers for STLSoft, UNIXSTL, PlatformSTL, and WinSTL; * tidy --- CHANGES.md | 1 + include/platformstl/platformstl.h | 11 +- include/platformstl/process/functions.h | 155 ++++++++++++++++ include/unixstl/process/functions.h | 173 ++++++++++++++++++ include/unixstl/unixstl.h | 2 +- include/winstl/process/functions.h | 45 ++++- test/unit/platformstl/CMakeLists.txt | 1 + test/unit/platformstl/process/CMakeLists.txt | 3 + .../process/functions/CMakeLists.txt | 3 + .../platformstl/process/functions/entry.c | 106 +++++++++++ test/unit/unixstl/CMakeLists.txt | 1 + test/unit/unixstl/process/CMakeLists.txt | 3 + .../unixstl/process/functions/CMakeLists.txt | 3 + test/unit/unixstl/process/functions/entry.c | 127 +++++++++++++ test/unit/versions/entry.cpp | 2 +- test/unit/winstl/CMakeLists.txt | 1 + test/unit/winstl/process/CMakeLists.txt | 3 + .../winstl/process/functions/CMakeLists.txt | 3 + test/unit/winstl/process/functions/entry.c | 116 ++++++++++++ 19 files changed, 746 insertions(+), 13 deletions(-) create mode 100644 include/platformstl/process/functions.h create mode 100644 include/unixstl/process/functions.h create mode 100644 test/unit/platformstl/process/CMakeLists.txt create mode 100644 test/unit/platformstl/process/functions/CMakeLists.txt create mode 100644 test/unit/platformstl/process/functions/entry.c create mode 100644 test/unit/unixstl/process/CMakeLists.txt create mode 100644 test/unit/unixstl/process/functions/CMakeLists.txt create mode 100644 test/unit/unixstl/process/functions/entry.c create mode 100644 test/unit/winstl/process/CMakeLists.txt create mode 100644 test/unit/winstl/process/functions/CMakeLists.txt create mode 100644 test/unit/winstl/process/functions/entry.c diff --git a/CHANGES.md b/CHANGES.md index 9df2b2ac..e4de2469 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,7 @@ ## 1.11.1-rc8 - 10th October 2026 +* Added `unixstl_C_get_current_process_id()` (**unixstl/process/functions.h**, new), `winstl_C_get_current_process_id()` (**winstl/process/functions.h**), and `platformstl_C_get_current_process_id()` (**platformstl/process/functions.h**, new), in terms of `getpid()` / `_getpid()`; * Fixed `stlsoft_C_environment_variable_exists_m()` when `getenv_s()` reports an existing empty variable; added component tests for `stlsoft::environment_variable_exists()`; * Scripts — **build_cmake.sh**, **clean_cmake.sh**, **ctest_cmake.sh**, **prepare_cmake.sh**, **remove_cmake_artefacts.sh**, **run_all_examples.sh**, and **run_all_scratch_tests.sh** rewritten to the common Synesis helper-script layout: builds go through `cmake --build` (with `--config` selected from `SIS_CMAKE_CONFIG` for multi-config generators) rather than `make` / `mingw32-make`; coloured output (`-A` / `--always-use-colours`, `SIS_CMAKE_ALWAYS_USE_COLOURS`, `NO_COLOR`); quoted paths and arguments; `.sis/project_name.txt` used in all status messages; * **prepare_cmake.sh** — added `--build-shared-libs` and `-s` / `--stlsoft-root-dir`; honours `SIS_CMAKE_GENERATOR` and `SIS_CMAKE_MINGW`; every `-D` option is passed on all generator paths; diff --git a/include/platformstl/platformstl.h b/include/platformstl/platformstl.h index 3227cca8..d2862a2d 100644 --- a/include/platformstl/platformstl.h +++ b/include/platformstl/platformstl.h @@ -5,7 +5,7 @@ * platform discriminations, and definitions of types. * * Created: 20th March 2005 - * Updated: 17th September 2026 + * Updated: 10th October 2026 * * Home: http://stlsoft.org/ * @@ -49,8 +49,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define PLATFORMSTL_VER_PLATFORMSTL_H_PLATFORMSTL_MAJOR 1 # define PLATFORMSTL_VER_PLATFORMSTL_H_PLATFORMSTL_MINOR 15 -# define PLATFORMSTL_VER_PLATFORMSTL_H_PLATFORMSTL_REVISION 8 -# define PLATFORMSTL_VER_PLATFORMSTL_H_PLATFORMSTL_EDIT 63 +# define PLATFORMSTL_VER_PLATFORMSTL_H_PLATFORMSTL_REVISION 9 +# define PLATFORMSTL_VER_PLATFORMSTL_H_PLATFORMSTL_EDIT 64 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ /** \file platformstl/platformstl.h @@ -145,13 +145,14 @@ # define _PLATFORMSTL_VER_1_9_2 0x010902ff /*!< Version 1.9.2 (with STLSoft 1.10.5) */ # define _PLATFORMSTL_VER_1_9_3 0x010903ff /*!< Version 1.9.3 (with STLSoft 1.11.1 alpha 8) */ # define _PLATFORMSTL_VER_1_10_0_A01 0x010a0041 /*!< Version 1.10.0 alpha 1 (with STLSoft 1.11.1 alpha 15) */ -# define _PLATFORMSTL_VER_1_10_0_B01 0x010a0081 /*!< Version 1.10.0 alpha 2 (with STLSoft 1.11.1 rc 3) */ +# define _PLATFORMSTL_VER_1_10_0_B01 0x010A0081 /*!< Version 1.10.0 beta 1 (with STLSoft 1.11.1 rc 3) */ +# define _PLATFORMSTL_VER_1_10_0_B02 0x010A0082 /*!< Version 1.10.0 beta 2 (with STLSoft 1.11.1 rc 8) */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ #define _PLATFORMSTL_VER_MAJOR 1 #define _PLATFORMSTL_VER_MINOR 10 #define _PLATFORMSTL_VER_PATCH 0 -#define _PLATFORMSTL_VER_ALPHABETA 0x81 +#define _PLATFORMSTL_VER_ALPHABETA 0x82 #define _PLATFORMSTL_VER \ (0\ diff --git a/include/platformstl/process/functions.h b/include/platformstl/process/functions.h new file mode 100644 index 00000000..d7af5bd0 --- /dev/null +++ b/include/platformstl/process/functions.h @@ -0,0 +1,155 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: platformstl/process/functions.h + * + * Purpose: Process functions. + * + * Created: 8th October 2026 + * Updated: 8th October 2026 + * + * Home: http://stlsoft.org/ + * + * Copyright (c) 2026, Matthew Wilson and Synesis Information Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name(s) of Matthew Wilson and Synesis Information Systems + * nor the names of any contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ////////////////////////////////////////////////////////////////////// */ + + +/** \file platformstl/process/functions.h + * + * \brief [C, C++] Process functions + * (\ref group__library__System "System" Library). + */ + +#ifndef PLATFORMSTL_INCL_PLATFORMSTL_PROCESS_H_FUNCTIONS +#define PLATFORMSTL_INCL_PLATFORMSTL_PROCESS_H_FUNCTIONS + +#ifndef PLATFORMSTL_DOCUMENTATION_SKIP_SECTION +# define PLATFORMSTL_VER_PLATFORMSTL_PROCESS_H_FUNCTIONS_MAJOR 1 +# define PLATFORMSTL_VER_PLATFORMSTL_PROCESS_H_FUNCTIONS_MINOR 0 +# define PLATFORMSTL_VER_PLATFORMSTL_PROCESS_H_FUNCTIONS_REVISION 1 +# define PLATFORMSTL_VER_PLATFORMSTL_PROCESS_H_FUNCTIONS_EDIT 1 +#endif /* !PLATFORMSTL_DOCUMENTATION_SKIP_SECTION */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#ifndef PLATFORMSTL_INCL_PLATFORMSTL_H_PLATFORMSTL +# include +#endif /* !PLATFORMSTL_INCL_PLATFORMSTL_H_PLATFORMSTL */ +#ifdef STLSOFT_TRACE_INCLUDE +# pragma message(__FILE__) +#endif /* STLSOFT_TRACE_INCLUDE */ + +#if 0 +#elif defined(PLATFORMSTL_OS_IS_UNIX) + +# include +#elif defined(PLATFORMSTL_OS_IS_WINDOWS) + +# include +#else + +# error Operating system not discriminated +#endif + +#include +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * namespace + */ + +#if !defined(PLATFORMSTL_NO_NAMESPACE) && \ + !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) +# if defined(STLSOFT_NO_NAMESPACE) +/* There is no stlsoft namespace, so must define ::platformstl */ +namespace platformstl +{ +# else +/* Define stlsoft::platformstl_project */ +namespace stlsoft +{ +namespace platformstl_project +{ +# endif /* STLSOFT_NO_NAMESPACE */ +#endif /* !PLATFORMSTL_NO_NAMESPACE */ + + +/* ///////////////////////////////////////////////////////////////////////// + * functions (C) + */ + +STLSOFT_INLINE +int +platformstl_C_get_current_process_id(void) +{ +#if 0 +#elif defined(PLATFORMSTL_OS_IS_UNIX) + + return UNIXSTL_NS_QUAL(unixstl_C_get_current_process_id)(); +#elif defined(PLATFORMSTL_OS_IS_WINDOWS) + + return WINSTL_NS_QUAL(winstl_C_get_current_process_id)(); +#else + +# error Platform not discriminated +#endif +} + + +/* ///////////////////////////////////////////////////////////////////////// + * namespace + */ + +#ifndef PLATFORMSTL_NO_NAMESPACE +# if defined(STLSOFT_NO_NAMESPACE) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) +} /* namespace platformstl */ +# else +} /* namespace platformstl_project */ +} /* namespace stlsoft */ +# endif /* STLSOFT_NO_NAMESPACE */ +#endif /* !PLATFORMSTL_NO_NAMESPACE */ + + +/* ///////////////////////////////////////////////////////////////////////// + * inclusion control + */ + +#ifdef STLSOFT_CF_PRAGMA_ONCE_SUPPORT +# pragma once +#endif /* STLSOFT_CF_PRAGMA_ONCE_SUPPORT */ + +#endif /* !PLATFORMSTL_INCL_PLATFORMSTL_PROCESS_H_FUNCTIONS */ + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/include/unixstl/process/functions.h b/include/unixstl/process/functions.h new file mode 100644 index 00000000..ddf65e78 --- /dev/null +++ b/include/unixstl/process/functions.h @@ -0,0 +1,173 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: unixstl/process/functions.h + * + * Purpose: Process functions. + * + * Created: 8th October 2026 + * Updated: 8th October 2026 + * + * Home: http://stlsoft.org/ + * + * Copyright (c) 2026, Matthew Wilson and Synesis Information Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name(s) of Matthew Wilson and Synesis Information Systems + * nor the names of any contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ////////////////////////////////////////////////////////////////////// */ + + +/** \file unixstl/process/functions.h + * + * \brief [C, C++] Process functions + * (\ref group__library__System "System" Library). + */ + +#ifndef UNIXSTL_INCL_UNIXSTL_PROCESS_H_FUNCTIONS +#define UNIXSTL_INCL_UNIXSTL_PROCESS_H_FUNCTIONS + +#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION +# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_MAJOR 1 +# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_MINOR 0 +# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_REVISION 1 +# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_EDIT 1 +#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#ifndef UNIXSTL_INCL_UNIXSTL_H_UNIXSTL +# include +#endif /* !UNIXSTL_INCL_UNIXSTL_H_UNIXSTL */ +#ifdef STLSOFT_TRACE_INCLUDE +# pragma message(__FILE__) +#endif /* STLSOFT_TRACE_INCLUDE */ + +#if 0 +#elif defined(_WIN32) &&\ + ( 0 ||\ + defined(STLSOFT_COMPILER_IS_MSVC) ||\ + defined(STLSOFT_COMPILER_IS_INTEL) ||\ + 0) + +# ifndef STLSOFT_INCL_H_PROCESS +# define STLSOFT_INCL_H_PROCESS +# include +# endif /* !STLSOFT_INCL_H_PROCESS */ +#else + +# ifndef STLSOFT_INCL_SYS_H_TYPES +# define STLSOFT_INCL_SYS_H_TYPES +# include +# endif /* !STLSOFT_INCL_SYS_H_TYPES */ +# ifndef STLSOFT_INCL_H_UNISTD +# define STLSOFT_INCL_H_UNISTD +# include +# endif /* !STLSOFT_INCL_H_UNISTD */ +#endif + + +/* ///////////////////////////////////////////////////////////////////////// + * namespace + */ + +#if !defined(UNIXSTL_NO_NAMESPACE) && \ + !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) +# if defined(STLSOFT_NO_NAMESPACE) +/* There is no stlsoft namespace, so must define ::unixstl */ +namespace unixstl +{ +# else +/* Define stlsoft::unixstl_project */ +namespace stlsoft +{ +namespace unixstl_project +{ +# endif /* STLSOFT_NO_NAMESPACE */ +#endif /* !UNIXSTL_NO_NAMESPACE */ + + +/* ///////////////////////////////////////////////////////////////////////// + * functions + */ + +/** \brief Obtains the id of the calling process. + * + * \ingroup group__library__System + * + * \return The process id, as obtained from \c _getpid() on Windows / UNIXem + * builds or \c getpid() otherwise. + */ +STLSOFT_INLINE +int +unixstl_C_get_current_process_id(void) +{ +#if 0 +#elif defined(_WIN32) && \ + ( 0 ||\ + defined(STLSOFT_COMPILER_IS_MSVC) ||\ + defined(STLSOFT_COMPILER_IS_INTEL) ||\ + 0) + + return STLSOFT_NS_GLOBAL(_getpid)(); +#else + + STLSOFT_STATIC_ASSERT(sizeof(pid_t) <= sizeof(int)); + + return STLSOFT_STATIC_CAST(int, STLSOFT_NS_GLOBAL(getpid)()); +#endif +} + + +/* ///////////////////////////////////////////////////////////////////////// + * namespace + */ + +#ifndef UNIXSTL_NO_NAMESPACE +# if defined(STLSOFT_NO_NAMESPACE) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) +} /* namespace unixstl */ +# else +} /* namespace unixstl_project */ +} /* namespace stlsoft */ +# endif /* STLSOFT_NO_NAMESPACE */ +#endif /* !UNIXSTL_NO_NAMESPACE */ + + +/* ///////////////////////////////////////////////////////////////////////// + * inclusion control + */ + +#ifdef STLSOFT_CF_PRAGMA_ONCE_SUPPORT +# pragma once +#endif /* STLSOFT_CF_PRAGMA_ONCE_SUPPORT */ + +#endif /* !UNIXSTL_INCL_UNIXSTL_PROCESS_H_FUNCTIONS */ + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/include/unixstl/unixstl.h b/include/unixstl/unixstl.h index 76874ced..1f74ad78 100644 --- a/include/unixstl/unixstl.h +++ b/include/unixstl/unixstl.h @@ -5,7 +5,7 @@ * platform discriminations, and definitions of types. * * Created: 15th January 2002 - * Updated: 8th October 2026 + * Updated: 10th October 2026 * * Home: http://stlsoft.org/ * diff --git a/include/winstl/process/functions.h b/include/winstl/process/functions.h index ed7f362b..b5915821 100644 --- a/include/winstl/process/functions.h +++ b/include/winstl/process/functions.h @@ -4,11 +4,11 @@ * Purpose: Process functions. * * Created: 12th March 2006 - * Updated: 24th December 2024 + * Updated: 8th October 2026 * * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2024, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2006-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -52,9 +52,9 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define WINSTL_VER_WINSTL_PROCESS_H_FUNCTIONS_MAJOR 1 -# define WINSTL_VER_WINSTL_PROCESS_H_FUNCTIONS_MINOR 1 -# define WINSTL_VER_WINSTL_PROCESS_H_FUNCTIONS_REVISION 7 -# define WINSTL_VER_WINSTL_PROCESS_H_FUNCTIONS_EDIT 35 +# define WINSTL_VER_WINSTL_PROCESS_H_FUNCTIONS_MINOR 2 +# define WINSTL_VER_WINSTL_PROCESS_H_FUNCTIONS_REVISION 1 +# define WINSTL_VER_WINSTL_PROCESS_H_FUNCTIONS_EDIT 37 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -69,6 +69,11 @@ # pragma message(__FILE__) #endif /* STLSOFT_TRACE_INCLUDE */ +#ifndef STLSOFT_INCL_H_PROCESS +# define STLSOFT_INCL_H_PROCESS +# include +#endif /* !STLSOFT_INCL_H_PROCESS */ + #ifndef STLSOFT_INCL_STLSOFT_QUALITY_H_CONTRACT # include #endif /* !STLSOFT_INCL_STLSOFT_QUALITY_H_CONTRACT */ @@ -144,6 +149,8 @@ winstl_C_CreateProcess9_a( , LPPROCESS_INFORMATION pi ) { + /* apply Null Object (Variable) pattern */ + STARTUPINFO si_; PROCESS_INFORMATION pi_; BOOL b; @@ -158,7 +165,18 @@ winstl_C_CreateProcess9_a( pi = &pi_; } - b = STLSOFT_NS_GLOBAL(CreateProcessA)(NULL, stlsoft_const_cast(ws_char_a_t*, cmdLine), processAttributes, threadAttributes, inheritsHandles, creationFlags, stlsoft_const_cast(ws_char_a_t*, environment), currentDirectory, si, pi); + b = STLSOFT_NS_GLOBAL(CreateProcessA)( + NULL + , stlsoft_const_cast(ws_char_a_t*, cmdLine) + , processAttributes + , threadAttributes + , inheritsHandles + , creationFlags + , stlsoft_const_cast(ws_char_a_t*, environment) + , currentDirectory + , si + , pi + ); if (b) { @@ -228,6 +246,21 @@ winstl_C_CreateProcess0A( return winstl_C_CreateProcessEA(cmdLine, NULL); } +/** + * \brief Obtains the id of the calling process. + * + * \ingroup group__library__System + * + * \return The process id, as obtained from \c _getpid(), which equals + * \c GetCurrentProcessId() cast to \c int. + */ +STLSOFT_INLINE +int +winstl_C_get_current_process_id(void) +{ + return STLSOFT_NS_GLOBAL(_getpid)(); +} + /* ///////////////////////////////////////////////////////////////////////// * obsolete functions diff --git a/test/unit/platformstl/CMakeLists.txt b/test/unit/platformstl/CMakeLists.txt index 19138ddd..985b6996 100644 --- a/test/unit/platformstl/CMakeLists.txt +++ b/test/unit/platformstl/CMakeLists.txt @@ -1,2 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(process) add_subdirectory(system) diff --git a/test/unit/platformstl/process/CMakeLists.txt b/test/unit/platformstl/process/CMakeLists.txt new file mode 100644 index 00000000..992517e9 --- /dev/null +++ b/test/unit/platformstl/process/CMakeLists.txt @@ -0,0 +1,3 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(functions) + diff --git a/test/unit/platformstl/process/functions/CMakeLists.txt b/test/unit/platformstl/process/functions/CMakeLists.txt new file mode 100644 index 00000000..bd138b53 --- /dev/null +++ b/test/unit/platformstl/process/functions/CMakeLists.txt @@ -0,0 +1,3 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.unit.platformstl.process.functions entry.c) + diff --git a/test/unit/platformstl/process/functions/entry.c b/test/unit/platformstl/process/functions/entry.c new file mode 100644 index 00000000..0133a8ab --- /dev/null +++ b/test/unit/platformstl/process/functions/entry.c @@ -0,0 +1,106 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: functions/entry.c + * + * Purpose: Unit-tests for `platformstl_C_get_current_process_id()`. + * + * Created: 8th October 2026 + * Updated: 8th October 2026 + * + * Copyright (c) 2026, Matthew Wilson and Synesis Information Systems + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +/* ///////////////////////////////////// + * test component header file include(s) + */ + +#include + +/* ///////////////////////////////////// + * general includes + */ + +/* xTests header files */ +#include +#include + +/* STLSoft header files */ +#include + +/* Standard C header files */ +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +static void TEST_EQUALS_SELECTED_PLATFORM_FUNCTION(void); +static void TEST_IS_POSITIVE(void); + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char *argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.platformstl.process.functions", verbosity)) + { + XTESTS_RUN_CASE(TEST_EQUALS_SELECTED_PLATFORM_FUNCTION); + XTESTS_RUN_CASE(TEST_IS_POSITIVE); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +static void TEST_EQUALS_SELECTED_PLATFORM_FUNCTION(void) +{ + int expected; + int actual; + +#if defined(PLATFORMSTL_OS_IS_UNIX) + + expected = unixstl_C_get_current_process_id(); +#elif defined(PLATFORMSTL_OS_IS_WINDOWS) + + expected = winstl_C_get_current_process_id(); +#else + +# error Platform not discriminated +#endif + + actual = platformstl_C_get_current_process_id(); + + TEST_INT_EQ(expected, actual); +} + +static void TEST_IS_POSITIVE(void) +{ + int const result = platformstl_C_get_current_process_id(); + + TEST_INT_GT(0, result); +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/unixstl/CMakeLists.txt b/test/unit/unixstl/CMakeLists.txt index 5eb6b8bd..ba184416 100644 --- a/test/unit/unixstl/CMakeLists.txt +++ b/test/unit/unixstl/CMakeLists.txt @@ -1,3 +1,4 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten add_subdirectory(filesystem) +add_subdirectory(process) add_subdirectory(shims) diff --git a/test/unit/unixstl/process/CMakeLists.txt b/test/unit/unixstl/process/CMakeLists.txt new file mode 100644 index 00000000..992517e9 --- /dev/null +++ b/test/unit/unixstl/process/CMakeLists.txt @@ -0,0 +1,3 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(functions) + diff --git a/test/unit/unixstl/process/functions/CMakeLists.txt b/test/unit/unixstl/process/functions/CMakeLists.txt new file mode 100644 index 00000000..6884e0ba --- /dev/null +++ b/test/unit/unixstl/process/functions/CMakeLists.txt @@ -0,0 +1,3 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.unit.unixstl.process.functions entry.c) + diff --git a/test/unit/unixstl/process/functions/entry.c b/test/unit/unixstl/process/functions/entry.c new file mode 100644 index 00000000..e3b090c5 --- /dev/null +++ b/test/unit/unixstl/process/functions/entry.c @@ -0,0 +1,127 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: functions/entry.c + * + * Purpose: Unit-tests for `unixstl_C_get_current_process_id()`. + * + * Created: 8th October 2026 + * Updated: 8th October 2026 + * + * Copyright (c) 2026, Matthew Wilson and Synesis Information Systems + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +/* ///////////////////////////////////// + * test component header file include(s) + */ + +#include + +/* ///////////////////////////////////// + * general includes + */ + +/* xTests header files */ +#include +#include + +/* STLSoft header files */ +#include + +/* Standard C header files */ +#include + +#if defined(_WIN32) && \ + ( defined(STLSOFT_COMPILER_IS_MSVC) || \ + defined(STLSOFT_COMPILER_IS_INTEL)) +# include +#else +# include +# include +#endif + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +static void TEST_EQUALS_NATIVE_PROCESS_ID(void); +static void TEST_IS_POSITIVE(void); +static void TEST_IS_STABLE(void); + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char *argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.unixstl.process.functions", verbosity)) + { + XTESTS_RUN_CASE(TEST_EQUALS_NATIVE_PROCESS_ID); + XTESTS_RUN_CASE(TEST_IS_POSITIVE); + XTESTS_RUN_CASE(TEST_IS_STABLE); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +static void TEST_EQUALS_NATIVE_PROCESS_ID(void) +{ + int expected; + int actual; + +#if 0 +#elif defined(_WIN32) && \ + ( 0 ||\ + defined(STLSOFT_COMPILER_IS_MSVC) ||\ + defined(STLSOFT_COMPILER_IS_INTEL) ||\ + 0) + + expected = _getpid(); +#else + + expected = STLSOFT_STATIC_CAST(int, getpid()); +#endif + + actual = unixstl_C_get_current_process_id(); + + TEST_INT_EQ(expected, actual); +} + +static void TEST_IS_POSITIVE(void) +{ + int const result = unixstl_C_get_current_process_id(); + + TEST_INT_GT(0, result); +} + +static void TEST_IS_STABLE(void) +{ + int const first = unixstl_C_get_current_process_id(); + int const second = unixstl_C_get_current_process_id(); + + TEST_INT_EQ(first, second); +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/versions/entry.cpp b/test/unit/versions/entry.cpp index 8b1cddeb..4f1128d1 100644 --- a/test/unit/versions/entry.cpp +++ b/test/unit/versions/entry.cpp @@ -152,7 +152,7 @@ static void TEST__ATLSTL_VER() static void TEST__PLATFORMSTL_VER() { - TEST_INT_EQ(_PLATFORMSTL_VER_1_10_0_B01, _PLATFORMSTL_VER); + TEST_INT_EQ(_PLATFORMSTL_VER_1_10_0_B02, _PLATFORMSTL_VER); } #if 0 diff --git a/test/unit/winstl/CMakeLists.txt b/test/unit/winstl/CMakeLists.txt index 668b342f..64aff324 100644 --- a/test/unit/winstl/CMakeLists.txt +++ b/test/unit/winstl/CMakeLists.txt @@ -4,5 +4,6 @@ add_subdirectory(conversion) add_subdirectory(diagnostics) add_subdirectory(filesystem) add_subdirectory(memory) +add_subdirectory(process) add_subdirectory(system) add_subdirectory(util) diff --git a/test/unit/winstl/process/CMakeLists.txt b/test/unit/winstl/process/CMakeLists.txt new file mode 100644 index 00000000..992517e9 --- /dev/null +++ b/test/unit/winstl/process/CMakeLists.txt @@ -0,0 +1,3 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(functions) + diff --git a/test/unit/winstl/process/functions/CMakeLists.txt b/test/unit/winstl/process/functions/CMakeLists.txt new file mode 100644 index 00000000..f7bbb016 --- /dev/null +++ b/test/unit/winstl/process/functions/CMakeLists.txt @@ -0,0 +1,3 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.unit.winstl.process.functions entry.c) + diff --git a/test/unit/winstl/process/functions/entry.c b/test/unit/winstl/process/functions/entry.c new file mode 100644 index 00000000..4f4cdb37 --- /dev/null +++ b/test/unit/winstl/process/functions/entry.c @@ -0,0 +1,116 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: functions/entry.c + * + * Purpose: Unit-tests for `winstl_C_get_current_process_id()`. + * + * Created: 8th October 2026 + * Updated: 8th October 2026 + * + * Copyright (c) 2026, Matthew Wilson and Synesis Information Systems + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +/* ///////////////////////////////////// + * test component header file include(s) + */ + +#include + +/* ///////////////////////////////////// + * general includes + */ + +/* xTests header files */ +#include +#include + +/* STLSoft header files */ +#include + +/* Standard C header files */ +#include + +#include +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +static void TEST_EQUALS_GETPID(void); +static void TEST_EQUALS_CURRENT_PROCESS_ID(void); +static void TEST_IS_POSITIVE(void); +static void TEST_IS_STABLE(void); + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char *argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.winstl.process.functions", verbosity)) + { + XTESTS_RUN_CASE(TEST_EQUALS_GETPID); + XTESTS_RUN_CASE(TEST_EQUALS_CURRENT_PROCESS_ID); + XTESTS_RUN_CASE(TEST_IS_POSITIVE); + XTESTS_RUN_CASE(TEST_IS_STABLE); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +static void TEST_EQUALS_GETPID(void) +{ + int const expected = _getpid(); + int const actual = winstl_C_get_current_process_id(); + + TEST_INT_EQ(expected, actual); +} + +static void TEST_EQUALS_CURRENT_PROCESS_ID(void) +{ + int const expected = STLSOFT_STATIC_CAST(int, GetCurrentProcessId()); + int const actual = winstl_C_get_current_process_id(); + + TEST_INT_EQ(expected, actual); +} + +static void TEST_IS_POSITIVE(void) +{ + int const result = winstl_C_get_current_process_id(); + + TEST_INT_GT(0, result); +} + +static void TEST_IS_STABLE(void) +{ + int const first = winstl_C_get_current_process_id(); + int const second = winstl_C_get_current_process_id(); + + TEST_INT_EQ(first, second); +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + From 72398f755fa165d2a456ea2fb153e749528b5b22 Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Fri, 9 Oct 2026 07:22:16 +1100 Subject: [PATCH 16/31] feat(stlsoft): add environment variable strtoll conversion (#50) * 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; * feat(stlsoft): add environment variable strtoll conversion Implement stlsoft_C_environment_variable_strtoll_m() with getenv() and strtoll() on UNIX, and getenv_s() with STLSOFT_C_AUTO_BUFFER on Windows; Add the C++ environment_variable_strtoll() wrapper and comprehensive component coverage for radix parsing, limits, invalid values, long values, whitespace, replacement, erasure, and wrapper behaviour; * fix * tidy --- CHANGES.md | 6 +- NEWS.md | 2 +- .../stlsoft/system/environment/functions.h | 183 +++++++- test/component/stlsoft/system/CMakeLists.txt | 1 + .../CMakeLists.txt | 2 + .../environment_variable_strtoll/entry.cpp | 404 ++++++++++++++++++ 6 files changed, 589 insertions(+), 9 deletions(-) create mode 100644 test/component/stlsoft/system/environment_variable_strtoll/CMakeLists.txt create mode 100644 test/component/stlsoft/system/environment_variable_strtoll/entry.cpp diff --git a/CHANGES.md b/CHANGES.md index e4de2469..85afe9d9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,8 +3,13 @@ ## 1.11.1-rc8 - 10th October 2026 +* Added `stlsoft_C_environment_variable_strtoll_m()` and `stlsoft::environment_variable_strtoll()`, with UNIX `getenv()` / `strtoll()` and Windows `getenv_s()` / `STLSOFT_C_AUTO_BUFFER` support; added component tests; * Added `unixstl_C_get_current_process_id()` (**unixstl/process/functions.h**, new), `winstl_C_get_current_process_id()` (**winstl/process/functions.h**), and `platformstl_C_get_current_process_id()` (**platformstl/process/functions.h**, new), in terms of `getpid()` / `_getpid()`; + * Fixed `stlsoft_C_environment_variable_exists_m()` when `getenv_s()` reports an existing empty variable; added component tests for `stlsoft::environment_variable_exists()`; + +* **test.unit.versions** — aligned with **1.11.1-rc8** (**_STLSOFT_VER_1_11_1_RC8**); + * Scripts — **build_cmake.sh**, **clean_cmake.sh**, **ctest_cmake.sh**, **prepare_cmake.sh**, **remove_cmake_artefacts.sh**, **run_all_examples.sh**, and **run_all_scratch_tests.sh** rewritten to the common Synesis helper-script layout: builds go through `cmake --build` (with `--config` selected from `SIS_CMAKE_CONFIG` for multi-config generators) rather than `make` / `mingw32-make`; coloured output (`-A` / `--always-use-colours`, `SIS_CMAKE_ALWAYS_USE_COLOURS`, `NO_COLOR`); quoted paths and arguments; `.sis/project_name.txt` used in all status messages; * **prepare_cmake.sh** — added `--build-shared-libs` and `-s` / `--stlsoft-root-dir`; honours `SIS_CMAKE_GENERATOR` and `SIS_CMAKE_MINGW`; every `-D` option is passed on all generator paths; * **run_all_unit_tests.sh** / **.cmd** — now run unit-test programs only (`--unit-only` accepted for compatibility; `--component-only` removed); @@ -16,7 +21,6 @@ * **.gitattributes** — Linguist language-bar policy: public C headers and sources are classified as C, C++ headers and sources as C++, and `*.cmake` as CMake; helper scripts, IDE project files, **CMakeLists.txt**, and **makefile** are excluded from the advertised language mix (`-linguist-detectable`); * CI — **ci-cell.yml** runs component tests via **run_all_component_tests.sh**; * **INSTALL.md** — documented **run_all_component_tests.sh**, **run_all_automated_tests.sh**, and **generate_doxygen.sh**; corrected the unit-test discovery patterns; -* **test.unit.versions** — aligned with **1.11.1-rc8** (**_STLSOFT_VER_1_11_1_RC8**); ## 1.11.1-rc7 - 30th September 2026 diff --git a/NEWS.md b/NEWS.md index 6dbaeec5..a38a0ced 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,7 @@ | Date | News Item | Details | | ------------------- | ----------------------------------- | ------- | -| 10th October 2026 | Release of [STLSoft 1.11.1-rc8](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc8) | `getenv_s()` empty-variable fix; component tests; `cmake --build` helper scripts; **run_all_component_tests.sh** / **run_all_automated_tests.sh**; **generate_doxygen.sh**; Linguist classification | +| 10th October 2026 | Release of [STLSoft 1.11.1-rc8](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc8) | `environment_variable_strtoll()`; `getenv_s()` empty-variable fix; component tests; `cmake --build` helper scripts; **run_all_component_tests.sh** / **run_all_automated_tests.sh**; **generate_doxygen.sh**; Linguist classification | | 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | counted NULs; `wchar_t` `string_begins_with`; bit intrinsics; `write_binary()`; `file_lines` mmap (~10–20× vs `fgetc`); compare and allocator units; MinGW static runtime; short test directories; nested **test/performance** | | 21st September 2026 | Release of [STLSoft 1.11.1-rc6](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc6) | ACE/ATL/MFC CI; Clang/macOS `stricmp` aliases | | 4th August 2026 | Release of [STLSoft 1.11.1-rc5](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc5) | `basic_simple_string<>#resize()`; **CHANGES.md**; docs | diff --git a/include/stlsoft/system/environment/functions.h b/include/stlsoft/system/environment/functions.h index e3492e7c..ce665a09 100644 --- a/include/stlsoft/system/environment/functions.h +++ b/include/stlsoft/system/environment/functions.h @@ -52,9 +52,9 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_MAJOR 1 -# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_MINOR 0 -# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_REVISION 4 -# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_EDIT 16 +# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_MINOR 1 +# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_REVISION 0 +# define STLSOFT_VER_STLSOFT_SYSTEM_ENVIRONMENT_H_FUNCTIONS_EDIT 18 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -69,6 +69,10 @@ # pragma message(__FILE__) #endif /* STLSOFT_TRACE_INCLUDE */ +#ifndef STLSOFT_INCL_STLSOFT_MEMORY_H_AUTO_BUFFER +# include +#endif /* !STLSOFT_INCL_STLSOFT_MEMORY_H_AUTO_BUFFER */ + #ifndef STLSOFT_INCL_STLSOFT_INTERNAL_H_SAFESTR # include #endif /* !STLSOFT_INCL_STLSOFT_INTERNAL_H_SAFESTR */ @@ -81,6 +85,10 @@ # define STLSOFT_INCL_H_STDLIB # include #endif /* !STLSOFT_INCL_H_STDLIB */ +#ifndef STLSOFT_INCL_H_STRING +# define STLSOFT_INCL_H_STRING +# include +#endif /* !STLSOFT_INCL_H_STRING */ /* ///////////////////////////////////////////////////////////////////////// @@ -98,11 +106,13 @@ namespace stlsoft */ /** Indicates whether the named environment variable exists. + * + * \param name The name of the environment variable. May not be NULL; * * \retval 0 The environment variable does not exist; * \retval !0 The environment variable does exist; * - * \pre (NULL != name) + * \pre NULL != name; */ STLSOFT_INLINE ss_truthy_t @@ -162,6 +172,155 @@ stlsoft_C_environment_variable_exists_a( #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ +/** Attempts to read a signed 64-bit integer value from the named + * environment variable. + * + * \param name The name of the environment variable. May not be NULL; + * \param result Pointer to a variable to receive the numeric result. On + * failure it is set to 0; + * + * \retval 0 The variable does not exist, the value is not a complete + * signed 64-bit integer, or the value is out of range. errno is EINVAL or + * ERANGE; + * \retval !0 The value was parsed and written through \c result; + * + * \pre NULL != name; + * \pre NULL != result; + * + * \note Interpreted with base 0, as with strtoll(): optional leading + * whitespace, an optional sign, then decimal, octal (leading 0), or + * hexadecimal (leading 0x). Unlike strtoll(), which accepts a numeric + * prefix followed by other characters, the entire value must be consumed. + * The complete environment-variable value is read before parsing. + */ +STLSOFT_INLINE +ss_truthy_t +stlsoft_C_environment_variable_strtoll_m( + char const* name +, ss_sint64_t* result +) STLSOFT_NOEXCEPT +{ + STLSOFT_ASSERT(NULL != name); + STLSOFT_ASSERT(NULL != result); + +#if 0 +#elif defined(STLSOFT_USING_SAFE_STR_FUNCTIONS) && \ + defined(STLSOFT_COMPILER_IS_MSVC) + + { + STLSOFT_C_AUTO_BUFFER_DECLARE(char, 21, buff); + size_t n; + errno_t e; + + STLSOFT_C_AUTO_BUFFER_INITIALISE_FROM_INTERNAL(buff); + + e = STLSOFT_NS_GLOBAL(getenv_s)( + &n + , buff.ptr + , buff.size + , name + ); + + if (ERANGE == e) + { + e = STLSOFT_C_AUTO_BUFFER_RESIZE(buff, n); + + if (0 == e) + { + e = STLSOFT_NS_GLOBAL(getenv_s)( + &n + , buff.ptr + , buff.size + , name + ); + } + } + + if (0 != e) + { + STLSOFT_C_AUTO_BUFFER_FREE(buff); + + errno = e; + + *result = 0; + + return 0; + } + else + { + char* endptr; + + errno = 0; + + *result = STLSOFT_NS_GLOBAL(strtoll)(buff.ptr, &endptr, 0); + + if (buff.ptr == endptr || + '\0' != *endptr || + ERANGE == errno) + { + if (0 == errno) + { + errno = EINVAL; + } + + *result = 0; + + STLSOFT_C_AUTO_BUFFER_FREE(buff); + + return 0; + } + else + { + STLSOFT_C_AUTO_BUFFER_FREE(buff); + + return 1; + } + } + } +#else + + { + char const* const value = STLSOFT_NS_GLOBAL(getenv)(name); + + if (NULL == value) + { + errno = EINVAL; + + *result = 0; + + return 0; + } + else + { + char* endptr; + + errno = 0; + + *result = STLSOFT_NS_GLOBAL(strtoll)(value, &endptr, 0); + + if (value == endptr || + '\0' != *endptr || + ERANGE == errno) + { + if (0 == errno) + { + errno = EINVAL; + } + + *result = 0; + + return 0; + } + else + { + return 1; + } + } + } +#endif +} + + /* ///////////////////////////////////////////////////////////////////////// * language */ @@ -176,12 +335,22 @@ stlsoft_C_environment_variable_exists_a( /** \see stlsoft_C_environment_variable_exists_m */ inline -ss_truthy_t +bool environment_variable_exists( char const* name -) +) STLSOFT_NOEXCEPT { - return stlsoft_C_environment_variable_exists_m(name); + return 0 != stlsoft_C_environment_variable_exists_m(name); +} + +inline +bool +environment_variable_strtoll( + char const* name +, ss_sint64_t* result +) STLSOFT_NOEXCEPT +{ + return 0 != stlsoft_C_environment_variable_strtoll_m(name, result); } diff --git a/test/component/stlsoft/system/CMakeLists.txt b/test/component/stlsoft/system/CMakeLists.txt index 071c04bc..452572ef 100644 --- a/test/component/stlsoft/system/CMakeLists.txt +++ b/test/component/stlsoft/system/CMakeLists.txt @@ -1,3 +1,4 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten add_subdirectory(environment_block) add_subdirectory(environment_variable_exists) +add_subdirectory(environment_variable_strtoll) diff --git a/test/component/stlsoft/system/environment_variable_strtoll/CMakeLists.txt b/test/component/stlsoft/system/environment_variable_strtoll/CMakeLists.txt new file mode 100644 index 00000000..ecaa534c --- /dev/null +++ b/test/component/stlsoft/system/environment_variable_strtoll/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.component.stlsoft.system.environment_variable_strtoll entry.cpp) diff --git a/test/component/stlsoft/system/environment_variable_strtoll/entry.cpp b/test/component/stlsoft/system/environment_variable_strtoll/entry.cpp new file mode 100644 index 00000000..1cc60278 --- /dev/null +++ b/test/component/stlsoft/system/environment_variable_strtoll/entry.cpp @@ -0,0 +1,404 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test/component/stlsoft/system/environment_variable_strtoll/entry.cpp + * + * Purpose: Component tests for + * `stlsoft_C_environment_variable_strtoll_m()`. + * + * Created: 28th September 2026 + * Updated: 8th October 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +/* ///////////////////////////////////// + * test component header file include(s) + */ + +#include + + +/* ///////////////////////////////////// + * general includes + */ + +/* xTests header files */ +#include +#include + +/* STLSoft header files */ +#include +#include + +/* Standard C header files */ +#include +#include +#include +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace { + + static void TEST_environment_variable_strtoll_WHEN_ABSENT(); + static void TEST_environment_variable_strtoll_WHEN_DECIMAL(); + static void TEST_environment_variable_strtoll_WHEN_BASE_PREFIXES(); + static void TEST_environment_variable_strtoll_WHEN_LEADING_WHITESPACE(); + static void TEST_environment_variable_strtoll_WHEN_NOT_COMPLETE(); + static void TEST_environment_variable_strtoll_WHEN_OUT_OF_RANGE(); + static void TEST_environment_variable_strtoll_WHEN_LONG_VALUE(); + static void TEST_environment_variable_strtoll_WHEN_ERASED(); + static void TEST_environment_variable_strtoll_WHEN_VALUE_REPLACED(); + static void TEST_environment_variable_strtoll_EXACT_NAME(); + static void TEST_environment_variable_strtoll_CASE_SENSITIVITY(); + static void TEST_environment_variable_strtoll_CPP_WRAPPER(); +#ifndef _WIN32 + static void TEST_environment_variable_strtoll_WHEN_EMPTY(); +#endif /* !_WIN32 */ +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.component.stlsoft.system.environment_variable_strtoll", verbosity)) + { + XTESTS_RUN_CASE(TEST_environment_variable_strtoll_WHEN_ABSENT); + XTESTS_RUN_CASE(TEST_environment_variable_strtoll_WHEN_DECIMAL); + XTESTS_RUN_CASE(TEST_environment_variable_strtoll_WHEN_BASE_PREFIXES); + XTESTS_RUN_CASE(TEST_environment_variable_strtoll_WHEN_LEADING_WHITESPACE); + XTESTS_RUN_CASE(TEST_environment_variable_strtoll_WHEN_NOT_COMPLETE); + XTESTS_RUN_CASE(TEST_environment_variable_strtoll_WHEN_OUT_OF_RANGE); + XTESTS_RUN_CASE(TEST_environment_variable_strtoll_WHEN_LONG_VALUE); + XTESTS_RUN_CASE(TEST_environment_variable_strtoll_WHEN_ERASED); + XTESTS_RUN_CASE(TEST_environment_variable_strtoll_WHEN_VALUE_REPLACED); + XTESTS_RUN_CASE(TEST_environment_variable_strtoll_EXACT_NAME); + XTESTS_RUN_CASE(TEST_environment_variable_strtoll_CASE_SENSITIVITY); + XTESTS_RUN_CASE(TEST_environment_variable_strtoll_CPP_WRAPPER); +#ifndef _WIN32 + XTESTS_RUN_CASE(TEST_environment_variable_strtoll_WHEN_EMPTY); +#endif /* !_WIN32 */ + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * constants + */ + +namespace { + + using platformstl::environment_variable_scope; + + stlsoft::ss_sint64_t const SENTINEL_ = 0x5a5a5a5a; + + char const VAR_NAME[] = "STLSOFT_CT_ENV_VAR_STRTOLL"; + char const VAR_NAME_EXTRA[] = "STLSOFT_CT_ENV_VAR_STRTOLL_EXTRA"; + char const VAR_NAME_LOWER[] = "stlsoft_ct_env_var_strtoll_case"; + char const VAR_NAME_PREFIX[] = "STLSOFT_CT_ENV_VAR_STRTOL"; + char const VAR_NAME_UPPER[] = "STLSOFT_CT_ENV_VAR_STRTOLL_CASE"; +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * macros + */ + +#define TEST_READ_PARSED_(name, expected) \ + \ + do \ + { \ + stlsoft::ss_sint64_t result_ = SENTINEL_; \ + \ + errno = EPERM; \ + \ + stlsoft::ss_truthy_t const parsed_ = \ + stlsoft::stlsoft_C_environment_variable_strtoll_m( \ + (name) \ + , &result_ \ + ); \ + \ + TEST_BOOLEAN_TRUE(parsed_); \ + TEST_INT_EQ((expected), result_); \ + TEST_INT_EQ(0, errno); \ + } while (0) + +#define TEST_READ_REJECTED_(name, expected_errno) \ + \ + do \ + { \ + stlsoft::ss_sint64_t result_ = SENTINEL_; \ + \ + errno = EPERM; \ + \ + stlsoft::ss_truthy_t const parsed_ = \ + stlsoft::stlsoft_C_environment_variable_strtoll_m( \ + (name) \ + , &result_ \ + ); \ + \ + TEST_BOOLEAN_FALSE(parsed_); \ + TEST_INT_EQ(0, result_); \ + TEST_INT_EQ((expected_errno), errno); \ + } while (0) + +#define TEST_PARSED_(value, expected) \ + \ + do \ + { \ + environment_variable_scope const scope_(VAR_NAME, (value)); \ + \ + TEST_READ_PARSED_(VAR_NAME, (expected)); \ + } while (0) + +#define TEST_REJECTED_(value, expected_errno) \ + \ + do \ + { \ + environment_variable_scope const scope_(VAR_NAME, (value)); \ + \ + TEST_READ_REJECTED_(VAR_NAME, (expected_errno)); \ + } while (0) + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace { + +static void fill_n_( + char* buff +, int n +, char ch +) +{ + int i; + + for (i = 0; i != n; ++i) + { + buff[i] = ch; + } + + buff[n] = '\0'; +} + +/* Absence is a failed lookup: the function returns 0, sets errno to EINVAL, + * and writes 0 through result. + */ +static void TEST_environment_variable_strtoll_WHEN_ABSENT() +{ + environment_variable_scope const absent(VAR_NAME, ss_nullptr_k); + + TEST_READ_REJECTED_(VAR_NAME, EINVAL); +} + +static void TEST_environment_variable_strtoll_WHEN_DECIMAL() +{ + TEST_PARSED_("0", 0); + TEST_PARSED_("00", 0); + TEST_PARSED_("+0", 0); + TEST_PARSED_("-0", 0); + TEST_PARSED_("1", 1); + TEST_PARSED_("42", 42); + TEST_PARSED_("+42", 42); + TEST_PARSED_("-42", -42); + TEST_PARSED_(" -42", -42); + TEST_PARSED_(" -42", -42); + TEST_PARSED_(" -42", -42); + TEST_PARSED_(" -42", -42); + TEST_PARSED_(" -42", -42); + TEST_PARSED_(" -42", -42); + TEST_PARSED_(" -42", -42); + TEST_PARSED_(" -42", -42); + TEST_PARSED_(" -42", -42); + TEST_PARSED_(" -42", -42); + TEST_PARSED_("-123456", -123456); + + TEST_PARSED_("9223372036854775807", STLSOFT_GEN_SINT64_SUFFIX(9223372036854775807)); + TEST_PARSED_("-9223372036854775807", -STLSOFT_GEN_SINT64_SUFFIX(9223372036854775807)); + TEST_PARSED_("-9223372036854775808", -STLSOFT_GEN_SINT64_SUFFIX(9223372036854775807) - 1); +} + +/* Base 0 follows strtoll(): a leading 0 selects octal and a leading 0x + * selects hexadecimal. The whole value must be one subject sequence. + */ +static void TEST_environment_variable_strtoll_WHEN_BASE_PREFIXES() +{ + TEST_PARSED_("010", 8); + TEST_PARSED_("+010", 8); + TEST_PARSED_("-010", -8); + TEST_PARSED_("0x10", 16); + TEST_PARSED_("0X10", 16); + TEST_PARSED_("0xff", 255); + TEST_PARSED_("0xFf", 255); + TEST_PARSED_("+0x10", 16); + TEST_PARSED_("-0x10", -16); + TEST_PARSED_("0x0", 0); +} + +/* Leading whitespace belongs to a strtoll() subject sequence. Trailing + * characters, including whitespace, do not. + */ +static void TEST_environment_variable_strtoll_WHEN_LEADING_WHITESPACE() +{ + TEST_PARSED_(" 42", 42); + TEST_PARSED_("\t42", 42); + TEST_PARSED_(" \t -42", -42); + TEST_PARSED_(" +0x10", 16); + + TEST_REJECTED_("42 ", EINVAL); + TEST_REJECTED_(" 42 ", EINVAL); + TEST_REJECTED_("42\n", EINVAL); +} + +static void TEST_environment_variable_strtoll_WHEN_NOT_COMPLETE() +{ + TEST_REJECTED_("abc", EINVAL); + TEST_REJECTED_(" ", EINVAL); + TEST_REJECTED_("+", EINVAL); + TEST_REJECTED_("-", EINVAL); + TEST_REJECTED_("++1", EINVAL); + TEST_REJECTED_("--1", EINVAL); + TEST_REJECTED_("0x", EINVAL); + TEST_REJECTED_("0xG", EINVAL); + TEST_REJECTED_("123abc", EINVAL); + TEST_REJECTED_("08", EINVAL); + TEST_REJECTED_("09", EINVAL); + TEST_REJECTED_("1.5", EINVAL); + TEST_REJECTED_("1e2", EINVAL); +} + +static void TEST_environment_variable_strtoll_WHEN_OUT_OF_RANGE() +{ + /* Out-of-range values are rejected with ERANGE and result is set to 0, + * rather than the saturated limits that strtoll() returns. + */ + TEST_REJECTED_("9223372036854775808", ERANGE); + TEST_REJECTED_("-9223372036854775809", ERANGE); +} + +/* The complete environment-variable value is read before parsing, so a + * valid value remains valid when preceded by substantial whitespace. + */ +static void TEST_environment_variable_strtoll_WHEN_LONG_VALUE() +{ + char text[1024]; + + fill_n_(text, 1000, ' '); + text[1000] = '-'; + text[1001] = '4'; + text[1002] = '2'; + text[1003] = '\0'; + TEST_PARSED_(text, -42); + + text[1003] = 'x'; + text[1004] = '\0'; + TEST_REJECTED_(text, EINVAL); +} + +static void TEST_environment_variable_strtoll_WHEN_ERASED() +{ + environment_variable_scope const present(VAR_NAME, "5"); + + TEST_READ_PARSED_(VAR_NAME, 5); + + environment_variable_scope const erased(VAR_NAME, ss_nullptr_k); + + TEST_READ_REJECTED_(VAR_NAME, EINVAL); +} + +static void TEST_environment_variable_strtoll_WHEN_VALUE_REPLACED() +{ + environment_variable_scope const first(VAR_NAME, "11"); + + TEST_READ_PARSED_(VAR_NAME, 11); + + environment_variable_scope const second(VAR_NAME, "22"); + + TEST_READ_PARSED_(VAR_NAME, 22); +} + +static void TEST_environment_variable_strtoll_EXACT_NAME() +{ + environment_variable_scope const extra_absent(VAR_NAME_EXTRA, ss_nullptr_k); + environment_variable_scope const prefix_absent(VAR_NAME_PREFIX, ss_nullptr_k); + environment_variable_scope const present(VAR_NAME, "42"); + + TEST_READ_PARSED_(VAR_NAME, 42); + TEST_READ_REJECTED_(VAR_NAME_EXTRA, EINVAL); + TEST_READ_REJECTED_(VAR_NAME_PREFIX, EINVAL); + + environment_variable_scope const erased(VAR_NAME, ss_nullptr_k); + environment_variable_scope const extra(VAR_NAME_EXTRA, "7"); + + TEST_READ_REJECTED_(VAR_NAME, EINVAL); + TEST_READ_PARSED_(VAR_NAME_EXTRA, 7); +} + +/* UNIX names are case-sensitive; the Windows CRT folds case. + */ +static void TEST_environment_variable_strtoll_CASE_SENSITIVITY() +{ + environment_variable_scope const lower(VAR_NAME_LOWER, ss_nullptr_k); + environment_variable_scope const upper(VAR_NAME_UPPER, "7"); + + TEST_READ_PARSED_(VAR_NAME_UPPER, 7); +#ifdef _WIN32 + + TEST_READ_PARSED_(VAR_NAME_LOWER, 7); +#else + + TEST_READ_REJECTED_(VAR_NAME_LOWER, EINVAL); +#endif +} + +static void TEST_environment_variable_strtoll_CPP_WRAPPER() +{ + environment_variable_scope const value(VAR_NAME, "9223372036854775807"); + stlsoft::ss_sint64_t result = SENTINEL_; + + TEST_BOOLEAN_TRUE(stlsoft::environment_variable_strtoll(VAR_NAME, &result)); + TEST_INT_EQ(STLSOFT_GEN_SINT64_SUFFIX(9223372036854775807), result); +} + +#ifndef _WIN32 + +/* An empty value is defined on UNIX, and it is not a number. The Windows + * CRT treats an empty assignment as erasure, so this case is UNIX-only. + */ +static void TEST_environment_variable_strtoll_WHEN_EMPTY() +{ + TEST_REJECTED_("", EINVAL); +} +#endif /* !_WIN32 */ +} // anonymous namespace + +#undef TEST_PARSED_ +#undef TEST_READ_PARSED_ +#undef TEST_READ_REJECTED_ +#undef TEST_REJECTED_ + + +/* ///////////////////////////// end of file //////////////////////////// */ + From bf0f9429220d5aadd2fb63718870a1df2848b271 Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Fri, 9 Oct 2026 08:35:08 +1100 Subject: [PATCH 17/31] feat(unixstl): add `filesystem_traits::rewind_dir()` (#55) * chore(layout): trivial whitespace changes to InetSTL component(s) * versions * fix(unixstl): define class_type in terms of char_type in traits Correct the definition of class_type in both filesystem_traits and system_traits for narrow and wide characters under unixstl. Previously, the wide-character specialisations erroneously defined class_type as the narrow specialisation (using us_char_a_t instead of us_char_w_t) due to copy-paste errors. Defining class_type as traits fixes this bug and ensures both specialisations are correct and consistent. - In filesystem_traits, define class_type as filesystem_traits; - In system_traits, define class_type as system_traits; - Bump file revision and edit numbers for both header files; - Update header file metadata banners to current date and copyright year; * versions * versions * refactor(unixstl,winstl): canonicalise preprocessor guards in *_traits Reshape conditional-compilation guards in the UNIXSTL and WinSTL **system_traits** and **filesystem_traits** headers so that future edits to the condition sets are single-line diffs, per **revisibility**. No behavioural change is intended: - Prefix affected guards with `#if 0` so that each real condition is an `#elif` and every condition term sits on its own line; - Add `0 ||` / `|| 0` and `1 &&` / `&& 1` sentinel terms to multi-term conditions so that the first and last terms can be edited in isolation; - Label `#endif` and `#else` comments with the `_WIN32` condition they close, replacing `OS` and unlabelled forms; - Remove the blank line that preceded `#ifdef _WIN32` blocks in the UNIXSTL **system_traits** and **filesystem_traits** path and compare functions; - Change the `buffer` parameter of **get_full_path_name_impl2()** from `char_type*` to `char_type buffer[]` in UNIXSTL **filesystem_traits**, matching sibling overloads (signature-equivalent); - Adjust blank lines around the WinSTL MSVC < 1200 **get_full_path_name()** shim and in UNIXSTL **call_getcwd_()**; * whitespace * whitespace * feat(unixstl): add filesystem_traits::rewind_dir() Add rewind_dir() to complement open_dir(), read_dir(), and close_dir(), so that a directory search can be restarted from its first entry without closing and reopening the handle. The implementation wraps rewinddir() and asserts a non-NULL handle; the wide-character specialisation gains the matching declaration. - Add component tests under filesystem_traits/opendir, built with xTests temp_directory and temp_file, covering rewind before any read, after a partial read, after exhaustion, on an empty directory, and repeatedly; - Add a scratch test and an example, the latter enumerating a directory in two passes (count, then collect) with a rewind between; - Record the 1.11.1-rc8 changes in CHANGES.md, NEWS.md, and EXAMPLES.md; - Bump the file versions of filesystem_traits.hpp and unixstl.h; * chore(stlsoft): merge dev into traits-conformance.rewinddir Merge dev into traits-conformance.rewinddir, bringing the helper-script, documentation, and CI work of 1.11.1-rc8 alongside rewind_dir(). Incoming from dev: - Rewrite build_cmake.sh, clean_cmake.sh, ctest_cmake.sh, prepare_cmake.sh, remove_cmake_artefacts.sh, run_all_examples.sh, and run_all_scratch_tests.sh to the common Synesis layout: cmake --build instead of make, coloured output, quoted paths; - Add prepare_cmake.sh options --build-shared-libs and -s/--stlsoft-root-dir; - Add run_all_component_tests, run_all_performance_tests, and run_all_automated_tests (.sh and .cmd); run_all_unit_tests now runs unit tests only; - Add generate_doxygen.sh, Doxyfile, and doc/mainpage.md for HTML API documentation; - Classify headers and sources as C/C++ and *.cmake as CMake in .gitattributes, excluding helper scripts and IDE files from the Linguist language bar; - Run component tests via run_all_component_tests.sh in ci-cell.yml; - Update INSTALL.md for 1.11.1-rc8 and the new scripts; - Bump Updated banners in stlsoft.h, CMakeLists.txt, and the versions test; Conflicts in CHANGES.md and NEWS.md were resolved by keeping both sides under a single 1.11.1-rc8 entry. --- CHANGES.md | 20 +- EXAMPLES.md | 1 + NEWS.md | 2 +- .../unixstl/filesystem/CMakeLists.txt | 1 + .../filesystem/rewind_dir/CMakeLists.txt | 2 + .../unixstl/filesystem/rewind_dir/main.cpp | 127 +++++ .../unixstl/filesystem/filesystem_traits.hpp | 29 +- include/unixstl/system/system_traits.hpp | 10 +- include/unixstl/unixstl.h | 4 +- .../winstl/filesystem/filesystem_traits.hpp | 12 +- include/winstl/system/system_traits.hpp | 6 +- .../unixstl/filesystem/CMakeLists.txt | 1 + .../filesystem_traits/CMakeLists.txt | 2 + .../filesystem_traits/opendir/CMakeLists.txt | 2 + .../filesystem_traits/opendir/entry.cpp | 449 ++++++++++++++++++ test/scratch/unixstl/CMakeLists.txt | 1 + .../scratch/unixstl/filesystem/CMakeLists.txt | 2 + .../filesystem/rewind_dir/CMakeLists.txt | 2 + .../unixstl/filesystem/rewind_dir/main.cpp | 112 +++++ 19 files changed, 756 insertions(+), 29 deletions(-) create mode 100644 examples/by_project/unixstl/filesystem/rewind_dir/CMakeLists.txt create mode 100644 examples/by_project/unixstl/filesystem/rewind_dir/main.cpp create mode 100644 test/component/unixstl/filesystem/filesystem_traits/CMakeLists.txt create mode 100644 test/component/unixstl/filesystem/filesystem_traits/opendir/CMakeLists.txt create mode 100644 test/component/unixstl/filesystem/filesystem_traits/opendir/entry.cpp create mode 100644 test/scratch/unixstl/filesystem/CMakeLists.txt create mode 100644 test/scratch/unixstl/filesystem/rewind_dir/CMakeLists.txt create mode 100644 test/scratch/unixstl/filesystem/rewind_dir/main.cpp diff --git a/CHANGES.md b/CHANGES.md index 85afe9d9..3169ace4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,19 +5,31 @@ * Added `stlsoft_C_environment_variable_strtoll_m()` and `stlsoft::environment_variable_strtoll()`, with UNIX `getenv()` / `strtoll()` and Windows `getenv_s()` / `STLSOFT_C_AUTO_BUFFER` support; added component tests; * Added `unixstl_C_get_current_process_id()` (**unixstl/process/functions.h**, new), `winstl_C_get_current_process_id()` (**winstl/process/functions.h**), and `platformstl_C_get_current_process_id()` (**platformstl/process/functions.h**, new), in terms of `getpid()` / `_getpid()`; +* **unixstl::filesystem_traits** — added `rewind_dir()` (wrapping `rewinddir()`) to complement `open_dir()`, `read_dir()`, and `close_dir()`, so that a directory search may be restarted from its first entry without closing and reopening the handle; * Fixed `stlsoft_C_environment_variable_exists_m()` when `getenv_s()` reports an existing empty variable; added component tests for `stlsoft::environment_variable_exists()`; +* **unixstl::filesystem_traits** — `class_type` is now defined in terms of `char_type` (the wide-character specialisation previously named the narrow specialisation); +* **unixstl** / **winstl** `system_traits` and `filesystem_traits` — canonicalised the conditional-compilation guards (no behavioural change); +* Component tests for `unixstl::filesystem_traits` (**test/component/unixstl/filesystem/filesystem_traits/opendir**) cover `open_dir()`, `read_dir()`, `rewind_dir()` (before any read, after a partial read, after exhaustion, on an empty directory, and repeatedly), and `close_dir()`; +* Scratch test **test/scratch/unixstl/filesystem/rewind_dir** — exercises `rewind_dir()` over a directory given on the command-line; +* Example **examples/by_project/unixstl/filesystem/rewind_dir** — enumerates a directory in two passes (count, then collect), using `rewind_dir()` between them; * **test.unit.versions** — aligned with **1.11.1-rc8** (**_STLSOFT_VER_1_11_1_RC8**); +* **unixstl** — **1.8.6 beta 7** (**_UNIXSTL_VER_1_8_6_B07**), with **STLSoft 1.11.1-rc8**; +* **winstl** — **1.13.0 beta 4** (**_WINSTL_VER_1_13_0_B04**), with **STLSoft 1.11.1-rc8**; +* **inetstl** — **1.5.0 alpha 3** (**_INETSTL_VER_1_5_0_A03**), with **STLSoft 1.11.1-rc8**; + +* Added **run_all_component_tests.sh** / **.cmd**, **run_all_performance_tests.sh** / **.cmd** (with `--gap-groups`), and **run_all_automated_tests.sh** / **.cmd** (unit then component; `--unit-only` / `--component-only`); +* Added **generate_doxygen.sh**, **Doxyfile**, and **doc/mainpage.md** — HTML API documentation generated from the public headers into **_build/doxygen/html**; +* **remove_cmake_artefacts.sh** — no longer removes **docs** or **Doxyfile**; iterates arrays safely; +* **batch_compile_check**, **execute_performance_tests.sh** — quote the `$(dirname ...)` directory resolution; + + * Scripts — **build_cmake.sh**, **clean_cmake.sh**, **ctest_cmake.sh**, **prepare_cmake.sh**, **remove_cmake_artefacts.sh**, **run_all_examples.sh**, and **run_all_scratch_tests.sh** rewritten to the common Synesis helper-script layout: builds go through `cmake --build` (with `--config` selected from `SIS_CMAKE_CONFIG` for multi-config generators) rather than `make` / `mingw32-make`; coloured output (`-A` / `--always-use-colours`, `SIS_CMAKE_ALWAYS_USE_COLOURS`, `NO_COLOR`); quoted paths and arguments; `.sis/project_name.txt` used in all status messages; * **prepare_cmake.sh** — added `--build-shared-libs` and `-s` / `--stlsoft-root-dir`; honours `SIS_CMAKE_GENERATOR` and `SIS_CMAKE_MINGW`; every `-D` option is passed on all generator paths; * **run_all_unit_tests.sh** / **.cmd** — now run unit-test programs only (`--unit-only` accepted for compatibility; `--component-only` removed); -* Added **run_all_component_tests.sh** / **.cmd**, **run_all_performance_tests.sh** / **.cmd** (with `--gap-groups`), and **run_all_automated_tests.sh** / **.cmd** (unit then component; `--unit-only` / `--component-only`); * **run_all_examples.sh** — retains `--skip-interactive` (**.github/ci_skip_interactive_examples.txt**, which prevents headless CI hanging on GUI examples) and its discovery of every executable under the **examples** tree, and now exports `SIS_EXAMPLE_SMOKE=1`; **run_all_scratch_tests.sh** / **.cmd** — removed `--verbosity`; -* **remove_cmake_artefacts.sh** — no longer removes **docs** or **Doxyfile**; iterates arrays safely; -* Added **generate_doxygen.sh**, **Doxyfile**, and **doc/mainpage.md** — HTML API documentation generated from the public headers into **_build/doxygen/html**; -* **batch_compile_check**, **execute_performance_tests.sh** — quote the `$(dirname ...)` directory resolution; * **.gitattributes** — Linguist language-bar policy: public C headers and sources are classified as C, C++ headers and sources as C++, and `*.cmake` as CMake; helper scripts, IDE project files, **CMakeLists.txt**, and **makefile** are excluded from the advertised language mix (`-linguist-detectable`); * CI — **ci-cell.yml** runs component tests via **run_all_component_tests.sh**; * **INSTALL.md** — documented **run_all_component_tests.sh**, **run_all_automated_tests.sh**, and **generate_doxygen.sh**; corrected the unit-test discovery patterns; diff --git a/EXAMPLES.md b/EXAMPLES.md index e12dae08..e5104e6a 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -15,6 +15,7 @@ | **glob_sequence** | [by_project/unixstl/filesystem/glob_sequence](./examples/by_project/unixstl/filesystem/glob_sequence/main.cpp) | Unix | List selected filesystem entries with `unixstl::glob_sequence` | | **home_directory** | [by_project/unixstl/system/home_directory](./examples/by_project/unixstl/system/home_directory/main.cpp) | Unix | Illustrates use of `unixstl::home_directory` | | **readdir_sequence** | [by_project/unixstl/filesystem/readdir_sequence](./examples/by_project/unixstl/filesystem/readdir_sequence/main.cpp) | Unix | List filesystem entries with `unixstl::readdir_sequence` | +| **rewind_dir** | [by_project/unixstl/filesystem/rewind_dir](./examples/by_project/unixstl/filesystem/rewind_dir/main.cpp) | Unix | Enumerate a directory twice with `unixstl::filesystem_traits<>::rewind_dir()` | | | | | | | **C.output_debug_line** | [by_project/winstl/diagnostics/C.output_debug_line](./examples/by_project/winstl/diagnostics/C.output_debug_line/main.c) | Windows | Emit debug strings with the C API `winstl_C_diagnostics_output_debug_line_*` | | **codepages** | [by_project/winstl/i18n/codepages](./examples/by_project/winstl/i18n/codepages/main.cpp) | Windows | Enumerate system code pages with `winstl::codepage_sequence` | diff --git a/NEWS.md b/NEWS.md index a38a0ced..74839ad5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,7 @@ | Date | News Item | Details | | ------------------- | ----------------------------------- | ------- | -| 10th October 2026 | Release of [STLSoft 1.11.1-rc8](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc8) | `environment_variable_strtoll()`; `getenv_s()` empty-variable fix; component tests; `cmake --build` helper scripts; **run_all_component_tests.sh** / **run_all_automated_tests.sh**; **generate_doxygen.sh**; Linguist classification | +| 10th October 2026 | Release of [STLSoft 1.11.1-rc8](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc8) | environment_variable_strtoll()`; `unixstl::filesystem_traits<>::rewind_dir()`; `class_type` and `getenv_s()` empty-variable fixes; component tests; `cmake --build` helper scripts; **run_all_component_tests.sh** / **run_all_automated_tests.sh**; **generate_doxygen.sh**; Linguist classification | | 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | counted NULs; `wchar_t` `string_begins_with`; bit intrinsics; `write_binary()`; `file_lines` mmap (~10–20× vs `fgetc`); compare and allocator units; MinGW static runtime; short test directories; nested **test/performance** | | 21st September 2026 | Release of [STLSoft 1.11.1-rc6](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc6) | ACE/ATL/MFC CI; Clang/macOS `stricmp` aliases | | 4th August 2026 | Release of [STLSoft 1.11.1-rc5](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc5) | `basic_simple_string<>#resize()`; **CHANGES.md**; docs | diff --git a/examples/by_project/unixstl/filesystem/CMakeLists.txt b/examples/by_project/unixstl/filesystem/CMakeLists.txt index 7dd9ccf9..06433e78 100644 --- a/examples/by_project/unixstl/filesystem/CMakeLists.txt +++ b/examples/by_project/unixstl/filesystem/CMakeLists.txt @@ -1,3 +1,4 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten add_subdirectory(glob_sequence) add_subdirectory(readdir_sequence) +add_subdirectory(rewind_dir) diff --git a/examples/by_project/unixstl/filesystem/rewind_dir/CMakeLists.txt b/examples/by_project/unixstl/filesystem/rewind_dir/CMakeLists.txt new file mode 100644 index 00000000..69e650c3 --- /dev/null +++ b/examples/by_project/unixstl/filesystem/rewind_dir/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_example_program(example.unixstl.filesystem.rewind_dir main.cpp) diff --git a/examples/by_project/unixstl/filesystem/rewind_dir/main.cpp b/examples/by_project/unixstl/filesystem/rewind_dir/main.cpp new file mode 100644 index 00000000..23fec8ac --- /dev/null +++ b/examples/by_project/unixstl/filesystem/rewind_dir/main.cpp @@ -0,0 +1,127 @@ +/* ///////////////////////////////////////////////////////////////////////// + * Purpose: Illustrates the use of `unixstl::filesystem_traits<>` functions + * `open_dir()`, `read_dir()`, `rewind_dir()`, and `close_dir()` to + * enumerate a directory in two passes: the first to count the + * entries, and the second - after rewinding - to collect their + * names into a container sized in advance. + * + * ////////////////////////////////////////////////////////////////////// */ + + +#include + +#include + +#include +#include +#include + +#include +#include + + +typedef unixstl::filesystem_traits fs_traits_t; + + +int main(int argc, char* argv[]) +{ + char const* const program_name = platformstl::get_executable_name_from_path(argv[0]).ptr; + char const* root_dir = ss_nullptr_k; + + if (argc > 1 && 0 == strcmp("--help", argv[1])) + { + std::cout + << "USAGE: " + << program_name + << " []" + << std::endl; + + return EXIT_SUCCESS; + } + + switch (argc) + { + case 1: + + root_dir = "."; + break; + case 2: + + root_dir = argv[1]; + break; + + default: + + std::cerr + << program_name + << ": " + << "too many arguments; use --help for usage" + << std::endl; + + return EXIT_FAILURE; + } + + DIR* const h = fs_traits_t::open_dir(root_dir); + + if (NULL == h) + { + std::cerr + << program_name + << ": " + << "could not open directory '" + << root_dir + << "'" + << std::endl; + + return EXIT_FAILURE; + } + else + { + std::vector names; + size_t count = 0; + + // pass 1: count the entries + + while (NULL != fs_traits_t::read_dir(h)) + { + ++count; + } + + std::cout + << "'" + << root_dir + << "' contains " + << count + << " entries (including '.' and '..')" + << std::endl; + + // rewind, so that the next read_dir() returns the first entry again + + fs_traits_t::rewind_dir(h); + + // pass 2: collect the names, without any reallocation + + names.reserve(count); + + for (struct dirent const* de; NULL != (de = fs_traits_t::read_dir(h)); ) + { + names.push_back(de->d_name); + } + + fs_traits_t::close_dir(h); + + for (std::vector::const_iterator i = names.begin(); names.end() != i; ++i) + { + std::cout + << "\t" + << *i + << std::endl; + } + } + + return EXIT_SUCCESS; +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/include/unixstl/filesystem/filesystem_traits.hpp b/include/unixstl/filesystem/filesystem_traits.hpp index c276159b..c392cdd0 100644 --- a/include/unixstl/filesystem/filesystem_traits.hpp +++ b/include/unixstl/filesystem/filesystem_traits.hpp @@ -59,9 +59,9 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MAJOR 4 -# define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MINOR 16 -# define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_REVISION 2 -# define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_EDIT 189 +# define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MINOR 17 +# define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_REVISION 1 +# define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_EDIT 190 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -120,7 +120,7 @@ #endif /* !STLSOFT_INCL_H_FCNTL */ #ifdef _WIN32 # include -# if defined(STLSOFT_COMPILER_IS_INTEL) || \ +# if defined(STLSOFT_COMPILER_IS_INTEL) ||\ defined(STLSOFT_COMPILER_IS_MSVC) # include # endif /* os && compiler */ @@ -177,7 +177,7 @@ */ #ifndef UNIXSTL_NO_NAMESPACE -# if defined(STLSOFT_NO_NAMESPACE) || \ +# if defined(STLSOFT_NO_NAMESPACE) ||\ defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) /* There is no stlsoft namespace, so must define ::unixstl */ namespace unixstl @@ -731,6 +731,11 @@ struct filesystem_traits static DIR* open_dir(char_type const* dir); /// Read an entry from the file-system search static struct dirent const* read_dir(DIR* h); + /// Resets the file-system search to the first entry, such that the + /// next call to read_dir() returns the first entry + /// + /// \pre NULL != h + static void rewind_dir(DIR* h); /// Closes the handle of the file-system search static void close_dir(DIR* h); /// @} @@ -2183,6 +2188,12 @@ return 0; { return ::readdir(h); } + static void rewind_dir(DIR* h) + { + UNIXSTL_ASSERT(NULL != h); + + ::rewinddir(h); + } static void close_dir(DIR* h) { ::closedir(h); @@ -2628,7 +2639,7 @@ return 0; static file_handle_type open_file(char_type const* fileName, int oflag, int pmode) { #if 0 -#elif defined(_WIN32) && \ +#elif defined(_WIN32) &&\ ( 0 ||\ defined(STLSOFT_COMPILER_IS_INTEL) ||\ defined(STLSOFT_COMPILER_IS_MSVC) ||\ @@ -2646,7 +2657,7 @@ return 0; static bool_type close_file(file_handle_type h) { #if 0 -#elif defined(_WIN32) && \ +#elif defined(_WIN32) &&\ ( 0 ||\ defined(STLSOFT_COMPILER_IS_INTEL) ||\ defined(STLSOFT_COMPILER_IS_MSVC) ||\ @@ -3182,6 +3193,8 @@ struct filesystem_traits ; static struct dirent const* read_dir(DIR* h) ; + static void rewind_dir(DIR* h) + ; static void close_dir(DIR* h) ; @@ -3217,7 +3230,7 @@ struct filesystem_traits */ #ifndef UNIXSTL_NO_NAMESPACE -# if defined(STLSOFT_NO_NAMESPACE) || \ +# if defined(STLSOFT_NO_NAMESPACE) ||\ defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) } // namespace unixstl # else diff --git a/include/unixstl/system/system_traits.hpp b/include/unixstl/system/system_traits.hpp index fa1543a5..3be24177 100644 --- a/include/unixstl/system/system_traits.hpp +++ b/include/unixstl/system/system_traits.hpp @@ -87,7 +87,7 @@ #endif /* !STLSOFT_INCL_STLSOFT_API_external_h_string */ #if 0 -#elif defined(_WIN32) || \ +#elif defined(_WIN32) ||\ defined(_WIN64) # include #endif /* Windows */ @@ -100,10 +100,10 @@ # include #endif /* !STLSOFT_INCL_H_FCNTL */ #if 0 -#elif defined(_WIN32) || \ +#elif defined(_WIN32) ||\ defined(_WIN64) # include -# if defined(STLSOFT_COMPILER_IS_INTEL) || \ +# if defined(STLSOFT_COMPILER_IS_INTEL) ||\ defined(STLSOFT_COMPILER_IS_MSVC) # include # endif /* os && compiler */ @@ -151,7 +151,7 @@ */ #ifndef UNIXSTL_NO_NAMESPACE -# if defined(STLSOFT_NO_NAMESPACE) || \ +# if defined(STLSOFT_NO_NAMESPACE) ||\ defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) /* There is no stlsoft namespace, so must define ::unixstl */ namespace unixstl @@ -872,7 +872,7 @@ struct system_traits /* ////////////////////////////////////////////////////////////////////// */ #ifndef UNIXSTL_NO_NAMESPACE -# if defined(STLSOFT_NO_NAMESPACE) || \ +# if defined(STLSOFT_NO_NAMESPACE) ||\ defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) } // namespace unixstl # else diff --git a/include/unixstl/unixstl.h b/include/unixstl/unixstl.h index 1f74ad78..33335107 100644 --- a/include/unixstl/unixstl.h +++ b/include/unixstl/unixstl.h @@ -50,8 +50,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_MAJOR 3 # define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_MINOR 11 -# define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_REVISION 4 -# define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_EDIT 131 +# define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_REVISION 5 +# define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_EDIT 132 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ /** \file unixstl/unixstl.h diff --git a/include/winstl/filesystem/filesystem_traits.hpp b/include/winstl/filesystem/filesystem_traits.hpp index 431f0d4e..fe194b8a 100644 --- a/include/winstl/filesystem/filesystem_traits.hpp +++ b/include/winstl/filesystem/filesystem_traits.hpp @@ -149,7 +149,7 @@ */ #ifndef WINSTL_NO_NAMESPACE -# if defined(STLSOFT_NO_NAMESPACE) || \ +# if defined(STLSOFT_NO_NAMESPACE) ||\ defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) /* There is no stlsoft namespace, so must define ::winstl */ namespace winstl @@ -973,7 +973,7 @@ struct filesystem_traits typedef DWORD error_type; typedef DWORD file_attributes_type; private: -#if !defined(STLSOFT_COMPILER_IS_MSVC) || \ +#if !defined(STLSOFT_COMPILER_IS_MSVC) ||\ _MSC_VER >= 1200 typedef STLSOFT_NS_QUAL(auto_buffer) buffer_type_; #endif /* compiler */ @@ -2237,7 +2237,7 @@ struct filesystem_traits WINSTL_ASSERT(NULL != path); WINSTL_ASSERT(NULL != stat_data); -#if !defined(STLSOFT_COMPILER_IS_MSVC) || \ +#if !defined(STLSOFT_COMPILER_IS_MSVC) ||\ _MSC_VER >= 1200 size_type const len = class_type::str_len(path); @@ -2595,7 +2595,7 @@ struct filesystem_traits typedef DWORD error_type; typedef DWORD file_attributes_type; private: -#if !defined(STLSOFT_COMPILER_IS_MSVC) || \ +#if !defined(STLSOFT_COMPILER_IS_MSVC) ||\ _MSC_VER >= 1200 typedef STLSOFT_NS_QUAL(auto_buffer) buffer_type_; #endif /* compiler */ @@ -3597,7 +3597,7 @@ struct filesystem_traits WINSTL_ASSERT(NULL != path); WINSTL_ASSERT(NULL != stat_data); -#if !defined(STLSOFT_COMPILER_IS_MSVC) || \ +#if !defined(STLSOFT_COMPILER_IS_MSVC) ||\ _MSC_VER >= 1200 size_type const len = class_type::str_len(path); @@ -3934,7 +3934,7 @@ struct filesystem_traits */ #ifndef WINSTL_NO_NAMESPACE -# if defined(STLSOFT_NO_NAMESPACE) || \ +# if defined(STLSOFT_NO_NAMESPACE) ||\ defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) } // namespace winstl # else diff --git a/include/winstl/system/system_traits.hpp b/include/winstl/system/system_traits.hpp index 0f1aaeb2..bc65f0af 100644 --- a/include/winstl/system/system_traits.hpp +++ b/include/winstl/system/system_traits.hpp @@ -83,7 +83,7 @@ #endif /* !STLSOFT_INCL_STLSOFT_INTERNAL_H_SAFESTR */ #if 0 -#elif defined(WINSTL_OS_IS_WIN64) || \ +#elif defined(WINSTL_OS_IS_WIN64) ||\ defined(_Wp64) # define _WINSTL_SYSTEM_TRAITS_USE_TRUNCATION_TESTING @@ -151,7 +151,7 @@ */ #ifndef WINSTL_NO_NAMESPACE -# if defined(STLSOFT_NO_NAMESPACE) || \ +# if defined(STLSOFT_NO_NAMESPACE) ||\ defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) /* There is no stlsoft namespace, so must define ::winstl */ namespace winstl @@ -1855,7 +1855,7 @@ struct system_traits */ #ifndef WINSTL_NO_NAMESPACE -# if defined(STLSOFT_NO_NAMESPACE) || \ +# if defined(STLSOFT_NO_NAMESPACE) ||\ defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) } // namespace winstl # else diff --git a/test/component/unixstl/filesystem/CMakeLists.txt b/test/component/unixstl/filesystem/CMakeLists.txt index 7d8d9318..be579252 100644 --- a/test/component/unixstl/filesystem/CMakeLists.txt +++ b/test/component/unixstl/filesystem/CMakeLists.txt @@ -1,4 +1,5 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(filesystem_traits) add_subdirectory(glob_sequence) add_subdirectory(memory_mapped_file) add_subdirectory(readdir_sequence) diff --git a/test/component/unixstl/filesystem/filesystem_traits/CMakeLists.txt b/test/component/unixstl/filesystem/filesystem_traits/CMakeLists.txt new file mode 100644 index 00000000..8460ebf3 --- /dev/null +++ b/test/component/unixstl/filesystem/filesystem_traits/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(opendir) diff --git a/test/component/unixstl/filesystem/filesystem_traits/opendir/CMakeLists.txt b/test/component/unixstl/filesystem/filesystem_traits/opendir/CMakeLists.txt new file mode 100644 index 00000000..204e5114 --- /dev/null +++ b/test/component/unixstl/filesystem/filesystem_traits/opendir/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.component.unixstl.filesystem.filesystem_traits.opendir entry.cpp) diff --git a/test/component/unixstl/filesystem/filesystem_traits/opendir/entry.cpp b/test/component/unixstl/filesystem/filesystem_traits/opendir/entry.cpp new file mode 100644 index 00000000..991257a2 --- /dev/null +++ b/test/component/unixstl/filesystem/filesystem_traits/opendir/entry.cpp @@ -0,0 +1,449 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test/component/unixstl/filesystem/filesystem_traits/opendir/entry.cpp) + * + * Purpose: Component-tests for `unixstl::filesystem_traits`, in respect of + * the directory-enumeration functions `open_dir()`, `read_dir()`, + * `rewind_dir()`, and `close_dir()`. + * + * Created: 8th October 2026 + * Updated: 8th October 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +/* ///////////////////////////////////// + * test component header file include(s) + */ + +#include + +/* ///////////////////////////////////// + * general includes + */ + +#include + +/* xTests header files */ +#include +#include +#include +#include + +/* Standard C++ header files */ +#include +#include +#include + +/* Standard C header files */ +#include +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace { + + static void TEST_open_dir_NONEXISTENT_directory(); + static void TEST_read_dir_EMPTY_directory(); + static void TEST_read_dir_NON_EMPTY_directory(); + static void TEST_rewind_dir_AFTER_EXHAUSTION(); + static void TEST_rewind_dir_AFTER_PARTIAL_READ(); + static void TEST_rewind_dir_BEFORE_ANY_READ(); + static void TEST_rewind_dir_EMPTY_directory(); + static void TEST_rewind_dir_MULTIPLE_times(); +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char *argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.component.unixstl.filesystem.filesystem_traits.opendir", verbosity)) + { + XTESTS_RUN_CASE(TEST_open_dir_NONEXISTENT_directory); + XTESTS_RUN_CASE(TEST_read_dir_EMPTY_directory); + XTESTS_RUN_CASE(TEST_read_dir_NON_EMPTY_directory); + XTESTS_RUN_CASE(TEST_rewind_dir_AFTER_EXHAUSTION); + XTESTS_RUN_CASE(TEST_rewind_dir_AFTER_PARTIAL_READ); + XTESTS_RUN_CASE(TEST_rewind_dir_BEFORE_ANY_READ); + XTESTS_RUN_CASE(TEST_rewind_dir_EMPTY_directory); + XTESTS_RUN_CASE(TEST_rewind_dir_MULTIPLE_times); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * types + */ + +namespace { + + typedef unixstl::filesystem_traits fs_traits_t; + typedef platformstl::path path_t; + typedef std::vector names_t; + using ::xtests::cpp::util::temp_directory; + using ::xtests::cpp::util::temp_file; +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * helper functions + */ + +namespace { + + /* Three temporary files, created in a given (temporary) directory, + * and deleted on destruction. Must be declared after, so destroyed + * before, the `temp_directory` in which they are created. + */ + class three_files + { + public: + explicit + three_files( + char const* dir + ) + : m_f0(temp_file::DeleteOnClose | temp_file::CloseOnOpen, dir) + , m_f1(temp_file::DeleteOnClose | temp_file::CloseOnOpen, dir) + , m_f2(temp_file::DeleteOnClose | temp_file::CloseOnOpen, dir) + {} + + public: + /* The names (i.e. without directory) of the files, sorted */ + names_t + names() const + { + names_t result; + + result.push_back(leaf_name(m_f0.c_str())); + result.push_back(leaf_name(m_f1.c_str())); + result.push_back(leaf_name(m_f2.c_str())); + + std::sort(result.begin(), result.end()); + + return result; + } + + private: + static + std::string + leaf_name( + char const* path + ) + { + char const* const sep = ::strrchr(path, '/'); + + return (NULL == sep) ? path : (sep + 1); + } + + private: + temp_file m_f0; + temp_file m_f1; + temp_file m_f2; + }; + + /* Reads up to `max` entries from `h` into `names`; returns the number + * of entries read + */ + static + size_t + read_entries( + DIR* h + , names_t& names + , size_t max + ) + { + size_t n = 0; + + for (struct dirent const* de; n < max && NULL != (de = fs_traits_t::read_dir(h)); ++n) + { + names.push_back(de->d_name); + } + + return n; + } + + /* Reads all remaining entries from `h` into `names`; returns the number + * of entries read + */ + static + size_t + read_all_entries( + DIR* h + , names_t& names + ) + { + return read_entries(h, names, ~size_t(0)); + } + + /* Removes the entries "." and ".." and sorts, so that sequences can be + * compared irrespective of the (unspecified) order of enumeration + */ + static + names_t + normalise( + names_t names + ) + { + names_t result; + + for (names_t::const_iterator i = names.begin(); names.end() != i; ++i) + { + if ("." != *i && ".." != *i) + { + result.push_back(*i); + } + } + + std::sort(result.begin(), result.end()); + + return result; + } + +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace { + +static void TEST_open_dir_NONEXISTENT_directory() +{ + temp_directory td(temp_directory::EmptyOnOpen | temp_directory::EmptyOnClose | temp_directory::RemoveOnClose); + path_t const path = path_t(td.c_str()) / "does-not-exist"; + + DIR* const h = fs_traits_t::open_dir(path.c_str()); + + TEST_BOOLEAN_TRUE(NULL == h); + + if (NULL != h) + { + fs_traits_t::close_dir(h); + } +} + +static void TEST_read_dir_EMPTY_directory() +{ + temp_directory td(temp_directory::EmptyOnOpen | temp_directory::EmptyOnClose | temp_directory::RemoveOnClose); + + DIR* const h = fs_traits_t::open_dir(td.c_str()); + + if (NULL == h) + { + TEST_FAIL("failed to open directory"); + } + else + { + names_t names; + + read_all_entries(h, names); + + TEST_INT_EQ(0u, normalise(names).size()); + + TEST_BOOLEAN_TRUE(NULL == fs_traits_t::read_dir(h)); + + fs_traits_t::close_dir(h); + } +} + +static void TEST_read_dir_NON_EMPTY_directory() +{ + temp_directory td(temp_directory::EmptyOnOpen | temp_directory::EmptyOnClose | temp_directory::RemoveOnClose); + + three_files files(td.c_str()); + + DIR* const h = fs_traits_t::open_dir(td.c_str()); + + if (NULL == h) + { + TEST_FAIL("failed to open directory"); + } + else + { + names_t names; + + read_all_entries(h, names); + + TEST_BOOLEAN_TRUE(files.names() == normalise(names)); + + fs_traits_t::close_dir(h); + } +} + +static void TEST_rewind_dir_BEFORE_ANY_READ() +{ + temp_directory td(temp_directory::EmptyOnOpen | temp_directory::EmptyOnClose | temp_directory::RemoveOnClose); + + three_files files(td.c_str()); + + DIR* const h = fs_traits_t::open_dir(td.c_str()); + + if (NULL == h) + { + TEST_FAIL("failed to open directory"); + } + else + { + names_t names; + + fs_traits_t::rewind_dir(h); + + read_all_entries(h, names); + + TEST_BOOLEAN_TRUE(files.names() == normalise(names)); + + fs_traits_t::close_dir(h); + } +} + +static void TEST_rewind_dir_AFTER_PARTIAL_READ() +{ + temp_directory td(temp_directory::EmptyOnOpen | temp_directory::EmptyOnClose | temp_directory::RemoveOnClose); + + three_files files(td.c_str()); + + DIR* const h = fs_traits_t::open_dir(td.c_str()); + + if (NULL == h) + { + TEST_FAIL("failed to open directory"); + } + else + { + names_t first_pass; + names_t second_pass; + + // Read the first two entries (of "." + ".." + 3 files, in some order) + + TEST_INT_EQ(2u, read_entries(h, first_pass, 2)); + + fs_traits_t::rewind_dir(h); + + read_all_entries(h, second_pass); + + // After the rewind, *all* entries are returned, including those + // that had been read before the rewind + + TEST_INT_EQ(5u, second_pass.size()); + TEST_BOOLEAN_TRUE(files.names() == normalise(second_pass)); + + fs_traits_t::close_dir(h); + } +} + +static void TEST_rewind_dir_AFTER_EXHAUSTION() +{ + temp_directory td(temp_directory::EmptyOnOpen | temp_directory::EmptyOnClose | temp_directory::RemoveOnClose); + + three_files files(td.c_str()); + + DIR* const h = fs_traits_t::open_dir(td.c_str()); + + if (NULL == h) + { + TEST_FAIL("failed to open directory"); + } + else + { + names_t first_pass; + names_t second_pass; + + read_all_entries(h, first_pass); + + TEST_BOOLEAN_TRUE(NULL == fs_traits_t::read_dir(h)); + + fs_traits_t::rewind_dir(h); + + read_all_entries(h, second_pass); + + TEST_BOOLEAN_TRUE(files.names() == normalise(first_pass)); + TEST_BOOLEAN_TRUE(files.names() == normalise(second_pass)); + TEST_INT_EQ(first_pass.size(), second_pass.size()); + + fs_traits_t::close_dir(h); + } +} + +static void TEST_rewind_dir_EMPTY_directory() +{ + temp_directory td(temp_directory::EmptyOnOpen | temp_directory::EmptyOnClose | temp_directory::RemoveOnClose); + + DIR* const h = fs_traits_t::open_dir(td.c_str()); + + if (NULL == h) + { + TEST_FAIL("failed to open directory"); + } + else + { + names_t names; + + read_all_entries(h, names); + + fs_traits_t::rewind_dir(h); + + names_t names_after; + + read_all_entries(h, names_after); + + TEST_INT_EQ(0u, normalise(names_after).size()); + TEST_INT_EQ(names.size(), names_after.size()); + + fs_traits_t::close_dir(h); + } +} + +static void TEST_rewind_dir_MULTIPLE_times() +{ + temp_directory td(temp_directory::EmptyOnOpen | temp_directory::EmptyOnClose | temp_directory::RemoveOnClose); + + three_files files(td.c_str()); + + DIR* const h = fs_traits_t::open_dir(td.c_str()); + + if (NULL == h) + { + TEST_FAIL("failed to open directory"); + } + else + { + for (int pass = 0; pass != 3; ++pass) + { + names_t names; + + read_all_entries(h, names); + + TEST_BOOLEAN_TRUE(files.names() == normalise(names)); + + fs_traits_t::rewind_dir(h); + } + + fs_traits_t::close_dir(h); + } +} +} // anonymous namespace + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/scratch/unixstl/CMakeLists.txt b/test/scratch/unixstl/CMakeLists.txt index beef2694..719e8486 100644 --- a/test/scratch/unixstl/CMakeLists.txt +++ b/test/scratch/unixstl/CMakeLists.txt @@ -1,3 +1,4 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(filesystem) add_subdirectory(synch) add_subdirectory(system) diff --git a/test/scratch/unixstl/filesystem/CMakeLists.txt b/test/scratch/unixstl/filesystem/CMakeLists.txt new file mode 100644 index 00000000..5fa1138e --- /dev/null +++ b/test/scratch/unixstl/filesystem/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(rewind_dir) diff --git a/test/scratch/unixstl/filesystem/rewind_dir/CMakeLists.txt b/test/scratch/unixstl/filesystem/rewind_dir/CMakeLists.txt new file mode 100644 index 00000000..586b2901 --- /dev/null +++ b/test/scratch/unixstl/filesystem/rewind_dir/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_example_program(test.scratch.unixstl.filesystem.rewind_dir main.cpp) diff --git a/test/scratch/unixstl/filesystem/rewind_dir/main.cpp b/test/scratch/unixstl/filesystem/rewind_dir/main.cpp new file mode 100644 index 00000000..595999e0 --- /dev/null +++ b/test/scratch/unixstl/filesystem/rewind_dir/main.cpp @@ -0,0 +1,112 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: rewind_dir/main.cpp + * + * Purpose: Scratch test for `unixstl::filesystem_traits<>::rewind_dir()`, + * exploring its interaction with `open_dir()`, `read_dir()`, and + * `close_dir()`, on a directory given on the command-line (or the + * current directory, if none is given). + * + * Created: 8th October 2026 + * Updated: 8th October 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +#include + +#include + +#include +#include + + +typedef unixstl::filesystem_traits fs_traits_t; + + +namespace { + + /* Reads up to `max` entries from `h`, printing each, and returns the + * number read + */ + size_t + dump_entries( + DIR* h + , char const* label + , size_t max + ) + { + size_t n = 0; + + fprintf(stdout, "%s:\n", label); + + for (struct dirent const* de; n < max && NULL != (de = fs_traits_t::read_dir(h)); ++n) + { + fprintf(stdout, "\t%s\n", de->d_name); + } + + fprintf(stdout, "\t(%lu entries)\n", static_cast(n)); + + return n; + } +} // anonymous namespace + + +int main(int argc, char* argv[]) +{ + char const* const program_name = platformstl::get_executable_name_from_path(argv[0]).ptr; + char const* dir = "."; + + if (argc > 1) + { + dir = argv[1]; + } + + DIR* const h = fs_traits_t::open_dir(dir); + + if (NULL == h) + { + fprintf(stderr, "%s: could not open directory '%s'\n", program_name, dir); + + return EXIT_FAILURE; + } + else + { + size_t const n1 = dump_entries(h, "first pass (full)", ~size_t(0)); + size_t const n2 = dump_entries(h, "(no rewind; expect nothing)", ~size_t(0)); + + fs_traits_t::rewind_dir(h); + + size_t const n3 = dump_entries(h, "second pass (after rewind)", ~size_t(0)); + + fs_traits_t::rewind_dir(h); + + size_t const n4 = dump_entries(h, "third pass (after rewind; first two entries only)", 2); + + fs_traits_t::rewind_dir(h); + + size_t const n5 = dump_entries(h, "fourth pass (after rewind from partial read)", ~size_t(0)); + + fs_traits_t::close_dir(h); + + fprintf(stdout, "\nsummary: n1=%lu; n2=%lu; n3=%lu; n4=%lu; n5=%lu\n" + , static_cast(n1) + , static_cast(n2) + , static_cast(n3) + , static_cast(n4) + , static_cast(n5) + ); + + if (0 != n2 || n1 != n3 || n1 != n5) + { + fprintf(stderr, "%s: unexpected entry counts\n", program_name); + + return EXIT_FAILURE; + } + } + + return EXIT_SUCCESS; +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + From 3d3412c28dc92023bf13cb3ca688171640f66aeb Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Fri, 9 Oct 2026 08:43:53 +1100 Subject: [PATCH 18/31] changes --- CHANGES.md | 59 +++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 3169ace4..45a2339e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,36 +3,35 @@ ## 1.11.1-rc8 - 10th October 2026 -* Added `stlsoft_C_environment_variable_strtoll_m()` and `stlsoft::environment_variable_strtoll()`, with UNIX `getenv()` / `strtoll()` and Windows `getenv_s()` / `STLSOFT_C_AUTO_BUFFER` support; added component tests; -* Added `unixstl_C_get_current_process_id()` (**unixstl/process/functions.h**, new), `winstl_C_get_current_process_id()` (**winstl/process/functions.h**), and `platformstl_C_get_current_process_id()` (**platformstl/process/functions.h**, new), in terms of `getpid()` / `_getpid()`; -* **unixstl::filesystem_traits** — added `rewind_dir()` (wrapping `rewinddir()`) to complement `open_dir()`, `read_dir()`, and `close_dir()`, so that a directory search may be restarted from its first entry without closing and reopening the handle; - -* Fixed `stlsoft_C_environment_variable_exists_m()` when `getenv_s()` reports an existing empty variable; added component tests for `stlsoft::environment_variable_exists()`; -* **unixstl::filesystem_traits** — `class_type` is now defined in terms of `char_type` (the wide-character specialisation previously named the narrow specialisation); -* **unixstl** / **winstl** `system_traits` and `filesystem_traits` — canonicalised the conditional-compilation guards (no behavioural change); - -* Component tests for `unixstl::filesystem_traits` (**test/component/unixstl/filesystem/filesystem_traits/opendir**) cover `open_dir()`, `read_dir()`, `rewind_dir()` (before any read, after a partial read, after exhaustion, on an empty directory, and repeatedly), and `close_dir()`; -* Scratch test **test/scratch/unixstl/filesystem/rewind_dir** — exercises `rewind_dir()` over a directory given on the command-line; -* Example **examples/by_project/unixstl/filesystem/rewind_dir** — enumerates a directory in two passes (count, then collect), using `rewind_dir()` between them; -* **test.unit.versions** — aligned with **1.11.1-rc8** (**_STLSOFT_VER_1_11_1_RC8**); - -* **unixstl** — **1.8.6 beta 7** (**_UNIXSTL_VER_1_8_6_B07**), with **STLSoft 1.11.1-rc8**; -* **winstl** — **1.13.0 beta 4** (**_WINSTL_VER_1_13_0_B04**), with **STLSoft 1.11.1-rc8**; -* **inetstl** — **1.5.0 alpha 3** (**_INETSTL_VER_1_5_0_A03**), with **STLSoft 1.11.1-rc8**; - -* Added **run_all_component_tests.sh** / **.cmd**, **run_all_performance_tests.sh** / **.cmd** (with `--gap-groups`), and **run_all_automated_tests.sh** / **.cmd** (unit then component; `--unit-only` / `--component-only`); -* Added **generate_doxygen.sh**, **Doxyfile**, and **doc/mainpage.md** — HTML API documentation generated from the public headers into **_build/doxygen/html**; -* **remove_cmake_artefacts.sh** — no longer removes **docs** or **Doxyfile**; iterates arrays safely; -* **batch_compile_check**, **execute_performance_tests.sh** — quote the `$(dirname ...)` directory resolution; - - -* Scripts — **build_cmake.sh**, **clean_cmake.sh**, **ctest_cmake.sh**, **prepare_cmake.sh**, **remove_cmake_artefacts.sh**, **run_all_examples.sh**, and **run_all_scratch_tests.sh** rewritten to the common Synesis helper-script layout: builds go through `cmake --build` (with `--config` selected from `SIS_CMAKE_CONFIG` for multi-config generators) rather than `make` / `mingw32-make`; coloured output (`-A` / `--always-use-colours`, `SIS_CMAKE_ALWAYS_USE_COLOURS`, `NO_COLOR`); quoted paths and arguments; `.sis/project_name.txt` used in all status messages; -* **prepare_cmake.sh** — added `--build-shared-libs` and `-s` / `--stlsoft-root-dir`; honours `SIS_CMAKE_GENERATOR` and `SIS_CMAKE_MINGW`; every `-D` option is passed on all generator paths; -* **run_all_unit_tests.sh** / **.cmd** — now run unit-test programs only (`--unit-only` accepted for compatibility; `--component-only` removed); -* **run_all_examples.sh** — retains `--skip-interactive` (**.github/ci_skip_interactive_examples.txt**, which prevents headless CI hanging on GUI examples) and its discovery of every executable under the **examples** tree, and now exports `SIS_EXAMPLE_SMOKE=1`; **run_all_scratch_tests.sh** / **.cmd** — removed `--verbosity`; -* **.gitattributes** — Linguist language-bar policy: public C headers and sources are classified as C, C++ headers and sources as C++, and `*.cmake` as CMake; helper scripts, IDE project files, **CMakeLists.txt**, and **makefile** are excluded from the advertised language mix (`-linguist-detectable`); -* CI — **ci-cell.yml** runs component tests via **run_all_component_tests.sh**; -* **INSTALL.md** — documented **run_all_component_tests.sh**, **run_all_automated_tests.sh**, and **generate_doxygen.sh**; corrected the unit-test discovery patterns; +* additions: + * Added `stlsoft_C_environment_variable_strtoll_m()` and `stlsoft::environment_variable_strtoll()`, with UNIX `getenv()` / `strtoll()` and Windows `getenv_s()` / `STLSOFT_C_AUTO_BUFFER` support; added component tests; + * Added `unixstl_C_get_current_process_id()` (**unixstl/process/functions.h**, new), `winstl_C_get_current_process_id()` (**winstl/process/functions.h**), and `platformstl_C_get_current_process_id()` (**platformstl/process/functions.h**, new), in terms of `getpid()` / `_getpid()`; + * **unixstl::filesystem_traits** — added `rewind_dir()` (wrapping `rewinddir()`) to complement `open_dir()`, `read_dir()`, and `close_dir()`, so that a directory search may be restarted from its first entry without closing and reopening the handle; +* fixes: + * Fixed `stlsoft_C_environment_variable_exists_m()` when `getenv_s()` reports an existing empty variable; added component tests for `stlsoft::environment_variable_exists()`; + * **unixstl::filesystem_traits** — `class_type` is now defined in terms of `char_type` (the wide-character specialisation previously named the narrow specialisation); + * **unixstl** / **winstl** `system_traits` and `filesystem_traits` — canonicalised the conditional-compilation guards (no behavioural change); +* testing: + * Component tests for `unixstl::filesystem_traits` (**test/component/unixstl/filesystem/filesystem_traits/opendir**) cover `open_dir()`, `read_dir()`, `rewind_dir()` (before any read, after a partial read, after exhaustion, on an empty directory, and repeatedly), and `close_dir()`; + * Scratch test **test/scratch/unixstl/filesystem/rewind_dir** — exercises `rewind_dir()` over a directory given on the command-line; + * Example **examples/by_project/unixstl/filesystem/rewind_dir** — enumerates a directory in two passes (count, then collect), using `rewind_dir()` between them; + * **test.unit.versions** — aligned with **1.11.1-rc8** (**_STLSOFT_VER_1_11_1_RC8**); +* version: + * **unixstl** — **1.8.6 beta 7** (**_UNIXSTL_VER_1_8_6_B07**), with **STLSoft 1.11.1-rc8**; + * **winstl** — **1.13.0 beta 4** (**_WINSTL_VER_1_13_0_B04**), with **STLSoft 1.11.1-rc8**; + * **inetstl** — **1.5.0 alpha 3** (**_INETSTL_VER_1_5_0_A03**), with **STLSoft 1.11.1-rc8**; +* boilerplate: + * Added **run_all_component_tests.sh** / **.cmd**, **run_all_performance_tests.sh** / **.cmd** (with `--gap-groups`), and **run_all_automated_tests.sh** / **.cmd** (unit then component; `--unit-only` / `--component-only`); + * Added **generate_doxygen.sh**, **Doxyfile**, and **doc/mainpage.md** — HTML API documentation generated from the public headers into **_build/doxygen/html**; + * **remove_cmake_artefacts.sh** — no longer removes **docs** or **Doxyfile**; iterates arrays safely; + * **batch_compile_check**, **execute_performance_tests.sh** — quote the `$(dirname ...)` directory resolution; + * Scripts — **build_cmake.sh**, **clean_cmake.sh**, **ctest_cmake.sh**, **prepare_cmake.sh**, **remove_cmake_artefacts.sh**, **run_all_examples.sh**, and **run_all_scratch_tests.sh** rewritten to the common Synesis helper-script layout: builds go through `cmake --build` (with `--config` selected from `SIS_CMAKE_CONFIG` for multi-config generators) rather than `make` / `mingw32-make`; coloured output (`-A` / `--always-use-colours`, `SIS_CMAKE_ALWAYS_USE_COLOURS`, `NO_COLOR`); quoted paths and arguments; `.sis/project_name.txt` used in all status messages; + * **prepare_cmake.sh** — added `--build-shared-libs` and `-s` / `--stlsoft-root-dir`; honours `SIS_CMAKE_GENERATOR` and `SIS_CMAKE_MINGW`; every `-D` option is passed on all generator paths; + * **run_all_unit_tests.sh** / **.cmd** — now run unit-test programs only (`--unit-only` accepted for compatibility; `--component-only` removed); + * **run_all_examples.sh** — retains `--skip-interactive` (**.github/ci_skip_interactive_examples.txt**, which prevents headless CI hanging on GUI examples) and its discovery of every executable under the **examples** tree, and now exports `SIS_EXAMPLE_SMOKE=1`; **run_all_scratch_tests.sh** / **.cmd** — removed `--verbosity`; + * **.gitattributes** — Linguist language-bar policy: public C headers and sources are classified as C, C++ headers and sources as C++, and `*.cmake` as CMake; helper scripts, IDE project files, **CMakeLists.txt**, and **makefile** are excluded from the advertised language mix (`-linguist-detectable`); + * CI — **ci-cell.yml** runs component tests via **run_all_component_tests.sh**; + * **INSTALL.md** — documented **run_all_component_tests.sh**, **run_all_automated_tests.sh**, and **generate_doxygen.sh**; corrected the unit-test discovery patterns; ## 1.11.1-rc7 - 30th September 2026 From be9562982966b9d51679d6bc80ea06ed4696e466 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 15 Oct 2026 11:13:33 +1100 Subject: [PATCH 19/31] feature(STLSoft): added `unixstl::system_traits<>::get_current_process_path()` and `winstl::system_traits<>::get_current_process_path()` Release **STLSoft** 1.11.1-rc9 (16th October 2026): - add `unixstl` / `winstl` `system_traits::get_current_process_path()` (multibyte and wide) with process_paths component tests; - bump **_STLSOFT_VER** to **1.11.1-rc9**, **unixstl** to **1.8.6 beta 8**, and **winstl** to **1.13.0 beta 5**; - align **test.unit.versions**, **CHANGES.md**, **NEWS.md**, and **INSTALL.md**; --- .vscode/settings.json | 3 + CHANGES.md | 12 + INSTALL.md | 18 +- NEWS.md | 1 + include/stlsoft/stlsoft.h | 9 +- include/unixstl/system/system_traits.hpp | 72 ++- include/unixstl/unixstl.h | 9 +- include/winstl/system/system_traits.hpp | 102 +++- include/winstl/winstl.h | 9 +- test/component/unixstl/system/CMakeLists.txt | 1 + .../system/process_paths/CMakeLists.txt | 2 + .../unixstl/system/process_paths/entry.cpp | 456 ++++++++++++++++ test/component/winstl/system/CMakeLists.txt | 1 + .../system/process_paths/CMakeLists.txt | 2 + .../winstl/system/process_paths/entry.cpp | 494 ++++++++++++++++++ test/unit/versions/entry.cpp | 6 +- 16 files changed, 1164 insertions(+), 33 deletions(-) create mode 100644 test/component/unixstl/system/process_paths/CMakeLists.txt create mode 100644 test/component/unixstl/system/process_paths/entry.cpp create mode 100644 test/component/winstl/system/process_paths/CMakeLists.txt create mode 100644 test/component/winstl/system/process_paths/entry.cpp diff --git a/.vscode/settings.json b/.vscode/settings.json index 6aa78f6c..e30f6b86 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -59,6 +59,9 @@ "C_Cpp.clang_format_style": "file", "C_Cpp.default.cStandard": "c17", "C_Cpp.default.cppStandard": "c++17", + "C_Cpp.default.defines": [ + // "STLSOFT_DOCUMENTATION_SKIP_SECTION", + ], "C_Cpp.enhancedColorization": "enabled", "C_Cpp.errorSquiggles": "enabled", "C_Cpp.formatting": "clangFormat", diff --git a/CHANGES.md b/CHANGES.md index 45a2339e..6b1179f5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,18 @@ # STLSoft - CHANGES +## 1.11.1-rc9 - 16th October 2026 + +* additions: + * Added `unixstl::system_traits<>::get_current_process_path()` and `winstl::system_traits<>::get_current_process_path()` (multibyte and wide), obtaining the current process image path with an optional basename path-separator out-parameter; +* testing: + * Component tests **test/component/unixstl/system/process_paths** (multibyte; multi-OS raw path oracle) and **test/component/winstl/system/process_paths** (multibyte and wide; `GetModuleFileName` oracle); + * **test.unit.versions** — aligned with **1.11.1-rc9** (**_STLSOFT_VER_1_11_1_RC9**); +* version: + * **unixstl** — **1.8.6 beta 8** (**_UNIXSTL_VER_1_8_6_B08**), with **STLSoft 1.11.1-rc9**; + * **winstl** — **1.13.0 beta 5** (**_WINSTL_VER_1_13_0_B05**), with **STLSoft 1.11.1-rc9**; + + ## 1.11.1-rc8 - 10th October 2026 * additions: diff --git a/INSTALL.md b/INSTALL.md index 13e5c0ee..7b04011e 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -23,17 +23,17 @@ There are three options for installing **STLSoft**, depending on how you obtain If you obtain the latest release as an archive from the [**STLSoft** GitHub Releases](https://github.com/synesissoftware/STLSoft/releases) page (legacy archives may also still appear on [SourceForge](https://sourceforge.net/projects/stlsoft/)): -1. Download the latest distribution, e.g. [**STLSoft-1.11.1-rc8.zip**](https://github.com/synesissoftware/STLSoft/archive/refs/tags/1.11.1-rc8.zip); +1. Download the latest distribution, e.g. [**STLSoft-1.11.1-rc9.zip**](https://github.com/synesissoftware/STLSoft/archive/refs/tags/1.11.1-rc9.zip); 2. Unzip it to a directory of your choice, as in: ```bash $ mkdir -p ~/open-source $ cd ~/open-source -$ unzip STLSoft-1.11.1-rc8.zip +$ unzip STLSoft-1.11.1-rc9.zip ``` -3. Define an environment variable `STLSOFT`, whose value is the directory in which you unzipped it, e.g. `STLSOFT=~/open-source/STLSoft-1.11.1-rc8`, and then specify `$(STLSOFT)/include` (**UNIX**) or `%STLSOFT%\include` (**Windows**) in your project files and makefiles; +3. Define an environment variable `STLSOFT`, whose value is the directory in which you unzipped it, e.g. `STLSOFT=~/open-source/STLSoft-1.11.1-rc9`, and then specify `$(STLSOFT)/include` (**UNIX**) or `%STLSOFT%\include` (**Windows**) in your project files and makefiles; ### Cloning project, using environment variables @@ -100,16 +100,16 @@ $ sudo cmake --install ${SIS_CMAKE_BUILD_DIR:-./_build} --config Release Unless you are certain that your projects, and all the projects upon which they depend, all use **STLSoft** via **CMake** then it is recommended that you define an `STLSOFT` environment variable. For example, if you're using **UNIX** and you install to -**/usr/local/stlsoft/STLSoft-1.11.1-rc8** +**/usr/local/stlsoft/STLSoft-1.11.1-rc9** then you should set the environment variable `STLSOFT` to -**/usr/local/stlsoft/STLSoft-1.11.1-rc8** -in which case the file `stlsoft/stlsoft.h`, for example, will be located in `/usr/local/stlsoft/STLSoft-1.11.1-rc8/include/stlsoft/stlsoft.h`. +**/usr/local/stlsoft/STLSoft-1.11.1-rc9** +in which case the file `stlsoft/stlsoft.h`, for example, will be located in `/usr/local/stlsoft/STLSoft-1.11.1-rc9/include/stlsoft/stlsoft.h`. Conversely, if you're using **Windows** and you install to -**C:\3pty\STLSoft\STLSoft-1.11.1-rc8** +**C:\3pty\STLSoft\STLSoft-1.11.1-rc9** then you should set the environment variable `STLSOFT` to -**C:\3pty\STLSoft\STLSoft-1.11.1-rc8** -in which case the file `stlsoft/stlsoft.h`, for example, will be located in `C:\3pty\STLSoft\STLSoft-1.11.1-rc8\include\stlsoft\stlsoft.h`. +**C:\3pty\STLSoft\STLSoft-1.11.1-rc9** +in which case the file `stlsoft/stlsoft.h`, for example, will be located in `C:\3pty\STLSoft\STLSoft-1.11.1-rc9\include\stlsoft\stlsoft.h`. The makefiles / project files of several other open-source projects expect this symbol, including: diff --git a/NEWS.md b/NEWS.md index 74839ad5..63bbdced 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ | Date | News Item | Details | | ------------------- | ----------------------------------- | ------- | +| 16th October 2026 | Release of [STLSoft 1.11.1-rc9](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc9) | `get_current_process_path()` on **unixstl** / **winstl** `system_traits`; process_paths component tests | | 10th October 2026 | Release of [STLSoft 1.11.1-rc8](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc8) | environment_variable_strtoll()`; `unixstl::filesystem_traits<>::rewind_dir()`; `class_type` and `getenv_s()` empty-variable fixes; component tests; `cmake --build` helper scripts; **run_all_component_tests.sh** / **run_all_automated_tests.sh**; **generate_doxygen.sh**; Linguist classification | | 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | counted NULs; `wchar_t` `string_begins_with`; bit intrinsics; `write_binary()`; `file_lines` mmap (~10–20× vs `fgetc`); compare and allocator units; MinGW static runtime; short test directories; nested **test/performance** | | 21st September 2026 | Release of [STLSoft 1.11.1-rc6](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc6) | ACE/ATL/MFC CI; Clang/macOS `stricmp` aliases | diff --git a/include/stlsoft/stlsoft.h b/include/stlsoft/stlsoft.h index 51d82f0c..c41f9809 100644 --- a/include/stlsoft/stlsoft.h +++ b/include/stlsoft/stlsoft.h @@ -5,7 +5,7 @@ * and platform discriminations, and definitions of types. * * Created: 15th January 2002 - * Updated: 10th October 2026 + * Updated: 15th October 2026 * * Home: http://stlsoft.org/ * @@ -55,8 +55,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_STLSOFT_H_STLSOFT_MAJOR 3 # define STLSOFT_VER_STLSOFT_H_STLSOFT_MINOR 57 -# define STLSOFT_VER_STLSOFT_H_STLSOFT_REVISION 20 -# define STLSOFT_VER_STLSOFT_H_STLSOFT_EDIT 608 +# define STLSOFT_VER_STLSOFT_H_STLSOFT_REVISION 21 +# define STLSOFT_VER_STLSOFT_H_STLSOFT_EDIT 609 #else /* ? STLSOFT_DOCUMENTATION_SKIP_SECTION */ /* # include "./internal/doxygen_defs.h" */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -423,12 +423,13 @@ # define _STLSOFT_VER_1_11_1_RC6 0x010b01c6 /*!< Version 1.11.1 rc 6 (21st September 2026) */ # define _STLSOFT_VER_1_11_1_RC7 0x010B01C7 /*!< Version 1.11.1 rc 7 (30th September 2026) */ # define _STLSOFT_VER_1_11_1_RC8 0x010B01C8 /*!< Version 1.11.1 rc 8 (10th October 2026) */ +# define _STLSOFT_VER_1_11_1_RC9 0x010B01C9 /*!< Version 1.11.1 rc 9 (16th October 2026) */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ #define _STLSOFT_VER_MAJOR 1 #define _STLSOFT_VER_MINOR 11 #define _STLSOFT_VER_PATCH 1 -#define _STLSOFT_VER_ALPHABETA 0xC8 +#define _STLSOFT_VER_ALPHABETA 0xC9 #define _STLSOFT_VER \ (0\ diff --git a/include/unixstl/system/system_traits.hpp b/include/unixstl/system/system_traits.hpp index 3be24177..44b215be 100644 --- a/include/unixstl/system/system_traits.hpp +++ b/include/unixstl/system/system_traits.hpp @@ -5,7 +5,7 @@ * Unicode specialisations thereof. * * Created: 15th November 2002 - * Updated: 8th October 2026 + * Updated: 15th October 2026 * * Home: http://stlsoft.org/ * @@ -54,9 +54,9 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_MAJOR 6 -# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_MINOR 2 -# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 3 -# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 141 +# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_MINOR 3 +# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 1 +# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 142 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -250,6 +250,42 @@ struct system_traits ); /// @} +/// \name Process Paths +/// @{ +public: + /// Attempt to obtain the current process's path. + /// + /// \param cch The number of elements available in \c buff available for + /// writing; + /// \param buff Pointer to the buffer into which \c cch result can be + /// written. May not be \c nullptr except when \c cch is 0; + /// \param ppFile Optional pointer to receive a mutating pointer. When + /// non-nullptr, *ppFile is always set to + /// nullptr; then, if and only if the full path was + /// written into \c buff, *ppFile is set to the last + /// path-name separator in \c buff, if any; + /// + /// \return If \c buff is sufficient for the full path and a terminating + /// NUL character then this returns the length of the path (excluding + /// the NUL character); otherwise, as much of the result as can be + /// written is done so and the full length + 1 (for the NUL character) + /// is returned, in order that client code can allocate all required + /// space. + /// \retval 0 The function failed, and more information can be obtained + /// from get_last_error(); + /// + /// \note + /// + /// \pre 0 == cch || nullptr != buff + static + size_type + get_current_process_path( + size_t cch + , char_type buff[/* cch */] + , char_type** ppFile + ) STLSOFT_NOEXCEPT; +/// @} + /// \name System Paths /// @{ public: @@ -577,6 +613,34 @@ struct system_traits } } + return 0; + } + +public: + static + size_type + get_current_process_path( + size_t cch + , char_type buff[/* cch */] + , char_type** ppFile + ) STLSOFT_NOEXCEPT + { + UNIXSTL_ASSERT(0 == cch || NULL != buff); + + char_type* dummy; + + if (NULL == ppFile) + { + ppFile = &dummy; + } + + *ppFile = NULL; + + + ((void)cch); + ((void)buff); + + return 0; } diff --git a/include/unixstl/unixstl.h b/include/unixstl/unixstl.h index 33335107..93fbcc99 100644 --- a/include/unixstl/unixstl.h +++ b/include/unixstl/unixstl.h @@ -5,7 +5,7 @@ * platform discriminations, and definitions of types. * * Created: 15th January 2002 - * Updated: 10th October 2026 + * Updated: 15th October 2026 * * Home: http://stlsoft.org/ * @@ -50,8 +50,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_MAJOR 3 # define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_MINOR 11 -# define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_REVISION 5 -# define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_EDIT 132 +# define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_REVISION 6 +# define UNIXSTL_VER_UNIXSTL_H_UNIXSTL_EDIT 133 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ /** \file unixstl/unixstl.h @@ -164,12 +164,13 @@ # define _UNIXSTL_VER_1_8_6_B05 0x01080685 /*!< Version 1.8.8 beta 5 (with STLSoft 1.11.1 rc 2) */ # define _UNIXSTL_VER_1_8_6_B06 0x01080686 /*!< Version 1.8.8 beta 6 (with STLSoft 1.11.1 rc 3) */ # define _UNIXSTL_VER_1_8_6_B07 0x01080687 /*!< Version 1.8.8 beta 7 (with STLSoft 1.11.1 rc 8) */ +# define _UNIXSTL_VER_1_8_6_B08 0x01080688 /*!< Version 1.8.8 beta 8 (with STLSoft 1.11.1 rc 9) */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ #define _UNIXSTL_VER_MAJOR 1 #define _UNIXSTL_VER_MINOR 8 #define _UNIXSTL_VER_PATCH 6 -#define _UNIXSTL_VER_ALPHABETA 0x87 +#define _UNIXSTL_VER_ALPHABETA 0x88 #define _UNIXSTL_VER \ (0\ diff --git a/include/winstl/system/system_traits.hpp b/include/winstl/system/system_traits.hpp index bc65f0af..47dfc575 100644 --- a/include/winstl/system/system_traits.hpp +++ b/include/winstl/system/system_traits.hpp @@ -5,14 +5,14 @@ * Unicode specialisations thereof. * * Created: 15th November 2002 - * Updated: 27th May 2025 + * Updated: 15th October 2026 * * Thanks: Austin Ziegler for spotting the defective pre-condition * enforcement of expand_environment_strings(). * * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2002-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -57,9 +57,9 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_MAJOR 6 -# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_MINOR 0 -# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 6 -# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 171 +# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_MINOR 1 +# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 1 +# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 172 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -266,6 +266,42 @@ struct system_traits #endif /* !NONLS */ /// @} +/// \name Process Paths +/// @{ +public: + /// Attempt to obtain the current process's path. + /// + /// \param cch The number of elements available in \c buff available for + /// writing; + /// \param buff Pointer to the buffer into which \c cch result can be + /// written. May not be \c nullptr except when \c cch is 0; + /// \param ppFile Optional pointer to receive a mutating pointer. When + /// non-nullptr, *ppFile is always set to + /// nullptr; then, if and only if the full path was + /// written into \c buff, *ppFile is set to the last + /// path-name separator in \c buff, if any; + /// + /// \return If \c buff is sufficient for the full path and a terminating + /// NUL character then this returns the length of the path (excluding + /// the NUL character); otherwise, as much of the result as can be + /// written is done so and the full length + 1 (for the NUL character) + /// is returned, in order that client code can allocate all required + /// space. + /// \retval 0 The function failed, and more information can be obtained + /// from get_last_error(); + /// + /// \note + /// + /// \pre 0 == cch || nullptr != buff + static + size_type + get_current_process_path( + size_t cch + , char_type buff[/* cch */] + , char_type** ppFile + ) STLSOFT_NOEXCEPT; +/// @} + /// \name System Paths /// @{ public: @@ -728,6 +764,34 @@ struct system_traits } #endif /* !NONLS */ +public: + static + size_type + get_current_process_path( + size_t cch + , char_type buff[/* cch */] + , char_type** ppFile + ) STLSOFT_NOEXCEPT + { + WINSTL_ASSERT(0 == cch || NULL != buff); + + char_type* dummy; + + if (NULL == ppFile) + { + ppFile = &dummy; + } + + *ppFile = NULL; + + + ((void)cch); + ((void)buff); + + + return 0; + } + public: static size_type @@ -1349,6 +1413,34 @@ struct system_traits } #endif /* !NONLS */ +public: + static + size_type + get_current_process_path( + size_t cch + , char_type buff[/* cch */] + , char_type** ppFile + ) STLSOFT_NOEXCEPT + { + WINSTL_ASSERT(0 == cch || NULL != buff); + + char_type* dummy; + + if (NULL == ppFile) + { + ppFile = &dummy; + } + + *ppFile = NULL; + + + ((void)cch); + ((void)buff); + + + return 0; + } + public: static size_type diff --git a/include/winstl/winstl.h b/include/winstl/winstl.h index 592659ec..e2111631 100644 --- a/include/winstl/winstl.h +++ b/include/winstl/winstl.h @@ -5,7 +5,7 @@ * platform discriminations, and definitions of types. * * Created: 15th January 2002 - * Updated: 8th October 2026 + * Updated: 16th October 2026 * * Home: http://stlsoft.org/ * @@ -50,8 +50,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define WINSTL_VER_WINSTL_H_WINSTL_MAJOR 3 # define WINSTL_VER_WINSTL_H_WINSTL_MINOR 18 -# define WINSTL_VER_WINSTL_H_WINSTL_REVISION 15 -# define WINSTL_VER_WINSTL_H_WINSTL_EDIT 245 +# define WINSTL_VER_WINSTL_H_WINSTL_REVISION 16 +# define WINSTL_VER_WINSTL_H_WINSTL_EDIT 246 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ /** \file winstl/winstl.h @@ -185,12 +185,13 @@ # define _WINSTL_VER_1_13_0_B02 0x010d0082 /*!< Version 1.13.0 beta 2 (with STLSoft 1.11.1 rc 4) */ # define _WINSTL_VER_1_13_0_B03 0x010d0083 /*!< Version 1.13.0 beta 3 (with STLSoft 1.11.1 rc 7) */ # define _WINSTL_VER_1_13_0_B04 0x010d0084 /*!< Version 1.13.0 beta 4 (with STLSoft 1.11.1 rc 8) */ +# define _WINSTL_VER_1_13_0_B05 0x010d0085 /*!< Version 1.13.0 beta 5 (with STLSoft 1.11.1 rc 9) */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ #define _WINSTL_VER_MAJOR 1 #define _WINSTL_VER_MINOR 13 #define _WINSTL_VER_PATCH 0 -#define _WINSTL_VER_ALPHABETA 0x84 +#define _WINSTL_VER_ALPHABETA 0x85 #define _WINSTL_VER \ (0\ diff --git a/test/component/unixstl/system/CMakeLists.txt b/test/component/unixstl/system/CMakeLists.txt index eefe07f3..62b6cb13 100644 --- a/test/component/unixstl/system/CMakeLists.txt +++ b/test/component/unixstl/system/CMakeLists.txt @@ -1,2 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten add_subdirectory(environment_variable) +add_subdirectory(process_paths) diff --git a/test/component/unixstl/system/process_paths/CMakeLists.txt b/test/component/unixstl/system/process_paths/CMakeLists.txt new file mode 100644 index 00000000..cadc56ac --- /dev/null +++ b/test/component/unixstl/system/process_paths/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.component.unixstl.system.process_paths entry.cpp) diff --git a/test/component/unixstl/system/process_paths/entry.cpp b/test/component/unixstl/system/process_paths/entry.cpp new file mode 100644 index 00000000..edee0eee --- /dev/null +++ b/test/component/unixstl/system/process_paths/entry.cpp @@ -0,0 +1,456 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test/component/unixstl/system/process_paths/entry.cpp + * + * Purpose: Component-tests for + * `unixstl::system_traits::get_current_process_path()` (multibyte). + * + * Created: 15th October 2026 + * Updated: 15th October 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +/* ///////////////////////////////////// + * test component header file include(s) + */ + +#include + +/* ///////////////////////////////////// + * general includes + */ + +/* xTests header files */ +#include +#include + +/* STLSoft header files */ +#include + +/* Standard C++ header files */ +#include + +/* Standard C header files */ +#include +#include +#include + +#if 0 +#elif defined(_WIN32) + +# include +#elif defined(__APPLE__) + +# include +# include +# include +#elif defined(__linux__) + +# include +#elif 0 ||\ + defined(__FreeBSD__) ||\ + defined(__NetBSD__) ||\ + defined(__OpenBSD__) ||\ + 0 + +# include +# include +#elif defined(__sun) + +# include +#endif + +#if !defined(PATH_MAX) +# define PATH_MAX 4096 +#endif + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace { + + static void TEST_SIZE_QUERY(); + static void TEST_EXACT_FIT(); + static void TEST_EXCESS_SPACE(); + static void TEST_INSUFFICIENT_SPACE(); + static void TEST_ppFile_NULL_ON_SUCCESS(); + static void TEST_ppFile_separator_on_success(); + static void TEST_ppFile_NULL_WHEN_INSUFFICIENT(); +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.component.unixstl.system.process_paths", verbosity)) + { + XTESTS_RUN_CASE(TEST_SIZE_QUERY); + XTESTS_RUN_CASE(TEST_EXACT_FIT); + XTESTS_RUN_CASE(TEST_EXCESS_SPACE); + XTESTS_RUN_CASE(TEST_INSUFFICIENT_SPACE); + XTESTS_RUN_CASE(TEST_ppFile_NULL_ON_SUCCESS); + XTESTS_RUN_CASE(TEST_ppFile_separator_on_success); + XTESTS_RUN_CASE(TEST_ppFile_NULL_WHEN_INSUFFICIENT); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * helpers + */ + +namespace { + +typedef unixstl::system_traits traits_m_t; + +/** Retrieves the full path of the current executable from the ambient OS + * API (not via STLSoft). + * + * \return 0 on success; -1 on failure. + */ +static +int +get_executable_path_( + char* path +, size_t size +) +{ + if (NULL == path || + 0 == size) + { + return -1; + } + +#if 0 +#elif defined(_WIN32) + + /* Windows / UNIXem: GetModuleFileNameA */ + { + DWORD const len = ::GetModuleFileNameA(NULL, path, static_cast(size - 1)); + + if (0 == len) + { + return -1; + } + + if (len == static_cast(size - 1) && + ERROR_INSUFFICIENT_BUFFER == ::GetLastError()) + { + return -1; + } + + path[len] = '\0'; + + return 0; + } +#elif defined(__APPLE__) + + /* macOS: prefer proc_pidpath; fallback to _NSGetExecutablePath (+ realpath). */ + { + pid_t const pid = ::getpid(); + int const ret = ::proc_pidpath(pid, path, static_cast(size)); + + if (ret <= 0) + { + uint32_t len = static_cast(size); + + if (0 != ::_NSGetExecutablePath(path, &len)) + { + return -1; + } + + { + char* const resolved = ::realpath(path, NULL); + + if (NULL != resolved) + { + ::strncpy(path, resolved, size - 1); + path[size - 1] = '\0'; + ::free(resolved); + } + } + } + + return 0; + } +#elif defined(__linux__) + + /* Linux: readlink("/proc/self/exe") */ + { + ssize_t const len = ::readlink("/proc/self/exe", path, size - 1); + + if (-1 == len) + { + return -1; + } + + path[len] = '\0'; + + return 0; + } +#elif 0 || \ + defined(__FreeBSD__) ||\ + defined(__NetBSD__) ||\ + defined(__OpenBSD__) ||\ + 0 + + /* BSD: sysctl(KERN_PROC_PATHNAME) */ + { + int mib[4]; + size_t len = size - 1; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + + if (0 != ::sysctl(mib, 4, path, &len, NULL, 0)) + { + return -1; + } + + path[len] = '\0'; + + return 0; + } +#elif defined(__sun) + + /* Solaris: getexecname() + realpath() */ + { + char const* const exe = ::getexecname(); + + if (NULL == exe) + { + return -1; + } + + if (NULL == ::realpath(exe, path)) + { + return -1; + } + + return 0; + } +#else + + STLSOFT_SUPPRESS_UNUSED(path); + STLSOFT_SUPPRESS_UNUSED(size); + + return -1; +#endif +} + +/** Obtains the current process image path from the ambient OS API, without + * going through STLSoft. + */ +static +std::string +obtain_raw_current_process_path() +{ + char path[PATH_MAX]; + + if (0 != get_executable_path_(path, sizeof(path))) + { + return std::string(); + } + + return std::string(path); +} + +static +char* +find_last_path_name_separator(char* s) +{ + char* last = NULL; + + for (; '\0' != *s; ++s) + { +#if defined(_WIN32) + + if ('\\' == *s || '/' == *s) +#else + + if ('/' == *s) +#endif + { + last = s; + } + } + + return last; +} + +static +char* +invalid_file_pointer() +{ + return reinterpret_cast(static_cast(-1)); +} +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace { + +static void TEST_SIZE_QUERY() +{ + std::string const expected = obtain_raw_current_process_path(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(0, NULL, &pFile); + + TEST_INT_EQ(expected.size() + 1, cch); + TEST_PTR_EQ(NULL, pFile); +} + +static void TEST_EXACT_FIT() +{ + std::string const expected = obtain_raw_current_process_path(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + size_t const len = expected.size(); + stlsoft::auto_buffer buff(len + 1); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(len, cch); + TEST_MS_EQ(expected.c_str(), &buff[0]); + TEST_CHAR_EQ('\0', buff[len]); +} + +static void TEST_EXCESS_SPACE() +{ + std::string const expected = obtain_raw_current_process_path(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + size_t const len = expected.size(); + stlsoft::auto_buffer buff(len + 64); + + ::memset(&buff[0], '~', buff.size()); + + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(len, cch); + TEST_MS_EQ(expected.c_str(), &buff[0]); + TEST_CHAR_EQ('\0', buff[len]); +} + +static void TEST_INSUFFICIENT_SPACE() +{ + std::string const expected = obtain_raw_current_process_path(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + size_t const len = expected.size(); + + /* One character short of an exact fit. */ + { + size_t const cchBuff = len; + stlsoft::auto_buffer buff(cchBuff); + + ::memset(&buff[0], '~', buff.size()); + + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(len + 1, cch); + TEST_PTR_EQ(NULL, pFile); + TEST_CHAR_EQ('\0', buff[cchBuff - 1]); + TEST_MS_EQ_N(expected.c_str(), &buff[0], cchBuff - 1); + } + + /* Single-character buffer: only the terminating NUL. */ + { + char buff[1] = { '~' }; + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(STLSOFT_NUM_ELEMENTS(buff), buff, &pFile); + + TEST_INT_EQ(len + 1, cch); + TEST_PTR_EQ(NULL, pFile); + TEST_CHAR_EQ('\0', buff[0]); + } +} + +static void TEST_ppFile_NULL_ON_SUCCESS() +{ + std::string const expected = obtain_raw_current_process_path(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer buff(expected.size() + 1); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], NULL); + + TEST_INT_EQ(expected.size(), cch); + TEST_MS_EQ(expected.c_str(), &buff[0]); +} + +static void TEST_ppFile_separator_on_success() +{ + std::string const expected = obtain_raw_current_process_path(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer buff(expected.size() + 1); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(expected.size(), cch); + TEST_MS_EQ(expected.c_str(), &buff[0]); + + char* const expectedSep = find_last_path_name_separator(&buff[0]); + + TEST_PTR_EQ(expectedSep, pFile); + + if (NULL != pFile) + { + TEST_MS_EQ(expectedSep + 1, pFile + 1); + } +} + +static void TEST_ppFile_NULL_WHEN_INSUFFICIENT() +{ + std::string const expected = obtain_raw_current_process_path(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + size_t const len = expected.size(); + stlsoft::auto_buffer buff(len); /* one short */ + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(len + 1, cch); + TEST_PTR_EQ(NULL, pFile); +} +} // anonymous namespace + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/component/winstl/system/CMakeLists.txt b/test/component/winstl/system/CMakeLists.txt index f200ec6e..331d1e0f 100644 --- a/test/component/winstl/system/CMakeLists.txt +++ b/test/component/winstl/system/CMakeLists.txt @@ -1,2 +1,3 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten add_subdirectory(directory_functions) +add_subdirectory(process_paths) diff --git a/test/component/winstl/system/process_paths/CMakeLists.txt b/test/component/winstl/system/process_paths/CMakeLists.txt new file mode 100644 index 00000000..056b6aa3 --- /dev/null +++ b/test/component/winstl/system/process_paths/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.component.winstl.system.process_paths entry.cpp) diff --git a/test/component/winstl/system/process_paths/entry.cpp b/test/component/winstl/system/process_paths/entry.cpp new file mode 100644 index 00000000..4011e540 --- /dev/null +++ b/test/component/winstl/system/process_paths/entry.cpp @@ -0,0 +1,494 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test/component/winstl/system/process_paths/entry.cpp + * + * Purpose: Component-tests for + * `winstl::system_traits::get_current_process_path()` (multibyte + * and wide-character). + * + * Created: 15th October 2026 + * Updated: 15th October 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +/* ///////////////////////////////////// + * test component header file include(s) + */ + +#include + +/* ///////////////////////////////////// + * general includes + */ + +/* xTests header files */ +#include +#include + +/* STLSoft header files */ +#include + +/* Standard C++ header files */ +#include + +/* Standard C / Windows header files */ +#include +#include +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace { + + static void TEST_SIZE_QUERY_m(); + static void TEST_SIZE_QUERY_w(); + static void TEST_EXACT_FIT_m(); + static void TEST_EXACT_FIT_w(); + static void TEST_EXCESS_SPACE_m(); + static void TEST_EXCESS_SPACE_w(); + static void TEST_INSUFFICIENT_SPACE_m(); + static void TEST_INSUFFICIENT_SPACE_w(); + static void TEST_ppFile_NULL_ON_SUCCESS_m(); + static void TEST_ppFile_NULL_ON_SUCCESS_w(); + static void TEST_ppFile_separator_ON_SUCCESS_m(); + static void TEST_ppFile_separator_ON_SUCCESS_w(); + static void TEST_ppFile_NULL_WHEN_INSUFFICIENT_m(); + static void TEST_ppFile_NULL_WHEN_INSUFFICIENT_w(); +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.component.winstl.system.process_paths", verbosity)) + { + XTESTS_RUN_CASE(TEST_SIZE_QUERY_m); + XTESTS_RUN_CASE(TEST_SIZE_QUERY_w); + XTESTS_RUN_CASE(TEST_EXACT_FIT_m); + XTESTS_RUN_CASE(TEST_EXACT_FIT_w); + XTESTS_RUN_CASE(TEST_EXCESS_SPACE_m); + XTESTS_RUN_CASE(TEST_EXCESS_SPACE_w); + XTESTS_RUN_CASE(TEST_INSUFFICIENT_SPACE_m); + XTESTS_RUN_CASE(TEST_INSUFFICIENT_SPACE_w); + XTESTS_RUN_CASE(TEST_ppFile_NULL_ON_SUCCESS_m); + XTESTS_RUN_CASE(TEST_ppFile_NULL_ON_SUCCESS_w); + XTESTS_RUN_CASE(TEST_ppFile_separator_ON_SUCCESS_m); + XTESTS_RUN_CASE(TEST_ppFile_separator_ON_SUCCESS_w); + XTESTS_RUN_CASE(TEST_ppFile_NULL_WHEN_INSUFFICIENT_m); + XTESTS_RUN_CASE(TEST_ppFile_NULL_WHEN_INSUFFICIENT_w); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * helpers + */ + +namespace { + +typedef winstl::system_traits traits_m_t; +typedef winstl::system_traits traits_w_t; + +/** Obtains the current process image path via GetModuleFileNameA. */ +static +std::string +obtain_raw_current_process_path_m() +{ + stlsoft::auto_buffer buff(MAX_PATH); + + for (;;) + { + DWORD const n = ::GetModuleFileNameA(NULL, &buff[0], static_cast(buff.size())); + + if (0 == n) + { + return std::string(); + } + + if (n < buff.size()) + { + return std::string(&buff[0], static_cast(n)); + } + + if (!buff.resize(buff.size() * 2)) + { + return std::string(); + } + } +} + +/** Obtains the current process image path via GetModuleFileNameW. */ +static +std::wstring +obtain_raw_current_process_path_w() +{ + stlsoft::auto_buffer buff(MAX_PATH); + + for (;;) + { + DWORD const n = ::GetModuleFileNameW(NULL, &buff[0], static_cast(buff.size())); + + if (0 == n) + { + return std::wstring(); + } + + if (n < buff.size()) + { + return std::wstring(&buff[0], static_cast(n)); + } + + if (!buff.resize(buff.size() * 2)) + { + return std::wstring(); + } + } +} + +static +char* +find_last_path_name_separator(char* s) +{ + char* last = NULL; + + for (; '\0' != *s; ++s) + { + if ('\\' == *s || '/' == *s) + { + last = s; + } + } + + return last; +} + +static +wchar_t* +find_last_path_name_separator(wchar_t* s) +{ + wchar_t* last = NULL; + + for (; L'\0' != *s; ++s) + { + if (L'\\' == *s || L'/' == *s) + { + last = s; + } + } + + return last; +} + +template +static +C* +invalid_file_pointer() +{ + return reinterpret_cast(static_cast(-1)); +} +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace { + +static void TEST_SIZE_QUERY_m() +{ + std::string const expected = obtain_raw_current_process_path_m(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(0, NULL, &pFile); + + TEST_INT_EQ(expected.size() + 1, cch); + TEST_PTR_EQ(NULL, pFile); +} + +static void TEST_SIZE_QUERY_w() +{ + std::wstring const expected = obtain_raw_current_process_path_w(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(0, NULL, &pFile); + + TEST_INT_EQ(expected.size() + 1, cch); + TEST_PTR_EQ(NULL, pFile); +} + +static void TEST_EXACT_FIT_m() +{ + std::string const expected = obtain_raw_current_process_path_m(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + size_t const len = expected.size(); + stlsoft::auto_buffer buff(len + 1); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(len, cch); + TEST_MS_EQ(expected.c_str(), &buff[0]); + TEST_CHAR_EQ('\0', buff[len]); +} + +static void TEST_EXACT_FIT_w() +{ + std::wstring const expected = obtain_raw_current_process_path_w(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + size_t const len = expected.size(); + stlsoft::auto_buffer buff(len + 1); + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(len, cch); + TEST_WS_EQ(expected.c_str(), &buff[0]); + TEST_CHAR_EQ(L'\0', buff[len]); +} + +static void TEST_EXCESS_SPACE_m() +{ + std::string const expected = obtain_raw_current_process_path_m(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + size_t const len = expected.size(); + stlsoft::auto_buffer buff(len + 64); + + ::memset(&buff[0], '~', buff.size()); + + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(len, cch); + TEST_MS_EQ(expected.c_str(), &buff[0]); + TEST_CHAR_EQ('\0', buff[len]); +} + +static void TEST_EXCESS_SPACE_w() +{ + std::wstring const expected = obtain_raw_current_process_path_w(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + size_t const len = expected.size(); + stlsoft::auto_buffer buff(len + 64); + + for (size_t i = 0; i != buff.size(); ++i) + { + buff[i] = L'~'; + } + + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(len, cch); + TEST_WS_EQ(expected.c_str(), &buff[0]); + TEST_CHAR_EQ(L'\0', buff[len]); +} + +static void TEST_INSUFFICIENT_SPACE_m() +{ + std::string const expected = obtain_raw_current_process_path_m(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + size_t const len = expected.size(); + + { + size_t const cchBuff = len; + stlsoft::auto_buffer buff(cchBuff); + + ::memset(&buff[0], '~', buff.size()); + + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(len + 1, cch); + TEST_PTR_EQ(NULL, pFile); + TEST_CHAR_EQ('\0', buff[cchBuff - 1]); + TEST_MS_EQ_N(expected.c_str(), &buff[0], cchBuff - 1); + } + + { + char buff[1] = { '~' }; + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(STLSOFT_NUM_ELEMENTS(buff), buff, &pFile); + + TEST_INT_EQ(len + 1, cch); + TEST_PTR_EQ(NULL, pFile); + TEST_CHAR_EQ('\0', buff[0]); + } +} + +static void TEST_INSUFFICIENT_SPACE_w() +{ + std::wstring const expected = obtain_raw_current_process_path_w(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + size_t const len = expected.size(); + + { + size_t const cchBuff = len; + stlsoft::auto_buffer buff(cchBuff); + + for (size_t i = 0; i != buff.size(); ++i) + { + buff[i] = L'~'; + } + + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(len + 1, cch); + TEST_PTR_EQ(NULL, pFile); + TEST_CHAR_EQ(L'\0', buff[cchBuff - 1]); + TEST_WS_EQ_N(expected.c_str(), &buff[0], cchBuff - 1); + } + + { + wchar_t buff[1] = { L'~' }; + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(STLSOFT_NUM_ELEMENTS(buff), buff, &pFile); + + TEST_INT_EQ(len + 1, cch); + TEST_PTR_EQ(NULL, pFile); + TEST_CHAR_EQ(L'\0', buff[0]); + } +} + +static void TEST_ppFile_NULL_ON_SUCCESS_m() +{ + std::string const expected = obtain_raw_current_process_path_m(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer buff(expected.size() + 1); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], NULL); + + TEST_INT_EQ(expected.size(), cch); + TEST_MS_EQ(expected.c_str(), &buff[0]); +} + +static void TEST_ppFile_NULL_ON_SUCCESS_w() +{ + std::wstring const expected = obtain_raw_current_process_path_w(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer buff(expected.size() + 1); + size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], NULL); + + TEST_INT_EQ(expected.size(), cch); + TEST_WS_EQ(expected.c_str(), &buff[0]); +} + +static void TEST_ppFile_separator_ON_SUCCESS_m() +{ + std::string const expected = obtain_raw_current_process_path_m(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer buff(expected.size() + 1); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(expected.size(), cch); + TEST_MS_EQ(expected.c_str(), &buff[0]); + + char* const expectedSep = find_last_path_name_separator(&buff[0]); + + TEST_PTR_EQ(expectedSep, pFile); + + if (NULL != pFile) + { + TEST_MS_EQ(expectedSep + 1, pFile + 1); + } +} + +static void TEST_ppFile_separator_ON_SUCCESS_w() +{ + std::wstring const expected = obtain_raw_current_process_path_w(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer buff(expected.size() + 1); + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(expected.size(), cch); + TEST_WS_EQ(expected.c_str(), &buff[0]); + + wchar_t* const expectedSep = find_last_path_name_separator(&buff[0]); + + TEST_PTR_EQ(expectedSep, pFile); + + if (NULL != pFile) + { + TEST_WS_EQ(expectedSep + 1, pFile + 1); + } +} + +static void TEST_ppFile_NULL_WHEN_INSUFFICIENT_m() +{ + std::string const expected = obtain_raw_current_process_path_m(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + size_t const len = expected.size(); + stlsoft::auto_buffer buff(len); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(len + 1, cch); + TEST_PTR_EQ(NULL, pFile); +} + +static void TEST_ppFile_NULL_WHEN_INSUFFICIENT_w() +{ + std::wstring const expected = obtain_raw_current_process_path_w(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + size_t const len = expected.size(); + stlsoft::auto_buffer buff(len); + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); + + TEST_INT_EQ(len + 1, cch); + TEST_PTR_EQ(NULL, pFile); +} +} // anonymous namespace + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/versions/entry.cpp b/test/unit/versions/entry.cpp index 4f1128d1..1ada7df0 100644 --- a/test/unit/versions/entry.cpp +++ b/test/unit/versions/entry.cpp @@ -133,7 +133,7 @@ namespace { static void TEST__STLSOFT_VER() { - TEST_INT_EQ(_STLSOFT_VER_1_11_1_RC8, _STLSOFT_VER); + TEST_INT_EQ(_STLSOFT_VER_1_11_1_RC9, _STLSOFT_VER); } #ifdef STLSOFT_HAS_ACE @@ -160,7 +160,7 @@ static void TEST__PLATFORMSTL_VER() static void TEST__UNIXSTL_VER() { - TEST_INT_EQ(_UNIXSTL_VER_1_8_6_B07, _UNIXSTL_VER); + TEST_INT_EQ(_UNIXSTL_VER_1_8_6_B08, _UNIXSTL_VER); } #elif defined(PLATFORMSTL_OS_IS_WINDOWS) @@ -171,7 +171,7 @@ static void TEST__COMSTL_VER() static void TEST__WINSTL_VER() { - TEST_INT_EQ(_WINSTL_VER_1_13_0_B04, _WINSTL_VER); + TEST_INT_EQ(_WINSTL_VER_1_13_0_B05, _WINSTL_VER); } #endif #ifdef STLSOFT_HAS_MFC From 1332a820ab5d217ac544b89158f76cead75f646c Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 15 Oct 2026 11:30:49 +1100 Subject: [PATCH 20/31] feature(get_current_process_path): WinSTL implementation --- include/unixstl/system/system_traits.hpp | 4 +- include/winstl/system/system_traits.hpp | 52 +++++++++++++----------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/include/unixstl/system/system_traits.hpp b/include/unixstl/system/system_traits.hpp index 44b215be..2e9edda4 100644 --- a/include/unixstl/system/system_traits.hpp +++ b/include/unixstl/system/system_traits.hpp @@ -280,7 +280,7 @@ struct system_traits static size_type get_current_process_path( - size_t cch + size_type cch , char_type buff[/* cch */] , char_type** ppFile ) STLSOFT_NOEXCEPT; @@ -620,7 +620,7 @@ struct system_traits static size_type get_current_process_path( - size_t cch + size_type cch , char_type buff[/* cch */] , char_type** ppFile ) STLSOFT_NOEXCEPT diff --git a/include/winstl/system/system_traits.hpp b/include/winstl/system/system_traits.hpp index 47dfc575..33088670 100644 --- a/include/winstl/system/system_traits.hpp +++ b/include/winstl/system/system_traits.hpp @@ -104,6 +104,10 @@ # include #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_RESIZEABLE_BUFFER_HELPERS */ +#ifndef WINSTL_INCL_WINSTL_FILESYSTEM_H_PATH_PARSE_FUNCTIONS +# include +#endif /*! WINSTL_INCL_WINSTL_FILESYSTEM_H_PATH_PARSE_FUNCTIONS */ + #if STLSOFT_LEAD_VER >= 0x010a0000 # ifndef WINSTL_INCL_WINSTL_SYSTEM_H_DIRECTORY_FUNCTIONS # include @@ -296,7 +300,7 @@ struct system_traits static size_type get_current_process_path( - size_t cch + size_type cch , char_type buff[/* cch */] , char_type** ppFile ) STLSOFT_NOEXCEPT; @@ -768,28 +772,29 @@ struct system_traits static size_type get_current_process_path( - size_t cch + size_type cch , char_type buff[/* cch */] , char_type** ppFile ) STLSOFT_NOEXCEPT { WINSTL_ASSERT(0 == cch || NULL != buff); - char_type* dummy; - - if (NULL == ppFile) + if (NULL != ppFile) { - ppFile = &dummy; + *ppFile = NULL; } - *ppFile = NULL; - - - ((void)cch); - ((void)buff); + size_type const n = class_type::GetModuleFileNameA(NULL, buff, cch); + if (n < cch) + { + if (NULL != ppFile) + { + *ppFile = const_cast(winstl_C_find_last_path_name_separator_len_m(buff, n)); + } + } - return 0; + return n; } public: @@ -1417,28 +1422,29 @@ struct system_traits static size_type get_current_process_path( - size_t cch + size_type cch , char_type buff[/* cch */] , char_type** ppFile ) STLSOFT_NOEXCEPT { WINSTL_ASSERT(0 == cch || NULL != buff); - char_type* dummy; - - if (NULL == ppFile) + if (NULL != ppFile) { - ppFile = &dummy; + *ppFile = NULL; } - *ppFile = NULL; - - - ((void)cch); - ((void)buff); + size_type const n = class_type::GetModuleFileNameW(NULL, buff, cch); + if (n < cch) + { + if (NULL != ppFile) + { + *ppFile = const_cast(winstl_C_find_last_path_name_separator_len_w(buff, n)); + } + } - return 0; + return n; } public: From 9ad41691d9c444714210c58e35c6c254e03961eb Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 15 Oct 2026 11:48:55 +1100 Subject: [PATCH 21/31] tidying --- .../winstl/api/internal/DynamicLinkLibrary.h | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/winstl/api/internal/DynamicLinkLibrary.h b/include/winstl/api/internal/DynamicLinkLibrary.h index a8aa905b..c1e5787e 100644 --- a/include/winstl/api/internal/DynamicLinkLibrary.h +++ b/include/winstl/api/internal/DynamicLinkLibrary.h @@ -5,11 +5,11 @@ * Library Functions API. * * Created: 30th November 2020 - * Updated: 26th May 2025 + * Updated: 15th October 2026 * * Home: http://stlsoft.org/ * - * Copyright (c) 2020-2025, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2020-2026, Matthew Wilson and Synesis Information Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -79,18 +79,18 @@ * specified module (that must have been loaded by the current process). * * \param hModule A handle to the loaded module for which the path is to be - * obtained; + * obtained; * \param filename A pointer to the buffer into which to write the path. May - * not be NULL unless \c cchFilename is 0; + * not be NULL unless \c cchFilename is 0; * \param cchFilename Number of available bytes in \c filename; * * \return The number of characters written if cchFilename is sufficient to - * hold the entire string; the number of characters required (including for - * terminating NUL character) if not. + * hold the entire string; the number of characters required (including + * for terminating NUL character) if not. * * \note The number of characters required returned is 2 (not 1) more than - * the number of characters in the string, due to the underlying API - * function not providing any direct indication as to (in)sufficient size. + * the number of characters in the string, due to the underlying API + * function not providing any direct indication as to (in)sufficient size. */ STLSOFT_INLINE DWORD @@ -238,18 +238,18 @@ WINSTL_API_INTERNAL_DynamicLinkLibrary_GetModuleFileNameA( * specified module (that must have been loaded by the current process). * * \param hModule A handle to the loaded module for which the path is to be - * obtained; + * obtained; * \param filename A pointer to the buffer into which to write the path. May - * not be NULL unless \c cchFilename is 0; + * not be NULL unless \c cchFilename is 0; * \param cchFilename Number of available characters in \c filename; * * \return The number of characters written if cchFilename is sufficient to - * hold the entire string; the number of characters required (including for - * terminating NUL character) if not. + * hold the entire string; the number of characters required (including + * for terminating NUL character) if not. * * \note The number of characters required returned is 2 (not 1) more than - * the number of characters in the string, due to the underlying API - * function not providing any direct indication as to (in)sufficient size. + * the number of characters in the string, due to the underlying API + * function not providing any direct indication as to (in)sufficient size. */ STLSOFT_INLINE DWORD From 76878c0c0e889798316ff574ee6507673cbaaac7 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 15 Oct 2026 12:01:23 +1100 Subject: [PATCH 22/31] docs(stlsoft): clarify get_current_process_path size-query contract Document that insufficient-buffer returns are at least path length + 1 (and may be larger); note the allocate-then-retry client pattern. Add a WinSTL-only caveat against sizing from a presumed path length; guard ppFile updates with a non-zero GMFN result; align winstl process_paths tests with size-query-then-allocate and GE checks. --- include/unixstl/system/system_traits.hpp | 16 ++-- include/winstl/system/system_traits.hpp | 27 ++++-- .../winstl/system/process_paths/entry.cpp | 93 ++++++++++++------- 3 files changed, 86 insertions(+), 50 deletions(-) diff --git a/include/unixstl/system/system_traits.hpp b/include/unixstl/system/system_traits.hpp index 2e9edda4..001d557b 100644 --- a/include/unixstl/system/system_traits.hpp +++ b/include/unixstl/system/system_traits.hpp @@ -55,8 +55,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_MAJOR 6 # define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_MINOR 3 -# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 1 -# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 142 +# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 2 +# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 143 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -267,14 +267,16 @@ struct system_traits /// /// \return If \c buff is sufficient for the full path and a terminating /// NUL character then this returns the length of the path (excluding - /// the NUL character); otherwise, as much of the result as can be - /// written is done so and the full length + 1 (for the NUL character) - /// is returned, in order that client code can allocate all required - /// space. + /// the NUL character). Otherwise, as much of the result as can be + /// written is done so and a character count of at least the + /// full length + 1 (for the NUL character) is returned, in order that + /// client code can allocate all required space. The returned demand + /// may exceed that minimum; /// \retval 0 The function failed, and more information can be obtained /// from get_last_error(); /// - /// \note + /// \note The normative client pattern is to call with \c cch of 0 to + /// obtain a sufficient size, allocate, then call again. /// /// \pre 0 == cch || nullptr != buff static diff --git a/include/winstl/system/system_traits.hpp b/include/winstl/system/system_traits.hpp index 33088670..47a10769 100644 --- a/include/winstl/system/system_traits.hpp +++ b/include/winstl/system/system_traits.hpp @@ -58,8 +58,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_MAJOR 6 # define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_MINOR 1 -# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 1 -# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 172 +# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 3 +# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 174 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -287,14 +287,21 @@ struct system_traits /// /// \return If \c buff is sufficient for the full path and a terminating /// NUL character then this returns the length of the path (excluding - /// the NUL character); otherwise, as much of the result as can be - /// written is done so and the full length + 1 (for the NUL character) - /// is returned, in order that client code can allocate all required - /// space. + /// the NUL character). Otherwise, as much of the result as can be + /// written is done so and a character count of at least the + /// full length + 1 (for the NUL character) is returned, in order that + /// client code can allocate all required space. The returned demand + /// may exceed that minimum; /// \retval 0 The function failed, and more information can be obtained /// from get_last_error(); /// - /// \note + /// \note The normative client pattern is to call with \c cch of 0 to + /// obtain a sufficient size, allocate, then call again. + /// + /// \note Due to idiosynchracies of the Windows API, you must use the + /// the function to query the required length, or pass PATH_MAX, and + /// not rely on any a priori knowledge you may have of the presumed + /// process path length. /// /// \pre 0 == cch || nullptr != buff static @@ -786,7 +793,8 @@ struct system_traits size_type const n = class_type::GetModuleFileNameA(NULL, buff, cch); - if (n < cch) + if (0 != n && + n < cch) { if (NULL != ppFile) { @@ -1436,7 +1444,8 @@ struct system_traits size_type const n = class_type::GetModuleFileNameW(NULL, buff, cch); - if (n < cch) + if (0 != n && + n < cch) { if (NULL != ppFile) { diff --git a/test/component/winstl/system/process_paths/entry.cpp b/test/component/winstl/system/process_paths/entry.cpp index 4011e540..b3287fbd 100644 --- a/test/component/winstl/system/process_paths/entry.cpp +++ b/test/component/winstl/system/process_paths/entry.cpp @@ -49,8 +49,8 @@ namespace { static void TEST_SIZE_QUERY_m(); static void TEST_SIZE_QUERY_w(); - static void TEST_EXACT_FIT_m(); - static void TEST_EXACT_FIT_w(); + static void TEST_SIZE_THEN_SUFFICIENT_m(); + static void TEST_SIZE_THEN_SUFFICIENT_w(); static void TEST_EXCESS_SPACE_m(); static void TEST_EXCESS_SPACE_w(); static void TEST_INSUFFICIENT_SPACE_m(); @@ -79,8 +79,8 @@ int main(int argc, char* argv[]) { XTESTS_RUN_CASE(TEST_SIZE_QUERY_m); XTESTS_RUN_CASE(TEST_SIZE_QUERY_w); - XTESTS_RUN_CASE(TEST_EXACT_FIT_m); - XTESTS_RUN_CASE(TEST_EXACT_FIT_w); + XTESTS_RUN_CASE(TEST_SIZE_THEN_SUFFICIENT_m); + XTESTS_RUN_CASE(TEST_SIZE_THEN_SUFFICIENT_w); XTESTS_RUN_CASE(TEST_EXCESS_SPACE_m); XTESTS_RUN_CASE(TEST_EXCESS_SPACE_w); XTESTS_RUN_CASE(TEST_INSUFFICIENT_SPACE_m); @@ -225,7 +225,8 @@ static void TEST_SIZE_QUERY_m() char* pFile = invalid_file_pointer(); size_t const cch = traits_m_t::get_current_process_path(0, NULL, &pFile); - TEST_INT_EQ(expected.size() + 1, cch); + /* Demand may exceed len+1 (WinSTL GetModuleFileName size protocol). */ + TEST_INT_GE(expected.size() + 1, cch); TEST_PTR_EQ(NULL, pFile); } @@ -238,36 +239,44 @@ static void TEST_SIZE_QUERY_w() wchar_t* pFile = invalid_file_pointer(); size_t const cch = traits_w_t::get_current_process_path(0, NULL, &pFile); - TEST_INT_EQ(expected.size() + 1, cch); + TEST_INT_GE(expected.size() + 1, cch); TEST_PTR_EQ(NULL, pFile); } -static void TEST_EXACT_FIT_m() +static void TEST_SIZE_THEN_SUFFICIENT_m() { std::string const expected = obtain_raw_current_process_path_m(); XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); - size_t const len = expected.size(); - stlsoft::auto_buffer buff(len + 1); - char* pFile = invalid_file_pointer(); - size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + size_t const len = expected.size(); + size_t const need = traits_m_t::get_current_process_path(0, NULL, NULL); + + XTESTS_REQUIRE(TEST_INT_GE(len + 1, need)); + + stlsoft::auto_buffer buff(need); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); TEST_INT_EQ(len, cch); TEST_MS_EQ(expected.c_str(), &buff[0]); TEST_CHAR_EQ('\0', buff[len]); } -static void TEST_EXACT_FIT_w() +static void TEST_SIZE_THEN_SUFFICIENT_w() { std::wstring const expected = obtain_raw_current_process_path_w(); XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); - size_t const len = expected.size(); - stlsoft::auto_buffer buff(len + 1); - wchar_t* pFile = invalid_file_pointer(); - size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); + size_t const len = expected.size(); + size_t const need = traits_w_t::get_current_process_path(0, NULL, NULL); + + XTESTS_REQUIRE(TEST_INT_GE(len + 1, need)); + + stlsoft::auto_buffer buff(need); + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); TEST_INT_EQ(len, cch); TEST_WS_EQ(expected.c_str(), &buff[0]); @@ -332,7 +341,7 @@ static void TEST_INSUFFICIENT_SPACE_m() char* pFile = invalid_file_pointer(); size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); - TEST_INT_EQ(len + 1, cch); + TEST_INT_GE(len + 1, cch); TEST_PTR_EQ(NULL, pFile); TEST_CHAR_EQ('\0', buff[cchBuff - 1]); TEST_MS_EQ_N(expected.c_str(), &buff[0], cchBuff - 1); @@ -343,7 +352,7 @@ static void TEST_INSUFFICIENT_SPACE_m() char* pFile = invalid_file_pointer(); size_t const cch = traits_m_t::get_current_process_path(STLSOFT_NUM_ELEMENTS(buff), buff, &pFile); - TEST_INT_EQ(len + 1, cch); + TEST_INT_GE(len + 1, cch); TEST_PTR_EQ(NULL, pFile); TEST_CHAR_EQ('\0', buff[0]); } @@ -369,7 +378,7 @@ static void TEST_INSUFFICIENT_SPACE_w() wchar_t* pFile = invalid_file_pointer(); size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); - TEST_INT_EQ(len + 1, cch); + TEST_INT_GE(len + 1, cch); TEST_PTR_EQ(NULL, pFile); TEST_CHAR_EQ(L'\0', buff[cchBuff - 1]); TEST_WS_EQ_N(expected.c_str(), &buff[0], cchBuff - 1); @@ -380,7 +389,7 @@ static void TEST_INSUFFICIENT_SPACE_w() wchar_t* pFile = invalid_file_pointer(); size_t const cch = traits_w_t::get_current_process_path(STLSOFT_NUM_ELEMENTS(buff), buff, &pFile); - TEST_INT_EQ(len + 1, cch); + TEST_INT_GE(len + 1, cch); TEST_PTR_EQ(NULL, pFile); TEST_CHAR_EQ(L'\0', buff[0]); } @@ -392,7 +401,11 @@ static void TEST_ppFile_NULL_ON_SUCCESS_m() XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); - stlsoft::auto_buffer buff(expected.size() + 1); + size_t const need = traits_m_t::get_current_process_path(0, NULL, NULL); + + XTESTS_REQUIRE(TEST_INT_GE(expected.size() + 1, need)); + + stlsoft::auto_buffer buff(need); size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], NULL); TEST_INT_EQ(expected.size(), cch); @@ -405,7 +418,11 @@ static void TEST_ppFile_NULL_ON_SUCCESS_w() XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); - stlsoft::auto_buffer buff(expected.size() + 1); + size_t const need = traits_w_t::get_current_process_path(0, NULL, NULL); + + XTESTS_REQUIRE(TEST_INT_GE(expected.size() + 1, need)); + + stlsoft::auto_buffer buff(need); size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], NULL); TEST_INT_EQ(expected.size(), cch); @@ -418,9 +435,13 @@ static void TEST_ppFile_separator_ON_SUCCESS_m() XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); - stlsoft::auto_buffer buff(expected.size() + 1); - char* pFile = invalid_file_pointer(); - size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + size_t const need = traits_m_t::get_current_process_path(0, NULL, NULL); + + XTESTS_REQUIRE(TEST_INT_GE(expected.size() + 1, need)); + + stlsoft::auto_buffer buff(need); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); TEST_INT_EQ(expected.size(), cch); TEST_MS_EQ(expected.c_str(), &buff[0]); @@ -441,9 +462,13 @@ static void TEST_ppFile_separator_ON_SUCCESS_w() XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); - stlsoft::auto_buffer buff(expected.size() + 1); - wchar_t* pFile = invalid_file_pointer(); - size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); + size_t const need = traits_w_t::get_current_process_path(0, NULL, NULL); + + XTESTS_REQUIRE(TEST_INT_GE(expected.size() + 1, need)); + + stlsoft::auto_buffer buff(need); + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); TEST_INT_EQ(expected.size(), cch); TEST_WS_EQ(expected.c_str(), &buff[0]); @@ -466,10 +491,10 @@ static void TEST_ppFile_NULL_WHEN_INSUFFICIENT_m() size_t const len = expected.size(); stlsoft::auto_buffer buff(len); - char* pFile = invalid_file_pointer(); - size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); - TEST_INT_EQ(len + 1, cch); + TEST_INT_GE(len + 1, cch); TEST_PTR_EQ(NULL, pFile); } @@ -481,10 +506,10 @@ static void TEST_ppFile_NULL_WHEN_INSUFFICIENT_w() size_t const len = expected.size(); stlsoft::auto_buffer buff(len); - wchar_t* pFile = invalid_file_pointer(); - size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); - TEST_INT_EQ(len + 1, cch); + TEST_INT_GE(len + 1, cch); TEST_PTR_EQ(NULL, pFile); } } // anonymous namespace From 2ea0facaa2d2b2418dca44ca46a9b13f68154cd0 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 15 Oct 2026 12:31:49 +1100 Subject: [PATCH 23/31] feat(unixstl): add get_current_process_path C API and traits wrap Add unixstl_C_get_current_process_path_m() with per-Unix image-path backends and len / len+1 size protocol; implement system_traits::get_current_process_path() as a thin wrap with ppFile separator handling, matching WinSTL. --- include/unixstl/process/functions.h | 399 ++++++++++++++++++++++- include/unixstl/system/system_traits.hpp | 32 +- 2 files changed, 406 insertions(+), 25 deletions(-) diff --git a/include/unixstl/process/functions.h b/include/unixstl/process/functions.h index ddf65e78..23f573bd 100644 --- a/include/unixstl/process/functions.h +++ b/include/unixstl/process/functions.h @@ -4,7 +4,7 @@ * Purpose: Process functions. * * Created: 8th October 2026 - * Updated: 8th October 2026 + * Updated: 15th October 2026 * * Home: http://stlsoft.org/ * @@ -51,9 +51,9 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_MAJOR 1 -# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_MINOR 0 +# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_MINOR 1 # define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_REVISION 1 -# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_EDIT 1 +# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_EDIT 2 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -68,17 +68,78 @@ # pragma message(__FILE__) #endif /* STLSOFT_TRACE_INCLUDE */ +#ifndef STLSOFT_INCL_H_ERRNO +# define STLSOFT_INCL_H_ERRNO +# include +#endif /* !STLSOFT_INCL_H_ERRNO */ +#ifndef STLSOFT_INCL_H_LIMITS +# define STLSOFT_INCL_H_LIMITS +# include +#endif /* !STLSOFT_INCL_H_LIMITS */ +#ifndef STLSOFT_INCL_H_STDLIB +# define STLSOFT_INCL_H_STDLIB +# include +#endif /* !STLSOFT_INCL_H_STDLIB */ +#ifndef STLSOFT_INCL_H_STRING +# define STLSOFT_INCL_H_STRING +# include +#endif /* !STLSOFT_INCL_H_STRING */ + #if 0 -#elif defined(_WIN32) &&\ - ( 0 ||\ - defined(STLSOFT_COMPILER_IS_MSVC) ||\ - defined(STLSOFT_COMPILER_IS_INTEL) ||\ - 0) +#elif defined(_WIN32) + +# ifndef WINSTL_INCL_WINSTL_API_external_h_DynamicLinkLibrary +# include +# endif /* !WINSTL_INCL_WINSTL_API_external_h_DynamicLinkLibrary */ # ifndef STLSOFT_INCL_H_PROCESS # define STLSOFT_INCL_H_PROCESS # include # endif /* !STLSOFT_INCL_H_PROCESS */ +# ifndef STLSOFT_INCL_H_WINDOWS +# define STLSOFT_INCL_H_WINDOWS +# include +# endif /* !STLSOFT_INCL_H_WINDOWS */ +#elif defined(__APPLE__) + +# ifndef STLSOFT_INCL_H_LIBPROC +# define STLSOFT_INCL_H_LIBPROC +# include +# endif /* !STLSOFT_INCL_H_LIBPROC */ +# ifndef STLSOFT_INCL_MACH_O_H_DYLD +# define STLSOFT_INCL_MACH_O_H_DYLD +# include +# endif /* !STLSOFT_INCL_MACH_O_H_DYLD */ +# ifndef STLSOFT_INCL_H_UNISTD +# define STLSOFT_INCL_H_UNISTD +# include +# endif /* !STLSOFT_INCL_H_UNISTD */ +#elif defined(__linux__) + +# ifndef STLSOFT_INCL_H_UNISTD +# define STLSOFT_INCL_H_UNISTD +# include +# endif /* !STLSOFT_INCL_H_UNISTD */ +#elif 0 ||\ + defined(__FreeBSD__) ||\ + defined(__NetBSD__) ||\ + defined(__OpenBSD__) ||\ + 0 + +# ifndef STLSOFT_INCL_SYS_H_SYSCTL +# define STLSOFT_INCL_SYS_H_SYSCTL +# include +# endif /* !STLSOFT_INCL_SYS_H_SYSCTL */ +# ifndef STLSOFT_INCL_SYS_H_TYPES +# define STLSOFT_INCL_SYS_H_TYPES +# include +# endif /* !STLSOFT_INCL_SYS_H_TYPES */ +#elif defined(__sun) + +# ifndef STLSOFT_INCL_H_UNISTD +# define STLSOFT_INCL_H_UNISTD +# include +# endif /* !STLSOFT_INCL_H_UNISTD */ #else # ifndef STLSOFT_INCL_SYS_H_TYPES @@ -128,11 +189,7 @@ int unixstl_C_get_current_process_id(void) { #if 0 -#elif defined(_WIN32) && \ - ( 0 ||\ - defined(STLSOFT_COMPILER_IS_MSVC) ||\ - defined(STLSOFT_COMPILER_IS_INTEL) ||\ - 0) +#elif defined(_WIN32) return STLSOFT_NS_GLOBAL(_getpid)(); #else @@ -143,6 +200,322 @@ unixstl_C_get_current_process_id(void) #endif } +/** \brief Obtains the fully qualified path of the current process image + * (multibyte). + * + * \ingroup group__library__System + * + * \param buff Destination buffer. May be \c NULL if and only if \c cch is + * 0; + * \param cch Number of characters available in \c buff, including space for + * a terminating NUL; + * + * \return If \c buff is sufficient for the full path and a terminating NUL + * character then this returns the length of the path (excluding the NUL + * character). Otherwise, as much of the result as can be written is done + * so and a character count of at least the full length + 1 (for + * the NUL character) is returned. The returned demand may exceed that + * minimum. Returns 0 on failure; + * + * \pre 0 == cch || NULL != buff + * + * \note The normative client pattern is to call with \c cch of 0 to obtain + * a sufficient size, allocate, then call again. + */ +STLSOFT_INLINE +us_size_t +unixstl_C_get_current_process_path_m( + us_char_a_t* buff +, us_size_t cch +) +{ +#if !defined(PATH_MAX) + us_char_a_t stack[4096]; +#else + us_char_a_t stack[PATH_MAX]; +#endif + us_char_a_t* path = &stack[0]; + us_char_a_t* heap = NULL; + us_size_t cap = STLSOFT_NUM_ELEMENTS(stack); + us_size_t len = 0; + us_size_t result; + + UNIXSTL_ASSERT(0 == cch || NULL != buff); + +#if 0 +#elif defined(_WIN32) + + /* NOTE: this only for UNIXem-ulation, so we don't care about its + * performance + */ + + /* Windows / UNIXem: GetModuleFileNameA */ + for (;;) + { + DWORD const n = WINSTL_API_EXTERNAL_DynamicLinkLibrary_GetModuleFileNameA(NULL, path, STLSOFT_STATIC_CAST(DWORD, cap)); + + if (0 == n) + { + if (NULL != heap) + { + STLSOFT_NS_GLOBAL(free)(heap); + } + + return 0; + } + + if (n < cap) + { + len = STLSOFT_STATIC_CAST(us_size_t, n); + break; + } + + { + us_size_t const newCap = cap * 2; + us_char_a_t* const newHeap = STLSOFT_STATIC_CAST(us_char_a_t*, STLSOFT_NS_GLOBAL(realloc)(heap, newCap * sizeof(us_char_a_t))); + + if (NULL == newHeap) + { + if (NULL != heap) + { + STLSOFT_NS_GLOBAL(free)(heap); + } + + errno = ENOMEM; + + return 0; + } + + heap = newHeap; + path = heap; + cap = newCap; + } + } +#elif defined(__APPLE__) + + /* macOS: prefer proc_pidpath; fallback to _NSGetExecutablePath (+ realpath). */ + { + int const ret = STLSOFT_NS_GLOBAL(proc_pidpath)(STLSOFT_NS_GLOBAL(getpid)(), path, STLSOFT_STATIC_CAST(uint32_t, cap)); + + if (ret <= 0) + { + uint32_t size = STLSOFT_STATIC_CAST(uint32_t, cap); + + if (0 != STLSOFT_NS_GLOBAL(_NSGetExecutablePath)(path, &size)) + { + us_char_a_t* const newHeap = STLSOFT_STATIC_CAST(us_char_a_t*, STLSOFT_NS_GLOBAL(malloc)(size * sizeof(us_char_a_t))); + + if (NULL == newHeap) + { + errno = ENOMEM; + + return 0; + } + + heap = newHeap; + path = heap; + cap = size; + + if (0 != STLSOFT_NS_GLOBAL(_NSGetExecutablePath)(path, &size)) + { + STLSOFT_NS_GLOBAL(free)(heap); + + return 0; + } + } + + { + char* const resolved = STLSOFT_NS_GLOBAL(realpath)(path, NULL); + + if (NULL != resolved) + { + us_size_t const cchResolved = STLSOFT_NS_GLOBAL(strlen)(resolved); + + if (cchResolved + 1 > cap) + { + us_char_a_t* const newHeap = STLSOFT_STATIC_CAST(us_char_a_t*, STLSOFT_NS_GLOBAL(realloc)(heap, (cchResolved + 1) * sizeof(us_char_a_t))); + + if (NULL == newHeap) + { + STLSOFT_NS_GLOBAL(free)(resolved); + if (NULL != heap) + { + STLSOFT_NS_GLOBAL(free)(heap); + } + + errno = ENOMEM; + + return 0; + } + + heap = newHeap; + path = heap; + cap = cchResolved + 1; + } + + STLSOFT_NS_GLOBAL(memcpy)(path, resolved, cchResolved + 1); + STLSOFT_NS_GLOBAL(free)(resolved); + } + } + } + + len = STLSOFT_NS_GLOBAL(strlen)(path); + } +#elif defined(__linux__) + + /* Linux: readlink("/proc/self/exe") */ + for (;;) + { + ssize_t const n = STLSOFT_NS_GLOBAL(readlink)("/proc/self/exe", path, cap); + + if (n < 0) + { + if (NULL != heap) + { + STLSOFT_NS_GLOBAL(free)(heap); + } + + return 0; + } + + if (STLSOFT_STATIC_CAST(us_size_t, n) < cap) + { + path[n] = '\0'; + len = STLSOFT_STATIC_CAST(us_size_t, n); + break; + } + + { + us_size_t const newCap = cap * 2; + us_char_a_t* const newHeap = STLSOFT_STATIC_CAST(us_char_a_t*, STLSOFT_NS_GLOBAL(realloc)(heap, newCap * sizeof(us_char_a_t))); + + if (NULL == newHeap) + { + if (NULL != heap) + { + STLSOFT_NS_GLOBAL(free)(heap); + } + + errno = ENOMEM; + + return 0; + } + + heap = newHeap; + path = heap; + cap = newCap; + } + } +#elif 0 ||\ + defined(__FreeBSD__) ||\ + defined(__NetBSD__) ||\ + defined(__OpenBSD__) ||\ + 0 + + /* BSD: sysctl(KERN_PROC_PATHNAME) */ + { + int mib[4]; + size_t cb = cap; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + + if (0 != STLSOFT_NS_GLOBAL(sysctl)(mib, 4, path, &cb, NULL, 0)) + { + if (ENOMEM == errno) + { + us_char_a_t* const newHeap = STLSOFT_STATIC_CAST(us_char_a_t*, STLSOFT_NS_GLOBAL(malloc)(cb)); + + if (NULL == newHeap) + { + errno = ENOMEM; + + return 0; + } + + heap = newHeap; + path = heap; + cap = cb; + + if (0 != STLSOFT_NS_GLOBAL(sysctl)(mib, 4, path, &cb, NULL, 0)) + { + STLSOFT_NS_GLOBAL(free)(heap); + + return 0; + } + } + else + { + return 0; + } + } + + len = STLSOFT_NS_GLOBAL(strlen)(path); + } +#elif defined(__sun) + + /* Solaris: getexecname() + realpath() */ + { + char const* const exe = STLSOFT_NS_GLOBAL(getexecname)(); + + if (NULL == exe) + { + return 0; + } + + if (NULL == STLSOFT_NS_GLOBAL(realpath)(exe, path)) + { + return 0; + } + + len = STLSOFT_NS_GLOBAL(strlen)(path); + } +#else + + STLSOFT_SUPPRESS_UNUSED(path); + STLSOFT_SUPPRESS_UNUSED(cap); + errno = ENOSYS; + + return 0; +#endif + + if (0 == cch) + { + result = len + 1; + } + else if (cch <= len) + { + us_size_t const nCopy = cch - 1; + + if (0 != nCopy) + { + STLSOFT_NS_GLOBAL(memcpy)(buff, path, nCopy * sizeof(us_char_a_t)); + } + + buff[nCopy] = '\0'; + result = len + 1; + } + else + { + if (0 != len) + { + STLSOFT_NS_GLOBAL(memcpy)(buff, path, len * sizeof(us_char_a_t)); + } + + buff[len] = '\0'; + result = len; + } + + if (NULL != heap) + { + STLSOFT_NS_GLOBAL(free)(heap); + } + + return result; +} + /* ///////////////////////////////////////////////////////////////////////// * namespace diff --git a/include/unixstl/system/system_traits.hpp b/include/unixstl/system/system_traits.hpp index 001d557b..fe0cf5e8 100644 --- a/include/unixstl/system/system_traits.hpp +++ b/include/unixstl/system/system_traits.hpp @@ -55,8 +55,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_MAJOR 6 # define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_MINOR 3 -# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 2 -# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 143 +# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 3 +# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 144 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -71,6 +71,12 @@ # pragma message(__FILE__) #endif /* STLSOFT_TRACE_INCLUDE */ +#ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_H_PATH_PARSE_FUNCTIONS +# include +#endif /* !UNIXSTL_INCL_UNIXSTL_FILESYSTEM_H_PATH_PARSE_FUNCTIONS */ +#ifndef UNIXSTL_INCL_UNIXSTL_PROCESS_H_FUNCTIONS +# include +#endif /* !UNIXSTL_INCL_UNIXSTL_PROCESS_H_FUNCTIONS */ #ifndef UNIXSTL_INCL_UNIXSTL_SYSTEM_H_DIRECTORY_FUNCTIONS # include #endif /* !UNIXSTL_INCL_UNIXSTL_SYSTEM_H_DIRECTORY_FUNCTIONS */ @@ -629,21 +635,23 @@ struct system_traits { UNIXSTL_ASSERT(0 == cch || NULL != buff); - char_type* dummy; - - if (NULL == ppFile) + if (NULL != ppFile) { - ppFile = &dummy; + *ppFile = NULL; } - *ppFile = NULL; - - - ((void)cch); - ((void)buff); + size_type const n = unixstl_C_get_current_process_path_m(buff, cch); + if (0 != n && + n < cch) + { + if (NULL != ppFile) + { + *ppFile = const_cast(unixstl_C_find_last_path_name_separator_len_m(buff, n)); + } + } - return 0; + return n; } public: From ee3ed426821f92acdddc3c5090ce3ad08168986a Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 15 Oct 2026 12:36:05 +1100 Subject: [PATCH 24/31] refactor(unixstl): use C auto_buffer for process path growth Replace manual realloc/free grow loops in unixstl_C_get_current_process_path_m with STLSOFT_C_AUTO_BUFFER_*; keep WINSTL_API_EXTERNAL GetModuleFileNameA for the UNIXem path. --- include/unixstl/process/functions.h | 193 ++++++++++++---------------- 1 file changed, 85 insertions(+), 108 deletions(-) diff --git a/include/unixstl/process/functions.h b/include/unixstl/process/functions.h index 23f573bd..9fbfd218 100644 --- a/include/unixstl/process/functions.h +++ b/include/unixstl/process/functions.h @@ -52,8 +52,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_MAJOR 1 # define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_MINOR 1 -# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_REVISION 1 -# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_EDIT 2 +# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_REVISION 2 +# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_EDIT 3 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -68,6 +68,10 @@ # pragma message(__FILE__) #endif /* STLSOFT_TRACE_INCLUDE */ +#ifndef STLSOFT_INCL_STLSOFT_MEMORY_H_AUTO_BUFFER +# include +#endif /* !STLSOFT_INCL_STLSOFT_MEMORY_H_AUTO_BUFFER */ + #ifndef STLSOFT_INCL_H_ERRNO # define STLSOFT_INCL_H_ERRNO # include @@ -96,10 +100,6 @@ # define STLSOFT_INCL_H_PROCESS # include # endif /* !STLSOFT_INCL_H_PROCESS */ -# ifndef STLSOFT_INCL_H_WINDOWS -# define STLSOFT_INCL_H_WINDOWS -# include -# endif /* !STLSOFT_INCL_H_WINDOWS */ #elif defined(__APPLE__) # ifndef STLSOFT_INCL_H_LIBPROC @@ -153,6 +153,19 @@ #endif +/* ///////////////////////////////////////////////////////////////////////// + * constants + */ + +#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION +# if !defined(PATH_MAX) +# define UNIXSTL_C_GET_CURRENT_PROCESS_PATH_INTERNAL_SIZE_ 4096 +# else +# define UNIXSTL_C_GET_CURRENT_PROCESS_PATH_INTERNAL_SIZE_ PATH_MAX +# endif +#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ + + /* ///////////////////////////////////////////////////////////////////////// * namespace */ @@ -229,19 +242,14 @@ unixstl_C_get_current_process_path_m( , us_size_t cch ) { -#if !defined(PATH_MAX) - us_char_a_t stack[4096]; -#else - us_char_a_t stack[PATH_MAX]; -#endif - us_char_a_t* path = &stack[0]; - us_char_a_t* heap = NULL; - us_size_t cap = STLSOFT_NUM_ELEMENTS(stack); - us_size_t len = 0; - us_size_t result; + STLSOFT_C_AUTO_BUFFER_DECLARE(us_char_a_t, UNIXSTL_C_GET_CURRENT_PROCESS_PATH_INTERNAL_SIZE_, ab); + us_size_t len = 0; + us_size_t result; UNIXSTL_ASSERT(0 == cch || NULL != buff); + STLSOFT_C_AUTO_BUFFER_INITIALISE_FROM_INTERNAL(ab); + #if 0 #elif defined(_WIN32) @@ -252,158 +260,126 @@ unixstl_C_get_current_process_path_m( /* Windows / UNIXem: GetModuleFileNameA */ for (;;) { - DWORD const n = WINSTL_API_EXTERNAL_DynamicLinkLibrary_GetModuleFileNameA(NULL, path, STLSOFT_STATIC_CAST(DWORD, cap)); + DWORD const n = WINSTL_API_EXTERNAL_DynamicLinkLibrary_GetModuleFileNameA( + NULL + , ab.ptr + , STLSOFT_STATIC_CAST(DWORD, ab.size) + ); if (0 == n) { - if (NULL != heap) - { - STLSOFT_NS_GLOBAL(free)(heap); - } + STLSOFT_C_AUTO_BUFFER_FREE(ab); return 0; } - if (n < cap) + if (n < ab.size) { len = STLSOFT_STATIC_CAST(us_size_t, n); break; } + if (0 != STLSOFT_C_AUTO_BUFFER_RESIZE(ab, ab.size * 2)) { - us_size_t const newCap = cap * 2; - us_char_a_t* const newHeap = STLSOFT_STATIC_CAST(us_char_a_t*, STLSOFT_NS_GLOBAL(realloc)(heap, newCap * sizeof(us_char_a_t))); - - if (NULL == newHeap) - { - if (NULL != heap) - { - STLSOFT_NS_GLOBAL(free)(heap); - } + errno = ENOMEM; - errno = ENOMEM; + STLSOFT_C_AUTO_BUFFER_FREE(ab); - return 0; - } - - heap = newHeap; - path = heap; - cap = newCap; + return 0; } } #elif defined(__APPLE__) /* macOS: prefer proc_pidpath; fallback to _NSGetExecutablePath (+ realpath). */ { - int const ret = STLSOFT_NS_GLOBAL(proc_pidpath)(STLSOFT_NS_GLOBAL(getpid)(), path, STLSOFT_STATIC_CAST(uint32_t, cap)); + int const ret = STLSOFT_NS_GLOBAL(proc_pidpath)( + STLSOFT_NS_GLOBAL(getpid)() + , ab.ptr + , STLSOFT_STATIC_CAST(uint32_t, ab.size) + ); if (ret <= 0) { - uint32_t size = STLSOFT_STATIC_CAST(uint32_t, cap); + uint32_t size = STLSOFT_STATIC_CAST(uint32_t, ab.size); - if (0 != STLSOFT_NS_GLOBAL(_NSGetExecutablePath)(path, &size)) + if (0 != STLSOFT_NS_GLOBAL(_NSGetExecutablePath)(ab.ptr, &size)) { - us_char_a_t* const newHeap = STLSOFT_STATIC_CAST(us_char_a_t*, STLSOFT_NS_GLOBAL(malloc)(size * sizeof(us_char_a_t))); - - if (NULL == newHeap) + if (0 != STLSOFT_C_AUTO_BUFFER_RESIZE(ab, size)) { errno = ENOMEM; + STLSOFT_C_AUTO_BUFFER_FREE(ab); + return 0; } - heap = newHeap; - path = heap; - cap = size; + size = STLSOFT_STATIC_CAST(uint32_t, ab.size); - if (0 != STLSOFT_NS_GLOBAL(_NSGetExecutablePath)(path, &size)) + if (0 != STLSOFT_NS_GLOBAL(_NSGetExecutablePath)(ab.ptr, &size)) { - STLSOFT_NS_GLOBAL(free)(heap); + STLSOFT_C_AUTO_BUFFER_FREE(ab); return 0; } } { - char* const resolved = STLSOFT_NS_GLOBAL(realpath)(path, NULL); + char* const resolved = STLSOFT_NS_GLOBAL(realpath)(ab.ptr, NULL); if (NULL != resolved) { us_size_t const cchResolved = STLSOFT_NS_GLOBAL(strlen)(resolved); - if (cchResolved + 1 > cap) + if (cchResolved + 1 > ab.size) { - us_char_a_t* const newHeap = STLSOFT_STATIC_CAST(us_char_a_t*, STLSOFT_NS_GLOBAL(realloc)(heap, (cchResolved + 1) * sizeof(us_char_a_t))); - - if (NULL == newHeap) + if (0 != STLSOFT_C_AUTO_BUFFER_RESIZE(ab, cchResolved + 1)) { STLSOFT_NS_GLOBAL(free)(resolved); - if (NULL != heap) - { - STLSOFT_NS_GLOBAL(free)(heap); - } errno = ENOMEM; + STLSOFT_C_AUTO_BUFFER_FREE(ab); + return 0; } - - heap = newHeap; - path = heap; - cap = cchResolved + 1; } - STLSOFT_NS_GLOBAL(memcpy)(path, resolved, cchResolved + 1); + STLSOFT_NS_GLOBAL(memcpy)(ab.ptr, resolved, cchResolved + 1); STLSOFT_NS_GLOBAL(free)(resolved); } } } - len = STLSOFT_NS_GLOBAL(strlen)(path); + len = STLSOFT_NS_GLOBAL(strlen)(ab.ptr); } #elif defined(__linux__) /* Linux: readlink("/proc/self/exe") */ for (;;) { - ssize_t const n = STLSOFT_NS_GLOBAL(readlink)("/proc/self/exe", path, cap); + ssize_t const n = STLSOFT_NS_GLOBAL(readlink)("/proc/self/exe", ab.ptr, ab.size); if (n < 0) { - if (NULL != heap) - { - STLSOFT_NS_GLOBAL(free)(heap); - } + STLSOFT_C_AUTO_BUFFER_FREE(ab); return 0; } - if (STLSOFT_STATIC_CAST(us_size_t, n) < cap) + if (STLSOFT_STATIC_CAST(us_size_t, n) < ab.size) { - path[n] = '\0'; + ab.ptr[n] = '\0'; len = STLSOFT_STATIC_CAST(us_size_t, n); break; } + if (0 != STLSOFT_C_AUTO_BUFFER_RESIZE(ab, ab.size * 2)) { - us_size_t const newCap = cap * 2; - us_char_a_t* const newHeap = STLSOFT_STATIC_CAST(us_char_a_t*, STLSOFT_NS_GLOBAL(realloc)(heap, newCap * sizeof(us_char_a_t))); - - if (NULL == newHeap) - { - if (NULL != heap) - { - STLSOFT_NS_GLOBAL(free)(heap); - } - - errno = ENOMEM; + errno = ENOMEM; - return 0; - } + STLSOFT_C_AUTO_BUFFER_FREE(ab); - heap = newHeap; - path = heap; - cap = newCap; + return 0; } } #elif 0 ||\ @@ -415,44 +391,44 @@ unixstl_C_get_current_process_path_m( /* BSD: sysctl(KERN_PROC_PATHNAME) */ { int mib[4]; - size_t cb = cap; + size_t cb = ab.size; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PATHNAME; mib[3] = -1; - if (0 != STLSOFT_NS_GLOBAL(sysctl)(mib, 4, path, &cb, NULL, 0)) + if (0 != STLSOFT_NS_GLOBAL(sysctl)(mib, 4, ab.ptr, &cb, NULL, 0)) { if (ENOMEM == errno) { - us_char_a_t* const newHeap = STLSOFT_STATIC_CAST(us_char_a_t*, STLSOFT_NS_GLOBAL(malloc)(cb)); - - if (NULL == newHeap) + if (0 != STLSOFT_C_AUTO_BUFFER_RESIZE(ab, cb)) { errno = ENOMEM; + STLSOFT_C_AUTO_BUFFER_FREE(ab); + return 0; } - heap = newHeap; - path = heap; - cap = cb; + cb = ab.size; - if (0 != STLSOFT_NS_GLOBAL(sysctl)(mib, 4, path, &cb, NULL, 0)) + if (0 != STLSOFT_NS_GLOBAL(sysctl)(mib, 4, ab.ptr, &cb, NULL, 0)) { - STLSOFT_NS_GLOBAL(free)(heap); + STLSOFT_C_AUTO_BUFFER_FREE(ab); return 0; } } else { + STLSOFT_C_AUTO_BUFFER_FREE(ab); + return 0; } } - len = STLSOFT_NS_GLOBAL(strlen)(path); + len = STLSOFT_NS_GLOBAL(strlen)(ab.ptr); } #elif defined(__sun) @@ -462,22 +438,26 @@ unixstl_C_get_current_process_path_m( if (NULL == exe) { + STLSOFT_C_AUTO_BUFFER_FREE(ab); + return 0; } - if (NULL == STLSOFT_NS_GLOBAL(realpath)(exe, path)) + if (NULL == STLSOFT_NS_GLOBAL(realpath)(exe, ab.ptr)) { + STLSOFT_C_AUTO_BUFFER_FREE(ab); + return 0; } - len = STLSOFT_NS_GLOBAL(strlen)(path); + len = STLSOFT_NS_GLOBAL(strlen)(ab.ptr); } #else - STLSOFT_SUPPRESS_UNUSED(path); - STLSOFT_SUPPRESS_UNUSED(cap); errno = ENOSYS; + STLSOFT_C_AUTO_BUFFER_FREE(ab); + return 0; #endif @@ -491,7 +471,7 @@ unixstl_C_get_current_process_path_m( if (0 != nCopy) { - STLSOFT_NS_GLOBAL(memcpy)(buff, path, nCopy * sizeof(us_char_a_t)); + STLSOFT_NS_GLOBAL(memcpy)(buff, ab.ptr, nCopy * sizeof(us_char_a_t)); } buff[nCopy] = '\0'; @@ -501,17 +481,14 @@ unixstl_C_get_current_process_path_m( { if (0 != len) { - STLSOFT_NS_GLOBAL(memcpy)(buff, path, len * sizeof(us_char_a_t)); + STLSOFT_NS_GLOBAL(memcpy)(buff, ab.ptr, len * sizeof(us_char_a_t)); } buff[len] = '\0'; result = len; } - if (NULL != heap) - { - STLSOFT_NS_GLOBAL(free)(heap); - } + STLSOFT_C_AUTO_BUFFER_FREE(ab); return result; } From f0d6424691bfc1072674e5dc2dd156c671dd6a87 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 15 Oct 2026 12:42:04 +1100 Subject: [PATCH 25/31] refactor(unixstl): single-exit cleanup for process path API Collapse repeated FREE+return-0 paths in unixstl_C_get_current_process_path_m onto a goto done label. --- include/unixstl/process/functions.h | 60 +++++++++-------------------- 1 file changed, 18 insertions(+), 42 deletions(-) diff --git a/include/unixstl/process/functions.h b/include/unixstl/process/functions.h index 9fbfd218..530b2f49 100644 --- a/include/unixstl/process/functions.h +++ b/include/unixstl/process/functions.h @@ -52,8 +52,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_MAJOR 1 # define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_MINOR 1 -# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_REVISION 2 -# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_EDIT 3 +# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_REVISION 3 +# define UNIXSTL_VER_UNIXSTL_PROCESS_H_FUNCTIONS_EDIT 4 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -244,7 +244,7 @@ unixstl_C_get_current_process_path_m( { STLSOFT_C_AUTO_BUFFER_DECLARE(us_char_a_t, UNIXSTL_C_GET_CURRENT_PROCESS_PATH_INTERNAL_SIZE_, ab); us_size_t len = 0; - us_size_t result; + us_size_t result = 0; UNIXSTL_ASSERT(0 == cch || NULL != buff); @@ -268,9 +268,7 @@ unixstl_C_get_current_process_path_m( if (0 == n) { - STLSOFT_C_AUTO_BUFFER_FREE(ab); - - return 0; + goto done; } if (n < ab.size) @@ -283,9 +281,7 @@ unixstl_C_get_current_process_path_m( { errno = ENOMEM; - STLSOFT_C_AUTO_BUFFER_FREE(ab); - - return 0; + goto done; } } #elif defined(__APPLE__) @@ -308,18 +304,14 @@ unixstl_C_get_current_process_path_m( { errno = ENOMEM; - STLSOFT_C_AUTO_BUFFER_FREE(ab); - - return 0; + goto done; } size = STLSOFT_STATIC_CAST(uint32_t, ab.size); if (0 != STLSOFT_NS_GLOBAL(_NSGetExecutablePath)(ab.ptr, &size)) { - STLSOFT_C_AUTO_BUFFER_FREE(ab); - - return 0; + goto done; } } @@ -338,9 +330,7 @@ unixstl_C_get_current_process_path_m( errno = ENOMEM; - STLSOFT_C_AUTO_BUFFER_FREE(ab); - - return 0; + goto done; } } @@ -361,9 +351,7 @@ unixstl_C_get_current_process_path_m( if (n < 0) { - STLSOFT_C_AUTO_BUFFER_FREE(ab); - - return 0; + goto done; } if (STLSOFT_STATIC_CAST(us_size_t, n) < ab.size) @@ -377,9 +365,7 @@ unixstl_C_get_current_process_path_m( { errno = ENOMEM; - STLSOFT_C_AUTO_BUFFER_FREE(ab); - - return 0; + goto done; } } #elif 0 ||\ @@ -406,25 +392,19 @@ unixstl_C_get_current_process_path_m( { errno = ENOMEM; - STLSOFT_C_AUTO_BUFFER_FREE(ab); - - return 0; + goto done; } cb = ab.size; if (0 != STLSOFT_NS_GLOBAL(sysctl)(mib, 4, ab.ptr, &cb, NULL, 0)) { - STLSOFT_C_AUTO_BUFFER_FREE(ab); - - return 0; + goto done; } } else { - STLSOFT_C_AUTO_BUFFER_FREE(ab); - - return 0; + goto done; } } @@ -438,16 +418,12 @@ unixstl_C_get_current_process_path_m( if (NULL == exe) { - STLSOFT_C_AUTO_BUFFER_FREE(ab); - - return 0; + goto done; } if (NULL == STLSOFT_NS_GLOBAL(realpath)(exe, ab.ptr)) { - STLSOFT_C_AUTO_BUFFER_FREE(ab); - - return 0; + goto done; } len = STLSOFT_NS_GLOBAL(strlen)(ab.ptr); @@ -456,9 +432,7 @@ unixstl_C_get_current_process_path_m( errno = ENOSYS; - STLSOFT_C_AUTO_BUFFER_FREE(ab); - - return 0; + goto done; #endif if (0 == cch) @@ -488,6 +462,8 @@ unixstl_C_get_current_process_path_m( result = len; } +done: + STLSOFT_C_AUTO_BUFFER_FREE(ab); return result; From 7d424d24990669be0b0c323ccf5cb61e5486853d Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 15 Oct 2026 12:42:14 +1100 Subject: [PATCH 26/31] TODO.md --- TODO.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/TODO.md b/TODO.md index fae197b5..970d41b7 100644 --- a/TODO.md +++ b/TODO.md @@ -34,6 +34,13 @@ * [ ] Remove **WTL**; * [ ] Resolve finally the structure and semantics of the top-level execution scripts (**run_all_unit_tests.sh**, **run_all_scratch_tests.sh**, **run_all_examples.sh**, **execute_performance_tests.sh**, and Windows `.cmd` counterparts) on all platforms — discovery globs, execute-bit / artifact restore, zero-match failure, verbosity, and CI wiring; * [ ] bring in some essential unit-tests from interal repo; +* [ ] Being the CONCEPTS documentation: + * [ ] auto-buffer; + * [ ] resizeable-buffer; + * [ ] string-access-shims; + * [ ] Null Object (variable); + * [ ] Externals (esp. not introducing sub-project's headers proper); + * [ ] ... ### 1.11.2 From 7bbc474c1163488f449b5d8f79dad5747232bad0 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 15 Oct 2026 13:53:35 +1100 Subject: [PATCH 27/31] feat(stlsoft): add resizeable-buffer get_current_process_path overloads Add T_resizeableBuffer overloads on unixstl/winstl system_traits that query, resize via stlsoft::resizeable_buffer_resize(), then fill; leave rb untouched on query/resize failure; set ppFile only after the final fill. Extend process_paths component tests and rc9 CHANGES/NEWS. --- CHANGES.md | 3 +- NEWS.md | 2 +- TODO.md | 1 + include/unixstl/system/system_traits.hpp | 68 +++++- include/winstl/system/system_traits.hpp | 104 +++++++- .../unixstl/system/process_paths/entry.cpp | 129 +++++++++- .../winstl/system/process_paths/entry.cpp | 224 +++++++++++++++++- 7 files changed, 523 insertions(+), 8 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 6b1179f5..5a815ef4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,8 +5,9 @@ * additions: * Added `unixstl::system_traits<>::get_current_process_path()` and `winstl::system_traits<>::get_current_process_path()` (multibyte and wide), obtaining the current process image path with an optional basename path-separator out-parameter; + * Added `T_resizeableBuffer` overloads of `get_current_process_path()` on **unixstl** / **winstl** `system_traits` (query → `stlsoft::resizeable_buffer_resize()` → fill; `ppFile` only after the final fill; resize failure sets `ENOMEM` / `ERROR_OUTOFMEMORY` and leaves the buffer unchanged); * testing: - * Component tests **test/component/unixstl/system/process_paths** (multibyte; multi-OS raw path oracle) and **test/component/winstl/system/process_paths** (multibyte and wide; `GetModuleFileName` oracle); + * Component tests **test/component/unixstl/system/process_paths** (multibyte; multi-OS raw path oracle; resizeable-buffer overloads for `auto_buffer` / `vector`, `ppFile`, and resize-failure) and **test/component/winstl/system/process_paths** (multibyte and wide; `GetModuleFileName` oracle; same resizeable-buffer coverage); * **test.unit.versions** — aligned with **1.11.1-rc9** (**_STLSOFT_VER_1_11_1_RC9**); * version: * **unixstl** — **1.8.6 beta 8** (**_UNIXSTL_VER_1_8_6_B08**), with **STLSoft 1.11.1-rc9**; diff --git a/NEWS.md b/NEWS.md index 63bbdced..d178b82b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,7 @@ | Date | News Item | Details | | ------------------- | ----------------------------------- | ------- | -| 16th October 2026 | Release of [STLSoft 1.11.1-rc9](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc9) | `get_current_process_path()` on **unixstl** / **winstl** `system_traits`; process_paths component tests | +| 16th October 2026 | Release of [STLSoft 1.11.1-rc9](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc9) | `get_current_process_path()` (+ resizeable-buffer overloads) on **unixstl** / **winstl** `system_traits`; process_paths component tests | | 10th October 2026 | Release of [STLSoft 1.11.1-rc8](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc8) | environment_variable_strtoll()`; `unixstl::filesystem_traits<>::rewind_dir()`; `class_type` and `getenv_s()` empty-variable fixes; component tests; `cmake --build` helper scripts; **run_all_component_tests.sh** / **run_all_automated_tests.sh**; **generate_doxygen.sh**; Linguist classification | | 30th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | counted NULs; `wchar_t` `string_begins_with`; bit intrinsics; `write_binary()`; `file_lines` mmap (~10–20× vs `fgetc`); compare and allocator units; MinGW static runtime; short test directories; nested **test/performance** | | 21st September 2026 | Release of [STLSoft 1.11.1-rc6](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc6) | ACE/ATL/MFC CI; Clang/macOS `stricmp` aliases | diff --git a/TODO.md b/TODO.md index 970d41b7..45acf072 100644 --- a/TODO.md +++ b/TODO.md @@ -40,6 +40,7 @@ * [ ] string-access-shims; * [ ] Null Object (variable); * [ ] Externals (esp. not introducing sub-project's headers proper); + * [ ] Conformance: Structural, Semantic, Intersecting; * [ ] ... diff --git a/include/unixstl/system/system_traits.hpp b/include/unixstl/system/system_traits.hpp index fe0cf5e8..86cdc50d 100644 --- a/include/unixstl/system/system_traits.hpp +++ b/include/unixstl/system/system_traits.hpp @@ -55,8 +55,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_MAJOR 6 # define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_MINOR 3 -# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 3 -# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 144 +# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 4 +# define UNIXSTL_VER_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 145 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -292,6 +292,36 @@ struct system_traits , char_type buff[/* cch */] , char_type** ppFile ) STLSOFT_NOEXCEPT; + + /// Attempt to obtain the current process's path into a resizeable + /// buffer. + /// + /// \param rb Reference to a resizeable buffer that will be resized as + /// required to hold the path and a terminating NUL character; + /// \param ppFile Optional pointer to receive a mutating pointer into + /// the final contents of \c rb. When non-nullptr, + /// *ppFile is set as for the raw overload, after the + /// final fill; + /// + /// \return The length of the path (excluding the NUL character) on + /// success; 0 on failure; + /// \retval 0 The function failed (query or resize). On query failure + /// \c rb is left unchanged; on resize failure + /// ENOMEM is set and \c rb is left unchanged. In neither + /// failure case is &rb[0] taken on an empty buffer; + /// + /// \note The normative pattern is a size query via the raw overload + /// with \c cch of 0, then resize, then fill — this overload performs + /// that sequence. \c ppFile is computed only after the final fill. + template< + ss_typename_param_k T_resizeableBuffer + > + static + size_type + get_current_process_path( + T_resizeableBuffer& rb + , char_type** ppFile = NULL + ); /// @} /// \name System Paths @@ -654,6 +684,40 @@ struct system_traits return n; } + template< + ss_typename_param_k T_resizeableBuffer + > + static + size_type + get_current_process_path( + T_resizeableBuffer& rb + , char_type** ppFile = NULL + ) + { + size_type const cchRequired = get_current_process_path( + 0 + , static_cast(NULL) + , static_cast(NULL) + ); + + if (0 == cchRequired) + { + return 0; + } + + if (rb.size() < cchRequired) + { + if (!STLSOFT_NS_QUAL(resizeable_buffer_resize)(rb, cchRequired)) + { + set_last_error(ENOMEM); + + return 0; + } + } + + return get_current_process_path(rb.size(), &rb[0], ppFile); + } + public: static size_type diff --git a/include/winstl/system/system_traits.hpp b/include/winstl/system/system_traits.hpp index 47a10769..a2e4ecf2 100644 --- a/include/winstl/system/system_traits.hpp +++ b/include/winstl/system/system_traits.hpp @@ -58,8 +58,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_MAJOR 6 # define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_MINOR 1 -# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 3 -# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 174 +# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_REVISION 4 +# define WINSTL_VER_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS_EDIT 175 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -311,6 +311,38 @@ struct system_traits , char_type buff[/* cch */] , char_type** ppFile ) STLSOFT_NOEXCEPT; + + /// Attempt to obtain the current process's path into a resizeable + /// buffer. + /// + /// \param rb Reference to a resizeable buffer that will be resized as + /// required to hold the path and a terminating NUL character; + /// \param ppFile Optional pointer to receive a mutating pointer into + /// the final contents of \c rb. When non-nullptr, + /// *ppFile is set as for the raw overload, after the + /// final fill; + /// + /// \return The length of the path (excluding the NUL character) on + /// success; 0 on failure; + /// \retval 0 The function failed (query or resize). On query failure + /// \c rb is left unchanged; on resize failure + /// ERROR_OUTOFMEMORY is set and \c rb is left unchanged. + /// In neither failure case is &rb[0] taken on an empty + /// buffer; + /// + /// \note The normative pattern is a size query via the raw overload + /// with \c cch of 0, then resize, then fill — this overload performs + /// that sequence (required on Windows; see the note on the raw + /// overload). \c ppFile is computed only after the final fill. + template< + ss_typename_param_k T_resizeableBuffer + > + static + size_type + get_current_process_path( + T_resizeableBuffer& rb + , char_type** ppFile = NULL + ); /// @} /// \name System Paths @@ -805,6 +837,40 @@ struct system_traits return n; } + template< + ss_typename_param_k T_resizeableBuffer + > + static + size_type + get_current_process_path( + T_resizeableBuffer& rb + , char_type** ppFile = NULL + ) + { + size_type const cchRequired = get_current_process_path( + 0 + , static_cast(NULL) + , static_cast(NULL) + ); + + if (0 == cchRequired) + { + return 0; + } + + if (rb.size() < cchRequired) + { + if (!STLSOFT_NS_QUAL(resizeable_buffer_resize)(rb, cchRequired)) + { + set_last_error(ERROR_OUTOFMEMORY); + + return 0; + } + } + + return get_current_process_path(rb.size(), &rb[0], ppFile); + } + public: static size_type @@ -1456,6 +1522,40 @@ struct system_traits return n; } + template< + ss_typename_param_k T_resizeableBuffer + > + static + size_type + get_current_process_path( + T_resizeableBuffer& rb + , char_type** ppFile = NULL + ) + { + size_type const cchRequired = get_current_process_path( + 0 + , static_cast(NULL) + , static_cast(NULL) + ); + + if (0 == cchRequired) + { + return 0; + } + + if (rb.size() < cchRequired) + { + if (!STLSOFT_NS_QUAL(resizeable_buffer_resize)(rb, cchRequired)) + { + set_last_error(ERROR_OUTOFMEMORY); + + return 0; + } + } + + return get_current_process_path(rb.size(), &rb[0], ppFile); + } + public: static size_type diff --git a/test/component/unixstl/system/process_paths/entry.cpp b/test/component/unixstl/system/process_paths/entry.cpp index edee0eee..375f5dde 100644 --- a/test/component/unixstl/system/process_paths/entry.cpp +++ b/test/component/unixstl/system/process_paths/entry.cpp @@ -2,7 +2,8 @@ * File: test/component/unixstl/system/process_paths/entry.cpp * * Purpose: Component-tests for - * `unixstl::system_traits::get_current_process_path()` (multibyte). + * `unixstl::system_traits::get_current_process_path()` (multibyte), + * including resizeable-buffer overloads. * * Created: 15th October 2026 * Updated: 15th October 2026 @@ -33,8 +34,10 @@ /* Standard C++ header files */ #include +#include /* Standard C header files */ +#include #include #include #include @@ -82,6 +85,11 @@ namespace { static void TEST_ppFile_NULL_ON_SUCCESS(); static void TEST_ppFile_separator_on_success(); static void TEST_ppFile_NULL_WHEN_INSUFFICIENT(); + static void TEST_RESIZEABLE_auto_buffer_SUCCESS(); + static void TEST_RESIZEABLE_vector_SUCCESS(); + static void TEST_RESIZEABLE_ppFile_NULL(); + static void TEST_RESIZEABLE_ppFile_separator(); + static void TEST_RESIZEABLE_resize_FAILURE_leaves_rb_untouched(); } // anonymous namespace @@ -105,6 +113,11 @@ int main(int argc, char* argv[]) XTESTS_RUN_CASE(TEST_ppFile_NULL_ON_SUCCESS); XTESTS_RUN_CASE(TEST_ppFile_separator_on_success); XTESTS_RUN_CASE(TEST_ppFile_NULL_WHEN_INSUFFICIENT); + XTESTS_RUN_CASE(TEST_RESIZEABLE_auto_buffer_SUCCESS); + XTESTS_RUN_CASE(TEST_RESIZEABLE_vector_SUCCESS); + XTESTS_RUN_CASE(TEST_RESIZEABLE_ppFile_NULL); + XTESTS_RUN_CASE(TEST_RESIZEABLE_ppFile_separator); + XTESTS_RUN_CASE(TEST_RESIZEABLE_resize_FAILURE_leaves_rb_untouched); XTESTS_PRINT_RESULTS(); @@ -306,6 +319,34 @@ invalid_file_pointer() { return reinterpret_cast(static_cast(-1)); } + +/** Minimal resizeable buffer whose #resize() always fails. */ +struct fail_on_resize_buffer +{ + typedef char value_type; + + std::vector storage; + + size_t size() const + { + return storage.size(); + } + + char& operator [](size_t i) + { + return storage[i]; + } + + char const& operator [](size_t i) const + { + return storage[i]; + } + + bool resize(size_t /* newSize */) + { + return false; + } +}; } // anonymous namespace @@ -449,6 +490,92 @@ static void TEST_ppFile_NULL_WHEN_INSUFFICIENT() TEST_INT_EQ(len + 1, cch); TEST_PTR_EQ(NULL, pFile); } + +static void TEST_RESIZEABLE_auto_buffer_SUCCESS() +{ + std::string const expected = obtain_raw_current_process_path(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer rb(0); + size_t const cch = traits_m_t::get_current_process_path(rb); + + TEST_INT_EQ(expected.size(), cch); + TEST_INT_GE(expected.size() + 1, rb.size()); + TEST_MS_EQ(expected.c_str(), &rb[0]); +} + +static void TEST_RESIZEABLE_vector_SUCCESS() +{ + std::string const expected = obtain_raw_current_process_path(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + std::vector rb; + size_t const cch = traits_m_t::get_current_process_path(rb); + + TEST_INT_EQ(expected.size(), cch); + TEST_INT_GE(expected.size() + 1, rb.size()); + TEST_MS_EQ(expected.c_str(), &rb[0]); +} + +static void TEST_RESIZEABLE_ppFile_NULL() +{ + std::string const expected = obtain_raw_current_process_path(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer rb(0); + size_t const cch = traits_m_t::get_current_process_path(rb, NULL); + + TEST_INT_EQ(expected.size(), cch); + TEST_MS_EQ(expected.c_str(), &rb[0]); +} + +static void TEST_RESIZEABLE_ppFile_separator() +{ + std::string const expected = obtain_raw_current_process_path(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer rb(0); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(rb, &pFile); + + TEST_INT_EQ(expected.size(), cch); + TEST_MS_EQ(expected.c_str(), &rb[0]); + + char* const expectedSep = find_last_path_name_separator(&rb[0]); + + TEST_PTR_EQ(expectedSep, pFile); + + if (NULL != pFile) + { + TEST_MS_EQ(expectedSep + 1, pFile + 1); + } +} + +static void TEST_RESIZEABLE_resize_FAILURE_leaves_rb_untouched() +{ + fail_on_resize_buffer rb; + + rb.storage.assign(4, 'X'); + + size_t const priorSize = rb.size(); + int const priorErrno = errno; + + errno = 0; + + size_t const cch = traits_m_t::get_current_process_path(rb); + + TEST_INT_EQ(0, cch); + TEST_INT_EQ(ENOMEM, errno); + TEST_INT_EQ(priorSize, rb.size()); + TEST_CHAR_EQ('X', rb.storage[0]); + TEST_CHAR_EQ('X', rb.storage[3]); + + errno = priorErrno; +} } // anonymous namespace diff --git a/test/component/winstl/system/process_paths/entry.cpp b/test/component/winstl/system/process_paths/entry.cpp index b3287fbd..d8ac7f48 100644 --- a/test/component/winstl/system/process_paths/entry.cpp +++ b/test/component/winstl/system/process_paths/entry.cpp @@ -3,7 +3,7 @@ * * Purpose: Component-tests for * `winstl::system_traits::get_current_process_path()` (multibyte - * and wide-character). + * and wide-character), including resizeable-buffer overloads. * * Created: 15th October 2026 * Updated: 15th October 2026 @@ -34,6 +34,7 @@ /* Standard C++ header files */ #include +#include /* Standard C / Windows header files */ #include @@ -61,6 +62,16 @@ namespace { static void TEST_ppFile_separator_ON_SUCCESS_w(); static void TEST_ppFile_NULL_WHEN_INSUFFICIENT_m(); static void TEST_ppFile_NULL_WHEN_INSUFFICIENT_w(); + static void TEST_RESIZEABLE_auto_buffer_SUCCESS_m(); + static void TEST_RESIZEABLE_auto_buffer_SUCCESS_w(); + static void TEST_RESIZEABLE_vector_SUCCESS_m(); + static void TEST_RESIZEABLE_vector_SUCCESS_w(); + static void TEST_RESIZEABLE_ppFile_NULL_m(); + static void TEST_RESIZEABLE_ppFile_NULL_w(); + static void TEST_RESIZEABLE_ppFile_separator_m(); + static void TEST_RESIZEABLE_ppFile_separator_w(); + static void TEST_RESIZEABLE_resize_FAILURE_leaves_rb_untouched_m(); + static void TEST_RESIZEABLE_resize_FAILURE_leaves_rb_untouched_w(); } // anonymous namespace @@ -91,6 +102,16 @@ int main(int argc, char* argv[]) XTESTS_RUN_CASE(TEST_ppFile_separator_ON_SUCCESS_w); XTESTS_RUN_CASE(TEST_ppFile_NULL_WHEN_INSUFFICIENT_m); XTESTS_RUN_CASE(TEST_ppFile_NULL_WHEN_INSUFFICIENT_w); + XTESTS_RUN_CASE(TEST_RESIZEABLE_auto_buffer_SUCCESS_m); + XTESTS_RUN_CASE(TEST_RESIZEABLE_auto_buffer_SUCCESS_w); + XTESTS_RUN_CASE(TEST_RESIZEABLE_vector_SUCCESS_m); + XTESTS_RUN_CASE(TEST_RESIZEABLE_vector_SUCCESS_w); + XTESTS_RUN_CASE(TEST_RESIZEABLE_ppFile_NULL_m); + XTESTS_RUN_CASE(TEST_RESIZEABLE_ppFile_NULL_w); + XTESTS_RUN_CASE(TEST_RESIZEABLE_ppFile_separator_m); + XTESTS_RUN_CASE(TEST_RESIZEABLE_ppFile_separator_w); + XTESTS_RUN_CASE(TEST_RESIZEABLE_resize_FAILURE_leaves_rb_untouched_m); + XTESTS_RUN_CASE(TEST_RESIZEABLE_resize_FAILURE_leaves_rb_untouched_w); XTESTS_PRINT_RESULTS(); @@ -207,6 +228,35 @@ invalid_file_pointer() { return reinterpret_cast(static_cast(-1)); } + +/** Minimal resizeable buffer whose #resize() always fails. */ +template +struct fail_on_resize_buffer +{ + typedef C value_type; + + std::vector storage; + + size_t size() const + { + return storage.size(); + } + + C& operator [](size_t i) + { + return storage[i]; + } + + C const& operator [](size_t i) const + { + return storage[i]; + } + + bool resize(size_t /* newSize */) + { + return false; + } +}; } // anonymous namespace @@ -512,6 +562,178 @@ static void TEST_ppFile_NULL_WHEN_INSUFFICIENT_w() TEST_INT_GE(len + 1, cch); TEST_PTR_EQ(NULL, pFile); } + +static void TEST_RESIZEABLE_auto_buffer_SUCCESS_m() +{ + std::string const expected = obtain_raw_current_process_path_m(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer rb(0); + size_t const cch = traits_m_t::get_current_process_path(rb); + + TEST_INT_EQ(expected.size(), cch); + TEST_INT_GE(expected.size() + 1, rb.size()); + TEST_MS_EQ(expected.c_str(), &rb[0]); +} + +static void TEST_RESIZEABLE_auto_buffer_SUCCESS_w() +{ + std::wstring const expected = obtain_raw_current_process_path_w(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer rb(0); + size_t const cch = traits_w_t::get_current_process_path(rb); + + TEST_INT_EQ(expected.size(), cch); + TEST_INT_GE(expected.size() + 1, rb.size()); + TEST_WS_EQ(expected.c_str(), &rb[0]); +} + +static void TEST_RESIZEABLE_vector_SUCCESS_m() +{ + std::string const expected = obtain_raw_current_process_path_m(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + std::vector rb; + size_t const cch = traits_m_t::get_current_process_path(rb); + + TEST_INT_EQ(expected.size(), cch); + TEST_INT_GE(expected.size() + 1, rb.size()); + TEST_MS_EQ(expected.c_str(), &rb[0]); +} + +static void TEST_RESIZEABLE_vector_SUCCESS_w() +{ + std::wstring const expected = obtain_raw_current_process_path_w(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + std::vector rb; + size_t const cch = traits_w_t::get_current_process_path(rb); + + TEST_INT_EQ(expected.size(), cch); + TEST_INT_GE(expected.size() + 1, rb.size()); + TEST_WS_EQ(expected.c_str(), &rb[0]); +} + +static void TEST_RESIZEABLE_ppFile_NULL_m() +{ + std::string const expected = obtain_raw_current_process_path_m(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer rb(0); + size_t const cch = traits_m_t::get_current_process_path(rb, NULL); + + TEST_INT_EQ(expected.size(), cch); + TEST_MS_EQ(expected.c_str(), &rb[0]); +} + +static void TEST_RESIZEABLE_ppFile_NULL_w() +{ + std::wstring const expected = obtain_raw_current_process_path_w(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer rb(0); + size_t const cch = traits_w_t::get_current_process_path(rb, NULL); + + TEST_INT_EQ(expected.size(), cch); + TEST_WS_EQ(expected.c_str(), &rb[0]); +} + +static void TEST_RESIZEABLE_ppFile_separator_m() +{ + std::string const expected = obtain_raw_current_process_path_m(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer rb(0); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(rb, &pFile); + + TEST_INT_EQ(expected.size(), cch); + TEST_MS_EQ(expected.c_str(), &rb[0]); + + char* const expectedSep = find_last_path_name_separator(&rb[0]); + + TEST_PTR_EQ(expectedSep, pFile); + + if (NULL != pFile) + { + TEST_MS_EQ(expectedSep + 1, pFile + 1); + } +} + +static void TEST_RESIZEABLE_ppFile_separator_w() +{ + std::wstring const expected = obtain_raw_current_process_path_w(); + + XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); + + stlsoft::auto_buffer rb(0); + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(rb, &pFile); + + TEST_INT_EQ(expected.size(), cch); + TEST_WS_EQ(expected.c_str(), &rb[0]); + + wchar_t* const expectedSep = find_last_path_name_separator(&rb[0]); + + TEST_PTR_EQ(expectedSep, pFile); + + if (NULL != pFile) + { + TEST_WS_EQ(expectedSep + 1, pFile + 1); + } +} + +static void TEST_RESIZEABLE_resize_FAILURE_leaves_rb_untouched_m() +{ + fail_on_resize_buffer rb; + + rb.storage.assign(4, 'X'); + + size_t const priorSize = rb.size(); + DWORD const priorError = ::GetLastError(); + + ::SetLastError(ERROR_SUCCESS); + + size_t const cch = traits_m_t::get_current_process_path(rb); + + TEST_INT_EQ(0, cch); + TEST_INT_EQ(ERROR_OUTOFMEMORY, ::GetLastError()); + TEST_INT_EQ(priorSize, rb.size()); + TEST_CHAR_EQ('X', rb.storage[0]); + TEST_CHAR_EQ('X', rb.storage[3]); + + ::SetLastError(priorError); +} + +static void TEST_RESIZEABLE_resize_FAILURE_leaves_rb_untouched_w() +{ + fail_on_resize_buffer rb; + + rb.storage.assign(4, L'X'); + + size_t const priorSize = rb.size(); + DWORD const priorError = ::GetLastError(); + + ::SetLastError(ERROR_SUCCESS); + + size_t const cch = traits_w_t::get_current_process_path(rb); + + TEST_INT_EQ(0, cch); + TEST_INT_EQ(ERROR_OUTOFMEMORY, ::GetLastError()); + TEST_INT_EQ(priorSize, rb.size()); + TEST_INT_EQ(L'X', rb.storage[0]); + TEST_INT_EQ(L'X', rb.storage[3]); + + ::SetLastError(priorError); +} } // anonymous namespace From 7518ac4e6b63272ff3a9fd29d7148f52c0acd1f8 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 15 Oct 2026 14:01:45 +1100 Subject: [PATCH 28/31] TODO.md --- TODO.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/TODO.md b/TODO.md index 45acf072..f50ecda5 100644 --- a/TODO.md +++ b/TODO.md @@ -17,6 +17,7 @@ - [1.11.9](#1119) - [1.11.10](#11110) - [1.11.11](#11111) + - [Cross-publish to STLSoft-1.11](#cross-publish-to-stlsoft-111) - [1.12](#112) - [Requires clarification by project maintainers](#requires-clarification-by-project-maintainers) - [Abandoned](#abandoned) @@ -104,6 +105,13 @@ Dedicated increment: **test analysis and coverage only** — no other product ch * [ ] Doxygen build (**Doxyfile**, **generate_doxygen.sh**) and deeper API documentation — see also [**KNOWN_ISSUES.md**](./KNOWN_ISSUES.md); +### Cross-publish to STLSoft-1.11 + +When tip **1.11** is finally complete, cross-publish into the versioned line **[synesissoftware/STLSoft-1.11](https://github.com/synesissoftware/STLSoft-1.11)** (not done for the interim VOLE / historical-consumer recognition work — that line was left unpushed on purpose). + +* [ ] Cross-publish the completed tip **1.11** tree into **STLSoft-1.11**, including the unknown-newer Visual C++ warn-not-error forward-warning from the **`prospective-msvc`** branch (and any related recognition / semi-freeze messaging needed for historical consumers); + + ## 1.12 From **1.12** onwards, every new component or feature must ship with an **example**, **unit tests**, and a **blog entry** on the new Website (website work is contemporaneous with 1.12). See **oss-library-modernisation** (STLSoft 1.12+ feature completeness). From 434b203f0c45cb727de2f97d2cbb142e78ad42a6 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 15 Oct 2026 14:15:58 +1100 Subject: [PATCH 29/31] fix(stlsoft): avoid wchar_t TEST_INT_EQ in process_paths tests xTests integer compares need integral_traits; wchar_t is incomplete, so use boolean equality for the wide resize-failure sentinel checks. --- test/component/winstl/system/process_paths/entry.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/component/winstl/system/process_paths/entry.cpp b/test/component/winstl/system/process_paths/entry.cpp index d8ac7f48..f37fb002 100644 --- a/test/component/winstl/system/process_paths/entry.cpp +++ b/test/component/winstl/system/process_paths/entry.cpp @@ -729,8 +729,8 @@ static void TEST_RESIZEABLE_resize_FAILURE_leaves_rb_untouched_w() TEST_INT_EQ(0, cch); TEST_INT_EQ(ERROR_OUTOFMEMORY, ::GetLastError()); TEST_INT_EQ(priorSize, rb.size()); - TEST_INT_EQ(L'X', rb.storage[0]); - TEST_INT_EQ(L'X', rb.storage[3]); + TEST_BOOLEAN_TRUE(L'X' == rb.storage[0]); + TEST_BOOLEAN_TRUE(L'X' == rb.storage[3]); ::SetLastError(priorError); } From e04d40987a6feb7fe23d701190acd995d357f2de Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Sun, 18 Oct 2026 06:02:34 +1100 Subject: [PATCH 30/31] simplification --- .../winstl/system/process_paths/entry.cpp | 74 ++++++------------- 1 file changed, 22 insertions(+), 52 deletions(-) diff --git a/test/component/winstl/system/process_paths/entry.cpp b/test/component/winstl/system/process_paths/entry.cpp index f37fb002..b4b1c38b 100644 --- a/test/component/winstl/system/process_paths/entry.cpp +++ b/test/component/winstl/system/process_paths/entry.cpp @@ -6,7 +6,7 @@ * and wide-character), including resizeable-buffer overloads. * * Created: 15th October 2026 - * Updated: 15th October 2026 + * Updated: 18th October 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -31,6 +31,7 @@ /* STLSoft header files */ #include +#include /* Standard C++ header files */ #include @@ -39,7 +40,6 @@ /* Standard C / Windows header files */ #include #include -#include /* ///////////////////////////////////////////////////////////////////////// @@ -48,10 +48,10 @@ namespace { - static void TEST_SIZE_QUERY_m(); - static void TEST_SIZE_QUERY_w(); - static void TEST_SIZE_THEN_SUFFICIENT_m(); - static void TEST_SIZE_THEN_SUFFICIENT_w(); + static void TEST_size_QUERY_m(); + static void TEST_size_QUERY_w(); + static void TEST_size_THEN_SUFFICIENT_m(); + static void TEST_size_THEN_SUFFICIENT_w(); static void TEST_EXCESS_SPACE_m(); static void TEST_EXCESS_SPACE_w(); static void TEST_INSUFFICIENT_SPACE_m(); @@ -88,10 +88,10 @@ int main(int argc, char* argv[]) if (XTESTS_START_RUNNER("test.component.winstl.system.process_paths", verbosity)) { - XTESTS_RUN_CASE(TEST_SIZE_QUERY_m); - XTESTS_RUN_CASE(TEST_SIZE_QUERY_w); - XTESTS_RUN_CASE(TEST_SIZE_THEN_SUFFICIENT_m); - XTESTS_RUN_CASE(TEST_SIZE_THEN_SUFFICIENT_w); + XTESTS_RUN_CASE(TEST_size_QUERY_m); + XTESTS_RUN_CASE(TEST_size_QUERY_w); + XTESTS_RUN_CASE(TEST_size_THEN_SUFFICIENT_m); + XTESTS_RUN_CASE(TEST_size_THEN_SUFFICIENT_w); XTESTS_RUN_CASE(TEST_EXCESS_SPACE_m); XTESTS_RUN_CASE(TEST_EXCESS_SPACE_w); XTESTS_RUN_CASE(TEST_INSUFFICIENT_SPACE_m); @@ -131,6 +131,10 @@ namespace { typedef winstl::system_traits traits_m_t; typedef winstl::system_traits traits_w_t; +typedef winstl::filesystem_traits fs_traits_m_t; +typedef winstl::filesystem_traits fs_traits_w_t; + + /** Obtains the current process image path via GetModuleFileNameA. */ static std::string @@ -187,40 +191,6 @@ obtain_raw_current_process_path_w() } } -static -char* -find_last_path_name_separator(char* s) -{ - char* last = NULL; - - for (; '\0' != *s; ++s) - { - if ('\\' == *s || '/' == *s) - { - last = s; - } - } - - return last; -} - -static -wchar_t* -find_last_path_name_separator(wchar_t* s) -{ - wchar_t* last = NULL; - - for (; L'\0' != *s; ++s) - { - if (L'\\' == *s || L'/' == *s) - { - last = s; - } - } - - return last; -} - template static C* @@ -266,7 +236,7 @@ struct fail_on_resize_buffer namespace { -static void TEST_SIZE_QUERY_m() +static void TEST_size_QUERY_m() { std::string const expected = obtain_raw_current_process_path_m(); @@ -280,7 +250,7 @@ static void TEST_SIZE_QUERY_m() TEST_PTR_EQ(NULL, pFile); } -static void TEST_SIZE_QUERY_w() +static void TEST_size_QUERY_w() { std::wstring const expected = obtain_raw_current_process_path_w(); @@ -293,7 +263,7 @@ static void TEST_SIZE_QUERY_w() TEST_PTR_EQ(NULL, pFile); } -static void TEST_SIZE_THEN_SUFFICIENT_m() +static void TEST_size_THEN_SUFFICIENT_m() { std::string const expected = obtain_raw_current_process_path_m(); @@ -313,7 +283,7 @@ static void TEST_SIZE_THEN_SUFFICIENT_m() TEST_CHAR_EQ('\0', buff[len]); } -static void TEST_SIZE_THEN_SUFFICIENT_w() +static void TEST_size_THEN_SUFFICIENT_w() { std::wstring const expected = obtain_raw_current_process_path_w(); @@ -496,7 +466,7 @@ static void TEST_ppFile_separator_ON_SUCCESS_m() TEST_INT_EQ(expected.size(), cch); TEST_MS_EQ(expected.c_str(), &buff[0]); - char* const expectedSep = find_last_path_name_separator(&buff[0]); + char* const expectedSep = fs_traits_m_t::find_last_path_name_separator(&buff[0]); TEST_PTR_EQ(expectedSep, pFile); @@ -523,7 +493,7 @@ static void TEST_ppFile_separator_ON_SUCCESS_w() TEST_INT_EQ(expected.size(), cch); TEST_WS_EQ(expected.c_str(), &buff[0]); - wchar_t* const expectedSep = find_last_path_name_separator(&buff[0]); + wchar_t* const expectedSep = fs_traits_w_t::find_last_path_name_separator(&buff[0]); TEST_PTR_EQ(expectedSep, pFile); @@ -658,7 +628,7 @@ static void TEST_RESIZEABLE_ppFile_separator_m() TEST_INT_EQ(expected.size(), cch); TEST_MS_EQ(expected.c_str(), &rb[0]); - char* const expectedSep = find_last_path_name_separator(&rb[0]); + char* const expectedSep = fs_traits_m_t::find_last_path_name_separator(&rb[0]); TEST_PTR_EQ(expectedSep, pFile); @@ -681,7 +651,7 @@ static void TEST_RESIZEABLE_ppFile_separator_w() TEST_INT_EQ(expected.size(), cch); TEST_WS_EQ(expected.c_str(), &rb[0]); - wchar_t* const expectedSep = find_last_path_name_separator(&rb[0]); + wchar_t* const expectedSep = fs_traits_w_t::find_last_path_name_separator(&rb[0]); TEST_PTR_EQ(expectedSep, pFile); From 45cac81ec3ea1dd8067de616ef366f039de83e5a Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Sun, 18 Oct 2026 06:17:45 +1100 Subject: [PATCH 31/31] simplification --- .../unixstl/system/process_paths/entry.cpp | 31 ++--------- .../winstl/system/process_paths/entry.cpp | 53 +++++++++---------- 2 files changed, 31 insertions(+), 53 deletions(-) diff --git a/test/component/unixstl/system/process_paths/entry.cpp b/test/component/unixstl/system/process_paths/entry.cpp index 375f5dde..f32271f4 100644 --- a/test/component/unixstl/system/process_paths/entry.cpp +++ b/test/component/unixstl/system/process_paths/entry.cpp @@ -6,7 +6,7 @@ * including resizeable-buffer overloads. * * Created: 15th October 2026 - * Updated: 15th October 2026 + * Updated: 18th October 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -31,6 +31,7 @@ /* STLSoft header files */ #include +#include /* Standard C++ header files */ #include @@ -134,6 +135,7 @@ int main(int argc, char* argv[]) namespace { +typedef unixstl::filesystem_traits fs_traits_m_t; typedef unixstl::system_traits traits_m_t; /** Retrieves the full path of the current executable from the ambient OS @@ -290,29 +292,6 @@ obtain_raw_current_process_path() return std::string(path); } -static -char* -find_last_path_name_separator(char* s) -{ - char* last = NULL; - - for (; '\0' != *s; ++s) - { -#if defined(_WIN32) - - if ('\\' == *s || '/' == *s) -#else - - if ('/' == *s) -#endif - { - last = s; - } - } - - return last; -} - static char* invalid_file_pointer() @@ -466,7 +445,7 @@ static void TEST_ppFile_separator_on_success() TEST_INT_EQ(expected.size(), cch); TEST_MS_EQ(expected.c_str(), &buff[0]); - char* const expectedSep = find_last_path_name_separator(&buff[0]); + char const* const expectedSep = fs_traits_m_t::find_last_path_name_separator(&buff[0]); TEST_PTR_EQ(expectedSep, pFile); @@ -545,7 +524,7 @@ static void TEST_RESIZEABLE_ppFile_separator() TEST_INT_EQ(expected.size(), cch); TEST_MS_EQ(expected.c_str(), &rb[0]); - char* const expectedSep = find_last_path_name_separator(&rb[0]); + char const* const expectedSep = fs_traits_m_t::find_last_path_name_separator(&rb[0]); TEST_PTR_EQ(expectedSep, pFile); diff --git a/test/component/winstl/system/process_paths/entry.cpp b/test/component/winstl/system/process_paths/entry.cpp index b4b1c38b..c4360129 100644 --- a/test/component/winstl/system/process_paths/entry.cpp +++ b/test/component/winstl/system/process_paths/entry.cpp @@ -128,11 +128,10 @@ int main(int argc, char* argv[]) namespace { -typedef winstl::system_traits traits_m_t; -typedef winstl::system_traits traits_w_t; - typedef winstl::filesystem_traits fs_traits_m_t; typedef winstl::filesystem_traits fs_traits_w_t; +typedef winstl::system_traits traits_m_t; +typedef winstl::system_traits traits_w_t; /** Obtains the current process image path via GetModuleFileNameA. */ @@ -269,14 +268,14 @@ static void TEST_size_THEN_SUFFICIENT_m() XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); - size_t const len = expected.size(); - size_t const need = traits_m_t::get_current_process_path(0, NULL, NULL); + size_t const len = expected.size(); + size_t const need = traits_m_t::get_current_process_path(0, NULL, NULL); XTESTS_REQUIRE(TEST_INT_GE(len + 1, need)); stlsoft::auto_buffer buff(need); - char* pFile = invalid_file_pointer(); - size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); TEST_INT_EQ(len, cch); TEST_MS_EQ(expected.c_str(), &buff[0]); @@ -289,14 +288,14 @@ static void TEST_size_THEN_SUFFICIENT_w() XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); - size_t const len = expected.size(); - size_t const need = traits_w_t::get_current_process_path(0, NULL, NULL); + size_t const len = expected.size(); + size_t const need = traits_w_t::get_current_process_path(0, NULL, NULL); XTESTS_REQUIRE(TEST_INT_GE(len + 1, need)); stlsoft::auto_buffer buff(need); - wchar_t* pFile = invalid_file_pointer(); - size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); TEST_INT_EQ(len, cch); TEST_WS_EQ(expected.c_str(), &buff[0]); @@ -460,13 +459,13 @@ static void TEST_ppFile_separator_ON_SUCCESS_m() XTESTS_REQUIRE(TEST_INT_GE(expected.size() + 1, need)); stlsoft::auto_buffer buff(need); - char* pFile = invalid_file_pointer(); - size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); TEST_INT_EQ(expected.size(), cch); TEST_MS_EQ(expected.c_str(), &buff[0]); - char* const expectedSep = fs_traits_m_t::find_last_path_name_separator(&buff[0]); + char const* const expectedSep = fs_traits_m_t::find_last_path_name_separator(&buff[0]); TEST_PTR_EQ(expectedSep, pFile); @@ -487,13 +486,13 @@ static void TEST_ppFile_separator_ON_SUCCESS_w() XTESTS_REQUIRE(TEST_INT_GE(expected.size() + 1, need)); stlsoft::auto_buffer buff(need); - wchar_t* pFile = invalid_file_pointer(); - size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); TEST_INT_EQ(expected.size(), cch); TEST_WS_EQ(expected.c_str(), &buff[0]); - wchar_t* const expectedSep = fs_traits_w_t::find_last_path_name_separator(&buff[0]); + wchar_t const* const expectedSep = fs_traits_w_t::find_last_path_name_separator(&buff[0]); TEST_PTR_EQ(expectedSep, pFile); @@ -511,8 +510,8 @@ static void TEST_ppFile_NULL_WHEN_INSUFFICIENT_m() size_t const len = expected.size(); stlsoft::auto_buffer buff(len); - char* pFile = invalid_file_pointer(); - size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(buff.size(), &buff[0], &pFile); TEST_INT_GE(len + 1, cch); TEST_PTR_EQ(NULL, pFile); @@ -526,8 +525,8 @@ static void TEST_ppFile_NULL_WHEN_INSUFFICIENT_w() size_t const len = expected.size(); stlsoft::auto_buffer buff(len); - wchar_t* pFile = invalid_file_pointer(); - size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(buff.size(), &buff[0], &pFile); TEST_INT_GE(len + 1, cch); TEST_PTR_EQ(NULL, pFile); @@ -622,13 +621,13 @@ static void TEST_RESIZEABLE_ppFile_separator_m() XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); stlsoft::auto_buffer rb(0); - char* pFile = invalid_file_pointer(); - size_t const cch = traits_m_t::get_current_process_path(rb, &pFile); + char* pFile = invalid_file_pointer(); + size_t const cch = traits_m_t::get_current_process_path(rb, &pFile); TEST_INT_EQ(expected.size(), cch); TEST_MS_EQ(expected.c_str(), &rb[0]); - char* const expectedSep = fs_traits_m_t::find_last_path_name_separator(&rb[0]); + char const* const expectedSep = fs_traits_m_t::find_last_path_name_separator(&rb[0]); TEST_PTR_EQ(expectedSep, pFile); @@ -645,13 +644,13 @@ static void TEST_RESIZEABLE_ppFile_separator_w() XTESTS_REQUIRE(TEST_BOOLEAN_TRUE(!expected.empty())); stlsoft::auto_buffer rb(0); - wchar_t* pFile = invalid_file_pointer(); - size_t const cch = traits_w_t::get_current_process_path(rb, &pFile); + wchar_t* pFile = invalid_file_pointer(); + size_t const cch = traits_w_t::get_current_process_path(rb, &pFile); TEST_INT_EQ(expected.size(), cch); TEST_WS_EQ(expected.c_str(), &rb[0]); - wchar_t* const expectedSep = fs_traits_w_t::find_last_path_name_separator(&rb[0]); + wchar_t const* const expectedSep = fs_traits_w_t::find_last_path_name_separator(&rb[0]); TEST_PTR_EQ(expectedSep, pFile);