Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/include/o3tl/string_view.hxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 */
9
10
#pragma once
11
12
#include <sal/config.h>
13
14
#include <cassert>
15
#include <cstddef>
16
#include <string>
17
#include <string_view>
18
#include <type_traits>
19
20
#include <o3tl/intcmp.hxx>
21
#include <rtl/character.hxx>
22
#include <rtl/ustring.h>
23
#include <rtl/math.h>
24
#include <sal/types.h>
25
26
namespace o3tl
27
{
28
// Like OUString::equalsAscii/OUString::equalsAsciiL, but for std::u16string_view:
29
inline bool equalsAscii(std::u16string_view s1, std::string_view s2)
30
32.0M
{
31
32.0M
    return s1.size() == s2.size()
32
1.03M
           && rtl_ustr_ascii_shortenedCompare_WithLength(s1.data(), s1.size(), s2.data(), s2.size())
33
1.03M
                  == 0;
34
32.0M
}
35
36
// Like OUString::compareToAscii, but for std::u16string_view and std::string_view:
37
inline int compareToAscii(std::u16string_view s1, std::string_view s2)
38
3.48k
{
39
3.48k
    return rtl_ustr_asciil_reverseCompare_WithLength(s1.data(), s1.size(), s2.data(), s2.size());
40
3.48k
};
41
42
// Like OUString::equalsIgnoreAsciiCase, but for two std::u16string_view:
43
inline bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
44
727k
{
45
727k
    if (s1.size() != s2.size())
46
396k
        return false;
47
330k
    if (s1.data() == s2.data())
48
32
        return true;
49
330k
    return rtl_ustr_compareIgnoreAsciiCase_WithLength(s1.data(), s1.size(), s2.data(), s2.size())
50
330k
           == 0;
51
330k
};
52
53
inline bool equalsIgnoreAsciiCase(std::u16string_view s1, std::string_view s2)
54
3.26M
{
55
3.26M
    return s1.size() == s2.size()
56
172k
           && (rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength(s1.data(), s1.size(),
57
172k
                                                                         s2.data(), s2.size())
58
172k
               == 0);
59
3.26M
}
60
61
inline bool equalsIgnoreAsciiCase(std::string_view s1, std::string_view s2)
62
1
{
63
1
    if (s1.size() != s2.size())
64
0
        return false;
65
1
    if (s1.data() == s2.data())
66
0
        return true;
67
1
    return rtl_str_compareIgnoreAsciiCase_WithLength(s1.data(), s1.size(), s2.data(), s2.size())
68
1
           == 0;
69
1
};
70
71
// Like OUString::compareToIgnoreAsciiCase, but for two std::u16string_view:
72
inline int compareToIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
73
12.8M
{
74
12.8M
    return rtl_ustr_compareIgnoreAsciiCase_WithLength(s1.data(), s1.size(), s2.data(), s2.size());
75
12.8M
};
76
77
// Like OUString::matchIgnoreAsciiCase, but for two std::u16string_view:
78
inline bool matchIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2,
79
                                 sal_Int32 fromIndex = 0)
80
6.75M
{
81
6.75M
    return rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength(
82
6.75M
               s1.data() + fromIndex, s1.size() - fromIndex, s2.data(), s2.size(), s2.size())
83
6.75M
           == 0;
84
6.75M
}
85
86
// Like OUString::matchIgnoreAsciiCase, but for std::u16string_view and std::string_view:
87
inline bool matchIgnoreAsciiCase(std::u16string_view s1, std::string_view s2,
88
                                 sal_Int32 fromIndex = 0)
89
456k
{
90
456k
    return rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength(
91
456k
               s1.data() + fromIndex, s1.size() - fromIndex, s2.data(), s2.size())
92
456k
           == 0;
93
456k
}
94
95
// Like OUString::endsWithIgnoreAsciiCase, but for std::u16string_view
96
inline bool endsWithIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2,
97
                                    std::u16string_view* rest = nullptr)
98
0
{
99
0
    auto const b = s2.size() <= s1.size() && matchIgnoreAsciiCase(s1, s2, s1.size() - s2.size());
100
0
    if (b && rest != nullptr)
101
0
    {
102
0
        *rest = s1.substr(0, s1.size() - s2.size());
103
0
    }
104
0
    return b;
105
0
}
106
107
inline bool endsWithIgnoreAsciiCase(std::u16string_view s1, std::string_view s2,
108
                                    std::u16string_view* rest = nullptr)
109
0
{
110
0
    auto const b = s2.size() <= s1.size()
111
0
                   && rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
112
0
                          s1.data() + s1.size() - s2.size(), s2.size(), s2.data(), s2.size())
