Skip to content

Commit 95e3e29

Browse files
committed
[WTF] Make CStringView handle only null termination related methods and add some helpers for spans to StringCommon
https://bugs.webkit.org/show_bug.cgi?id=299946 Reviewed by Darin Adler. Improved several comparisons, like starts, ends, contains, find, both case and aware and not. Also some more useful conversions and parsing. For this, some more tweaks and templating was needed as many string management methods consider Latin1Character only and CStringView handles char8_t. Fly-by: fix return value of isEmpty to be bool instead of size_t and renamed length into lengthInBytes. GStreamer code using CStringView already was adapted to this. Tests: Tools/TestWebKitAPI/Tests/WTF/CString.cpp Tools/TestWebKitAPI/Tests/WTF/CStringView.cpp Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp Tools/TestWebKitAPI/Tests/WTF/StringCommon.cpp * Source/WTF/wtf/StdLibExtras.h: (WTF::find): (WTF::contains): (WTF::ByteCastTraits<T>::cast): (WTF::ByteCastTraits<T::cast): (WTF::byteCast): * Source/WTF/wtf/text/ASCIILiteral.h: (WTF::StringLiterals::operator_spanChar8): * Source/WTF/wtf/text/CString.cpp: (WTF::convertASCIICase): (WTF::convertToASCIILowercase): (WTF::convertToASCIIUppercase): * Source/WTF/wtf/text/CString.h: * Source/WTF/wtf/text/CStringView.cpp: (WTF::CStringView::dump const): (WTF::CStringView::toString const): Deleted. * Source/WTF/wtf/text/CStringView.h: (WTF::operator==): * Source/WTF/wtf/text/ParsingUtilities.h: (WTF::requires): * Source/WTF/wtf/text/StringCommon.h: (WTF::unsafeSpanChar8): (WTF::equal): (WTF::requires): (WTF::equalIgnoringASCIICase): (WTF::findIgnoringASCIICase): (WTF::containsIgnoringASCIICase): (WTF::find): (WTF::contains): (WTF::reverseFind): (WTF::equalLettersIgnoringASCIICaseWithLength): (WTF::startsWith): (WTF::endsWith): (WTF::endsWithLettersIgnoringASCIICaseCommon): (WTF::endsWithLettersIgnoringASCIICase): (WTF::startsWithLettersIgnoringASCIICaseCommon): (WTF::startsWithLettersIgnoringASCIICase): * Source/WTF/wtf/text/StringToIntegerConversion.h: (WTF::parseInteger): (WTF::parseIntegerAllowingTrailingJunk): * Source/WebCore/Modules/mediastream/gstreamer/GStreamerMediaEndpoint.cpp: (WebCore::GStreamerMediaEndpoint::requestPad): * Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpReceiverBackend.cpp: (WebCore::GStreamerRtpReceiverBackend::getParameters): * Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpTransceiverBackend.cpp: (WebCore::GStreamerRtpTransceiverBackend::setCodecPreferences): * Source/WebCore/Modules/mediastream/gstreamer/GStreamerStatsCollector.cpp: (WebCore::RTCStatsReport::Stats::Stats): (WebCore::RTCStatsReport::RtpStreamStats::RtpStreamStats): (WebCore::RTCStatsReport::CodecStats::CodecStats): (WebCore::RTCStatsReport::RemoteInboundRtpStreamStats::RemoteInboundRtpStreamStats): (WebCore::RTCStatsReport::RemoteOutboundRtpStreamStats::RemoteOutboundRtpStreamStats): (WebCore::RTCStatsReport::InboundRtpStreamStats::InboundRtpStreamStats): (WebCore::RTCStatsReport::OutboundRtpStreamStats::OutboundRtpStreamStats): (WebCore::RTCStatsReport::TransportStats::TransportStats): (WebCore::RTCStatsReport::IceCandidateStats::IceCandidateStats): (WebCore::RTCStatsReport::IceCandidatePairStats::IceCandidatePairStats): * Source/WebCore/Modules/mediastream/gstreamer/GStreamerWebRTCUtils.cpp: (WebCore::toRTCEncodingParameters): (WebCore::toRTCCodecParameters): (WebCore::toRTCRtpSendParameters): (WebCore::capsFromRtpCapabilities): (WebCore::capsFromSDPMedia): (WebCore::extractMidAndRidFromRTPBuffer): * Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp: (WebCore::doCapsHaveType): * Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.cpp: (WebCore::GStreamerRegistryScanner::fillVideoRtpCapabilities): * Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp: (WebCore::MediaPlayerPrivateGStreamer::handleMessage): (WebCore::MediaPlayerPrivateGStreamer::loadNextLocation): * Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp: (transformInPlace): * Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp: (WebCore::AppendPipeline::parseDemuxerSrcPadCaps): * Source/WebCore/platform/gstreamer/GStreamerElementHarness.cpp: (WebCore::MermaidBuilder::describeCaps): * Source/WebCore/platform/gstreamer/VideoEncoderPrivateGStreamer.cpp: (annexBStreamFormatCapsFieldValue): (videoEncoderSetEncoder): (webkit_video_encoder_class_init): * Source/WebCore/platform/mediastream/gstreamer/GStreamerAudioRTPPacketizer.cpp: (WebCore::GStreamerAudioRTPPacketizer::create): * Source/WebCore/platform/mediastream/gstreamer/GStreamerCaptureDeviceManager.cpp: (WebCore::GStreamerCaptureDeviceManager::captureDeviceFromGstDevice): * Source/WebCore/platform/mediastream/gstreamer/GStreamerIncomingTrackProcessor.cpp: (WebCore::GStreamerIncomingTrackProcessor::configure): (WebCore::GStreamerIncomingTrackProcessor::incomingTrackProcessor): * Source/WebCore/platform/mediastream/gstreamer/GStreamerMockDeviceProvider.cpp: (webkitGstMockDeviceProviderSwitchDefaultDevice): * Source/WebCore/platform/mediastream/gstreamer/GStreamerRTPPacketizer.cpp: (WebCore::GStreamerRTPPacketizer::rtpStreamId const): * Source/WebCore/platform/mediastream/gstreamer/GStreamerVideoCapturer.cpp: (WebCore::GStreamerVideoCapturer::reconfigure): * Source/WebCore/platform/mediastream/gstreamer/GStreamerVideoRTPPacketizer.cpp: (WebCore::GStreamerVideoRTPPacketizer::create): * Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingAudioSourceGStreamer.cpp: (WebCore::RealtimeOutgoingAudioSourceGStreamer::setInitialParameters): * Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingMediaSourceGStreamer.cpp: (WebCore::RealtimeOutgoingMediaSourceGStreamer::setParameters): * Tools/TestWebKitAPI/Tests/WTF/CString.cpp: (TEST(WTF, CStringNullStringConstructor)): (TEST(WTF, CStringEmptyEmptyConstructor)): (TEST(WTF, CStringViewASCIICaseConversions)): * Tools/TestWebKitAPI/Tests/WTF/CStringView.cpp: (TestWebKitAPI::TEST(WTF, CStringViewSize)): (TestWebKitAPI::TEST(WTF, CStringViewFrom)): (TestWebKitAPI::TEST(WTF, CStringViewEquality)): (TestWebKitAPI::TEST(WTF, CStringViewLength)): Deleted. * Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp: (TestWebKitAPI::TEST(StringBuilderTest, Append)): * Tools/TestWebKitAPI/Tests/WTF/StringCommon.cpp: (TestWebKitAPI::TEST(WTF_StringCommon, Equal)): (TestWebKitAPI::TEST(WTF_StringCommon, EqualIgnoringASCIICase)): (TestWebKitAPI::TEST(WTF_StringCommon, StartsWith)): (TestWebKitAPI::TEST(WTF_StringCommon, EndsWith)): (TestWebKitAPI::TEST(WTF_StringCommon, Find)): (TestWebKitAPI::TEST(WTF_StringCommon, ReverseFind)): (TestWebKitAPI::TEST(WTF_StringCommon, Contains)): (TestWebKitAPI::TEST(WTF_StringCommon, StartsWithLettersIgnoringASCIICase)): (TestWebKitAPI::TEST(WTF_StringCommon, EndsWithLettersIgnoringASCIICase)): (TestWebKitAPI::TEST(WTF_StringCommon, FindIgnoringASCIICase)): (TestWebKitAPI::TEST(WTF_StringCommon, ContainsIgnoringASCIICase)): (TestWebKitAPI::TEST(WTF_StringCommon, CharactersAreAllASCII)): Canonical link: https://commits.webkit.org/303011@main Signed-off-by: Xabier Rodriguez Calvar <calvaris@igalia.com>
1 parent c23f6c2 commit 95e3e29

