Skip to content

Commit 77a07fb

Browse files
committed
[共通] levenshtein-sse.hpp 非依存の String::levenshteinDistanceFrom() を非 SSE 向けに追加 #1239
1 parent b27886b commit 77a07fb

File tree

2 files changed

+86
-38
lines changed

2 files changed

+86
-38
lines changed

Siv3D/src/Siv3D/String/Levenshtein.cpp

+76-16
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,88 @@
1111

1212
# include <Siv3D/Common.hpp>
1313
# include <Siv3D/String.hpp>
14+
# include <Siv3D/Array.hpp>
15+
# include <Siv3D/SIMD.hpp>
1416

15-
# if defined(__GNUC__)
16-
_Pragma("GCC diagnostic push")
17-
_Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")
17+
# if SIV3D_INTRINSIC(SSE)
18+
19+
# if defined(_M_X64)
20+
# define __SSE__ 1
21+
# define __SSE2__ 1
22+
# define __SSE3__ 1
23+
# define __SSSE3__ 1
24+
# define __SSE4_1__ 1
25+
# define __SSE4_2__ 1
1826
# endif
19-
# if defined(__clang__)
20-
_Pragma("clang diagnostic push")
21-
_Pragma("clang diagnostic ignored \"-Wunused-parameter\"")
22-
_Pragma("clang diagnostic ignored \"-Wshorten-64-to-32\"")
27+
28+
# include <ThirdParty/levenshtein-sse/levenshtein-sse.hpp>
2329
# endif
24-
SIV3D_DISABLE_MSVC_WARNINGS_PUSH(4100)
25-
SIV3D_DISABLE_MSVC_WARNINGS_PUSH(4267)
26-
# include <ThirdParty/levenshtein-sse/levenshtein-sse.hpp>
27-
SIV3D_DISABLE_MSVC_WARNINGS_POP()
28-
SIV3D_DISABLE_MSVC_WARNINGS_POP()
29-
SIV3D_DISABLE_CLANG_WARNINGS_POP()
30-
SIV3D_DISABLE_GCC_WARNINGS_POP()
3130

3231
namespace s3d
3332
{
34-
size_t String::levenshteinDistanceFrom(const StringView other) const noexcept
33+
namespace
3534
{
36-
return levenshteinSSE::levenshtein(begin(), end(), other.begin(), other.end());
35+
[[nodiscard]]
36+
static size_t LevenshteinDistance(const StringView s1, const StringView s2) noexcept
37+
{
38+
const size_t minSize = s1.size();
39+
const size_t maxSize = s2.size();
40+
41+
if (maxSize < minSize)
42+
{
43+
return LevenshteinDistance(s2, s1);
44+
}
45+
46+
Array<size_t> distances(minSize + 1);
47+
48+
for (size_t i = 0; i <= minSize; ++i)
49+
{
50+
distances[i] = i;
51+
}
52+
53+
for (size_t k = 1; k <= maxSize; ++k)
54+
{
55+
size_t t = distances[0];
56+
57+
++distances[0];
58+
59+
for (size_t i = 1; i <= minSize; ++i)
60+
{
61+
const size_t old = distances[i];
62+
63+
if (s1[i - 1] == s2[k - 1])
64+
{
65+
distances[i] = t;
66+
}
67+
else
68+
{
69+
distances[i] = (Min(Min(distances[i - 1], distances[i]), t) + 1);
70+
}
71+
72+
t = old;
73+
}
74+
}
75+
76+
return distances[minSize];
77+
}
78+
}
79+
80+
////////////////////////////////////////////////////////////////
81+
//
82+
// levenshteinDistanceFrom
83+
//
84+
////////////////////////////////////////////////////////////////
85+
86+
String::size_type String::levenshteinDistanceFrom(const StringView other) const noexcept
87+
{
88+
# if SIV3D_INTRINSIC(SSE)
89+
90+
return levenshteinSSE::levenshtein(m_string, other);
91+
92+
# else
93+
94+
return LevenshteinDistance(m_string, other);
95+
96+
# endif
3797
}
3898
}

