RapidFuzz
Loading...
Searching...
No Matches
PatternMatchVector.hpp
1/* SPDX-License-Identifier: MIT */
2/* Copyright (c) 2022 Max Bachmann */
3
4#pragma once
5#include <array>
6#include <stdint.h>
7#include <stdio.h>
8
9#include <rapidfuzz/details/GrowingHashmap.hpp>
10#include <rapidfuzz/details/Matrix.hpp>
11#include <rapidfuzz/details/Range.hpp>
12#include <rapidfuzz/details/intrinsics.hpp>
13
14namespace rapidfuzz {
15namespace detail {
16
17struct BitvectorHashmap {
18 BitvectorHashmap() : m_map()
19 {}
20
21 template <typename CharT>
22 uint64_t get(CharT key) const noexcept
23 {
24 return m_map[lookup(static_cast<uint64_t>(key))].value;
25 }
26
27 template <typename CharT>
28 uint64_t& operator[](CharT key) noexcept
29 {
30 uint32_t i = lookup(static_cast<uint64_t>(key));
31 m_map[i].key = static_cast<uint64_t>(key);
32 return m_map[i].value;
33 }
34
35private:
40 uint32_t lookup(uint64_t key) const noexcept
41 {
42 uint32_t i = key % 128;
43
44 if (!m_map[i].value || m_map[i].key == key) return i;
45
46 uint64_t perturb = key;
47 while (true) {
48 i = (static_cast<uint64_t>(i) * 5 + perturb + 1) % 128;
49 if (!m_map[i].value || m_map[i].key == key) return i;
50
51 perturb >>= 5;
52 }
53 }
54
55 struct MapElem {
56 uint64_t key = 0;
57 uint64_t value = 0;
58 };
59 std::array<MapElem, 128> m_map;
60};
61
62struct PatternMatchVector {
63 PatternMatchVector() : m_extendedAscii()
64 {}
65
66 template <typename InputIt>
67 PatternMatchVector(const Range<InputIt>& s) : m_extendedAscii()
68 {
69 insert(s);
70 }
71
72 size_t size() const noexcept
73 {
74 return 1;
75 }
76
77 template <typename InputIt>
78 void insert(const Range<InputIt>& s) noexcept
79 {
80 uint64_t mask = 1;
81 for (const auto& ch : s) {
82 insert_mask(ch, mask);
83 mask <<= 1;
84 }
85 }
86
87 template <typename CharT>
88 void insert(CharT key, int64_t pos) noexcept
89 {
90 insert_mask(key, UINT64_C(1) << pos);
91 }
92
93 uint64_t get(char key) const noexcept
94 {
96 return m_extendedAscii[static_cast<uint8_t>(key)];
97 }
98
99 template <typename CharT>
100 uint64_t get(CharT key) const noexcept
101 {
102 if (key >= 0 && key <= 255)
103 return m_extendedAscii[static_cast<uint8_t>(key)];
104 else
105 return m_map.get(key);
106 }
107
108 template <typename CharT>
109 uint64_t get(size_t block, CharT key) const noexcept
110 {
111 assert(block == 0);
112 (void)block;
113 return get(key);
114 }
115
116 void insert_mask(char key, uint64_t mask) noexcept
117 {
119 m_extendedAscii[static_cast<uint8_t>(key)] |= mask;
120 }
121
122 template <typename CharT>
123 void insert_mask(CharT key, uint64_t mask) noexcept
124 {
125 if (key >= 0 && key <= 255)
126 m_extendedAscii[static_cast<uint8_t>(key)] |= mask;
127 else
128 m_map[key] |= mask;
129 }
130
131private:
132 BitvectorHashmap m_map;
133 std::array<uint64_t, 256> m_extendedAscii;
134};
135
136struct BlockPatternMatchVector {
137 BlockPatternMatchVector() = delete;
138
139 BlockPatternMatchVector(size_t str_len)
140 : m_block_count(ceil_div(str_len, 64)), m_map(nullptr), m_extendedAscii(256, m_block_count, 0)
141 {}
142
143 template <typename InputIt>
144 BlockPatternMatchVector(const Range<InputIt>& s) : BlockPatternMatchVector(s.size())
145 {
146 insert(s);
147 }
148
149 ~BlockPatternMatchVector()
150 {
151 delete[] m_map;
152 }
153
154 size_t size() const noexcept
155 {
156 return m_block_count;
157 }
158
159 template <typename CharT>
160 void insert(size_t block, CharT ch, int pos) noexcept
161 {
162 uint64_t mask = UINT64_C(1) << pos;
163 insert_mask(block, ch, mask);
164 }
165
172 template <typename InputIt>
173 void insert(const Range<InputIt>& s) noexcept
174 {
175 uint64_t mask = 1;
176 size_t i = 0;
177 for (auto iter = s.begin(); iter != s.end(); ++iter, ++i) {
178 size_t block = i / 64;
179 insert_mask(block, *iter, mask);
180 mask = rotl(mask, 1);
181 }
182 }
183
184 template <typename CharT>
185 void insert_mask(size_t block, CharT key, uint64_t mask) noexcept
186 {
187 assert(block < size());
188 if (key >= 0 && key <= 255)
189 m_extendedAscii[static_cast<uint8_t>(key)][block] |= mask;
190 else {
191 if (!m_map) m_map = new BitvectorHashmap[m_block_count];
192 m_map[block][key] |= mask;
193 }
194 }
195
196 void insert_mask(size_t block, char key, uint64_t mask) noexcept
197 {
198 insert_mask(block, static_cast<uint8_t>(key), mask);
199 }
200
201 template <typename CharT>
202 uint64_t get(size_t block, CharT key) const noexcept
203 {
204 if (key >= 0 && key <= 255)
205 return m_extendedAscii[static_cast<uint8_t>(key)][block];
206 else if (m_map)
207 return m_map[block].get(key);
208 else
209 return 0;
210 }
211
212 uint64_t get(size_t block, char ch) const noexcept
213 {
214 return get(block, static_cast<uint8_t>(ch));
215 }
216
217private:
218 size_t m_block_count;
219 BitvectorHashmap* m_map;
220 BitMatrix<uint64_t> m_extendedAscii;
221};
222
223} // namespace detail
224} // namespace rapidfuzz