Coverage Report

Created: 2026-09-28 10:59

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
26.4M
{
31
26.4M
    return s1.size() == s2.size()
32
852k
           && rtl_ustr_ascii_shortenedCompare_WithLength(s1.data(), s1.size(), s2.data(), s2.size())
33
852k
                  == 0;
34
26.4M
}
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
1.39k
{
39
1.39k
    return rtl_ustr_asciil_reverseCompare_WithLength(s1.data(), s1.size(), s2.data(), s2.size());
40
1.39k
};
41
42
// Like OUString::equalsIgnoreAsciiCase, but for two std::u16string_view:
43
inline bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
44
2.19M
{
45
2.19M
    if (s1.size() != s2.size())
46
1.89M
        return false;
47
299k
    if (s1.data() == s2.data())
48
35
        return true;
49
299k
    return rtl_ustr_compareIgnoreAsciiCase_WithLength(s1.data(), s1.size(), s2.data(), s2.size())
50
299k
           == 0;
51
299k
};
52
53
inline bool equalsIgnoreAsciiCase(std::u16string_view s1, std::string_view s2)
54
3.79M
{
55
3.79M
    return s1.size() == s2.size()
56
206k
           && (rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength(s1.data(), s1.size(),
57
206k
                                                                         s2.data(), s2.size())
58
206k
               == 0);
59
3.79M
}
60
61
inline bool equalsIgnoreAsciiCase(std::string_view s1, std::string_view s2)
62
13
{
63
13
    if (s1.size() != s2.size())
64
12
        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
18.1M
{
74
18.1M
    return rtl_ustr_compareIgnoreAsciiCase_WithLength(s1.data(), s1.size(), s2.data(), s2.size());
75
18.1M
};
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
5.54M
{
81
5.54M
    return rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength(
82
5.54M
               s1.data() + fromIndex, s1.size() - fromIndex, s2.data(), s2.size(), s2.size())
83
5.54M
           == 0;
84
5.54M
}
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
265k
{
90
265k
    return rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength(
91
265k
               s1.data() + fromIndex, s1.size() - fromIndex, s2.data(), s2.size())
92
265k
           == 0;
93
265k
}
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
93.5k
{
132
93.5k
    assert(position <= sv.size());
133
93.5k
    auto const n = sv.find(delimiter, position);
134
93.5k
    std::basic_string_view<charT, traits> t;
135
93.5k
    if (n == std::string_view::npos)
136
76.4k
    {
137
76.4k
        t = sv.substr(position);
138
76.4k
        position = std::string_view::npos;
139
76.4k
    }
140
17.0k
    else
141
17.0k
    {
142
17.0k
        t = sv.substr(position, n - position);
143
17.0k
        position = n + 1;
144
17.0k
    }
145
93.5k
    return t;
146
93.5k
}
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
85.6k
{
132
85.6k
    assert(position <= sv.size());
133
85.6k
    auto const n = sv.find(delimiter, position);
134
85.6k
    std::basic_string_view<charT, traits> t;
135
85.6k
    if (n == std::string_view::npos)
136
69.8k
    {
137
69.8k
        t = sv.substr(position);
138
69.8k
        position = std::string_view::npos;
139
69.8k
    }
140
15.7k
    else
141
15.7k
    {
142
15.7k
        t = sv.substr(position, n - position);
143
15.7k
        position = n + 1;
144
15.7k
    }
145
85.6k
    return t;
146
85.6k
}
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
7.89k
{
132
7.89k
    assert(position <= sv.size());
133
7.89k
    auto const n = sv.find(delimiter, position);
134
7.89k
    std::basic_string_view<charT, traits> t;
135
7.89k
    if (n == std::string_view::npos)
136
6.55k
    {
137
6.55k
        t = sv.substr(position);
138
6.55k
        position = std::string_view::npos;
139
6.55k
    }
140
1.33k
    else
141
1.33k
    {
142
1.33k
        t = sv.substr(position, n - position);
143
1.33k
        position = n + 1;
144
1.33k
    }
145
7.89k
    return t;
146
7.89k
}
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
7.89k
{
154
7.89k
    return getToken<char>(sv, delimiter, position);
155
7.89k
}
156
inline std::u16string_view getToken(std::u16string_view sv, char16_t delimiter,
157
                                    std::size_t& position)
158
85.6k
{
159
85.6k
    return getToken<char16_t>(sv, delimiter, position);
160
85.6k
}
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
5.61M
{
172
5.61M
    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
5.61M
    if (rnIndex >= 0 && nToken >= 0)
177
3.37M
    {
178
3.37M
        const charT* pOrgCharStr = pStr.data();
179
3.37M
        const charT* pCharStr = pOrgCharStr + rnIndex;
180
3.37M
        sal_Int32 nLen = pStr.size() - rnIndex;
181
3.37M
        sal_Int32 nTokCount = 0;
182
3.37M
        const charT* pCharStrStart = pCharStr;
183
121M
        while (nLen > 0)
184
119M
        {
185
119M
            if (*pCharStr == cTok)
186
1.33M
            {
187
1.33M
                nTokCount++;
188
189
1.33M
                if (nTokCount > nToken)
190
1.12M
                    break;
191
215k
                if (nTokCount == nToken)
192
215k
                    pCharStrStart = pCharStr + 1;
193
215k
            }
194
195
117M
            pCharStr++;
196
117M
            nLen--;
197
117M
        }
198
3.37M
        if (nTokCount >= nToken)
199
3.37M
        {
200
3.37M
            if (nLen > 0)
201
1.12M
                rnIndex = pCharStr - pOrgCharStr + 1;
202
2.25M
            else
203
2.25M
                rnIndex = -1;
204
3.37M
            return std::basic_string_view<charT, traits>(pCharStrStart, pCharStr - pCharStrStart);
205
3.37M
        }
206
3.37M
    }
207
208
2.24M
    rnIndex = -1;
209
2.24M
    return std::basic_string_view<charT, traits>();
210
5.61M
}
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
5.61M
{
172
5.61M
    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
5.61M
    if (rnIndex >= 0 && nToken >= 0)
177
3.37M
    {
178
3.37M
        const charT* pOrgCharStr = pStr.data();
179
3.37M
        const charT* pCharStr = pOrgCharStr + rnIndex;
180
3.37M
        sal_Int32 nLen = pStr.size() - rnIndex;
181
3.37M
        sal_Int32 nTokCount = 0;
182
3.37M
        const charT* pCharStrStart = pCharStr;
183
121M
        while (nLen > 0)
184
119M
        {
185
119M
            if (*pCharStr == cTok)
186
1.33M
            {
187
1.33M
                nTokCount++;
188
189
1.33M
                if (nTokCount > nToken)
190
1.12M
                    break;
191
215k
                if (nTokCount == nToken)
192
215k
                    pCharStrStart = pCharStr + 1;
193
215k
            }
194
195
117M
            pCharStr++;
196
117M
            nLen--;
197
117M
        }
198
3.37M
        if (nTokCount >= nToken)
199
3.37M
        {
200
3.37M
            if (nLen > 0)
201
1.12M
                rnIndex = pCharStr - pOrgCharStr + 1;
202
2.25M
            else
203
2.25M
                rnIndex = -1;
204
3.37M
            return std::basic_string_view<charT, traits>(pCharStrStart, pCharStr - pCharStrStart);
205
3.37M
        }
206
3.37M
    }
207
208
2.24M
    rnIndex = -1;
209
2.24M
    return std::basic_string_view<charT, traits>();
210
5.61M
}
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
5.57M
{
222
5.57M
    return getToken<char16_t>(sv, nToken, cTok, rnIndex);
223
5.57M
}
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
47.6k
{
231
47.6k
    sal_Int32 nIndex = 0;
232
47.6k
    return getToken<char16_t>(sv, nToken, cTok, nIndex);
233
47.6k
}
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
25.0M
{
241
25.0M
#if defined __cpp_lib_starts_ends_with
242
25.0M
    return sv.starts_with(x);
243
#else
244
    return sv.substr(0, x.size()) == x;
245
#endif
246
25.0M
}
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
24.8M
{
241
24.8M
#if defined __cpp_lib_starts_ends_with
242
24.8M
    return sv.starts_with(x);
243
#else
244
    return sv.substr(0, x.size()) == x;
245
#endif
246
24.8M
}
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
165k
{
241
165k
#if defined __cpp_lib_starts_ends_with
242
165k
    return sv.starts_with(x);
243
#else
244
    return sv.substr(0, x.size()) == x;
245
#endif
246
165k
}
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
4.05M
{
259
4.05M
#if defined __cpp_lib_starts_ends_with
260
4.05M
    return sv.starts_with(x);
261
#else
262
    return starts_with(sv, std::basic_string_view<charT, traits>(x));
263
#endif
264
4.05M
}
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
4.05M
{
259
4.05M
#if defined __cpp_lib_starts_ends_with
260
4.05M
    return sv.starts_with(x);
261
#else
262
    return starts_with(sv, std::basic_string_view<charT, traits>(x));
263
#endif
264
4.05M
}
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
858
{
259
858
#if defined __cpp_lib_starts_ends_with
260
858
    return sv.starts_with(x);
261
#else
262
    return starts_with(sv, std::basic_string_view<charT, traits>(x));
263
#endif
264
858
}
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.24M
{
269
1.24M
#if defined __cpp_lib_starts_ends_with
270
1.24M
    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.24M
}
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.24M
{
269
1.24M
#if defined __cpp_lib_starts_ends_with
270
1.24M
    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.24M
}
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
669k
{
288
669k
#if defined __cpp_lib_starts_ends_with
289
669k
    return sv.ends_with(x);
290
#else
291
    return ends_with(sv, std::basic_string_view<charT, traits>(x));
292
#endif
293
669k
}
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
165k
{
300
165k
    return starts_with<char>(sv, x);
301
165k
}
302
constexpr bool starts_with(std::u16string_view sv, std::u16string_view x) noexcept
303
24.8M
{
304
24.8M
    return starts_with<char16_t>(sv, x);
305
24.8M
}
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.24M
{
312
1.24M
    return ends_with<char16_t>(sv, x);
313
1.24M
}
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
172k
{
323
172k
    assert(rest != nullptr);
324
172k
    auto const found = starts_with(sv, x);
325
172k
    if (found)
326
37.5k
    {
327
37.5k
        *rest = sv.substr(x.length());
328
37.5k
    }
329
172k
    return found;
330
172k
}
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
172k
{
323
172k
    assert(rest != nullptr);
324
172k
    auto const found = starts_with(sv, x);
325
172k
    if (found)
326
37.5k
    {
327
37.5k
        *rest = sv.substr(x.length());
328
37.5k
    }
329
172k
    return found;
330
172k
}
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
225k
{
347
225k
    assert(rest != nullptr);
348
225k
    auto const found = starts_with(sv, x);
349
225k
    if (found)
350
100k
    {
351
100k
        *rest = sv.substr(traits::length(x));
352
100k
    }
353
225k
    return found;
354
225k
}
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
225k
{
347
225k
    assert(rest != nullptr);
348
225k
    auto const found = starts_with(sv, x);
349
225k
    if (found)
350
100k
    {
351
100k
        *rest = sv.substr(traits::length(x));
352
100k
    }
353
225k
    return found;
354
225k
}
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
2
{
384
2
    assert(rest != nullptr);
385
2
    auto const found = ends_with(sv, x);
386
2
    if (found)
387
2
    {
388
2
        *rest = sv.substr(0, sv.length() - traits::length(x));
389
2
    }
390
2
    return found;
391
2
}
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
172k
{
403
172k
    return starts_with<char16_t>(sv, x, rest);
404
172k
}
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
57.9M
{
419
    /* Space or Control character? */
420
57.9M
    if ((c <= 32) && c)
421
7.38M
        return true;
422
423
    /* Only in the General Punctuation area Space or Control characters are included? */
424
50.6M
    if ((c < 0x2000) || (c > 0x2029))
425
50.6M
        return false;
426
427
10.8k
    if ((c <= 0x200B) || /* U+2000 - U+200B All Spaces */
428
7.51k
        (c >= 0x2028)) /* U+2028 LINE SEPARATOR, U+2029 PARAGRAPH SEPARATOR */
429
3.83k
        return true;
430
431
7.05k
    return false;
432
10.8k
}
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
3.07M
{
439
3.07M
    auto pFirst = str.data();
440
3.07M
    auto pLast = pFirst + str.size();
441
442
9.23M
    while ((pFirst < pLast) && internal::implIsWhitespace(*pFirst))
443
6.15M
        ++pFirst;
444
445
3.07M
    if (pFirst == pLast)
446
921k
        return {};
447
448
2.15M
    do
449
3.30M
        --pLast;
450
3.30M
    while (internal::implIsWhitespace(*pLast));
451
452
2.15M
    return std::basic_string_view<charT, traits>(pFirst, pLast - pFirst + 1);
453
3.07M
}
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
2.90k
{
439
2.90k
    auto pFirst = str.data();
440
2.90k
    auto pLast = pFirst + str.size();
441
442
3.17k
    while ((pFirst < pLast) && internal::implIsWhitespace(*pFirst))
443
272
        ++pFirst;
444
445
2.90k
    if (pFirst == pLast)
446
3
        return {};
447
448
2.89k
    do
449
2.89k
        --pLast;
450
2.89k
    while (internal::implIsWhitespace(*pLast));
451
452
2.89k
    return std::basic_string_view<charT, traits>(pFirst, pLast - pFirst + 1);
453
2.90k
}
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
3.07M
{
439
3.07M
    auto pFirst = str.data();
440
3.07M
    auto pLast = pFirst + str.size();
441
442
9.23M
    while ((pFirst < pLast) && internal::implIsWhitespace(*pFirst))
443
6.15M
        ++pFirst;
444
445
3.07M
    if (pFirst == pLast)
446
921k
        return {};
447
448
2.15M
    do
449
3.30M
        --pLast;
450
3.30M
    while (internal::implIsWhitespace(*pLast));
451
452
2.15M
    return std::basic_string_view<charT, traits>(pFirst, pLast - pFirst + 1);
453
3.07M
}
454
455
// "deduction guides"
456
457
2.90k
inline auto trim(std::string_view str) { return trim<>(str); }
458
3.07M
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
27.9M
{
463
27.9M
    sal_Int64 n = rtl_ustr_toInt64_WithLength(str.data(), radix, str.size());
464
27.9M
    if (n < SAL_MIN_INT32 || n > SAL_MAX_INT32)
465
55.4k
        n = 0;
466
27.9M
    return n;
467
27.9M
}
468
inline sal_Int32 toInt32(std::string_view str, sal_Int16 radix = 10)
469
11.5M
{
470
11.5M
    sal_Int64 n = rtl_str_toInt64_WithLength(str.data(), radix, str.size());
471
11.5M
    if (n < SAL_MIN_INT32 || n > SAL_MAX_INT32)
472
6.11k
        n = 0;
473
11.5M
    return n;
474
11.5M
}
475
476
// Like OString::toUInt32, but for std::string_view:
477
inline sal_uInt32 toUInt32(std::u16string_view str, sal_Int16 radix = 10)
478
12.4k
{
479
12.4k
    sal_Int64 n = rtl_ustr_toInt64_WithLength(str.data(), radix, str.size());
480
12.4k
    if (n < 0 || n > SAL_MAX_UINT32)
481
0
        n = 0;
482
12.4k
    return n;
483
12.4k
}
484
inline sal_uInt32 toUInt32(std::string_view str, sal_Int16 radix = 10)
485
339k
{
486
339k
    sal_Int64 n = rtl_str_toInt64_WithLength(str.data(), radix, str.size());
487
339k
    if (n < 0 || n > SAL_MAX_UINT32)
488
1
        n = 0;
489
339k
    return n;
490
339k
}
491
492
// Like OString::toInt64, but for std::string_view:
493
inline sal_Int64 toInt64(std::u16string_view str, sal_Int16 radix = 10)
494
21.5k
{
495
21.5k
    return rtl_ustr_toInt64_WithLength(str.data(), radix, str.size());
496
21.5k
}
497
inline sal_Int64 toInt64(std::string_view str, sal_Int16 radix = 10)
498
39.7k
{
499
39.7k
    return rtl_str_toInt64_WithLength(str.data(), radix, str.size());
500
39.7k
}
501
502
// Like OString::toDouble, but for std::string_view:
503
inline double toDouble(std::u16string_view str)
504
857
{
505
857
    return rtl_math_uStringToDouble(str.data(), str.data() + str.size(), '.', 0, nullptr, nullptr);
506
857
}
507
inline double toDouble(std::string_view str)
508
955k
{
509
955k
    return rtl_math_stringToDouble(str.data(), str.data() + str.size(), '.', 0, nullptr, nullptr);
510
955k
}
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
1.78G
{
517
1.78G
    std::size_t n;
518
1.78G
    char16_t cu;
519
1.78G
    sal_uInt32 cp;
520
1.78G
    assert(indexUtf16 != nullptr);
521
1.78G
    n = *indexUtf16;
522
1.78G
    assert(n <= string.length());
523
1.82G
    while (incrementCodePoints < 0)
524
41.1M
    {
525
41.1M
        assert(n > 0);
526
41.1M
        cu = string[--n];
527
41.1M
        if (rtl::isLowSurrogate(cu) && n != 0 && rtl::isHighSurrogate(string[n - 1]))
528
24.6k
        {
529
24.6k
            --n;
530
24.6k
        }
531
41.1M
        ++incrementCodePoints;
532
41.1M
    }
533
1.78G
    assert(n < string.length());
534
1.78G
    cu = string[n];
535
1.78G
    if (rtl::isHighSurrogate(cu) && string.length() - n >= 2 && rtl::isLowSurrogate(string[n + 1]))
536
644k
    {
537
644k
        cp = rtl::combineSurrogates(cu, string[n + 1]);
538
644k
    }
539
1.78G
    else
540
1.78G
    {
541
1.78G
        cp = cu;
542
1.78G
    }
543
2.96G
    while (incrementCodePoints > 0)
544
1.18G
    {
545
1.18G
        assert(n < string.length());
546
1.18G
        cu = string[n++];
547
1.18G
        if (rtl::isHighSurrogate(cu) && n != string.length() && rtl::isLowSurrogate(string[n]))
548
416k
        {
549
416k
            ++n;
550
416k
        }
551
1.18G
        --incrementCodePoints;
552
1.18G
    }
553
    assert(n <= string.length());
554
1.78G
    *indexUtf16 = n;
555
1.78G
    return cp;
556
1.78G
}
_ZN4o3tl17iterateCodePointsIiQoosr3stdE9is_same_vIT_iEsr3stdE9is_same_vIS1_mEEEjNSt3__117basic_string_viewIDsNS2_11char_traitsIDsEEEEPS1_i
Line
Count
Source
516
1.78G
{
517
1.78G
    std::size_t n;
518
1.78G
    char16_t cu;
519
1.78G
    sal_uInt32 cp;
520
1.78G
    assert(indexUtf16 != nullptr);
521
1.78G
    n = *indexUtf16;
522
1.78G
    assert(n <= string.length());
523
1.82G
    while (incrementCodePoints < 0)
524
41.1M
    {
525
41.1M
        assert(n > 0);
526
41.1M
        cu = string[--n];
527
41.1M
        if (rtl::isLowSurrogate(cu) && n != 0 && rtl::isHighSurrogate(string[n - 1]))
528
24.6k
        {
529
24.6k
            --n;
530
24.6k
        }
531
41.1M
        ++incrementCodePoints;
532
41.1M
    }
533
1.78G
    assert(n < string.length());
534
1.78G
    cu = string[n];
535
1.78G
    if (rtl::isHighSurrogate(cu) && string.length() - n >= 2 && rtl::isLowSurrogate(string[n + 1]))
536
644k
    {
537
644k
        cp = rtl::combineSurrogates(cu, string[n + 1]);
538
644k
    }
539
1.78G
    else
540
1.78G
    {
541
1.78G
        cp = cu;
542
1.78G
    }
543
2.96G
    while (incrementCodePoints > 0)
544
1.18G
    {
545
1.18G
        assert(n < string.length());
546
1.18G
        cu = string[n++];
547
1.18G
        if (rtl::isHighSurrogate(cu) && n != string.length() && rtl::isLowSurrogate(string[n]))
548
416k
        {
549
416k
            ++n;
550
416k
        }
551
1.18G
        --incrementCodePoints;
552
1.18G
    }
553
    assert(n <= string.length());
554
1.78G
    *indexUtf16 = n;
555
1.78G
    return cp;
556
1.78G
}
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: */