7#include <rapidfuzz/details/config.hpp>
19struct LevenshteinWeightTable {
53 EditOp(EditType type_,
size_t src_pos_,
size_t dest_pos_)
58inline bool operator==(EditOp a, EditOp b)
60 return (a.type == b.type) && (a.src_pos == b.src_pos) && (a.dest_pos == b.dest_pos);
63inline bool operator!=(EditOp a, EditOp b)
91 Opcode(EditType type_,
size_t src_begin_,
size_t src_end_,
size_t dest_begin_,
size_t dest_end_)
96inline bool operator==(Opcode a, Opcode b)
98 return (a.type == b.type) && (a.src_begin == b.src_begin) && (a.src_end == b.src_end) &&
99 (a.dest_begin == b.dest_begin) && (a.dest_end == b.dest_end);
102inline bool operator!=(Opcode a, Opcode b)
108template <
typename Vec>
109auto vector_slice(
const Vec& vec,
int start,
int stop,
int step) -> Vec
113 if (step == 0)
throw std::invalid_argument(
"slice step cannot be zero");
114 if (step < 0)
throw std::invalid_argument(
"step sizes below 0 lead to an invalid order of editops");
117 start = std::max<int>(start +
static_cast<int>(vec.size()), 0);
118 else if (start >
static_cast<int>(vec.size()))
119 start =
static_cast<int>(vec.size());
122 stop = std::max<int>(stop +
static_cast<int>(vec.size()), 0);
123 else if (stop >
static_cast<int>(vec.size()))
124 stop =
static_cast<int>(vec.size());
126 if (start >= stop)
return new_vec;
128 int count = (stop - 1 - start) / step + 1;
129 new_vec.reserve(
static_cast<size_t>(count));
131 for (
int i = start; i < stop; i += step)
132 new_vec.push_back(vec[
static_cast<size_t>(i)]);
137template <
typename Vec>
138void vector_remove_slice(Vec& vec,
int start,
int stop,
int step)
140 if (step == 0)
throw std::invalid_argument(
"slice step cannot be zero");
141 if (step < 0)
throw std::invalid_argument(
"step sizes below 0 lead to an invalid order of editops");
144 start = std::max<int>(start +
static_cast<int>(vec.size()), 0);
145 else if (start >
static_cast<int>(vec.size()))
146 start =
static_cast<int>(vec.size());
149 stop = std::max<int>(stop +
static_cast<int>(vec.size()), 0);
150 else if (stop >
static_cast<int>(vec.size()))
151 stop =
static_cast<int>(vec.size());
153 if (start >= stop)
return;
155 auto iter = vec.begin() + start;
156 for (
int i = start; i < static_cast<int>(vec.size()); i++)
157 if (i >= stop || ((i - start) % step != 0)) *(iter++) = vec[
static_cast<size_t>(i)];
159 vec.resize(
static_cast<size_t>(std::distance(vec.begin(), iter)));
167class Editops :
private std::vector<EditOp> {
169 using std::vector<EditOp>::size_type;
171 Editops() noexcept : src_len(0), dest_len(0)
174 Editops(size_type count,
const EditOp& value) : std::vector<EditOp>(count, value), src_len(0), dest_len(0)
177 explicit Editops(size_type count) : std::vector<EditOp>(count), src_len(0), dest_len(0)
180 Editops(
const Editops& other)
181 : std::vector<EditOp>(other), src_len(other.src_len), dest_len(other.dest_len)
184 Editops(
const Opcodes& other);
186 Editops(Editops&& other)
noexcept
191 Editops& operator=(Editops other)
noexcept
198 using std::vector<EditOp>::at;
199 using std::vector<EditOp>::operator[];
200 using std::vector<EditOp>::front;
201 using std::vector<EditOp>::back;
202 using std::vector<EditOp>::data;
205 using std::vector<EditOp>::begin;
206 using std::vector<EditOp>::cbegin;
207 using std::vector<EditOp>::end;
208 using std::vector<EditOp>::cend;
209 using std::vector<EditOp>::rbegin;
210 using std::vector<EditOp>::crbegin;
211 using std::vector<EditOp>::rend;
212 using std::vector<EditOp>::crend;
215 using std::vector<EditOp>::empty;
216 using std::vector<EditOp>::size;
217 using std::vector<EditOp>::max_size;
218 using std::vector<EditOp>::reserve;
219 using std::vector<EditOp>::capacity;
220 using std::vector<EditOp>::shrink_to_fit;
223 using std::vector<EditOp>::clear;
224 using std::vector<EditOp>::insert;
225 using std::vector<EditOp>::emplace;
226 using std::vector<EditOp>::erase;
227 using std::vector<EditOp>::push_back;
228 using std::vector<EditOp>::emplace_back;
229 using std::vector<EditOp>::pop_back;
230 using std::vector<EditOp>::resize;
232 void swap(Editops& rhs)
noexcept
234 std::swap(src_len, rhs.src_len);
235 std::swap(dest_len, rhs.dest_len);
236 std::vector<EditOp>::swap(rhs);
239 Editops slice(
int start,
int stop,
int step = 1)
const
241 Editops ed_slice = detail::vector_slice(*
this, start, stop, step);
242 ed_slice.src_len = src_len;
243 ed_slice.dest_len = dest_len;
247 void remove_slice(
int start,
int stop,
int step = 1)
249 detail::vector_remove_slice(*
this, start, stop, step);
252 Editops reverse()
const
254 Editops reversed = *
this;
255 std::reverse(reversed.begin(), reversed.end());
259 size_t get_src_len() const noexcept
263 void set_src_len(
size_t len)
noexcept
267 size_t get_dest_len() const noexcept
271 void set_dest_len(
size_t len)
noexcept
276 Editops inverse()
const
278 Editops inv_ops = *
this;
279 std::swap(inv_ops.src_len, inv_ops.dest_len);
280 for (
auto& op : inv_ops) {
281 std::swap(op.src_pos, op.dest_pos);
282 if (op.type == EditType::Delete)
283 op.type = EditType::Insert;
284 else if (op.type == EditType::Insert)
285 op.type = EditType::Delete;
290 Editops remove_subsequence(
const Editops& subsequence)
const
293 result.set_src_len(src_len);
294 result.set_dest_len(dest_len);
296 if (subsequence.size() > size())
throw std::invalid_argument(
"subsequence is not a subsequence");
298 result.resize(size() - subsequence.size());
302 auto op_iter = begin();
304 size_t result_pos = 0;
305 for (
const auto& sop : subsequence) {
306 for (; op_iter != op_end && sop != *op_iter; op_iter++) {
307 if (result_pos >= result.size())
throw std::invalid_argument(
"subsequence is not a subsequence");
309 result[result_pos] = *op_iter;
310 result[result_pos].src_pos =
311 static_cast<size_t>(
static_cast<ptrdiff_t
>(result[result_pos].src_pos) + offset);
315 if (op_iter == op_end)
throw std::invalid_argument(
"subsequence is not a subsequence");
317 if (sop.type == EditType::Insert)
319 else if (sop.type == EditType::Delete)
325 for (; op_iter != op_end; op_iter++) {
326 result[result_pos] = *op_iter;
327 result[result_pos].src_pos =
328 static_cast<size_t>(
static_cast<ptrdiff_t
>(result[result_pos].src_pos) + offset);
340inline bool operator==(
const Editops& lhs,
const Editops& rhs)
342 if (lhs.get_src_len() != rhs.get_src_len() || lhs.get_dest_len() != rhs.get_dest_len())
return false;
344 if (lhs.size() != rhs.size())
return false;
346 return std::equal(lhs.begin(), lhs.end(), rhs.begin());
349inline bool operator!=(
const Editops& lhs,
const Editops& rhs)
351 return !(lhs == rhs);
354inline void swap(Editops& lhs, Editops& rhs)
noexcept(
noexcept(lhs.swap(rhs)))
359class Opcodes :
private std::vector<Opcode> {
361 using std::vector<Opcode>::size_type;
363 Opcodes() noexcept : src_len(0), dest_len(0)
366 Opcodes(size_type count,
const Opcode& value) : std::vector<Opcode>(count, value), src_len(0), dest_len(0)
369 explicit Opcodes(size_type count) : std::vector<Opcode>(count), src_len(0), dest_len(0)
372 Opcodes(
const Opcodes& other)
373 : std::vector<Opcode>(other), src_len(other.src_len), dest_len(other.dest_len)
376 Opcodes(
const Editops& other);
378 Opcodes(Opcodes&& other)
noexcept
383 Opcodes& operator=(Opcodes other)
noexcept
390 using std::vector<Opcode>::at;
391 using std::vector<Opcode>::operator[];
392 using std::vector<Opcode>::front;
393 using std::vector<Opcode>::back;
394 using std::vector<Opcode>::data;
397 using std::vector<Opcode>::begin;
398 using std::vector<Opcode>::cbegin;
399 using std::vector<Opcode>::end;
400 using std::vector<Opcode>::cend;
401 using std::vector<Opcode>::rbegin;
402 using std::vector<Opcode>::crbegin;
403 using std::vector<Opcode>::rend;
404 using std::vector<Opcode>::crend;
407 using std::vector<Opcode>::empty;
408 using std::vector<Opcode>::size;
409 using std::vector<Opcode>::max_size;
410 using std::vector<Opcode>::reserve;
411 using std::vector<Opcode>::capacity;
412 using std::vector<Opcode>::shrink_to_fit;
415 using std::vector<Opcode>::clear;
416 using std::vector<Opcode>::insert;
417 using std::vector<Opcode>::emplace;
418 using std::vector<Opcode>::erase;
419 using std::vector<Opcode>::push_back;
420 using std::vector<Opcode>::emplace_back;
421 using std::vector<Opcode>::pop_back;
422 using std::vector<Opcode>::resize;
424 void swap(Opcodes& rhs)
noexcept
426 std::swap(src_len, rhs.src_len);
427 std::swap(dest_len, rhs.dest_len);
428 std::vector<Opcode>::swap(rhs);
431 Opcodes slice(
int start,
int stop,
int step = 1)
const
433 Opcodes ed_slice = detail::vector_slice(*
this, start, stop, step);
434 ed_slice.src_len = src_len;
435 ed_slice.dest_len = dest_len;
439 Opcodes reverse()
const
441 Opcodes reversed = *
this;
442 std::reverse(reversed.begin(), reversed.end());
446 size_t get_src_len() const noexcept
450 void set_src_len(
size_t len)
noexcept
454 size_t get_dest_len() const noexcept
458 void set_dest_len(
size_t len)
noexcept
463 Opcodes inverse()
const
465 Opcodes inv_ops = *
this;
466 std::swap(inv_ops.src_len, inv_ops.dest_len);
467 for (
auto& op : inv_ops) {
468 std::swap(op.src_begin, op.dest_begin);
469 std::swap(op.src_end, op.dest_end);
470 if (op.type == EditType::Delete)
471 op.type = EditType::Insert;
472 else if (op.type == EditType::Insert)
473 op.type = EditType::Delete;
483inline bool operator==(
const Opcodes& lhs,
const Opcodes& rhs)
485 if (lhs.get_src_len() != rhs.get_src_len() || lhs.get_dest_len() != rhs.get_dest_len())
return false;
487 if (lhs.size() != rhs.size())
return false;
489 return std::equal(lhs.begin(), lhs.end(), rhs.begin());
492inline bool operator!=(
const Opcodes& lhs,
const Opcodes& rhs)
494 return !(lhs == rhs);
497inline void swap(Opcodes& lhs, Opcodes& rhs)
noexcept(
noexcept(lhs.swap(rhs)))
502inline Editops::Editops(
const Opcodes& other)
504 src_len = other.get_src_len();
505 dest_len = other.get_dest_len();
506 for (
const auto& op : other) {
508 case EditType::None:
break;
510 case EditType::Replace:
511 for (
size_t j = 0; j < op.src_end - op.src_begin; j++)
512 push_back({EditType::Replace, op.src_begin + j, op.dest_begin + j});
515 case EditType::Insert:
516 for (
size_t j = 0; j < op.dest_end - op.dest_begin; j++)
517 push_back({EditType::Insert, op.src_begin, op.dest_begin + j});
520 case EditType::Delete:
521 for (
size_t j = 0; j < op.src_end - op.src_begin; j++)
522 push_back({EditType::Delete, op.src_begin + j, op.dest_begin});
528inline Opcodes::Opcodes(
const Editops& other)
530 src_len = other.get_src_len();
531 dest_len = other.get_dest_len();
534 for (
size_t i = 0; i < other.size();) {
535 if (src_pos < other[i].src_pos || dest_pos < other[i].dest_pos) {
536 push_back({EditType::None, src_pos, other[i].src_pos, dest_pos, other[i].dest_pos});
537 src_pos = other[i].src_pos;
538 dest_pos = other[i].dest_pos;
541 size_t src_begin = src_pos;
542 size_t dest_begin = dest_pos;
543 EditType type = other[i].type;
546 case EditType::None:
break;
548 case EditType::Replace:
553 case EditType::Insert: dest_pos++;
break;
555 case EditType::Delete: src_pos++;
break;
558 }
while (i < other.size() && other[i].type == type && src_pos == other[i].src_pos &&
559 dest_pos == other[i].dest_pos);
561 push_back({type, src_begin, src_pos, dest_begin, dest_pos});
564 if (src_pos < other.get_src_len() || dest_pos < other.get_dest_len()) {
565 push_back({EditType::None, src_pos, other.get_src_len(), dest_pos, other.get_dest_len()});
570struct ScoreAlignment {
577 ScoreAlignment() : score(T()), src_start(0), src_end(0), dest_start(0), dest_end(0)
580 ScoreAlignment(T score_,
size_t src_start_,
size_t src_end_,
size_t dest_start_,
size_t dest_end_)
582 src_start(src_start_),
584 dest_start(dest_start_),
590inline bool operator==(
const ScoreAlignment<T>& a,
const ScoreAlignment<T>& b)
592 return (a.score == b.score) && (a.src_start == b.src_start) && (a.src_end == b.src_end) &&
593 (a.dest_start == b.dest_start) && (a.dest_end == b.dest_end);
Edit operations used by the Levenshtein distance.
Definition types.hpp:45
EditType type
Definition types.hpp:46
size_t dest_pos
Definition types.hpp:48
size_t src_pos
Definition types.hpp:47
Edit operations used by the Levenshtein distance.
Definition types.hpp:81
EditType type
Definition types.hpp:82
size_t dest_end
Definition types.hpp:86
size_t src_end
Definition types.hpp:84
size_t dest_begin
Definition types.hpp:85
size_t src_begin
Definition types.hpp:83