1
// This file is based on strnatcmp.c by Martin Pool
2
// Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
4
// Copyright (C) 2020, the Celestia Development Team
6
// This software is provided 'as-is', without any express or implied
7
// warranty. In no event will the authors be held liable for any damages
8
// arising from the use of this software.
10
// Permission is granted to anyone to use this software for any purpose,
11
// including commercial applications, and to alter it and redistribute it
12
// freely, subject to the following restrictions:
14
// 1. The origin of this software must not be misrepresented; you must not
15
// claim that you wrote the original software. If you use this software
16
// in a product, an acknowledgment in the product documentation would be
17
// appreciated but is not required.
18
// 2. Altered source versions must be plainly marked as such, and must not be
19
// misrepresented as being the original software.
20
// 3. This notice may not be removed or altered from any source distribution.
28
#include <celutil/utf8.h>
34
using MaybeChar = std::optional<std::int32_t>;
40
return c.has_value() &&
41
c >= 0 && c <= WCHAR_MAX &&
42
std::iswdigit(static_cast<std::wint_t>(*c));
45
inline bool isSpace(MaybeChar c)
47
return c.has_value() &&
48
c >= 0 && c<= WCHAR_MAX &&
56
explicit CharMapper(std::string_view _sv) : sv(_sv) {}
60
auto svSize = static_cast<std::int32_t>(sv.size());
65
if (!UTF8Decode(sv, offset, ch))
76
std::int32_t offset{ 0 };
81
right(CharMapper& a, MaybeChar& ca, CharMapper& b, MaybeChar& cb)
85
// The longest run of digits wins. That aside, the greatest value
86
// wins, but we can't know that it will until we've scanned both
87
// numbers to know that they have the same magnitude, so we remember
92
return isDigit(cb) ? -1 : bias;
111
left(CharMapper& a, MaybeChar& ca, CharMapper& b, MaybeChar& cb)
113
// Compare two left-aligned numbers: the first to have a
114
// different value wins.
118
return isDigit(cb) ? -1 : 0;
132
strnatcmp0(CharMapper& a, CharMapper& b)
134
// skip over leading space
135
MaybeChar ca = a.next();
139
MaybeChar cb = b.next();
146
return cb.has_value() ? -1 : 0;
150
// process run of digits
151
if (std::iswdigit(*ca) && std::iswdigit(*cb))
153
int r = (*ca == L'0' || *cb == L'0')
155
: right(a, ca, b, cb);
172
} // end unnamed namespace
176
strnatcmp(std::string_view a, std::string_view b)
178
CharMapper aMapper{a};
179
CharMapper bMapper{b};
180
return strnatcmp0(aMapper, bMapper);