113
0
                          == 0;
114
0
    if (b && rest != nullptr)
115
0
    {
116
0
        *rest = s1.substr(0, s1.size() - s2.size());
117
0
    }
118
0
    return b;
119
0
}
120
121
// Similar to O[U]String::getToken, returning the first token of a std::[u16]string_view starting
122
// at a given position.
123
//
124
// Attention:  There are two sets of o3tl::getToken overloads here.  This first set has an interface
125
// based on std::size_t length parameters, and its semantics don't match those of
126
// O[U]String::getToken exactly (buf if needed, it can be extended to return the n'th token instead
127
// of just the first, and/or support an initial position of npos, to make the semantics match).
128
template <typename charT, typename traits = std::char_traits<charT>>
129
inline std::basic_string_view<charT, traits> getToken(std::basic_string_view<charT, traits> sv,
130
                                                      charT delimiter, std::size_t& position)
131
43.7k
{
132
43.7k
    assert(position <= sv.size());
133
43.7k
    auto const n = sv.find(delimiter, position);
134
43.7k
    std::basic_string_view<charT, traits> t;
135
43.7k
    if (n == std::string_view::npos)
136
22.5k
    {
137
22.5k
        t = sv.substr(position);
138
22.5k
        position = std::string_view::npos;
139
22.5k
    }
140
21.2k
    else
141
21.2k
    {
142
21.2k
        t = sv.substr(position, n - position);
143
21.2k
        position = n + 1;
144
21.2k
    }
145
43.7k
    return t;
146
43.7k
}
std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> > o3tl::getToken<char16_t, std::__1::char_traits<char16_t> >(std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >, char16_t, unsigned long&)
Line
Count
Source
131
37.4k
{
132
37.4k
    assert(position <= sv.size());
133
37.4k
    auto const n = sv.find(delimiter, position);
134
37.4k
    std::basic_string_view<charT, traits> t;
135
37.4k
    if (n == std::string_view::npos)
136
17.0k
    {
137
17.0k
        t = sv.substr(position);
138
17.0k
        position = std::string_view::npos;
139
17.0k
    }
140
20.3k
    else
141
20.3k
    {
142
20.3k
        t = sv.substr(position, n - position);
143
20.3k
        position = n + 1;
144
20.3k
    }
145
37.4k
    return t;
146
37.4k
}
std::__1::basic_string_view<char, std::__1::char_traits<char> > o3tl::getToken<char, std::__1::char_traits<char> >(std::__1::basic_string_view<char, std::__1::char_traits<char> >, char, unsigned long&)
Line
Count
Source
131
6.29k
{
132
6.29k
    assert(position <= sv.size());
133
6.29k
    auto const n = sv.find(delimiter, position);
134
6.29k
    std::basic_string_view<charT, traits> t;
135
6.29k
    if (n == std::string_view::npos)
136
5.48k
    {
137
5.48k
        t = sv.substr(position);
138
5.48k
        position = std::string_view::npos;
139
5.48k
    }
140
810
    else
141
810
    {
142
810
        t = sv.substr(position, n - position);
143
810
        position = n + 1;
144
810
    }
145
6.29k
    return t;
146
6.29k
}
147
// The following two overloads prevent overload resolution mistakes that would occur with their
148
// template counterpart, when sv is of a type that is implicitly convertible to basic_string_view
149
// (like OString or OUString), in which case overload resolution would erroneously choose the
150
// three-argument overloads (taking sv, nToken, cTok) from the second set of
151
// o3tl::getToken overloads below:
152
inline std::string_view getToken(std::string_view sv, char delimiter, std::size_t& position)
153
6.29k
{
154
6.29k
    return getToken<char>(sv, delimiter, position);
155
6.29k
}
156
inline std::u16string_view getToken(std::u16string_view sv, char16_t delimiter,
157
                                    std::size_t& position)
158
37.4k
{
159
37.4k
    return getToken<char16_t>(sv, delimiter, position);
160
37.4k
}
161
162
// Similar to O[U]String::getToken.
163
//
164
// Attention:  There are two sets of o3tl::getToken overloads here.  This second set has an
165
// interface based on sal_Int32 length parameters, and is meant to be a drop-in replacement for
166
// O[U]String::getToken.
167
template <typename charT, typename traits = std::char_traits<charT>>
168
inline std::basic_string_view<charT, traits> getToken(std::basic_string_view<charT, traits> pStr,
169
                                                      sal_Int32 nToken, charT cTok,
170
                                                      sal_Int32& rnIndex)