32 files changed

Lines changed: 673 additions & 158 deletions

Source/WTF/wtf/StdLibExtras.h

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <wtf/CheckedArithmetic.h>
3838
#include <wtf/Compiler.h>
3939
#include <wtf/GetPtr.h>
40+
#include <wtf/NotFound.h>
4041
#include <wtf/TypeCasts.h>
4142

4243
// Use this macro to declare and define a debug-only global variable that may have a
@@ -779,31 +780,77 @@ int compareSpans(std::span<T, TExtent> a, std::span<U, UExtent> b)
779780
return result;
780781
}
781782

782-
template<typename T> concept ByteType = sizeof(T) == 1 && ((std::is_integral_v<T> && !std::same_as<T, bool>) || std::same_as<T, std::byte>) && !std::is_const_v<T>;
783+
template<typename T, typename U>
784+
concept TriviallyComparableCodeUnits = std::is_same_v<std::remove_const_t<T>, std::remove_const_t<U>> || (!std::is_same_v<std::remove_const_t<T>, char8_t> && !std::is_same_v<std::remove_const_t<U>, char8_t>);
785+
786+
template<typename T>
787+
concept CanBeConstByteType = sizeof(T) == 1 && ((std::is_integral_v<T> && !std::same_as<T, bool>) || std::same_as<T, std::byte>);
788+
789+
template<typename T, typename U>
790+
concept TriviallyComparableOneByteCodeUnits = TriviallyComparableCodeUnits<T, U> && CanBeConstByteType<T> && CanBeConstByteType<U>;
791+
792+
// Returns the index of the first occurrence of |needed| in |haystack| or notFound if not present.
793+
template<typename T, std::size_t TExtent, typename U, std::size_t UExtent>
794+
requires(TriviallyComparableOneByteCodeUnits<T, U>)
795+
size_t find(std::span<T, TExtent> haystack, std::span<U, UExtent> needle)
796+
{
797+
#if !HAVE(MEMMEM)
798+
if (needle.empty())
799+
return 0;
800+
801+
if (haystack.size() < needle.size())
802+
return notFound;
803+
804+
size_t lastPossiblePosition = haystack.size() - needle.size();
805+
806+
for (size_t i = 0; i <= lastPossiblePosition; ++i) {
807+
auto candidateSpan = haystack.subspan(i, needle.size());
808+
if (equalSpans(candidateSpan, needle))
809+
return i;
810+
}
811+
812+
return notFound;
813+
#else
814+
auto* result = static_cast<T*>(memmem(haystack.data(), haystack.size(), needle.data(), needle.size())); // NOLINT
815+
if (!result)
816+
return notFound;
817+
return result - haystack.data();
818+
#endif
819+
}
820+
821+
template<typename T, std::size_t TExtent, typename U, std::size_t UExtent>
822+
requires(TriviallyComparableOneByteCodeUnits<T, U>)
823+
size_t contains(std::span<T, TExtent> haystack, std::span<U, UExtent> needle)
824+
{
825+
return find(haystack, needle) != notFound;
826+
}
827+
828+
template<typename T>
829+
concept NonConstByteType = CanBeConstByteType<T> && !std::is_const_v<T>;
783830

