Bug 1601859 - Vendor cubeb-pulse-rs. r=kinetik
[gecko.git] / mfbt / Utf8.h
blob6a1167b5ecf63d34fbd65f142084e5362f69cadf
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * UTF-8-related functionality, including a type-safe structure representing a
9 * UTF-8 code unit.
12 #ifndef mozilla_Utf8_h
13 #define mozilla_Utf8_h
15 #include "mozilla/Casting.h" // for mozilla::AssertedCast
16 #include "mozilla/IntegerTypeTraits.h" // for mozilla::MaxValue
17 #include "mozilla/Likely.h" // for MOZ_UNLIKELY
18 #include "mozilla/Maybe.h" // for mozilla::Maybe
19 #include "mozilla/Span.h" // for mozilla::Span
20 #include "mozilla/TextUtils.h" // for mozilla::IsAscii and via Latin1.h for
21 // encoding_rs_mem.h and MOZ_HAS_JSRUST.
22 #include "mozilla/Tuple.h" // for mozilla::Tuple
23 #include "mozilla/Types.h" // for MFBT_API
25 #include <limits.h> // for CHAR_BIT
26 #include <stddef.h> // for size_t
27 #include <stdint.h> // for uint8_t
29 #if MOZ_HAS_JSRUST()
30 // Can't include mozilla/Encoding.h here.
31 extern "C" {
32 // Declared as uint8_t instead of char to match declaration in another header.
33 size_t encoding_utf8_valid_up_to(uint8_t const* buffer, size_t buffer_len);
35 #else
36 namespace mozilla {
37 namespace detail {
38 extern MFBT_API bool IsValidUtf8(const void* aCodeUnits, size_t aCount);
39 }; // namespace detail
40 }; // namespace mozilla
41 #endif // MOZ_HAS_JSRUST
43 namespace mozilla {
45 union Utf8Unit;
47 static_assert(CHAR_BIT == 8,
48 "Utf8Unit won't work so well with non-octet chars");
50 /**
51 * A code unit within a UTF-8 encoded string. (A code unit is the smallest
52 * unit within the Unicode encoding of a string. For UTF-8 this is an 8-bit
53 * number; for UTF-16 it would be a 16-bit number.)
55 * This is *not* the same as a single code point: in UTF-8, non-ASCII code
56 * points are constituted by multiple code units.
58 union Utf8Unit {
59 private:
60 // Utf8Unit is a union wrapping a raw |char|. The C++ object model and C++
61 // requirements as to how objects may be accessed with respect to their actual
62 // types (almost?) uniquely compel this choice.
64 // Our requirements for a UTF-8 code unit representation are:
66 // 1. It must be "compatible" with C++ character/string literals that use
67 // the UTF-8 encoding. Given a properly encoded C++ literal, you should
68 // be able to use |Utf8Unit| and friends to access it; given |Utf8Unit|
69 // and friends (particularly UnicodeData), you should be able to access
70 // C++ character types for their contents.
71 // 2. |Utf8Unit| and friends must convert to/from |char| and |char*| only by
72 // explicit operation.
73 // 3. |Utf8Unit| must participate in overload resolution and template type
74 // equivalence (that is, given |template<class> class X|, when |X<T>| and
75 // |X<U>| are the same type) distinctly from the C++ character types.
77 // And a few nice-to-haves (at least for the moment):
79 // 4. The representation should use unsigned numbers, to avoid undefined
80 // behavior that can arise with signed types, and because Unicode code
81 // points and code units are unsigned.
82 // 5. |Utf8Unit| and friends should be convertible to/from |unsigned char|
83 // and |unsigned char*|, for APIs that (because of #4 above) use those
84 // types as the "natural" choice for UTF-8 data.
86 // #1 requires that |Utf8Unit| "incorporate" a C++ character type: one of
87 // |{,{un,}signed} char|.[0] |uint8_t| won't work because it might not be a
88 // C++ character type.
90 // #2 and #3 mean that |Utf8Unit| can't *be* such a type (or a typedef to one:
91 // typedefs don't generate *new* types, just type aliases). This requires a
92 // compound type.
94 // The ultimate representation (and character type in it) is constrained by
95 // C++14 [basic.lval]p10 that defines how objects may be accessed, with
96 // respect to the dynamic type in memory and the actual type used to access
97 // them. It reads:
99 // If a program attempts to access the stored value of an object
100 // through a glvalue of other than one of the following types the
101 // behavior is undefined:
103 // 1. the dynamic type of the object,
104 // 2. a cv-qualified version of the dynamic type of the object,
105 // ...other types irrelevant here...
106 // 3. an aggregate or union type that includes one of the
107 // aforementioned types among its elements or non-static data
108 // members (including, recursively, an element or non-static
109 // data member of a subaggregate or contained union),
110 // ...more irrelevant types...
111 // 4. a char or unsigned char type.
113 // Accessing (wrapped) UTF-8 data as |char|/|unsigned char| is allowed no
114 // matter the representation by #4. (Briefly set aside what values are seen.)
115 // (And #2 allows |const| on either the dynamic type or the accessing type.)
116 // (|signed char| is really only useful for small signed numbers, not
117 // characters, so we ignore it.)
119 // If we interpret contents as |char|/|unsigned char| contrary to the actual
120 // type stored there, what happens? C++14 [basic.fundamental]p1 requires
121 // character types be identically aligned/sized; C++14 [basic.fundamental]p3
122 // requires |signed char| and |unsigned char| have the same value
123 // representation. C++ doesn't require identical bitwise representation, tho.
124 // Practically we could assume it, but this verges on C++ spec bits best not
125 // *relied* on for correctness, if possible.
127 // So we don't expose |Utf8Unit|'s contents as |unsigned char*|: only |char|
128 // and |char*|. Instead we safely expose |unsigned char| by fully-defined
129 // *integral conversion* (C++14 [conv.integral]p2). Integral conversion from
130 // |unsigned char| → |char| has only implementation-defined behavior. It'd be
131 // better not to depend on that, but given twos-complement won, it should be
132 // okay. (Also |unsigned char*| is awkward enough to work with for strings
133 // that it probably doesn't appear in string manipulation much anyway, only in
134 // places that should really use |Utf8Unit| directly.)
136 // The opposite direction -- interpreting |char| or |char*| data through
137 // |Utf8Unit| -- isn't tricky as long as |Utf8Unit| contains a |char| as
138 // decided above, using #3. An "aggregate or union" will work that contains a
139 // |char|. Oddly, an aggregate won't work: C++14 [dcl.init.aggr]p1 says
140 // aggregates must have "no private or protected non-static data members", and
141 // we want to keep the inner |char| hidden. So a |struct| is out, and only
142 // |union| remains.
144 // (Enums are not "an aggregate or union type", so [maybe surprisingly] we
145 // can't make |Utf8Unit| an enum class with |char| underlying type, because we
146 // are given no license to treat |char| memory as such an |enum|'s memory.)
148 // Therefore |Utf8Unit| is a union type with a |char| non-static data member.
149 // This satisfies all our requirements. It also supports the nice-to-haves of
150 // creating a |Utf8Unit| from an |unsigned char|, and being convertible to
151 // |unsigned char|. It doesn't satisfy the nice-to-haves of using an
152 // |unsigned char| internally, nor of letting us wrap an existing
153 // |unsigned char| or pointer to one. We probably *could* do these, if we
154 // were willing to rely harder on implementation-defined behaviors, but for
155 // now we privilege C++'s main character type over some conceptual purity.
157 // 0. There's a proposal for a UTF-8 character type distinct from the existing
158 // C++ narrow character types:
160 // http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0482r0.html
162 // but it hasn't been standardized (and might never be), and none of the
163 // compilers we really care about have implemented it. Maybe someday we
164 // can change our implementation to it without too much trouble, if we're
165 // lucky...
166 char mValue = '\0';
168 public:
169 Utf8Unit() = default;
171 explicit constexpr Utf8Unit(char aUnit) : mValue(aUnit) {}
173 explicit constexpr Utf8Unit(unsigned char aUnit)
174 : mValue(static_cast<char>(aUnit)) {
175 // Per the above comment, the prior cast is integral conversion with
176 // implementation-defined semantics, and we regretfully but unavoidably
177 // assume the conversion does what we want it to.
180 constexpr bool operator==(const Utf8Unit& aOther) const {
181 return mValue == aOther.mValue;
184 constexpr bool operator!=(const Utf8Unit& aOther) const {
185 return !(*this == aOther);
188 /** Convert a UTF-8 code unit to a raw char. */
189 constexpr char toChar() const {
190 // Only a |char| is ever permitted to be written into this location, so this
191 // is both permissible and returns the desired value.
192 return mValue;
195 /** Convert a UTF-8 code unit to a raw unsigned char. */
196 constexpr unsigned char toUnsignedChar() const {
197 // Per the above comment, this is well-defined integral conversion.
198 return static_cast<unsigned char>(mValue);
201 /** Convert a UTF-8 code unit to a uint8_t. */
202 constexpr uint8_t toUint8() const {
203 // Per the above comment, this is well-defined integral conversion.
204 return static_cast<uint8_t>(mValue);
207 // We currently don't expose |&mValue|. |UnicodeData| sort of does, but
208 // that's a somewhat separate concern, justified in different comments in
209 // that other code.
213 * Reinterpret the address of a UTF-8 code unit as |const unsigned char*|.
215 * Assuming proper backing has been set up, the resulting |const unsigned char*|
216 * may validly be dereferenced.
218 * No access is provided to mutate this underlying memory as |unsigned char|.
219 * Presently memory inside |Utf8Unit| is *only* stored as |char|, and we are
220 * loath to offer a way to write non-|char| data until absolutely necessary.
222 inline const unsigned char* Utf8AsUnsignedChars(const Utf8Unit* aUnits) {
223 static_assert(sizeof(Utf8Unit) == sizeof(unsigned char),
224 "sizes must match to permissibly reinterpret_cast<>");
225 static_assert(alignof(Utf8Unit) == alignof(unsigned char),
226 "alignment must match to permissibly reinterpret_cast<>");
228 // The static_asserts above only enable the reinterpret_cast<> to occur.
230 // Dereferencing the resulting pointer is a separate question. Any object's
231 // memory may be interpreted as |unsigned char| per C++11 [basic.lval]p10, but
232 // this doesn't guarantee what values will be observed. If |char| is
233 // implemented to act like |unsigned char|, we're good to go: memory for the
234 // |char| in |Utf8Unit| acts as we need. But if |char| is implemented to act
235 // like |signed char|, dereferencing produces the right value only if the
236 // |char| types all use two's-complement representation. Every modern
237 // compiler does this, and there's a C++ proposal to standardize it.
238 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0907r0.html So
239 // *technically* this is implementation-defined -- but everyone does it and
240 // this behavior is being standardized.
241 return reinterpret_cast<const unsigned char*>(aUnits);
244 /** Returns true iff |aUnit| is an ASCII value. */
245 constexpr bool IsAscii(Utf8Unit aUnit) {
246 return IsAscii(aUnit.toUnsignedChar());
250 * Return true if the given span of memory consists of a valid UTF-8
251 * string and false otherwise.
253 * The string *may* contain U+0000 NULL code points.
255 inline bool IsUtf8(mozilla::Span<const char> aString) {
256 #if MOZ_HAS_JSRUST()
257 size_t length = aString.Length();
258 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(aString.Elements());
259 // For short strings, the function call is a pessimization, and the SIMD
260 // code won't have a chance to kick in anyway.
261 if (length < 16) {
262 for (size_t i = 0; i < length; i++) {
263 if (ptr[i] >= 0x80U) {
264 ptr += i;
265 length -= i;
266 goto end;
269 return true;
271 end:
272 return length == encoding_utf8_valid_up_to(ptr, length);
273 #else
274 return detail::IsValidUtf8(aString.Elements(), aString.Length());
275 #endif
278 #if MOZ_HAS_JSRUST()
280 // See Latin1.h for conversions between Latin1 and UTF-8.
283 * Returns the index of the start of the first malformed byte
284 * sequence or the length of the string if there are none.
286 inline size_t Utf8ValidUpTo(mozilla::Span<const char> aString) {
287 return encoding_utf8_valid_up_to(
288 reinterpret_cast<const uint8_t*>(aString.Elements()), aString.Length());
292 * Converts potentially-invalid UTF-16 to UTF-8 replacing lone surrogates
293 * with the REPLACEMENT CHARACTER.
295 * The length of aDest must be at least the length of aSource times three.
297 * Returns the number of code units written.
299 inline size_t ConvertUtf16toUtf8(mozilla::Span<const char16_t> aSource,
300 mozilla::Span<char> aDest) {
301 return encoding_mem_convert_utf16_to_utf8(
302 aSource.Elements(), aSource.Length(), aDest.Elements(), aDest.Length());
306 * Converts potentially-invalid UTF-8 to UTF-16 replacing malformed byte
307 * sequences with the REPLACEMENT CHARACTER with potentially insufficient
308 * output space.
310 * Returns the number of code units read and the number of bytes written.
312 * If the output isn't large enough, not all input is consumed.
314 * The conversion is guaranteed to be complete if the length of aDest is
315 * at least the length of aSource times three.
317 * The output is always valid UTF-8 ending on scalar value boundary
318 * even in the case of partial conversion.
320 * The semantics of this function match the semantics of
321 * TextEncoder.encodeInto.
322 * https://encoding.spec.whatwg.org/#dom-textencoder-encodeinto
324 inline mozilla::Tuple<size_t, size_t> ConvertUtf16toUtf8Partial(
325 mozilla::Span<const char16_t> aSource, mozilla::Span<char> aDest) {
326 size_t srcLen = aSource.Length();
327 size_t dstLen = aDest.Length();
328 encoding_mem_convert_utf16_to_utf8_partial(aSource.Elements(), &srcLen,
329 aDest.Elements(), &dstLen);
330 return mozilla::MakeTuple(srcLen, dstLen);
334 * Converts potentially-invalid UTF-8 to UTF-16 replacing malformed byte
335 * sequences with the REPLACEMENT CHARACTER.
337 * Returns the number of code units written.
339 * The length of aDest must be at least one greater than the length of aSource
340 * even though the last slot isn't written to.
342 * If you know that the input is valid for sure, use
343 * UnsafeConvertValidUtf8toUtf16() instead.
345 inline size_t ConvertUtf8toUtf16(mozilla::Span<const char> aSource,
346 mozilla::Span<char16_t> aDest) {
347 return encoding_mem_convert_utf8_to_utf16(
348 aSource.Elements(), aSource.Length(), aDest.Elements(), aDest.Length());
352 * Converts known-valid UTF-8 to UTF-16. If the input might be invalid,
353 * use ConvertUtf8toUtf16() or ConvertUtf8toUtf16WithoutReplacement() instead.
355 * Returns the number of code units written.
357 * The length of aDest must be at least the length of aSource.
359 inline size_t UnsafeConvertValidUtf8toUtf16(mozilla::Span<const char> aSource,
360 mozilla::Span<char16_t> aDest) {
361 return encoding_mem_convert_utf8_to_utf16(
362 aSource.Elements(), aSource.Length(), aDest.Elements(), aDest.Length());
366 * Converts potentially-invalid UTF-8 to valid UTF-16 signaling on error.
368 * Returns the number of code units written or `mozilla::Nothing` if the
369 * input was invalid.
371 * The length of the destination buffer must be at least the length of the
372 * source buffer.
374 * When the input was invalid, some output may have been written.
376 * If you know that the input is valid for sure, use
377 * UnsafeConvertValidUtf8toUtf16() instead.
379 inline mozilla::Maybe<size_t> ConvertUtf8toUtf16WithoutReplacement(
380 mozilla::Span<const char> aSource, mozilla::Span<char16_t> aDest) {
381 size_t written = encoding_mem_convert_utf8_to_utf16_without_replacement(
382 aSource.Elements(), aSource.Length(), aDest.Elements(), aDest.Length());
383 if (MOZ_UNLIKELY(written == mozilla::MaxValue<size_t>::value)) {
384 return mozilla::Nothing();
386 return mozilla::Some(written);
389 #endif // MOZ_HAS_JSRUST
392 * Returns true iff |aUnit| is a UTF-8 trailing code unit matching the pattern
393 * 0b10xx'xxxx.
395 inline bool IsTrailingUnit(Utf8Unit aUnit) {
396 return (aUnit.toUint8() & 0b1100'0000) == 0b1000'0000;
400 * Given |aLeadUnit| that is a non-ASCII code unit, a pointer to an |Iter aIter|
401 * that (initially) itself points one unit past |aLeadUnit|, and
402 * |const EndIter& aEnd| that denotes the end of the UTF-8 data when compared
403 * against |*aIter| using |aEnd - *aIter|:
405 * If |aLeadUnit| and subsequent code units computed using |*aIter| (up to
406 * |aEnd|) encode a valid code point -- not exceeding Unicode's range, not a
407 * surrogate, in shortest form -- then return Some(that code point) and advance
408 * |*aIter| past those code units.
410 * Otherwise decrement |*aIter| (so that it points at |aLeadUnit|) and return
411 * Nothing().
413 * |Iter| and |EndIter| are generalized concepts most easily understood as if
414 * they were |const char*|, |const unsigned char*|, or |const Utf8Unit*|:
415 * iterators that when dereferenced can be used to construct a |Utf8Unit| and
416 * that can be compared and modified in certain limited ways. (Carefully note
417 * that this function mutates |*aIter|.) |Iter| and |EndIter| are template
418 * parameters to support more-complicated adaptor iterators.
420 * The template parameters after |Iter| allow users to implement custom handling
421 * for various forms of invalid UTF-8. A version of this function that defaults
422 * all such handling to no-ops is defined below this function. To learn how to
423 * define your own custom handling, consult the implementation of that function,
424 * which documents exactly how custom handler functors are invoked.
426 * This function is MOZ_ALWAYS_INLINE: if you don't need that, use the version
427 * of this function without the "Inline" suffix on the name.
429 template <typename Iter, typename EndIter, class OnBadLeadUnit,
430 class OnNotEnoughUnits, class OnBadTrailingUnit, class OnBadCodePoint,
431 class OnNotShortestForm>
432 MOZ_ALWAYS_INLINE Maybe<char32_t> DecodeOneUtf8CodePointInline(
433 const Utf8Unit aLeadUnit, Iter* aIter, const EndIter& aEnd,
434 OnBadLeadUnit aOnBadLeadUnit, OnNotEnoughUnits aOnNotEnoughUnits,
435 OnBadTrailingUnit aOnBadTrailingUnit, OnBadCodePoint aOnBadCodePoint,
436 OnNotShortestForm aOnNotShortestForm) {
437 MOZ_ASSERT(Utf8Unit((*aIter)[-1]) == aLeadUnit);
439 char32_t n = aLeadUnit.toUint8();
440 MOZ_ASSERT(!IsAscii(n));
442 // |aLeadUnit| determines the number of trailing code units in the code point
443 // and the bits of |aLeadUnit| that contribute to the code point's value.
444 uint8_t remaining;
445 uint32_t min;
446 if ((n & 0b1110'0000) == 0b1100'0000) {
447 remaining = 1;
448 min = 0x80;
449 n &= 0b0001'1111;
450 } else if ((n & 0b1111'0000) == 0b1110'0000) {
451 remaining = 2;
452 min = 0x800;
453 n &= 0b0000'1111;
454 } else if ((n & 0b1111'1000) == 0b1111'0000) {
455 remaining = 3;
456 min = 0x10000;
457 n &= 0b0000'0111;
458 } else {
459 *aIter -= 1;
460 aOnBadLeadUnit();
461 return Nothing();
464 // If the code point would require more code units than remain, the encoding
465 // is invalid.
466 auto actual = aEnd - *aIter;
467 if (MOZ_UNLIKELY(actual < remaining)) {
468 *aIter -= 1;
469 aOnNotEnoughUnits(AssertedCast<uint8_t>(actual + 1), remaining + 1);
470 return Nothing();
473 for (uint8_t i = 0; i < remaining; i++) {
474 const Utf8Unit unit(*(*aIter)++);
476 // Every non-leading code unit in properly encoded UTF-8 has its high
477 // bit set and the next-highest bit unset.
478 if (MOZ_UNLIKELY(!IsTrailingUnit(unit))) {
479 uint8_t unitsObserved = i + 1 + 1;
480 *aIter -= unitsObserved;
481 aOnBadTrailingUnit(unitsObserved);
482 return Nothing();
485 // The code point being encoded is the concatenation of all the
486 // unconstrained bits.
487 n = (n << 6) | (unit.toUint8() & 0b0011'1111);
490 // UTF-16 surrogates and values outside the Unicode range are invalid.
491 if (MOZ_UNLIKELY(n > 0x10FFFF || (0xD800 <= n && n <= 0xDFFF))) {
492 uint8_t unitsObserved = remaining + 1;
493 *aIter -= unitsObserved;
494 aOnBadCodePoint(n, unitsObserved);
495 return Nothing();
498 // Overlong code points are also invalid.
499 if (MOZ_UNLIKELY(n < min)) {
500 uint8_t unitsObserved = remaining + 1;
501 *aIter -= unitsObserved;
502 aOnNotShortestForm(n, unitsObserved);
503 return Nothing();
506 return Some(n);
510 * Identical to the above function, but not forced to be instantiated inline --
511 * the compiler is permitted to common up separate invocations if it chooses.
513 template <typename Iter, typename EndIter, class OnBadLeadUnit,
514 class OnNotEnoughUnits, class OnBadTrailingUnit, class OnBadCodePoint,
515 class OnNotShortestForm>
516 inline Maybe<char32_t> DecodeOneUtf8CodePoint(
517 const Utf8Unit aLeadUnit, Iter* aIter, const EndIter& aEnd,
518 OnBadLeadUnit aOnBadLeadUnit, OnNotEnoughUnits aOnNotEnoughUnits,
519 OnBadTrailingUnit aOnBadTrailingUnit, OnBadCodePoint aOnBadCodePoint,
520 OnNotShortestForm aOnNotShortestForm) {
521 return DecodeOneUtf8CodePointInline(aLeadUnit, aIter, aEnd, aOnBadLeadUnit,
522 aOnNotEnoughUnits, aOnBadTrailingUnit,
523 aOnBadCodePoint, aOnNotShortestForm);
527 * Like the always-inlined function above, but with no-op behavior from all
528 * trailing if-invalid notifier functors.
530 * This function is MOZ_ALWAYS_INLINE: if you don't need that, use the version
531 * of this function without the "Inline" suffix on the name.
533 template <typename Iter, typename EndIter>
534 MOZ_ALWAYS_INLINE Maybe<char32_t> DecodeOneUtf8CodePointInline(
535 const Utf8Unit aLeadUnit, Iter* aIter, const EndIter& aEnd) {
536 // aOnBadLeadUnit is called when |aLeadUnit| itself is an invalid lead unit in
537 // a multi-unit code point. It is passed no arguments: the caller already has
538 // |aLeadUnit| on hand, so no need to provide it again.
539 auto onBadLeadUnit = []() {};
541 // aOnNotEnoughUnits is called when |aLeadUnit| properly indicates a code
542 // point length, but there aren't enough units from |*aIter| to |aEnd| to
543 // satisfy that length. It is passed the number of code units actually
544 // available (according to |aEnd - *aIter|) and the number of code units that
545 // |aLeadUnit| indicates are needed. Both numbers include the contribution
546 // of |aLeadUnit| itself: so |aUnitsAvailable <= 3|, |aUnitsNeeded <= 4|, and
547 // |aUnitsAvailable < aUnitsNeeded|. As above, it also is not passed the lead
548 // code unit.
549 auto onNotEnoughUnits = [](uint8_t aUnitsAvailable, uint8_t aUnitsNeeded) {};
551 // aOnBadTrailingUnit is called when one of the trailing code units implied by
552 // |aLeadUnit| doesn't match the 0b10xx'xxxx bit pattern that all UTF-8
553 // trailing code units must satisfy. It is passed the total count of units
554 // observed (including |aLeadUnit|). The bad trailing code unit will
555 // conceptually be at |(*aIter)[aUnitsObserved - 1]| if this functor is
556 // called, and so |aUnitsObserved <= 4|.
557 auto onBadTrailingUnit = [](uint8_t aUnitsObserved) {};
559 // aOnBadCodePoint is called when a structurally-correct code point encoding
560 // is found, but the *value* that is encoded is not a valid code point: either
561 // because it exceeded the U+10FFFF Unicode maximum code point, or because it
562 // was a UTF-16 surrogate. It is passed the non-code point value and the
563 // number of code units used to encode it.
564 auto onBadCodePoint = [](char32_t aBadCodePoint, uint8_t aUnitsObserved) {};
566 // aOnNotShortestForm is called when structurally-correct encoding is found,
567 // but the encoded value should have been encoded in fewer code units (e.g.
568 // mis-encoding U+0000 as 0b1100'0000 0b1000'0000 in two code units instead of
569 // as 0b0000'0000). It is passed the mis-encoded code point (which will be
570 // valid and not a surrogate) and the count of code units that mis-encoded it.
571 auto onNotShortestForm = [](char32_t aBadCodePoint, uint8_t aUnitsObserved) {
574 return DecodeOneUtf8CodePointInline(aLeadUnit, aIter, aEnd, onBadLeadUnit,
575 onNotEnoughUnits, onBadTrailingUnit,
576 onBadCodePoint, onNotShortestForm);
580 * Identical to the above function, but not forced to be instantiated inline --
581 * the compiler/linker are allowed to common up separate invocations.
583 template <typename Iter, typename EndIter>
584 inline Maybe<char32_t> DecodeOneUtf8CodePoint(const Utf8Unit aLeadUnit,
585 Iter* aIter,
586 const EndIter& aEnd) {
587 return DecodeOneUtf8CodePointInline(aLeadUnit, aIter, aEnd);
590 } // namespace mozilla
592 #endif /* mozilla_Utf8_h */