Siv3D/src/ThirdParty/levenshtein-sse/levenshtein-sse.hpp

+10-22
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,7 @@
1212
#include <iterator>
1313
#include <cstdint>
1414
#include <cassert>
15-
16-
# include <Siv3D/SIMD.hpp>
17-
# ifndef __SSE2__
18-
# define __SSE2__ 1
19-
# endif
20-
# ifndef __SSSE3__
21-
# define __SSSE3__ 1
22-
# endif
23-
# ifndef __SSE4_1__
24-
# define __SSE4_1__ 1
25-
# endif
26-
27-
#ifdef __AVX2__
28-
#include <immintrin.h>
29-
#endif
15+
#include <limits>
3016

3117
namespace levenshteinSSE {
3218

@@ -198,9 +184,9 @@ constexpr std::size_t alignment = 1;
198184
template<typename Vec1, typename Vec2, typename Iterator1, typename Iterator2>
199185
struct LevenshteinIterationBase {
200186
static inline void perform(const Iterator1& a, const Iterator2& b,
201-
std::size_t& i, std::size_t j, std::size_t bLen, Vec1& diag, const Vec2& diag2)
187+
std::size_t& i, std::size_t j, [[maybe_unused]] std::size_t bLen, Vec1& diag, const Vec2& diag2)
202188
{
203-
std::size_t min = std::min(diag2[i], diag2[i-1]);
189+
std::uint32_t min = static_cast<std::uint32_t>(std::min(diag2[i], diag2[i-1]));
204190
if (min < diag[i-1]) {
205191
diag[i] = min + 1;
206192
}
@@ -280,7 +266,7 @@ static inline void performSIMD(const T* a, const T* b,
280266

281267
#ifdef __SSSE3__
282268
static inline void performSSE(const T* a, const T* b,
283-
std::size_t& i, std::size_t j, std::size_t bLen,
269+
std::size_t& i, std::size_t j, [[maybe_unused]] std::size_t bLen,
284270
std::uint32_t* diag, const std::uint32_t* diag2)
285271
{
286272
const __m128i one128_epi32 = _mm_set1_epi32(1);
@@ -315,10 +301,10 @@ static inline void performSSE(const T* a, const T* b,
315301
// We support 1, 2, and 4 byte objects for SSE comparison.
316302
// We always process 16 entries at once, so we may need multiple fetches
317303
// depending on object size.
318-
if (sizeof(T) <= 2) {
304+
if constexpr (sizeof(T) <= 2) {
319305
__m128i substitutionCost16LX, substitutionCost16HX;
320306

321-
if (sizeof(T) == 1) {
307+
if constexpr (sizeof(T) == 1) {
322308
__m128i a_ = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&a[i-16]));
323309
__m128i b_ = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&b[j-1]));
324310
a_ = _mm_shuffle_epi8(a_, reversedIdentity128_epi8);
@@ -782,10 +768,10 @@ T levenshteinDiagonal(Iterator1 a, Iterator1 aEnd, Iterator2 b, Iterator2 bEnd)
782768
::perform(a, b, i, j, bLen, diag, diag2);
783769
}
784770

785-
diag[0] = k;
771+
diag[0] = static_cast<T>(k);
786772

787773
if (k <= aLen) {
788-
diag[k] = k;
774+
diag[k] = static_cast<T>(k);
789775
}
790776

791777
if (k == aLen + bLen) {
@@ -796,6 +782,8 @@ T levenshteinDiagonal(Iterator1 a, Iterator1 aEnd, Iterator2 b, Iterator2 bEnd)
796782
// switch buffers
797783
std::swap(diag, diag2);
798784
}
785+
786+
assert(0);
799787
}
800788

801789
/**

0 commit comments

Comments
 (0)