784831
template<typename> struct ByteCastTraits;
785832

786-
template<ByteType T> struct ByteCastTraits<T> {
787-
template<ByteType U> static constexpr U cast(T character) { return static_cast<U>(character); }
833+
template<NonConstByteType T> struct ByteCastTraits<T> {
834+
template<NonConstByteType U> static constexpr U cast(T character) { return static_cast<U>(character); }
788835
};
789836

790-
template<ByteType T> struct ByteCastTraits<T*> {
791-
template<ByteType U> static constexpr auto cast(T* pointer) { return std::bit_cast<U*>(pointer); }
837+
template<NonConstByteType T> struct ByteCastTraits<T*> {
838+
template<NonConstByteType U> static constexpr auto cast(T* pointer) { return std::bit_cast<U*>(pointer); }
792839
};
793840

794-
template<ByteType T> struct ByteCastTraits<const T*> {
795-
template<ByteType U> static constexpr auto cast(const T* pointer) { return std::bit_cast<const U*>(pointer); }
841+
template<NonConstByteType T> struct ByteCastTraits<const T*> {
842+
template<NonConstByteType U> static constexpr auto cast(const T* pointer) { return std::bit_cast<const U*>(pointer); }
796843
};
797844

798-
template<ByteType T, size_t Extent> struct ByteCastTraits<std::span<T, Extent>> {
799-
template<ByteType U> static constexpr auto cast(std::span<T, Extent> span) { return spanReinterpretCast<U>(span); }
845+
template<NonConstByteType T, size_t Extent> struct ByteCastTraits<std::span<T, Extent>> {
846+
template<NonConstByteType U> static constexpr auto cast(std::span<T, Extent> span) { return spanReinterpretCast<U>(span); }
800847
};
801848

802-
template<ByteType T, size_t Extent> struct ByteCastTraits<std::span<const T, Extent>> {
803-
template<ByteType U> static constexpr auto cast(std::span<const T, Extent> span) { return spanReinterpretCast<const U>(span); }
849+
template<NonConstByteType T, size_t Extent> struct ByteCastTraits<std::span<const T, Extent>> {
850+
template<NonConstByteType U> static constexpr auto cast(std::span<const T, Extent> span) { return spanReinterpretCast<const U>(span); }
804851
};
805852

806-
template<ByteType T, typename U> constexpr auto byteCast(const U& value)
853+
template<NonConstByteType T, typename U> constexpr auto byteCast(const U& value)
807854
{
808855
return ByteCastTraits<U>::template cast<T>(value);
809856
}

Source/WTF/wtf/text/ASCIILiteral.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ class ASCIILiteral final {
6363

6464
constexpr const char* characters() const { return m_charactersWithNullTerminator.data(); }
6565
constexpr size_t length() const { return !m_charactersWithNullTerminator.empty() ? m_charactersWithNullTerminator.size() - 1 : 0; }
66-
std::span<const Latin1Character> span8() const { return { std::bit_cast<const Latin1Character*>(characters()), length() }; }
66+
constexpr std::span<const char> span() const { return m_charactersWithNullTerminator.first(length()); }
67+
std::span<const Latin1Character> span8() const { return byteCast<Latin1Character>(m_charactersWithNullTerminator.first(length())); }
68+
std::span<const char8_t> spanChar8() const { return byteCast<char8_t>(m_charactersWithNullTerminator.first(length())); }
6769
std::span<const char> spanIncludingNullTerminator() const { return m_charactersWithNullTerminator; }
6870
size_t isEmpty() const { return m_charactersWithNullTerminator.size() <= 1; }
6971

@@ -148,6 +150,16 @@ constexpr std::span<const Latin1Character> operator"" _span(const char* characte
148150
return std::span { std::bit_cast<const Latin1Character*>(characters), n };
149151
}
150152

153+
constexpr std::span<const char8_t> operator""_spanChar8(const char* characters, size_t n)
154+
{
155+
auto span = byteCast<char8_t>(unsafeMakeSpan(characters, n));
156+
#if ASSERT_ENABLED
157+
for (size_t i = 0, size = span.size(); i < size; ++i)
158+
ASSERT_UNDER_CONSTEXPR_CONTEXT(isASCII(span[i]));
159+
#endif
160+
return span;
161+
}
162+
151163
} // inline StringLiterals
152164

153165
} // namespace WTF

Source/WTF/wtf/text/CString.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,30 @@ bool CStringHash::equal(const CString& a, const CString& b)
177177
return a == b;
178178
}
179179

180+
enum class ASCIICase { Lower, Upper };
181+
182+
template<ASCIICase type>
183+
CString convertASCIICase(std::span<const char8_t> input)
184+
{
185+
if (input.empty())
186+
return CString(""_s);
187+
188+
std::span<char> characters;
189+
auto result = CString::newUninitialized(input.size(), characters);
190+
size_t i = 0;
191+
for (auto character : input)
192+
characters[i++] = type == ASCIICase::Lower ? toASCIILower(character) : toASCIIUpper(character);
193+
return result;
194+
}
195+
196+
CString convertToASCIILowercase(std::span<const char8_t> string)
197+
{
198+
return convertASCIICase<ASCIICase::Lower>(string);
199+
}
200+
201+
CString convertToASCIIUppercase(std::span<const char8_t> string)
202+
{
203+
return convertASCIICase<ASCIICase::Upper>(string);
204+
}
205+
180206
} // namespace WTF

Source/WTF/wtf/text/CString.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class CString final {
9393
size_t length() const;
9494

9595
bool isNull() const { return !m_buffer; }
96+
bool isEmpty() const { return isNull() || m_buffer->length() <= 1; }
9697
bool isSafeToSendToAnotherThread() const;
9798

9899
CStringBuffer* buffer() const LIFETIME_BOUND { return m_buffer.get(); }
@@ -114,6 +115,9 @@ WTF_EXPORT_PRIVATE bool operator==(const CString&, const CString&);
114115
WTF_EXPORT_PRIVATE bool operator==(const CString&, const char*);
115116
WTF_EXPORT_PRIVATE bool operator<(const CString&, const CString&);
116117

118+
WTF_EXPORT_PRIVATE CString convertToASCIILowercase(std::span<const char8_t>);
119+
WTF_EXPORT_PRIVATE CString convertToASCIIUppercase(std::span<const char8_t>);
120+
117121
struct CStringHash {
118122
static unsigned hash(const CString& string) { return string.hash(); }
119123
WTF_EXPORT_PRIVATE static bool equal(const CString& a, const CString& b);
@@ -158,3 +162,5 @@ inline size_t CString::length() const
158162
} // namespace WTF
159163

160164
using WTF::CString;
165+
using WTF::convertToASCIILowercase;
166+
using WTF::convertToASCIIUppercase;

Source/WTF/wtf/text/CStringView.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,12 @@
3030
#include <wtf/text/CStringView.h>
3131

3232
#include <wtf/PrintStream.h>
33-
#include <wtf/text/MakeString.h>
34-
#include <wtf/text/WTFString.h>
3533

3634
namespace WTF {
3735

38-
String CStringView::toString() const
39-
{
40-
return String::fromUTF8(span8());
41-
}
42-
4336
void CStringView::dump(PrintStream& out) const
4437
{
45-
out.print(span8());
38+
out.print(span());
4639
}
4740

4841
} // namespace WTF

Source/WTF/wtf/text/CStringView.h

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,15 @@
3434
#include <wtf/Compiler.h>
3535
#include <wtf/ForbidHeapAllocation.h>
3636
#include <wtf/Forward.h>
37-
#include <wtf/HashFunctions.h>
3837
#include <wtf/StdLibExtras.h>
3938
#include <wtf/text/ASCIILiteral.h>
40-
#include <wtf/text/SuperFastHash.h>
4139

4240
namespace WTF {
4341

4442
class PrintStream;
45-
class String;
4643

47-
// This is a class designed to contain a UTF8 string, untouched. Interactions with other string classes in WebKit should
48-
// be handled with care or perform a string conversion through the String class, with the exception of ASCIILiteral
49-
// because ASCII characters are also UTF8.
44+
// This is a class designed to contain a null terminated UTF8 string, untouched. It contains char8_t to avoid mixing
45+
// incompatible encodings at compile time.
5046
class CStringView final {
5147
WTF_FORBID_HEAP_ALLOCATION;
5248
public:
@@ -70,17 +66,15 @@ class CStringView final {
7066
m_spanWithNullTerminator = byteCast<char8_t>(literal.spanIncludingNullTerminator());
7167
}
7268

73-
unsigned hash() const;
7469
bool isNull() const { return m_spanWithNullTerminator.empty(); }
7570

76-
// This method is designed to interface with external C functions handling UTF8 strings. Interactions with other
77-
// strings should be done through String with the exception of ASCIILiteral because ASCII is also UTF8.
71+
// This member function is designed to interface with external C functions handling UTF8 strings. Interactions with
72+
// other strings should be handled by using the span.
7873
const char* utf8() const LIFETIME_BOUND { return reinterpret_cast<const char*>(m_spanWithNullTerminator.data()); }
79-
size_t length() const { return m_spanWithNullTerminator.size() > 0 ? m_spanWithNullTerminator.size() - 1 : 0; }
80-
std::span<const char8_t> span8() const LIFETIME_BOUND { return m_spanWithNullTerminator.first(length()); }
74+
size_t lengthInBytes() const { return m_spanWithNullTerminator.size() > 0 ? m_spanWithNullTerminator.size() - 1 : 0; }
75+
std::span<const char8_t> span() const LIFETIME_BOUND { return m_spanWithNullTerminator.first(lengthInBytes()); }
8176
std::span<const char8_t> spanIncludingNullTerminator() const LIFETIME_BOUND { return m_spanWithNullTerminator; }
82-
size_t isEmpty() const { return m_spanWithNullTerminator.size() <= 1; }
83-
WTF_EXPORT_PRIVATE String toString() const;
77+
bool isEmpty() const { return m_spanWithNullTerminator.size() <= 1; }
8478

8579
explicit operator bool() const { return !isEmpty(); }
8680
bool operator!() const { return isEmpty(); }
@@ -96,16 +90,12 @@ class CStringView final {
9690

9791
inline bool operator==(CStringView a, CStringView b)
9892
{
99-
if (!a || !b)
100-
return a.utf8() == b.utf8();
101-
return equalSpans(a.span8(), b.span8());
93+
return equalSpans(a.span(), b.span());
10294
}
10395

10496
inline bool operator==(CStringView a, ASCIILiteral b)
10597
{
106-
if (a.isEmpty() || b.isEmpty())
107-
return a.utf8() == b.characters();
108-
return equalSpans(a.span8(), byteCast<char8_t>(b.span8()));
98+
return equalSpans(a.span(), byteCast<char8_t>(b.span()));
10999
}
110100

111101
inline bool operator==(ASCIILiteral a, CStringView b)

Source/WTF/wtf/text/ParsingUtilities.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,24 @@ template<bool characterPredicate(char16_t)> bool skipExactly(std::span<const cha
130130
return false;
131131
}
132132

133+
template<bool characterPredicate(char8_t), typename CharacterType> bool skipExactly(std::span<CharacterType>& buffer) requires(std::is_same_v<std::remove_const_t<CharacterType>, char8_t>)
134+
{
135+
if (!buffer.empty() && characterPredicate(buffer[0])) {
136+
skip(buffer, 1);
137+
return true;
138+
}
139+
return false;
140+
}
141+
142+
template<bool characterPredicate(char), typename CharacterType> bool skipExactly(std::span<CharacterType>& buffer) requires(std::is_same_v<std::remove_const_t<CharacterType>, char>)
143+
{
144+
if (!buffer.empty() && characterPredicate(buffer[0])) {
145+
skip(buffer, 1);
146+
return true;
147+
}
148+
return false;
149+
}
150+
133151
template<typename CharacterType, typename DelimiterType> void skipUntil(StringParsingBuffer<CharacterType>& buffer, DelimiterType delimiter)
134152
{
135153
while (buffer.hasCharactersRemaining() && *buffer != delimiter)
@@ -160,6 +178,22 @@ template<bool characterPredicate(char16_t)> void skipUntil(std::span<const char1
160178
skip(data, index);
161179
}
162180

181+
template<bool characterPredicate(char8_t), typename CharacterType> void skipUntil(std::span<CharacterType>& data) requires(std::is_same_v<std::remove_const_t<CharacterType>, char8_t>)
182+
{
183+
size_t index = 0;
184+
while (index < data.size() && !characterPredicate(data[index]))
185+
++index;
186+
skip(data, index);
187+
}
188+
189+
template<bool characterPredicate(char), typename CharacterType> void skipUntil(std::span<CharacterType>& data) requires(std::is_same_v<std::remove_const_t<CharacterType>, char>)
190+
{
191+
size_t index = 0;
192+
while (index < data.size() && !characterPredicate(data[index]))
193+
++index;
194+
skip(data, index);
195+
}
196+
163197
template<bool characterPredicate(Latin1Character)> void skipUntil(StringParsingBuffer<Latin1Character>& buffer)
164198
{
165199
while (buffer.hasCharactersRemaining() && !characterPredicate(*buffer))
@@ -202,6 +236,22 @@ template<bool characterPredicate(char16_t)> void skipWhile(std::span<const char1
202236
skip(data, index);
203237
}
204238

239+
template<bool characterPredicate(char8_t), typename CharacterType> void skipWhile(std::span<CharacterType>& data) requires(std::is_same_v<std::remove_const_t<CharacterType>, char8_t>)
240+
{
241+
size_t index = 0;
242+
while (index < data.size() && characterPredicate(data[index]))
243+
++index;
244+
skip(data, index);
245+
}
246+
247+
template<bool characterPredicate(char), typename CharacterType> void skipWhile(std::span<CharacterType>& data) requires(std::is_same_v<std::remove_const_t<CharacterType>, char>)
248+
{
249+
size_t index = 0;
250+
while (index < data.size() && characterPredicate(data[index]))
251+
++index;
252+
skip(data, index);
253+
}
254+
205255
template<bool characterPredicate(Latin1Character)> void skipWhile(StringParsingBuffer<Latin1Character>& buffer)
206256
{
207257
while (buffer.hasCharactersRemaining() && characterPredicate(*buffer))

0 commit comments

Comments
 (0)