171
4.86M
{
172
4.86M
    assert(o3tl::IntCmp(rnIndex) <= o3tl::IntCmp(pStr.size()));
173
174
    // Return an empty string and set rnIndex to -1 if either nToken or rnIndex is
175
    // negative:
176
4.86M
    if (rnIndex >= 0 && nToken >= 0)
177
4.85M
    {
178
4.85M
        const charT* pOrgCharStr = pStr.data();
179
4.85M
        const charT* pCharStr = pOrgCharStr + rnIndex;
180
4.85M
        sal_Int32 nLen = pStr.size() - rnIndex;
181
4.85M
        sal_Int32 nTokCount = 0;
182
4.85M
        const charT* pCharStrStart = pCharStr;
183
182M
        while (nLen > 0)
184
179M
        {
185
179M
            if (*pCharStr == cTok)
186
1.84M
            {
187
1.84M
                nTokCount++;
188
189
1.84M
                if (nTokCount > nToken)
190
1.63M
                    break;
191
211k
                if (nTokCount == nToken)
192
211k
                    pCharStrStart = pCharStr + 1;
193
211k
            }
194
195
177M
            pCharStr++;
196
177M
            nLen--;
197
177M
        }
198
4.85M
        if (nTokCount >= nToken)
199
4.85M
        {
200
4.85M
            if (nLen > 0)
201
1.63M
                rnIndex = pCharStr - pOrgCharStr + 1;
202
3.21M
            else
203
3.21M
                rnIndex = -1;
204
4.85M
            return std::basic_string_view<charT, traits>(pCharStrStart, pCharStr - pCharStrStart);
205
4.85M
        }
206
4.85M
    }
207
208
13.1k
    rnIndex = -1;
209
13.1k
    return std::basic_string_view<charT, traits>();
210
4.86M
}
Unexecuted instantiation: std::__1::basic_string_view<char, std::__1::char_traits<char> > o3tl::getToken<char, std::__1::char_traits<char> >(std::__1::basic_string_view<char, std::__1::char_traits<char> >, int, char, int&)
std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> > o3tl::getToken<char16_t, std::__1::char_traits<char16_t> >(std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >, int, char16_t, int&)
Line
Count
Source
171
4.86M
{
172
4.86M
    assert(o3tl::IntCmp(rnIndex) <= o3tl::IntCmp(pStr.size()));
173
174
    // Return an empty string and set rnIndex to -1 if either nToken or rnIndex is
175
    // negative:
176
4.86M
    if (rnIndex >= 0 && nToken >= 0)
177
4.85M
    {
178
4.85M
        const charT* pOrgCharStr = pStr.data();
179
4.85M
        const charT* pCharStr = pOrgCharStr + rnIndex;
180
4.85M
        sal_Int32 nLen = pStr.size() - rnIndex;
181
4.85M
        sal_Int32 nTokCount = 0;
182
4.85M
        const charT* pCharStrStart = pCharStr;
183
182M
        while (nLen > 0)
184
179M
        {
185
179M
            if (*pCharStr == cTok)
186
1.84M
            {
187
1.84M
                nTokCount++;
188
189
1.84M
                if (nTokCount > nToken)
190
1.63M
                    break;
191
211k
                if (nTokCount == nToken)
192
211k
                    pCharStrStart = pCharStr + 1;
193
211k
            }
194
195
177M
            pCharStr++;
196
177M
            nLen--;
197
177M
        }
198
4.85M
        if (nTokCount >= nToken)
199
4.85M
        {
200
4.85M
            if (nLen > 0)
201
1.63M
                rnIndex = pCharStr - pOrgCharStr + 1;
202
3.21M
            else
203
3.21M
                rnIndex = -1;
204
4.85M
            return std::basic_string_view<charT, traits>(pCharStrStart, pCharStr - pCharStrStart);
205
4.85M
        }
206
4.85M
    }
207
208
13.1k
    rnIndex = -1;
209
13.1k
    return std::basic_string_view<charT, traits>();
210
4.86M
}
211
// The following two overloads prevent deduction failures that would occur with their template
212
// counterpart, when sv is of a type that is implicitly convertible to basic_string_view (like
213
// OString or OUString):
214
inline std::string_view getToken(std::string_view sv, sal_Int32 nToken, char cTok,
215
                                 sal_Int32& rnIndex)
216
0
{
217
0
    return getToken<char>(sv, nToken, cTok, rnIndex);
218
0
}
219
inline std::u16string_view getToken(std::u16string_view sv, sal_Int32 nToken, char16_t cTok,
220
                                    sal_Int32& rnIndex)
