RapidFuzz
Loading...
Searching...
No Matches
common_impl.hpp
1/* SPDX-License-Identifier: MIT */
2/* Copyright © 2020 Max Bachmann */
3
4#include <algorithm>
5#include <array>
6#include <iterator>
7
8namespace rapidfuzz {
9namespace detail {
10
11template <typename InputIt1, typename InputIt2>
12DecomposedSet<InputIt1, InputIt2, InputIt1> set_decomposition(SplittedSentenceView<InputIt1> a,
13 SplittedSentenceView<InputIt2> b)
14{
15 a.dedupe();
16 b.dedupe();
17
18 RangeVec<InputIt1> intersection;
19 RangeVec<InputIt1> difference_ab;
20 RangeVec<InputIt2> difference_ba = b.words();
21
22 for (const auto& current_a : a.words()) {
23 auto element_b = std::find(difference_ba.begin(), difference_ba.end(), current_a);
24
25 if (element_b != difference_ba.end()) {
26 difference_ba.erase(element_b);
27 intersection.push_back(current_a);
28 }
29 else {
30 difference_ab.push_back(current_a);
31 }
32 }
33
34 return {difference_ab, difference_ba, intersection};
35}
36
37template <class InputIt1, class InputIt2>
38std::pair<InputIt1, InputIt2> rf_mismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2)
39{
40 while (first1 != last1 && first2 != last2 && *first1 == *first2)
41 ++first1, ++first2;
42
43 return std::make_pair(first1, first2);
44}
45
49template <typename InputIt1, typename InputIt2>
50size_t remove_common_prefix(Range<InputIt1>& s1, Range<InputIt2>& s2)
51{
52 auto first1 = std::begin(s1);
53 size_t prefix = static_cast<size_t>(
54 std::distance(first1, rf_mismatch(first1, std::end(s1), std::begin(s2), std::end(s2)).first));
55 s1.remove_prefix(prefix);
56 s2.remove_prefix(prefix);
57 return prefix;
58}
59
63template <typename InputIt1, typename InputIt2>
64size_t remove_common_suffix(Range<InputIt1>& s1, Range<InputIt2>& s2)
65{
66 auto rfirst1 = s1.rbegin();
67 size_t suffix = static_cast<size_t>(
68 std::distance(rfirst1, rf_mismatch(rfirst1, s1.rend(), s2.rbegin(), s2.rend()).first));
69 s1.remove_suffix(suffix);
70 s2.remove_suffix(suffix);
71 return suffix;
72}
73
77template <typename InputIt1, typename InputIt2>
78StringAffix remove_common_affix(Range<InputIt1>& s1, Range<InputIt2>& s2)
79{
80 return StringAffix{remove_common_prefix(s1, s2), remove_common_suffix(s1, s2)};
81}
82
83template <typename, typename = void>
84struct is_space_dispatch_tag : std::integral_constant<int, 0> {};
85
86template <typename CharT>
87struct is_space_dispatch_tag<CharT, typename std::enable_if<sizeof(CharT) == 1>::type>
88 : std::integral_constant<int, 1> {};
89
90/*
91 * Implementation of is_space for char types that are at least 2 Byte in size
92 */
93template <typename CharT>
94bool is_space_impl(const CharT ch, std::integral_constant<int, 0>)
95{
96 switch (ch) {
97 case 0x0009:
98 case 0x000A:
99 case 0x000B:
100 case 0x000C:
101 case 0x000D:
102 case 0x001C:
103 case 0x001D:
104 case 0x001E:
105 case 0x001F:
106 case 0x0020:
107 case 0x0085:
108 case 0x00A0:
109 case 0x1680:
110 case 0x2000:
111 case 0x2001:
112 case 0x2002:
113 case 0x2003:
114 case 0x2004:
115 case 0x2005:
116 case 0x2006:
117 case 0x2007:
118 case 0x2008:
119 case 0x2009:
120 case 0x200A:
121 case 0x2028:
122 case 0x2029:
123 case 0x202F:
124 case 0x205F:
125 case 0x3000: return true;
126 }
127 return false;
128}
129
130/*
131 * Implementation of is_space for char types that are 1 Byte in size
132 */
133template <typename CharT>
134bool is_space_impl(const CharT ch, std::integral_constant<int, 1>)
135{
136 switch (ch) {
137 case 0x0009:
138 case 0x000A:
139 case 0x000B:
140 case 0x000C:
141 case 0x000D:
142 case 0x001C:
143 case 0x001D:
144 case 0x001E:
145 case 0x001F:
146 case 0x0020: return true;
147 }
148 return false;
149}
150
151/*
152 * checks whether unicode characters have the bidirectional
153 * type 'WS', 'B' or 'S' or the category 'Zs'
154 */
155template <typename CharT>
156bool is_space(const CharT ch)
157{
158 return is_space_impl(ch, is_space_dispatch_tag<CharT>{});
159}
160
161template <typename InputIt, typename CharT>
162SplittedSentenceView<InputIt> sorted_split(InputIt first, InputIt last)
163{
164 RangeVec<InputIt> splitted;
165 auto second = first;
166
167 for (; first != last; first = second + 1) {
168 second = std::find_if(first, last, is_space<CharT>);
169
170 if (first != second) {
171 splitted.emplace_back(first, second);
172 }
173
174 if (second == last) break;
175 }
176
177 std::sort(splitted.begin(), splitted.end());
178
179 return SplittedSentenceView<InputIt>(splitted);
180}
181
182} // namespace detail
183} // namespace rapidfuzz