/** @internal */ template<typename CP32, bool skipSurrogates> class CodePointsIterator {
static_assert(sizeof(CP32) == 4, "CP32 must be a 32-bit type to hold a code point");
public: /** C++ iterator boilerplate @internal */
using value_type = CP32; /** C++ iterator boilerplate @internal */
using reference = value_type; /** C++ iterator boilerplate @internal */
using pointer = CP32 *; /** C++ iterator boilerplate @internal */
using difference_type = int32_t; /** C++ iterator boilerplate @internal */
using iterator_category = std::forward_iterator_tag;
private: // Order of fields with padding and access frequency in mind.
CP32 c_;
uint8_t len_;
UnitIter start_;
UnitIter limit_;
};
#ifndef U_IN_DOXYGEN // Partial template specialization for single-pass input iterator. // No UnitIter field, no getter for it, no stringView(). template<typename CP32, typename UnitIter> class UnsafeCodeUnits<
CP32,
UnitIter,
std::enable_if_t<!prv::forward_iterator<UnitIter>>> {
static_assert(sizeof(CP32) == 4, "CP32 must be a 32-bit type to hold a code point");
public:
UnsafeCodeUnits(CP32 codePoint, uint8_t length) : c_(codePoint), len_(length) {}
// Note: readAndInc() functions take both a p0 and a p iterator. // They must have the same value. // For a multi-pass UnitIter, the caller must copy its p into a local variable p0, // and readAndInc() copies p0 and the incremented p into the CodeUnits. // For a single-pass UnitIter, which may not be default-constructible nor coypable, // the caller can pass p into both references, and readAndInc() does not use p0 // and constructs CodeUnits without them. // Moving the p0 variable into the call site avoids having to declare it inside readAndInc() // which may not be possible for a single-pass iterator.
// UTF-8 template<typename CP32, UTFIllFormedBehavior behavior, typename UnitIter, typename LimitIter> class UTFImpl<
CP32, behavior,
UnitIter, LimitIter,
std::enable_if_t<sizeof(typename prv::iter_value_t<UnitIter>) == 1>> {
static_assert(sizeof(CP32) == 4, "CP32 must be a 32-bit type to hold a code point");
static_assert(behavior != UTF_BEHAVIOR_SURROGATE, "For 8-bit strings, the SURROGATE option does not have an equivalent.");
public: // Handle ill-formed UTF-8
U_FORCE_INLINE static CP32 sub() { if constexpr (behavior == UTF_BEHAVIOR_NEGATIVE) { return U_SENTINEL;
} else {
static_assert(behavior == UTF_BEHAVIOR_FFFD); return0xfffd;
}
}
U_FORCE_INLINE staticvoid inc(UnitIter &p, const LimitIter &limit) { // Very similar to U8_FWD_1().
uint8_t b = *p;
++p; if (U8_IS_LEAD(b) && p != limit) {
uint8_t t1 = *p; if ((0xe0 <= b && b < 0xf0)) { if (U8_IS_VALID_LEAD3_AND_T1(b, t1) &&
++p != limit && U8_IS_TRAIL(*p)) {
++p;
}
} elseif (b < 0xe0) { if (U8_IS_TRAIL(t1)) {
++p;
}
} else/* b >= 0xf0 */ { if (U8_IS_VALID_LEAD4_AND_T1(b, t1) &&
++p != limit && U8_IS_TRAIL(*p) &&
++p != limit && U8_IS_TRAIL(*p)) {
++p;
}
}
}
}
U_FORCE_INLINE staticvoid dec(UnitIter start, UnitIter &p) { // Very similar to U8_BACK_1().
uint8_t c = *--p; if (U8_IS_TRAIL(c) && p != start) {
UnitIter p1 = p;
uint8_t b1 = *--p1; if (U8_IS_LEAD(b1)) { if (b1 < 0xe0 ||
(b1 < 0xf0 ?
U8_IS_VALID_LEAD3_AND_T1(b1, c) :
U8_IS_VALID_LEAD4_AND_T1(b1, c))) {
p = p1; return;
}
} elseif (U8_IS_TRAIL(b1) && p1 != start) {
uint8_t b2 = *--p1; if (0xe0 <= b2 && b2 <= 0xf4) { if (b2 < 0xf0 ?
U8_IS_VALID_LEAD3_AND_T1(b2, b1) :
U8_IS_VALID_LEAD4_AND_T1(b2, b1)) {
p = p1; return;
}
} elseif (U8_IS_TRAIL(b2) && p1 != start) {
uint8_t b3 = *--p1; if (0xf0 <= b3 && b3 <= 0xf4 && U8_IS_VALID_LEAD4_AND_T1(b3, b2)) {
p = p1; return;
}
}
}
}
}
U_FORCE_INLINE static CodeUnits<CP32, UnitIter> decAndRead(UnitIter start, UnitIter &p) { // Very similar to U8_PREV_OR_FFFD().
UnitIter p0 = p;
CP32 c = uint8_t(*--p); if (U8_IS_SINGLE(c)) { return {c, 1, true, p, p0};
} if (U8_IS_TRAIL(c) && p != start) {
UnitIter p1 = p;
uint8_t b1 = *--p1; if (U8_IS_LEAD(b1)) { if (b1 < 0xe0) {
p = p1;
c = ((b1 - 0xc0) << 6) | (c & 0x3f); return {c, 2, true, p, p0};
} elseif (b1 < 0xf0 ?
U8_IS_VALID_LEAD3_AND_T1(b1, c) :
U8_IS_VALID_LEAD4_AND_T1(b1, c)) { // Truncated 3- or 4-byte sequence.
p = p1; return {sub(), 2, false, p, p0};
}
} elseif (U8_IS_TRAIL(b1) && p1 != start) { // Extract the value bits from the last trail byte.
c &= 0x3f;
uint8_t b2 = *--p1; if (0xe0 <= b2 && b2 <= 0xf4) { if (b2 < 0xf0) {
b2 &= 0xf; if (U8_IS_VALID_LEAD3_AND_T1(b2, b1)) {
p = p1;
c = (b2 << 12) | ((b1 & 0x3f) << 6) | c; return {c, 3, true, p, p0};
}
} elseif (U8_IS_VALID_LEAD4_AND_T1(b2, b1)) { // Truncated 4-byte sequence.
p = p1; return {sub(), 3, false, p, p0};
}
} elseif (U8_IS_TRAIL(b2) && p1 != start) {
uint8_t b3 = *--p1; if (0xf0 <= b3 && b3 <= 0xf4) {
b3 &= 7; if (U8_IS_VALID_LEAD4_AND_T1(b3, b2)) {
p = p1;
c = (b3 << 18) | ((b2 & 0x3f) << 12) | ((b1 & 0x3f) << 6) | c; return {c, 4, true, p, p0};
}
}
}
}
} return {sub(), 1, false, p, p0};
}
};
// UTF-16 template<typename CP32, UTFIllFormedBehavior behavior, typename UnitIter, typename LimitIter> class UTFImpl<
CP32, behavior,
UnitIter, LimitIter,
std::enable_if_t<sizeof(typename prv::iter_value_t<UnitIter>) == 2>> {
static_assert(sizeof(CP32) == 4, "CP32 must be a 32-bit type to hold a code point");
public: // Handle ill-formed UTF-16: One unpaired surrogate.
U_FORCE_INLINE static CP32 sub(CP32 surrogate) { if constexpr (behavior == UTF_BEHAVIOR_NEGATIVE) { return U_SENTINEL;
} elseif constexpr (behavior == UTF_BEHAVIOR_FFFD) { return0xfffd;
} else {
static_assert(behavior == UTF_BEHAVIOR_SURROGATE); return surrogate;
}
}
U_FORCE_INLINE staticvoid inc(UnitIter &p, const LimitIter &limit) { // Very similar to U16_FWD_1(). auto c = *p;
++p; if (U16_IS_LEAD(c) && p != limit && U16_IS_TRAIL(*p)) {
++p;
}
}
U_FORCE_INLINE staticvoid dec(UnitIter start, UnitIter &p) { // Very similar to U16_BACK_1().
UnitIter p1; if (U16_IS_TRAIL(*--p) && p != start && (p1 = p, U16_IS_LEAD(*--p1))) {
p = p1;
}
}
template<typename CP32, typename UnitIter, typename = void> class UnsafeUTFImpl;
// UTF-8 template<typename CP32, typename UnitIter> class UnsafeUTFImpl<
CP32,
UnitIter,
std::enable_if_t<sizeof(typename prv::iter_value_t<UnitIter>) == 1>> {
static_assert(sizeof(CP32) == 4, "CP32 must be a 32-bit type to hold a code point");
public:
U_FORCE_INLINE staticvoid inc(UnitIter &p) { // Very similar to U8_FWD_1_UNSAFE().
uint8_t b = *p;
std::advance(p, 1 + U8_COUNT_TRAIL_BYTES_UNSAFE(b));
}
U_FORCE_INLINE staticvoid dec(UnitIter &p) { // Very similar to U8_BACK_1_UNSAFE(). while (U8_IS_TRAIL(*--p)) {}
}
U_FORCE_INLINE static UnsafeCodeUnits<CP32, UnitIter> readAndInc(UnitIter &p0, UnitIter &p) {
constexpr bool isMultiPass = prv::forward_iterator<UnitIter>; // Very similar to U8_NEXT_UNSAFE().
CP32 c = uint8_t(*p);
++p; if (U8_IS_SINGLE(c)) { if constexpr (isMultiPass) { return {c, 1, p0, p};
} else { return {c, 1};
}
} elseif (c < 0xe0) {
c = ((c & 0x1f) << 6) | (*p & 0x3f);
++p; if constexpr (isMultiPass) { return {c, 2, p0, p};
} else { return {c, 2};
}
} elseif (c < 0xf0) { // No need for (c&0xf) because the upper bits are truncated // after <<12 in the cast to uint16_t.
c = uint16_t(c << 12) | ((*p & 0x3f) << 6);
++p;
c |= *p & 0x3f;
++p; if constexpr (isMultiPass) { return {c, 3, p0, p};
} else { return {c, 3};
}
} else {
c = ((c & 7) << 18) | ((*p & 0x3f) << 12);
++p;
c |= (*p & 0x3f) << 6;
++p;
c |= *p & 0x3f;
++p; if constexpr (isMultiPass) { return {c, 4, p0, p};
} else { return {c, 4};
}
}
}
U_FORCE_INLINE static UnsafeCodeUnits<CP32, UnitIter> decAndRead(UnitIter &p) { // Very similar to U8_PREV_UNSAFE().
UnitIter p0 = p;
CP32 c = uint8_t(*--p); if (U8_IS_SINGLE(c)) { return {c, 1, p, p0};
} // U8_IS_TRAIL(c) if well-formed
c &= 0x3f;
uint8_t count = 1; for (uint8_t shift = 6;;) {
uint8_t b = *--p; if (b >= 0xc0) {
U8_MASK_LEAD_BYTE(b, count);
c |= uint32_t{b} << shift; break;
} else {
c |= (uint32_t{b} & 0x3f) << shift;
++count;
shift += 6;
}
}
++count; return {c, count, p, p0};
}
};
// UTF-16 template<typename CP32, typename UnitIter> class UnsafeUTFImpl<
CP32,
UnitIter,
std::enable_if_t<sizeof(typename prv::iter_value_t<UnitIter>) == 2>> {
static_assert(sizeof(CP32) == 4, "CP32 must be a 32-bit type to hold a code point");
public:
U_FORCE_INLINE staticvoid inc(UnitIter &p) { // Very similar to U16_FWD_1_UNSAFE(). auto c = *p;
++p; if (U16_IS_LEAD(c)) {
++p;
}
}
U_FORCE_INLINE staticvoid dec(UnitIter &p) { // Very similar to U16_BACK_1_UNSAFE(). if (U16_IS_TRAIL(*--p)) {
--p;
}
}
U_FORCE_INLINE static UnsafeCodeUnits<CP32, UnitIter> readAndInc(UnitIter &p0, UnitIter &p) {
constexpr bool isMultiPass = prv::forward_iterator<UnitIter>; // Very similar to U16_NEXT_UNSAFE().
CP32 c = static_cast<CP32>(*p);
++p; if (!U16_IS_LEAD(c)) { if constexpr (isMultiPass) { return {c, 1, p0, p};
} else { return {c, 1};
}
} else {
uint16_t c2 = *p;
++p;
c = U16_GET_SUPPLEMENTARY(c, c2); if constexpr (isMultiPass) { return {c, 2, p0, p};
} else { return {c, 2};
}
}
}
U_FORCE_INLINE static UnsafeCodeUnits<CP32, UnitIter> decAndRead(UnitIter &p) { // Very similar to U16_PREV_UNSAFE().
UnitIter p0 = p;
CP32 c = static_cast<CP32>(*--p); if (!U16_IS_TRAIL(c)) { return {c, 1, p, p0};
} else {
uint16_t c2 = *--p;
c = U16_GET_SUPPLEMENTARY(c2, c); return {c, 2, p, p0};
}
}
};
// UTF-32: trivial template<typename CP32, typename UnitIter> class UnsafeUTFImpl<
CP32,
UnitIter,
std::enable_if_t<sizeof(typename prv::iter_value_t<UnitIter>) == 4>> {
static_assert(sizeof(CP32) == 4, "CP32 must be a 32-bit type to hold a code point");
public:
U_FORCE_INLINE staticvoid inc(UnitIter &p) {
++p;
}
#if U_CPLUSPLUS_VERSION < 20 // C++17: Need to define all four combinations of == / != vs. parameter order. // Once we require C++20, we could remove all but the first == because // the compiler would generate the rest.
// operator*() etc. are logically const. mutable UnitIter p_; // In a validating iterator, we need start_ & limit_ so that when we read a code point // (forward or backward) we can test if there are enough code units.
UnitIter start_;
LimitIter limit_; // Keep state so that we call readAndInc() only once for both operator*() and ++ // to make it easy for the compiler to optimize. mutable CodeUnits<CP32, UnitIter> units_; // >0: units_ = readAndInc(), p_ = units limit // which means that p_ is ahead of its logical position // 0: initial state // <0: units_ = decAndRead(), p_ = units start mutable int8_t state_ = 0;
};
#ifndef U_IN_DOXYGEN // Partial template specialization for single-pass input iterator. template<typename CP32, UTFIllFormedBehavior behavior, typename UnitIter, typename LimitIter> class UTFIterator<
CP32, behavior,
UnitIter, LimitIter,
std::enable_if_t<!prv::forward_iterator<UnitIter>>> {
static_assert(sizeof(CP32) == 4, "CP32 must be a 32-bit type to hold a code point");
using Impl = UTFImpl<CP32, behavior, UnitIter, LimitIter>;
// Proxy type for post-increment return value, to make *iter++ work. // Also for operator->() (required by LegacyInputIterator) // so that we don't promise always returning CodeUnits. class Proxy {
public: explicit Proxy(CodeUnits<CP32, UnitIter> &units) : units_(units) {}
CodeUnits<CP32, UnitIter> &operator*() { return units_; }
CodeUnits<CP32, UnitIter> *operator->() { return &units_; } private:
CodeUnits<CP32, UnitIter> units_;
};
public:
using value_type = CodeUnits<CP32, UnitIter>;
using reference = value_type;
using pointer = Proxy;
using difference_type = prv::iter_difference_t<UnitIter>;
using iterator_category = std::input_iterator_tag;
// Constructs an iterator start or limit sentinel. // Requires p to be copyable.
U_FORCE_INLINE explicit UTFIterator(UnitIter p) : p_(std::move(p)), limit_(p_) {}
U_FORCE_INLINE booloperator==(const UTFIterator &other) const { return p_ == other.p_ && ahead_ == other.ahead_; // Strictly speaking, we should check if the logical position is the same. // However, we cannot advance, or do arithmetic with, a single-pass UnitIter.
}
U_FORCE_INLINE booloperator!=(const UTFIterator &other) const { return !operator==(other); }
U_FORCE_INLINE UTFIterator &operator++() { // pre-increment if (ahead_) { // operator*() called readAndInc() so p_ is already ahead.
ahead_ = false;
} else {
Impl::inc(p_, limit_);
} return *this;
}
U_FORCE_INLINE Proxy operator++(int) { // post-increment if (ahead_) { // operator*() called readAndInc() so p_ is already ahead.
ahead_ = false;
} else {
units_ = Impl::readAndInc(p_, p_, limit_); // keep this->ahead_ == false
} return Proxy(units_);
}
private: // operator*() etc. are logically const. mutable UnitIter p_; // In a validating iterator, we need limit_ so that when we read a code point // we can test if there are enough code units.
LimitIter limit_; // Keep state so that we call readAndInc() only once for both operator*() and ++ // so that we can use a single-pass input iterator for UnitIter. mutable CodeUnits<CP32, UnitIter> units_ = {0, 0, false}; // true: units_ = readAndInc(), p_ = units limit // which means that p_ is ahead of its logical position // false: initial state mutablebool ahead_ = false;
}; #endif// U_IN_DOXYGEN
} // namespace U_HEADER_ONLY_NAMESPACE
#ifndef U_IN_DOXYGEN // Bespoke specialization of reverse_iterator. // The default implementation implements reverse operator*() and ++ in a way // that does most of the same work twice for reading variable-length sequences. template<typename CP32, UTFIllFormedBehavior behavior, typename UnitIter> class std::reverse_iterator<U_HEADER_ONLY_NAMESPACE::UTFIterator<CP32, behavior, UnitIter>> {
static_assert(sizeof(CP32) == 4, "CP32 must be a 32-bit type to hold a code point");
using Impl = U_HEADER_ONLY_NAMESPACE::UTFImpl<CP32, behavior, UnitIter>;
using CodeUnits_ = U_HEADER_ONLY_NAMESPACE::CodeUnits<CP32, UnitIter>;
// Proxy type for operator->() (required by LegacyInputIterator) // so that we don't promise always returning CodeUnits. class Proxy {
public: explicit Proxy(CodeUnits_ units) : units_(units) {}
CodeUnits_ &operator*() { return units_; }
CodeUnits_ *operator->() { return &units_; } private:
CodeUnits_ units_;
};
public:
using value_type = CodeUnits_;
using reference = value_type;
using pointer = Proxy;
using difference_type = U_HEADER_ONLY_NAMESPACE::prv::iter_difference_t<UnitIter>;
using iterator_category = std::bidirectional_iterator_tag;
// operator*() etc. are logically const. mutable UnitIter p_; // In a validating iterator, we need start_ & limit_ so that when we read a code point // (forward or backward) we can test if there are enough code units.
UnitIter start_;
UnitIter limit_; // Keep state so that we call decAndRead() only once for both operator*() and ++ // to make it easy for the compiler to optimize. mutable CodeUnits_ units_; // >0: units_ = readAndInc(), p_ = units limit // 0: initial state // <0: units_ = decAndRead(), p_ = units start // which means that p_ is behind its logical position mutable int8_t state_ = 0;
}; #endif// U_IN_DOXYGEN
// Note: We should only enable the following factory function for a copyable UnitIter. // In C++17, we would have to partially specialize with enable_if_t testing for forward_iterator, // but a function template partial specialization is not allowed. // In C++20, we might be able to require the std::copyable concept.
// operator*() etc. are logically const. mutable UnitIter p_; // Keep state so that we call readAndInc() only once for both operator*() and ++ // to make it easy for the compiler to optimize. mutable UnsafeCodeUnits<CP32, UnitIter> units_; // >0: units_ = readAndInc(), p_ = units limit // which means that p_ is ahead of its logical position // 0: initial state // <0: units_ = decAndRead(), p_ = units start mutable int8_t state_ = 0;
};
#ifndef U_IN_DOXYGEN // Partial template specialization for single-pass input iterator. template<typename CP32, typename UnitIter> class UnsafeUTFIterator<
CP32,
UnitIter,
std::enable_if_t<!prv::forward_iterator<UnitIter>>> {
static_assert(sizeof(CP32) == 4, "CP32 must be a 32-bit type to hold a code point");
using Impl = UnsafeUTFImpl<CP32, UnitIter>;
// Proxy type for post-increment return value, to make *iter++ work. // Also for operator->() (required by LegacyInputIterator) // so that we don't promise always returning UnsafeCodeUnits. class Proxy {
public: explicit Proxy(UnsafeCodeUnits<CP32, UnitIter> &units) : units_(units) {}
UnsafeCodeUnits<CP32, UnitIter> &operator*() { return units_; }
UnsafeCodeUnits<CP32, UnitIter> *operator->() { return &units_; } private:
UnsafeCodeUnits<CP32, UnitIter> units_;
};
public:
using value_type = UnsafeCodeUnits<CP32, UnitIter>;
using reference = value_type;
using pointer = Proxy;
using difference_type = prv::iter_difference_t<UnitIter>;
using iterator_category = std::input_iterator_tag;
U_FORCE_INLINE booloperator==(const UnsafeUTFIterator &other) const { return p_ == other.p_ && ahead_ == other.ahead_; // Strictly speaking, we should check if the logical position is the same. // However, we cannot advance, or do arithmetic with, a single-pass UnitIter.
}
U_FORCE_INLINE booloperator!=(const UnsafeUTFIterator &other) const { return !operator==(other); }
U_FORCE_INLINE UnsafeUTFIterator &operator++() { // pre-increment if (ahead_) { // operator*() called readAndInc() so p_ is already ahead.
ahead_ = false;
} else {
Impl::inc(p_);
} return *this;
}
U_FORCE_INLINE Proxy operator++(int) { // post-increment if (ahead_) { // operator*() called readAndInc() so p_ is already ahead.
ahead_ = false;
} else {
units_ = Impl::readAndInc(p_, p_); // keep this->ahead_ == false
} return Proxy(units_);
}
private: // operator*() etc. are logically const. mutable UnitIter p_; // Keep state so that we call readAndInc() only once for both operator*() and ++ // so that we can use a single-pass input iterator for UnitIter. mutable UnsafeCodeUnits<CP32, UnitIter> units_ = {0, 0}; // true: units_ = readAndInc(), p_ = units limit // which means that p_ is ahead of its logical position // false: initial state mutablebool ahead_ = false;
}; #endif// U_IN_DOXYGEN
} // namespace U_HEADER_ONLY_NAMESPACE
#ifndef U_IN_DOXYGEN // Bespoke specialization of reverse_iterator. // The default implementation implements reverse operator*() and ++ in a way // that does most of the same work twice for reading variable-length sequences. template<typename CP32, typename UnitIter> class std::reverse_iterator<U_HEADER_ONLY_NAMESPACE::UnsafeUTFIterator<CP32, UnitIter>> {
static_assert(sizeof(CP32) == 4, "CP32 must be a 32-bit type to hold a code point");
using Impl = U_HEADER_ONLY_NAMESPACE::UnsafeUTFImpl<CP32, UnitIter>;
using UnsafeCodeUnits_ = U_HEADER_ONLY_NAMESPACE::UnsafeCodeUnits<CP32, UnitIter>;
// Proxy type for operator->() (required by LegacyInputIterator) // so that we don't promise always returning UnsafeCodeUnits. class Proxy {
public: explicit Proxy(UnsafeCodeUnits_ units) : units_(units) {}
UnsafeCodeUnits_ &operator*() { return units_; }
UnsafeCodeUnits_ *operator->() { return &units_; } private:
UnsafeCodeUnits_ units_;
};
public:
using value_type = UnsafeCodeUnits_;
using reference = value_type;
using pointer = Proxy;
using difference_type = U_HEADER_ONLY_NAMESPACE::prv::iter_difference_t<UnitIter>;
using iterator_category = std::bidirectional_iterator_tag;
// operator*() etc. are logically const. mutable UnitIter p_; // Keep state so that we call decAndRead() only once for both operator*() and ++ // to make it easy for the compiler to optimize. mutable UnsafeCodeUnits_ units_; // >0: units_ = readAndInc(), p_ = units limit // 0: initial state // <0: units_ = decAndRead(), p_ = units start // which means that p_ is behind its logical position mutable int8_t state_ = 0;
}; #endif// U_IN_DOXYGEN
/** @internal */ template<typename CP32> struct UnsafeUTFStringCodePointsAdaptor #if U_CPLUSPLUS_VERSION >= 23 && __cpp_lib_ranges >= 2022'02 && \
__cpp_lib_bind_back >= 2022'02 // http://wg21.link/P2387R3.
: std::ranges::range_adaptor_closure<UnsafeUTFStringCodePointsAdaptor<CP32>> #endif
{ /** @internal */ template<typename Range> autooperator()(Range &&unitRange) const { #ifdefined(__cpp_lib_ranges) && __cpp_lib_ranges >= 2021'10 // We need https://wg21.link/P2415R2. return UnsafeUTFStringCodePoints<CP32, std::ranges::views::all_t<Range>>(std::forward<Range>(unitRange)); #else if constexpr (prv::is_basic_string_view_v<std::decay_t<Range>>) { // Take basic_string_view by copy, not by reference. In C++20 this is handled by // all_t<Range>, which is Range if Range is a view. return UnsafeUTFStringCodePoints<CP32, std::decay_t<Range>>(std::forward<Range>(unitRange));
} else { return UnsafeUTFStringCodePoints<CP32, Range>(std::forward<Range>(unitRange));
} #endif
}
};
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.165Bemerkung:
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.