221
4.80M
{
222
4.80M
    return getToken<char16_t>(sv, nToken, cTok, rnIndex);
223
4.80M
}
224
inline std::string_view getToken(std::string_view sv, sal_Int32 nToken, char cTok)
225
0
{
226
0
    sal_Int32 nIndex = 0;
227
0
    return getToken<char>(sv, nToken, cTok, nIndex);
228
0
}
229
inline std::u16string_view getToken(std::u16string_view sv, sal_Int32 nToken, char16_t cTok)
230
64.3k
{
231
64.3k
    sal_Int32 nIndex = 0;
232
64.3k
    return getToken<char16_t>(sv, nToken, cTok, nIndex);
233
64.3k
}
234
235
// Implementations of C++20 std::basic_string_view::starts_with and
236
// std::basic_string_view::ends_with, until we can use those directly on all platforms:
237
template <typename charT, typename traits = std::char_traits<charT>>
238
constexpr bool starts_with(std::basic_string_view<charT, traits> sv,
239
                           std::basic_string_view<charT, traits> x) noexcept
240
93.6M
{
241
93.6M
#if defined __cpp_lib_starts_ends_with
242
93.6M
    return sv.starts_with(x);
243
#else
244
    return sv.substr(0, x.size()) == x;
245
#endif
246
93.6M
}
bool o3tl::starts_with<char16_t, std::__1::char_traits<char16_t> >(std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >, std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >)
Line
Count
Source
240
93.4M
{
241
93.4M
#if defined __cpp_lib_starts_ends_with
242
93.4M
    return sv.starts_with(x);
243
#else
244
    return sv.substr(0, x.size()) == x;
245
#endif
246
93.4M
}
bool o3tl::starts_with<char, std::__1::char_traits<char> >(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Line
Count
Source
240
169k
{
241
169k
#if defined __cpp_lib_starts_ends_with
242
169k
    return sv.starts_with(x);
243
#else
244
    return sv.substr(0, x.size()) == x;
245
#endif
246
169k
}
247
template <typename charT, typename traits = std::char_traits<charT>>
248
constexpr bool starts_with(std::basic_string_view<charT, traits> sv, charT x) noexcept
249
{
250
#if defined __cpp_lib_starts_ends_with
251
    return sv.starts_with(x);
252
#else
253
    return !sv.empty() && traits::eq(sv.front(), x);
254
#endif
255
}
256
template <typename charT, typename traits = std::char_traits<charT>>
257
constexpr bool starts_with(std::basic_string_view<charT, traits> sv, charT const* x)
258
5.09M
{
259
5.09M
#if defined __cpp_lib_starts_ends_with
260
5.09M
    return sv.starts_with(x);
261
#else
262
    return starts_with(sv, std::basic_string_view<charT, traits>(x));
263
#endif
264
5.09M
}
bool o3tl::starts_with<char16_t, std::__1::char_traits<char16_t> >(std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >, char16_t const*)
Line
Count
Source
258
5.09M
{
259
5.09M
#if defined __cpp_lib_starts_ends_with
260
5.09M
    return sv.starts_with(x);
261
#else
262
    return starts_with(sv, std::basic_string_view<charT, traits>(x));
263
#endif
264
5.09M
}
bool o3tl::starts_with<char, std::__1::char_traits<char> >(std::__1::basic_string_view<char, std::__1::char_traits<char> >, char const*)
Line
Count
Source
258
577
{
259
577
#if defined __cpp_lib_starts_ends_with
260
577
    return sv.starts_with(x);
261
#else
262
    return starts_with(sv, std::basic_string_view<charT, traits>(x));
263
#endif
264
577
}
265
template <typename charT, typename traits = std::char_traits<charT>>
266
constexpr bool ends_with(std::basic_string_view<charT, traits> sv,
267
                         std::basic_string_view<charT, traits> x) noexcept
268
1.75M
{
269
1.75M
#if defined __cpp_lib_starts_ends_with
270
1.75M
    return sv.ends_with(x);
271
#else
272
    return sv.size() >= x.size()
273
           && sv.compare(sv.size() - x.size(), std::basic_string_view<charT, traits>::npos, x) == 0;
274
#endif
275
1.75M
}
Unexecuted instantiation: bool o3tl::ends_with<char, std::__1::char_traits<char> >(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >)
bool o3tl::ends_with<char16_t, std::__1::char_traits<char16_t> >(std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >, std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >)
Line
Count
Source
268
1.75M
{
269
1.75M
#if defined __cpp_lib_starts_ends_with
270
1.75M
    return sv.ends_with(x);
271
#else
272
    return sv.size() >= x.size()
273
           && sv.compare(sv.size() - x.size(), std::basic_string_view<charT, traits>::npos, x) == 0;
274
#endif
275
1.75M
}
276
template <typename charT, typename traits = std::char_traits<charT>>
277
constexpr bool ends_with(std::basic_string_view<charT, traits> sv, charT x) noexcept
278
{
279
#if defined __cpp_lib_starts_ends_with
280
    return sv.ends_with(x);
281
#else
282
    return !sv.empty() && traits::eq(sv.back(), x);
283
#endif
284
}
285
template <typename charT, typename traits = std::char_traits<charT>>
286
constexpr bool ends_with(std::basic_string_view<charT, traits> sv, charT const* x)
287
1.25M
{
288
1.25M
#if defined __cpp_lib_starts_ends_with
289
1.25M
    return sv.ends_with(x);
290
#else
291
    return ends_with(sv, std::basic_string_view<charT, traits>(x));
292
#endif
293
1.25M
}
294
// The following overloads prevent deduction failures that would occur with their template
295
// counterparts, when x is of a type that is implicitly convertible to basic_string_view (like
296
// OString or OUString, and we only bother to provide overloads for the char and char16_t cases, not
297
// also for char32_t and wchar_t, nor for C++20 char8_t):
298
constexpr bool starts_with(std::string_view sv, std::string_view x) noexcept
299
169k
{
300
169k
    return starts_with<char>(sv, x);
301
169k
}
302
constexpr bool starts_with(std::u16string_view sv, std::u16string_view x) noexcept
303
93.4M
{
304
93.4M
    return starts_with<char16_t>(sv, x);
305
93.4M
}
306
constexpr bool ends_with(std::string_view sv, std::string_view x) noexcept
307
0
{
308
0
    return ends_with<char>(sv, x);
309
0
}
310
constexpr bool ends_with(std::u16string_view sv, std::u16string_view x) noexcept
311
1.75M
{
312
1.75M
    return ends_with<char16_t>(sv, x);
313
1.75M
}
314
315
// Variants of C++20 std::basic_string_view::starts_with and
316
// std::basic_string_view::ends_with that have a rest out parameter, similar to our OString and
317
// OUString startsWith and endsWith member functions:
318
template <typename charT, typename traits = std::char_traits<charT>>
319
constexpr bool starts_with(std::basic_string_view<charT, traits> sv,
320
                           std::basic_string_view<charT, traits> x,
321
                           std::basic_string_view<charT, traits>* rest) noexcept
322
210k
{
323
210k
    assert(rest != nullptr);
324
210k
    auto const found = starts_with(sv, x);
325
210k
    if (found)
326
47.2k
    {
327
47.2k
        *rest = sv.substr(x.length());
328
47.2k
    }
329
210k
    return found;
330
210k
}
Unexecuted instantiation: bool o3tl::starts_with<char, std::__1::char_traits<char> >(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >*)
bool o3tl::starts_with<char16_t, std::__1::char_traits<char16_t> >(std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >, std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >, std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >*)
Line
Count
Source
322
210k
{
323
210k
    assert(rest != nullptr);
324
210k
    auto const found = starts_with(sv, x);
325
210k
    if (found)
326
47.2k
    {
327
47.2k
        *rest = sv.substr(x.length());
328
47.2k
    }
329
210k
    return found;
330
210k
}
331
template <typename charT, typename traits = std::char_traits<charT>>
332
constexpr bool starts_with(std::basic_string_view<charT, traits> sv, charT x,
333
                           std::basic_string_view<charT, traits>* rest) noexcept
334
{
335
    assert(rest != nullptr);
336
    auto const found = starts_with(sv, x);
337
    if (found)
338
    {
339
        *rest = sv.substr(1);
340
    }
341
    return found;
342
}
343
template <typename charT, typename traits = std::char_traits<charT>>
344
constexpr bool starts_with(std::basic_string_view<charT, traits> sv, charT const* x,
345
                           std::basic_string_view<charT, traits>* rest)
346
336k
{
347
336k
    assert(rest != nullptr);
348
336k
    auto const found = starts_with(sv, x);
349
336k
    if (found)
350
145k
    {
351
145k
        *rest = sv.substr(traits::length(x));
352
145k
    }
353
336k
    return found;
354
336k
}
bool o3tl::starts_with<char16_t, std::__1::char_traits<char16_t> >(std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >, char16_t const*, std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >*)
Line
Count
Source
346
336k
{
347
336k
    assert(rest != nullptr);
348
336k
    auto const found = starts_with(sv, x);
349
336k
    if (found)
350
145k
    {
351
145k
        *rest = sv.substr(traits::length(x));
352
145k
    }
353
336k
    return found;
354
336k
}
Unexecuted instantiation: bool o3tl::starts_with<char, std::__1::char_traits<char> >(std::__1::basic_string_view<char, std::__1::char_traits<char> >, char const*, std::__1::basic_string_view<char, std::__1::char_traits<char> >*)
355
template <typename charT, typename traits = std::char_traits<charT>>
356
constexpr bool ends_with(std::basic_string_view<charT, traits> sv,
357
                         std::basic_string_view<charT, traits> x,
358
                         std::basic_string_view<charT, traits>* rest) noexcept
359
0
{
360
0
    assert(rest != nullptr);
361
0
    auto const found = ends_with(sv, x);
362
0
    if (found)
363
0
    {
364
0
        *rest = sv.substr(0, sv.length() - x.length());
365
0
    }
366
0
    return found;
367
0
}
Unexecuted instantiation: bool o3tl::ends_with<char, std::__1::char_traits<char> >(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >*)
Unexecuted instantiation: bool o3tl::ends_with<char16_t, std::__1::char_traits<char16_t> >(std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >, std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >, std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >*)
368
template <typename charT, typename traits = std::char_traits<charT>>
369
constexpr bool ends_with(std::basic_string_view<charT, traits> sv, charT x,
370
                         std::basic_string_view<charT, traits>* rest) noexcept
371
{
372
    assert(rest != nullptr);
373
    auto const found = ends_with(sv, x);
374
    if (found)
375
    {
376
        *rest = sv.substr(0, sv.length() - 1);
377
    }
378
    return found;
379
}
380
template <typename charT, typename traits = std::char_traits<charT>>
381
constexpr bool ends_with(std::basic_string_view<charT, traits> sv, charT const* x,
382
                         std::basic_string_view<charT, traits>* rest)
383
5
{
384
5
    assert(rest != nullptr);
385
5
    auto const found = ends_with(sv, x);
386
5
    if (found)
387
5
    {
388
5
        *rest = sv.substr(0, sv.length() - traits::length(x));
389
5
    }
390
5
    return found;
391
5
}
392
// The following overloads prevent deduction failures that would occur with their template
393
// counterparts, when x is of a type that is implicitly convertible to basic_string_view (like
394
// OString or OUString, and we only bother to provide overloads for the char and char16_t cases, not
395
// also for char32_t and wchar_t, nor for C++20 char8_t):
396
constexpr bool starts_with(std::string_view sv, std::string_view x, std::string_view* rest) noexcept
397
0
{
398
0
    return starts_with<char>(sv, x, rest);
399
0
}
400
constexpr bool starts_with(std::u16string_view sv, std::u16string_view x,
401
                           std::u16string_view* rest) noexcept
402
210k
{
403
210k
    return starts_with<char16_t>(sv, x, rest);
404
210k
}
405
constexpr bool ends_with(std::string_view sv, std::string_view x, std::string_view* rest) noexcept
406
0
{
407
0
    return ends_with<char>(sv, x, rest);
408
0
}
409
constexpr bool ends_with(std::u16string_view sv, std::u16string_view x,
410
                         std::u16string_view* rest) noexcept
411
0
{
412
0
    return ends_with<char16_t>(sv, x, rest);
413
0
}
414
415
namespace internal
416
{
417
inline bool implIsWhitespace(sal_Unicode c)
418
134M
{
419
    /* Space or Control character? */
420
134M
    if ((c <= 32) && c)
421
10.3M
        return true;
422
423
    /* Only in the General Punctuation area Space or Control characters are included? */
424
123M
    if ((c < 0x2000) || (c > 0x2029))
425
123M
        return false;
426
427
16.1k
    if ((c <= 0x200B) || /* U+2000 - U+200B All Spaces */
428
15.4k
        (c >= 0x2028)) /* U+2028 LINE SEPARATOR, U+2029 PARAGRAPH SEPARATOR */
429
1.48k
        return true;
430
431
14.6k
    return false;
432
16.1k
}
433
} // namespace internal
434
435
// Like OUString::trim, but for std::[u16]string_view:
436
template <typename charT, typename traits = std::char_traits<charT>>
437
std::basic_string_view<charT, traits> trim(std::basic_string_view<charT, traits> str)
438
4.38M
{
439
4.38M
    auto pFirst = str.data();
440
4.38M
    auto pLast = pFirst + str.size();
441
442
12.8M
    while ((pFirst < pLast) && internal::implIsWhitespace(*pFirst))
443
8.44M
        ++pFirst;
444
445
4.38M
    if (pFirst == pLast)
446
1.25M
        return {};
447
448
3.12M
    do
449
4.94M
        --pLast;
450
4.94M
    while (internal::implIsWhitespace(*pLast));
451
452
3.12M
    return std::basic_string_view<charT, traits>(pFirst, pLast - pFirst + 1);
453
4.38M
}
std::__1::basic_string_view<char, std::__1::char_traits<char> > o3tl::trim<char, std::__1::char_traits<char> >(std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Line
Count
Source
438
8.79k
{
439
8.79k
    auto pFirst = str.data();
440
8.79k
    auto pLast = pFirst + str.size();
441
442
9.05k
    while ((pFirst < pLast) && internal::implIsWhitespace(*pFirst))
443
267
        ++pFirst;
444
445
8.79k
    if (pFirst == pLast)
446
6
        return {};
447
448
8.78k
    do
449
8.78k
        --pLast;
450
8.78k
    while (internal::implIsWhitespace(*pLast));
451
452
8.78k
    return std::basic_string_view<charT, traits>(pFirst, pLast - pFirst + 1);
453
8.79k
}
std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> > o3tl::trim<char16_t, std::__1::char_traits<char16_t> >(std::__1::basic_string_view<char16_t, std::__1::char_traits<char16_t> >)
Line
Count
Source
438
4.37M
{
439
4.37M
    auto pFirst = str.data();
440
4.37M
    auto pLast = pFirst + str.size();
441
442
12.8M
    while ((pFirst < pLast) && internal::implIsWhitespace(*pFirst))
443
8.44M
        ++pFirst;
444
445
4.37M
    if (pFirst == pLast)
446
1.25M
        return {};
447
448
3.11M
    do
449
4.94M
        --pLast;
450
4.94M
    while (internal::implIsWhitespace(*pLast));
451
452
3.11M
    return std::basic_string_view<charT, traits>(pFirst, pLast - pFirst + 1);
453
4.37M
}
454
455
// "deduction guides"
456
457
8.79k
inline auto trim(std::string_view str) { return trim<>(str); }
458
4.37M
inline auto trim(std::u16string_view str) { return trim<>(str); }
459
460
// Like OString::toInt32, but for std::string_view:
461
inline sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix = 10)
462
100M
{
463
100M
    sal_Int64 n = rtl_ustr_toInt64_WithLength(str.data(), radix, str.size());
464
100M
    if (n < SAL_MIN_INT32 || n > SAL_MAX_INT32)
465
63.4k
        n = 0;
466
100M
    return n;
467
100M
}
468
inline sal_Int32 toInt32(std::string_view str, sal_Int16 radix = 10)
469
8.97M
{
470
8.97M
    sal_Int64 n = rtl_str_toInt64_WithLength(str.data(), radix, str.size());
471
8.97M
    if (n < SAL_MIN_INT32 || n > SAL_MAX_INT32)
472
4.15k
        n = 0;
473
8.97M
    return n;
474
8.97M
}
475
476
// Like OString::toUInt32, but for std::string_view:
477
inline sal_uInt32 toUInt32(std::u16string_view str, sal_Int16 radix = 10)
478
6.43k
{
479
6.43k
    sal_Int64 n = rtl_ustr_toInt64_WithLength(str.data(), radix, str.size());
480
6.43k
    if (n < 0 || n > SAL_MAX_UINT32)
481
0
        n = 0;
482
6.43k
    return n;
483
6.43k
}
484
inline sal_uInt32 toUInt32(std::string_view str, sal_Int16 radix = 10)
485
381k
{
486
381k
    sal_Int64 n = rtl_str_toInt64_WithLength(str.data(), radix, str.size());
487
381k
    if (n < 0 || n > SAL_MAX_UINT32)
488
1
        n = 0;
489
381k
    return n;
490
381k
}
491
492
// Like OString::toInt64, but for std::string_view:
493
inline sal_Int64 toInt64(std::u16string_view str, sal_Int16 radix = 10)
494
27.3k
{
495
27.3k
    return rtl_ustr_toInt64_WithLength(str.data(), radix, str.size());
496
27.3k
}
497
inline sal_Int64 toInt64(std::string_view str, sal_Int16 radix = 10)
498
5.25k
{
499
5.25k
    return rtl_str_toInt64_WithLength(str.data(), radix, str.size());
500
5.25k
}
501
502
// Like OString::toDouble, but for std::string_view:
503
inline double toDouble(std::u16string_view str)
504
776
{
505
776
    return rtl_math_uStringToDouble(str.data(), str.data() + str.size(), '.', 0, nullptr, nullptr);
506
776
}
507
inline double toDouble(std::string_view str)
508
986k
{
509
986k
    return rtl_math_stringToDouble(str.data(), str.data() + str.size(), '.', 0, nullptr, nullptr);
510
986k
}
511
512
// Like OUString::iterateCodePoints, but for std::string_view:
513
template <typename T>
514
requires(std::is_same_v<T, sal_Int32> || std::is_same_v<T, std::size_t>) sal_uInt32
515
    iterateCodePoints(std::u16string_view string, T* indexUtf16, sal_Int32 incrementCodePoints = 1)
516
5.15G
{
517
5.15G
    std::size_t n;
518
5.15G
    char16_t cu;
519
5.15G
    sal_uInt32 cp;
520
5.15G
    assert(indexUtf16 != nullptr);
521
5.15G
    n = *indexUtf16;
522
5.15G
    assert(n <= string.length());
523
5.22G
    while (incrementCodePoints < 0)
524
70.1M
    {
525
70.1M
        assert(n > 0);
526
70.1M
        cu = string[--n];
527
70.1M
        if (rtl::isLowSurrogate(cu) && n != 0 && rtl::isHighSurrogate(string[n - 1]))
528
116k
        {
529
116k
            --n;
530
116k
        }
531
70.1M
        ++incrementCodePoints;
532
70.1M
    }
533
5.15G
    assert(n < string.length());
534
5.15G
    cu = string[n];
535
5.15G
    if (rtl::isHighSurrogate(cu) && string.length() - n >= 2 && rtl::isLowSurrogate(string[n + 1]))
536
2.75M
    {
537
2.75M
        cp = rtl::combineSurrogates(cu, string[n + 1]);
538
2.75M
    }
539
5.15G
    else
540
5.15G
    {
541
5.15G
        cp = cu;
542
5.15G
    }
543
9.04G
    while (incrementCodePoints > 0)
544
3.88G
    {
545
3.88G
        assert(n < string.length());
546
3.88G
        cu = string[n++];
547
3.88G
        if (rtl::isHighSurrogate(cu) && n != string.length() && rtl::isLowSurrogate(string[n]))
548
1.87M
        {
549
1.87M
            ++n;
550
1.87M
        }
551
3.88G
        --incrementCodePoints;
552
3.88G
    }
553
    assert(n <= string.length());
554
5.15G
    *indexUtf16 = n;
555
5.15G
    return cp;
556
5.15G
}
_ZN4o3tl17iterateCodePointsIiQoosr3stdE9is_same_vIT_iEsr3stdE9is_same_vIS1_mEEEjNSt3__117basic_string_viewIDsNS2_11char_traitsIDsEEEEPS1_i
Line
Count
Source
516
5.15G
{
517
5.15G
    std::size_t n;
518
5.15G
    char16_t cu;
519
5.15G
    sal_uInt32 cp;
520
5.15G
    assert(indexUtf16 != nullptr);
521
5.15G
    n = *indexUtf16;
522
5.15G
    assert(n <= string.length());
523
5.22G
    while (incrementCodePoints < 0)
524
70.1M
    {
525
70.1M
        assert(n > 0);
526
70.1M
        cu = string[--n];
527
70.1M
        if (rtl::isLowSurrogate(cu) && n != 0 && rtl::isHighSurrogate(string[n - 1]))
528
116k
        {
529
116k
            --n;
530
116k
        }
531
70.1M
        ++incrementCodePoints;
532
70.1M
    }
533
5.15G
    assert(n < string.length());
534
5.15G
    cu = string[n];
535
5.15G
    if (rtl::isHighSurrogate(cu) && string.length() - n >= 2 && rtl::isLowSurrogate(string[n + 1]))
536
2.75M
    {
537
2.75M
        cp = rtl::combineSurrogates(cu, string[n + 1]);
538
2.75M
    }
539
5.15G
    else
540
5.15G
    {
541
5.15G
        cp = cu;
542
5.15G
    }
543
9.04G
    while (incrementCodePoints > 0)
544
3.88G
    {
545
3.88G
        assert(n < string.length());
546
3.88G
        cu = string[n++];
547
3.88G
        if (rtl::isHighSurrogate(cu) && n != string.length() && rtl::isLowSurrogate(string[n]))
548
1.87M
        {
549
1.87M
            ++n;
550
1.87M
        }
551
3.88G
        --incrementCodePoints;
552
3.88G
    }
553
    assert(n <= string.length());
554
5.15G
    *indexUtf16 = n;
555
5.15G
    return cp;
556
5.15G
}
Unexecuted instantiation: _ZN4o3tl17iterateCodePointsImQoosr3stdE9is_same_vIT_iEsr3stdE9is_same_vIS1_mEEEjNSt3__117basic_string_viewIDsNS2_11char_traitsIDsEEEEPS1_i
557
558
} // namespace
559
560
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */