Skip to content

Instantly share code, notes, and snippets.

@stevemk14ebr
Created November 16, 2018 15:43
Show Gist options
  • Save stevemk14ebr/8b2eeeb360a9eefa77c37714c9aa4037 to your computer and use it in GitHub Desktop.
Save stevemk14ebr/8b2eeeb360a9eefa77c37714c9aa4037 to your computer and use it in GitHub Desktop.
https://www.unknowncheats.me/forum/c-and-c-/307336-compile-time-pattern.html
#include <type_traits>
#include <algorithm>
#include <cstdint>
constexpr std::uint8_t parse_hex(char c) {
if (c >= '0' && c <= '9') return c - '0';
if ((c | 32) >= 'a' && (c | 32) <= 'f') return (c | 32) - 'a' + 10;
if (c == '?') return 0;
}
template<char Hi, char Lo>
struct pattern_entry : std::integral_constant<std::uint8_t, parse_hex(Hi) * 16 + parse_hex(Lo)> {};
constexpr std::size_t pow2floor(std::size_t num, std::size_t cur = 2) {
return num == 0 ? 0 : (cur > num ? cur / 2 : pow2floor(num, cur * 2));
}
template<std::size_t S> struct uint_ { using type = std::uint8_t; };
template<> struct uint_<2> { using type = std::uint16_t; };
template<> struct uint_<4> { using type = std::uint32_t; };
template<> struct uint_<8> { using type = std::uint64_t; };
template<class... Bs>
class pattern {
constexpr static std::size_t _find_wildcard(std::size_t cur_idx) {
constexpr bool is_wildcard[]{std::is_same_v<Bs, pattern_entry<'?', '?'>>...};
for(std::size_t i = cur_idx; i != sizeof...(Bs); ++i)
if(is_wildcard[i])
return i - cur_idx;
return sizeof... (Bs) - cur_idx;
}
public:
template<std::size_t I = 0>
static bool compare(const std::uint8_t* bytes) noexcept {
if constexpr(I < sizeof... (Bs)) {
constexpr std::size_t cmp_size = pow2floor(std::min<std::size_t>(_find_wildcard(I), 8));
using cmp_type = const typename uint_<cmp_size>::type*;
constexpr std::uint8_t values[]{Bs::value...};
if constexpr(cmp_size != 0)
if(*reinterpret_cast<cmp_type>(bytes + I) != *reinterpret_cast<cmp_type>(values + I))
return false;
return compare<I + std::max<std::size_t>(cmp_size, 1u)>(bytes);
}
return true;
}
static const std::uint8_t* find(const std::uint8_t* first, const std::uint8_t* const last) noexcept {
for(const auto new_last = last - sizeof...(Bs); first < new_last; ++first)
if(compare(first))
return first;
return last;
}
};
template<class P>
auto parse_pattern(P) -> P;
template<char Space, char Hi, char Lo, char... Rest, class... Bs>
auto parse_pattern(pattern<Bs...>) -> decltype(parse_pattern<Rest...>(pattern<Bs..., pattern_entry<Hi, Lo>>{}));
#include<array>
namespace ct
{
template<class T, T...Cs>
struct String{};
template<class char_type, class lambda_t, size_t...I>
constexpr auto make_cx_string(lambda_t lambda[[maybe_unused]], std::index_sequence<I...>)
{
return String<char_type, lambda()[I]...>{};
}
}
#define XS(str) (ct::make_cx_string<char>([]()constexpr{return(str);},std::make_index_sequence<sizeof(str)/sizeof(char) - 1>{}))
template<class CharT, CharT...Cs>
auto _make_pattern(ct::String<CharT,Cs...>)->decltype(parse_pattern<' ', Cs...>(pattern<>{}));
#define make_pattern(string) _make_pattern(XS(string))
const std::uint8_t* find(const std::uint8_t* first, const std::uint8_t* last) {
return make_pattern("0A 1B ?? 01 23 7f ?? FF FF FF FF FF FF FF FF").find(first, last);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment