Adds pattern scanning functionality and corner case tests

Implements a pattern scanning feature that allows searching for byte patterns within a byte range.

Adds `scan_for_pattern` method to `PatternScanner` to locate a pattern within a byte span.

Adds corner case tests to verify functionality and handle invalid inputs.
This commit is contained in:
2025-10-05 06:37:20 +03:00
parent 160b51da94
commit 06f9a8c9ee
3 changed files with 47 additions and 2 deletions

View File

@@ -7,12 +7,20 @@
#include <optional> #include <optional>
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#include <span>
// ReSharper disable once CppInconsistentNaming // ReSharper disable once CppInconsistentNaming
class unit_test_pattern_scan_read_test_Test; class unit_test_pattern_scan_read_test_Test;
// ReSharper disable once CppInconsistentNaming
class unit_test_pattern_scan_corner_case_1_Test; class unit_test_pattern_scan_corner_case_1_Test;
// ReSharper disable once CppInconsistentNaming
class unit_test_pattern_scan_corner_case_2_Test; class unit_test_pattern_scan_corner_case_2_Test;
// ReSharper disable once CppInconsistentNaming
class unit_test_pattern_scan_corner_case_3_Test; class unit_test_pattern_scan_corner_case_3_Test;
// ReSharper disable once CppInconsistentNaming
class unit_test_pattern_scan_corner_case_4_Test;
namespace omath namespace omath
{ {
enum class PatternScanError enum class PatternScanError
@@ -25,7 +33,11 @@ namespace omath
friend unit_test_pattern_scan_corner_case_1_Test; friend unit_test_pattern_scan_corner_case_1_Test;
friend unit_test_pattern_scan_corner_case_2_Test; friend unit_test_pattern_scan_corner_case_2_Test;
friend unit_test_pattern_scan_corner_case_3_Test; friend unit_test_pattern_scan_corner_case_3_Test;
friend unit_test_pattern_scan_corner_case_4_Test;
public: public:
[[nodiscard]]
static std::optional<std::span<std::byte>::const_iterator>
scan_for_pattern(const std::string_view& pattern, const std::span<std::byte>& range);
private: private:
[[nodiscard]] [[nodiscard]]
static std::expected<std::vector<std::optional<std::byte>>, PatternScanError> static std::expected<std::vector<std::optional<std::byte>>, PatternScanError>

View File

@@ -7,6 +7,33 @@
namespace omath namespace omath
{ {
std::optional<std::span<std::byte>::const_iterator>
PatternScanner::scan_for_pattern(const std::string_view& pattern, const std::span<std::byte>& range)
{
const auto parsed_pattern = parse_pattern(pattern);
if (!parsed_pattern)
return std::nullopt;
const std::ptrdiff_t scan_size =
static_cast<std::ptrdiff_t>(range.size()) - static_cast<std::ptrdiff_t>(pattern.size());
for (std::ptrdiff_t i = 0; i < scan_size; i++)
{
bool found = true;
for (std::ptrdiff_t j = 0; j < static_cast<std::ptrdiff_t>(pattern.size()); j++)
{
found = parsed_pattern->at(j) == std::nullopt || parsed_pattern->at(j) == *(range.data() + i + j);
if (!found)
break;
}
if (found)
return range.begin() + i;
}
return std::nullopt;
}
std::expected<std::vector<std::optional<std::byte>>, PatternScanError> std::expected<std::vector<std::optional<std::byte>>, PatternScanError>
PatternScanner::parse_pattern(const std::string_view& pattern_string) PatternScanner::parse_pattern(const std::string_view& pattern_string)
{ {
@@ -39,14 +66,13 @@ namespace omath
std::uint8_t value = 0; std::uint8_t value = 0;
// ReSharper disable once CppTooWideScopeInitStatement // ReSharper disable once CppTooWideScopeInitStatement
const auto [_, error_code] = std::from_chars(byte_str.data(), byte_str.data()+byte_str.size(), value, 16); const auto [_, error_code] = std::from_chars(byte_str.data(), byte_str.data() + byte_str.size(), value, 16);
if (error_code != std::errc{}) if (error_code != std::errc{})
return std::unexpected(PatternScanError::INVALID_PATTERN_STRING); return std::unexpected(PatternScanError::INVALID_PATTERN_STRING);
pattern.emplace_back(static_cast<std::byte>(value)); pattern.emplace_back(static_cast<std::byte>(value));
start = end != pattern_string.end() ? std::next(end) : end; start = end != pattern_string.end() ? std::next(end) : end;
} }
return pattern; return pattern;

View File

@@ -45,3 +45,10 @@ TEST(unit_test_pattern_scan, corner_case_3)
EXPECT_EQ(result->at(2), std::nullopt); EXPECT_EQ(result->at(2), std::nullopt);
EXPECT_EQ(result->at(3), static_cast<std::byte>(0xE9)); EXPECT_EQ(result->at(3), static_cast<std::byte>(0xE9));
} }
TEST(unit_test_pattern_scan, corner_case_4)
{
const auto result = omath::PatternScanner::parse_pattern("X ? ?? E9 ");
EXPECT_FALSE(result.has_value());
}