-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathCompileTimePattern.hpp
137 lines (130 loc) · 4.1 KB
/
CompileTimePattern.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#pragma once
#include "Pattern.hpp"
#include <array>
namespace patterns {
namespace detail {
constexpr size_t pattern_length(const char* s, size_t nstr, bool pad = true) {
size_t res = 0;
#ifdef __arm64__
bool align = false;
#endif
for (auto i = 0; i < nstr - 1; i += 2) {
auto c = s[i];
if (c == 'X' || c == 'x') {
while (s[i + 1] != ' ')
++i;
continue;
}
else if (c == '/') {
#ifdef __arm64__
while (i < nstr - 1 && (c = s[++i])) {
if (c == 'a') {
align = true;
break;
}
}
#endif
break;
}
else if (c != ' ')
++res;
else --i;
}
#ifdef __arm64__
while (pad && align && res % sizeof(uint32_t))
++res;
#else
while (pad && res % sizeof(void*))
++res;
#endif
return res;
}
template<size_t nstr>
constexpr size_t pattern_length(const char(&s)[nstr], bool pad = true) {
return pattern_length(s, nstr, pad);
}
#if __cplusplus > 201703L
template <size_t nstr>
struct const_string {
char data[nstr]{};
static constexpr size_t length = nstr - 1;
static constexpr size_t size = nstr;
constexpr const_string(const char(&s)[nstr]) {
std::copy_n(s, length, data);
}
};
#endif
}
template<size_t nstr, size_t narr>
class CompileTimePattern : public Pattern {
std::array<uint8_t, narr> m_pattern;
std::array<uint8_t, narr> m_mask;
public:
constexpr CompileTimePattern(const char* p) :
m_pattern{}, m_mask{}
{
length_ = narr;
auto n = 0;
for (auto i = 0; i < nstr; i += 2) {
auto ptr = &p[i];
if (p[i] == '?') {
m_pattern[n] = 0;
m_mask[n] = 0;
++n;
}
// Capture where we have our offset marker 'X' at
else if (*ptr == 'X' || *ptr == 'x') {
offset_ = n;
if (p[i + 1] != ' ') {
#ifndef __arm64__
insn_len_ = get_inst_len_opt(&p[++i]);
#endif
while (p[i + 1] != ' ')
++i;
}
}
// Break from parsing the pattern, since / at the end starts the flags
else if (*ptr == '/') {
++ptr;
handle_options(ptr);
break;
}
else if (*ptr != ' ') {
m_pattern[n] = value(ptr);
m_mask[n] = 0xFF;
++n;
}
else --i;
}
#ifdef __arm64__
while (align_ && n % align_size_) {
m_pattern[n] = 0;
m_mask[n] = 0;
++n;
}
#else
while (n % sizeof(void*)) {
m_pattern[n] = 0;
m_mask[n] = 0;
++n;
}
#endif
}
virtual const uint8_t* pattern() const override {
return m_pattern.data();
}
virtual const uint8_t* mask() const override {
return m_mask.data();
}
};
}
#if __cplusplus > 201703L
template<patterns::detail::const_string str>
constexpr auto operator"" _ctpattern() {
return patterns::CompileTimePattern<str.length, patterns::detail::pattern_length(str.data, str.size)>(str.data);
}
#else
#ifndef COMPILETIME_PATTERN
#define COMPILETIME_PATTERN(x) patterns::CompileTimePattern<sizeof(x)-1, patterns::detail::pattern_length(x)>(x)
#endif
#endif