LCOV - code coverage report
Current view: top level - port - utf8.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 69 337 20.5 %
Date: 2024-11-21 22:18:42 Functions: 4 4 100.0 %

          Line data    Source code
       1             : // NOTE: for GDAL, this is an extract from the https://github.com/sheredom/utf8.h
       2             : // code
       3             : 
       4             : /* The latest version of this library is available on GitHub;
       5             :  * https://github.com/sheredom/utf8.h */
       6             : 
       7             : /* This is free and unencumbered software released into the public domain.
       8             :  *
       9             :  * Anyone is free to copy, modify, publish, use, compile, sell, or
      10             :  * distribute this software, either in source code form or as a compiled
      11             :  * binary, for any purpose, commercial or non-commercial, and by any
      12             :  * means.
      13             :  *
      14             :  * In jurisdictions that recognize copyright laws, the author or authors
      15             :  * of this software dedicate any and all copyright interest in the
      16             :  * software to the public domain. We make this dedication for the benefit
      17             :  * of the public at large and to the detriment of our heirs and
      18             :  * successors. We intend this dedication to be an overt act of
      19             :  * relinquishment in perpetuity of all present and future rights to this
      20             :  * software under copyright law.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      23             :  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      24             :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      25             :  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
      26             :  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      27             :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      28             :  * OTHER DEALINGS IN THE SOFTWARE.
      29             :  *
      30             :  * For more information, please refer to <http://unlicense.org/> */
      31             : 
      32             : #ifndef SHEREDOM_UTF8_H_INCLUDED
      33             : #define SHEREDOM_UTF8_H_INCLUDED
      34             : 
      35             : #if defined(_MSC_VER)
      36             : #pragma warning(push)
      37             : 
      38             : /* disable warning: no function prototype given: converting '()' to '(void)' */
      39             : #pragma warning(disable : 4255)
      40             : 
      41             : /* disable warning: '__cplusplus' is not defined as a preprocessor macro,
      42             :  * replacing with '0' for '#if/#elif' */
      43             : #pragma warning(disable : 4668)
      44             : 
      45             : /* disable warning: bytes padding added after construct */
      46             : #pragma warning(disable : 4820)
      47             : #endif
      48             : 
      49             : #include <stddef.h>
      50             : #include <stdlib.h>
      51             : 
      52             : #if defined(_MSC_VER)
      53             : #pragma warning(pop)
      54             : #endif
      55             : 
      56             : #if defined(_MSC_VER) && (_MSC_VER < 1920)
      57             : typedef __int32 utf8_int32_t;
      58             : #else
      59             : #include <stdint.h>
      60             : typedef int32_t utf8_int32_t;
      61             : #endif
      62             : 
      63             : #if defined(__clang__)
      64             : #pragma clang diagnostic push
      65             : #pragma clang diagnostic ignored "-Wold-style-cast"
      66             : #pragma clang diagnostic ignored "-Wcast-qual"
      67             : 
      68             : #if __has_warning("-Wunsafe-buffer-usage")
      69             : #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
      70             : #endif
      71             : #endif
      72             : 
      73             : namespace {
      74             : 
      75             : #if defined(_MSC_VER)
      76             : #define utf8_nonnull
      77             : #define utf8_pure
      78             : #define utf8_restrict __restrict
      79             : #define utf8_weak __inline
      80             : #elif defined(__clang__) || defined(__GNUC__)
      81             : #define utf8_nonnull __attribute__((nonnull))
      82             : #define utf8_pure __attribute__((pure))
      83             : #define utf8_restrict __restrict__
      84             : #define utf8_weak __attribute__((weak))
      85             : #else
      86             : #define utf8_nonnull
      87             : #define utf8_pure
      88             : #define utf8_restrict
      89             : #define utf8_weak
      90             : #endif
      91             : 
      92             : #ifdef __cplusplus
      93             : #define utf8_null NULL
      94             : #else
      95             : #define utf8_null 0
      96             : #endif
      97             : 
      98             : #if (defined(__cplusplus) && __cplusplus >= 201402L)
      99             : #define utf8_constexpr14 constexpr
     100             : #define utf8_constexpr14_impl constexpr
     101             : #else
     102             : /* constexpr and weak are incompatible. so only enable one of them */
     103             : #define utf8_constexpr14 utf8_weak
     104             : #define utf8_constexpr14_impl
     105             : #endif
     106             : 
     107             : #if defined(__cplusplus) && __cplusplus >= 202002L
     108             : using utf8_int8_t = char8_t; /* Introduced in C++20 */
     109             : #else
     110             : typedef char utf8_int8_t;
     111             : #endif
     112             : 
     113             : #if 0
     114             : /* Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 >
     115             :  * src2 respectively, case insensitive. */
     116             : utf8_constexpr14 utf8_nonnull utf8_pure int
     117             : utf8casecmp(const utf8_int8_t *src1, const utf8_int8_t *src2);
     118             : 
     119             : /* Append the utf8 string src onto the utf8 string dst. */
     120             : utf8_nonnull utf8_weak utf8_int8_t *
     121             : utf8cat(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src);
     122             : 
     123             : /* Find the first match of the utf8 codepoint chr in the utf8 string src. */
     124             : utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
     125             : utf8chr(const utf8_int8_t *src, utf8_int32_t chr);
     126             : 
     127             : /* Return less than 0, 0, greater than 0 if src1 < src2,
     128             :  * src1 == src2, src1 > src2 respectively. */
     129             : utf8_constexpr14 utf8_nonnull utf8_pure int utf8cmp(const utf8_int8_t *src1,
     130             :                                                     const utf8_int8_t *src2);
     131             : 
     132             : /* Copy the utf8 string src onto the memory allocated in dst. */
     133             : utf8_nonnull utf8_weak utf8_int8_t *
     134             : utf8cpy(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src);
     135             : 
     136             : /* Number of utf8 codepoints in the utf8 string src that consists entirely
     137             :  * of utf8 codepoints not from the utf8 string reject. */
     138             : utf8_constexpr14 utf8_nonnull utf8_pure size_t
     139             : utf8cspn(const utf8_int8_t *src, const utf8_int8_t *reject);
     140             : 
     141             : /* Duplicate the utf8 string src by getting its size, malloc'ing a new buffer
     142             :  * copying over the data, and returning that. Or 0 if malloc failed. */
     143             : utf8_weak utf8_int8_t *utf8dup(const utf8_int8_t *src);
     144             : 
     145             : /* Number of utf8 codepoints in the utf8 string str,
     146             :  * excluding the null terminating byte. */
     147             : utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8len(const utf8_int8_t *str);
     148             : 
     149             : /* Similar to utf8len, except that only at most n bytes of src are looked. */
     150             : utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8nlen(const utf8_int8_t *str,
     151             :                                                         size_t n);
     152             : 
     153             : /* Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 >
     154             :  * src2 respectively, case insensitive. Checking at most n bytes of each utf8
     155             :  * string. */
     156             : utf8_constexpr14 utf8_nonnull utf8_pure int
     157             : utf8ncasecmp(const utf8_int8_t *src1, const utf8_int8_t *src2, size_t n);
     158             : 
     159             : /* Append the utf8 string src onto the utf8 string dst,
     160             :  * writing at most n+1 bytes. Can produce an invalid utf8
     161             :  * string if n falls partway through a utf8 codepoint. */
     162             : utf8_nonnull utf8_weak utf8_int8_t *
     163             : utf8ncat(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src,
     164             :          size_t n);
     165             : 
     166             : /* Return less than 0, 0, greater than 0 if src1 < src2,
     167             :  * src1 == src2, src1 > src2 respectively. Checking at most n
     168             :  * bytes of each utf8 string. */
     169             : utf8_constexpr14 utf8_nonnull utf8_pure int
     170             : utf8ncmp(const utf8_int8_t *src1, const utf8_int8_t *src2, size_t n);
     171             : 
     172             : /* Copy the utf8 string src onto the memory allocated in dst.
     173             :  * Copies at most n bytes. If n falls partway through a utf8
     174             :  * codepoint, or if dst doesn't have enough room for a null
     175             :  * terminator, the final string will be cut short to preserve
     176             :  * utf8 validity. */
     177             : 
     178             : utf8_nonnull utf8_weak utf8_int8_t *
     179             : utf8ncpy(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src,
     180             :          size_t n);
     181             : 
     182             : /* Similar to utf8dup, except that at most n bytes of src are copied. If src is
     183             :  * longer than n, only n bytes are copied and a null byte is added.
     184             :  *
     185             :  * Returns a new string if successful, 0 otherwise */
     186             : utf8_weak utf8_int8_t *utf8ndup(const utf8_int8_t *src, size_t n);
     187             : 
     188             : /* Locates the first occurrence in the utf8 string str of any byte in the
     189             :  * utf8 string accept, or 0 if no match was found. */
     190             : utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
     191             : utf8pbrk(const utf8_int8_t *str, const utf8_int8_t *accept);
     192             : 
     193             : /* Find the last match of the utf8 codepoint chr in the utf8 string src. */
     194             : utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
     195             : utf8rchr(const utf8_int8_t *src, int chr);
     196             : 
     197             : /* Number of bytes in the utf8 string str,
     198             :  * including the null terminating byte. */
     199             : utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8size(const utf8_int8_t *str);
     200             : 
     201             : /* Similar to utf8size, except that the null terminating byte is excluded. */
     202             : utf8_constexpr14 utf8_nonnull utf8_pure size_t
     203             : utf8size_lazy(const utf8_int8_t *str);
     204             : 
     205             : /* Similar to utf8size, except that only at most n bytes of src are looked and
     206             :  * the null terminating byte is excluded. */
     207             : utf8_constexpr14 utf8_nonnull utf8_pure size_t
     208             : utf8nsize_lazy(const utf8_int8_t *str, size_t n);
     209             : 
     210             : /* Number of utf8 codepoints in the utf8 string src that consists entirely
     211             :  * of utf8 codepoints from the utf8 string accept. */
     212             : utf8_constexpr14 utf8_nonnull utf8_pure size_t
     213             : utf8spn(const utf8_int8_t *src, const utf8_int8_t *accept);
     214             : 
     215             : /* The position of the utf8 string needle in the utf8 string haystack. */
     216             : utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
     217             : utf8str(const utf8_int8_t *haystack, const utf8_int8_t *needle);
     218             : 
     219             : /* The position of the utf8 string needle in the utf8 string haystack, case
     220             :  * insensitive. */
     221             : utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
     222             : utf8casestr(const utf8_int8_t *haystack, const utf8_int8_t *needle);
     223             : 
     224             : /* Return 0 on success, or the position of the invalid
     225             :  * utf8 codepoint on failure. */
     226             : utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
     227             : utf8valid(const utf8_int8_t *str);
     228             : 
     229             : /* Similar to utf8valid, except that only at most n bytes of src are looked. */
     230             : utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
     231             : utf8nvalid(const utf8_int8_t *str, size_t n);
     232             : 
     233             : /* Given a null-terminated string, makes the string valid by replacing invalid
     234             :  * codepoints with a 1-byte replacement. Returns 0 on success. */
     235             : utf8_nonnull utf8_weak int utf8makevalid(utf8_int8_t *str,
     236             :                                          const utf8_int32_t replacement);
     237             : #endif
     238             : /* Sets out_codepoint to the current utf8 codepoint in str, and returns the
     239             :  * address of the next utf8 codepoint after the current one in str. */
     240             : utf8_constexpr14 utf8_nonnull utf8_int8_t *
     241             : utf8codepoint(const utf8_int8_t *utf8_restrict str,
     242             :               utf8_int32_t *utf8_restrict out_codepoint);
     243             : 
     244             : /* Calculates the size of the next utf8 codepoint in str. */
     245             : utf8_constexpr14 utf8_nonnull size_t
     246             : utf8codepointcalcsize(const utf8_int8_t *str);
     247             : 
     248             : #if 0
     249             : /* Returns the size of the given codepoint in bytes. */
     250             : utf8_constexpr14 size_t utf8codepointsize(utf8_int32_t chr);
     251             : 
     252             : /* Write a codepoint to the given string, and return the address to the next
     253             :  * place after the written codepoint. Pass how many bytes left in the buffer to
     254             :  * n. If there is not enough space for the codepoint, this function returns
     255             :  * null. */
     256             : utf8_nonnull utf8_weak utf8_int8_t *
     257             : utf8catcodepoint(utf8_int8_t *str, utf8_int32_t chr, size_t n);
     258             : 
     259             : /* Returns 1 if the given character is lowercase, or 0 if it is not. */
     260             : utf8_constexpr14 int utf8islower(utf8_int32_t chr);
     261             : 
     262             : /* Returns 1 if the given character is uppercase, or 0 if it is not. */
     263             : utf8_constexpr14 int utf8isupper(utf8_int32_t chr);
     264             : 
     265             : /* Transform the given string into all lowercase codepoints. */
     266             : utf8_nonnull utf8_weak void utf8lwr(utf8_int8_t *utf8_restrict str);
     267             : 
     268             : /* Transform the given string into all uppercase codepoints. */
     269             : utf8_nonnull utf8_weak void utf8upr(utf8_int8_t *utf8_restrict str);
     270             : #endif
     271             : 
     272             : /* Make a codepoint lower case if possible. */
     273             : utf8_constexpr14 utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp);
     274             : 
     275             : /* Make a codepoint upper case if possible. */
     276             : utf8_constexpr14 utf8_int32_t utf8uprcodepoint(utf8_int32_t cp);
     277             : 
     278             : #if 0
     279             : /* Sets out_codepoint to the current utf8 codepoint in str, and returns the
     280             :  * address of the previous utf8 codepoint before the current one in str. */
     281             : utf8_constexpr14 utf8_nonnull utf8_int8_t *
     282             : utf8rcodepoint(const utf8_int8_t *utf8_restrict str,
     283             :                utf8_int32_t *utf8_restrict out_codepoint);
     284             : 
     285             : /* Duplicate the utf8 string src by getting its size, calling alloc_func_ptr to
     286             :  * copy over data to a new buffer, and returning that. Or 0 if alloc_func_ptr
     287             :  * returned null. */
     288             : utf8_weak utf8_int8_t *utf8dup_ex(const utf8_int8_t *src,
     289             :                                   utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *,
     290             :                                                                  size_t),
     291             :                                   utf8_int8_t *user_data);
     292             : 
     293             : /* Similar to utf8dup, except that at most n bytes of src are copied. If src is
     294             :  * longer than n, only n bytes are copied and a null byte is added.
     295             :  *
     296             :  * Returns a new string if successful, 0 otherwise. */
     297             : utf8_weak utf8_int8_t *utf8ndup_ex(const utf8_int8_t *src, size_t n,
     298             :                                    utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *,
     299             :                                                                   size_t),
     300             :                                    utf8_int8_t *user_data);
     301             : #endif
     302             : 
     303             : #undef utf8_weak
     304             : #undef utf8_pure
     305             : #undef utf8_nonnull
     306             : 
     307             : #if 0
     308             : utf8_constexpr14_impl int utf8casecmp(const utf8_int8_t *src1,
     309             :                                       const utf8_int8_t *src2) {
     310             :   utf8_int32_t src1_lwr_cp = 0, src2_lwr_cp = 0, src1_upr_cp = 0,
     311             :                src2_upr_cp = 0, src1_orig_cp = 0, src2_orig_cp = 0;
     312             : 
     313             :   for (;;) {
     314             :     src1 = utf8codepoint(src1, &src1_orig_cp);
     315             :     src2 = utf8codepoint(src2, &src2_orig_cp);
     316             : 
     317             :     /* lower the srcs if required */
     318             :     src1_lwr_cp = utf8lwrcodepoint(src1_orig_cp);
     319             :     src2_lwr_cp = utf8lwrcodepoint(src2_orig_cp);
     320             : 
     321             :     /* lower the srcs if required */
     322             :     src1_upr_cp = utf8uprcodepoint(src1_orig_cp);
     323             :     src2_upr_cp = utf8uprcodepoint(src2_orig_cp);
     324             : 
     325             :     /* check if the lowered codepoints match */
     326             :     if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) {
     327             :       return 0;
     328             :     } else if ((src1_lwr_cp == src2_lwr_cp) || (src1_upr_cp == src2_upr_cp)) {
     329             :       continue;
     330             :     }
     331             : 
     332             :     /* if they don't match, then we return the difference between the characters
     333             :      */
     334             :     return src1_lwr_cp - src2_lwr_cp;
     335             :   }
     336             : }
     337             : 
     338             : utf8_int8_t *utf8cat(utf8_int8_t *utf8_restrict dst,
     339             :                      const utf8_int8_t *utf8_restrict src) {
     340             :   utf8_int8_t *d = dst;
     341             :   /* find the null terminating byte in dst */
     342             :   while ('\0' != *d) {
     343             :     d++;
     344             :   }
     345             : 
     346             :   /* overwriting the null terminating byte in dst, append src byte-by-byte */
     347             :   while ('\0' != *src) {
     348             :     *d++ = *src++;
     349             :   }
     350             : 
     351             :   /* write out a new null terminating byte into dst */
     352             :   *d = '\0';
     353             : 
     354             :   return dst;
     355             : }
     356             : 
     357             : utf8_constexpr14_impl utf8_int8_t *utf8chr(const utf8_int8_t *src,
     358             :                                            utf8_int32_t chr) {
     359             :   utf8_int8_t c[5] = {'\0', '\0', '\0', '\0', '\0'};
     360             : 
     361             :   if (0 == chr) {
     362             :     /* being asked to return position of null terminating byte, so
     363             :      * just run s to the end, and return! */
     364             :     while ('\0' != *src) {
     365             :       src++;
     366             :     }
     367             :     return (utf8_int8_t *)src;
     368             :   } else if (0 == ((utf8_int32_t)0xffffff80 & chr)) {
     369             :     /* 1-byte/7-bit ascii
     370             :      * (0b0xxxxxxx) */
     371             :     c[0] = (utf8_int8_t)chr;
     372             :   } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) {
     373             :     /* 2-byte/11-bit utf8 code point
     374             :      * (0b110xxxxx 0b10xxxxxx) */
     375             :     c[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)(chr >> 6));
     376             :     c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
     377             :   } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) {
     378             :     /* 3-byte/16-bit utf8 code point
     379             :      * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */
     380             :     c[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)(chr >> 12));
     381             :     c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
     382             :     c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
     383             :   } else { /* if (0 == ((int)0xffe00000 & chr)) { */
     384             :     /* 4-byte/21-bit utf8 code point
     385             :      * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */
     386             :     c[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)(chr >> 18));
     387             :     c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f));
     388             :     c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
     389             :     c[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
     390             :   }
     391             : 
     392             :   /* we've made c into a 2 utf8 codepoint string, one for the chr we are
     393             :    * seeking, another for the null terminating byte. Now use utf8str to
     394             :    * search */
     395             :   return utf8str(src, c);
     396             : }
     397             : 
     398             : utf8_constexpr14_impl int utf8cmp(const utf8_int8_t *src1,
     399             :                                   const utf8_int8_t *src2) {
     400             :   while (('\0' != *src1) || ('\0' != *src2)) {
     401             :     if (*src1 < *src2) {
     402             :       return -1;
     403             :     } else if (*src1 > *src2) {
     404             :       return 1;
     405             :     }
     406             : 
     407             :     src1++;
     408             :     src2++;
     409             :   }
     410             : 
     411             :   /* both utf8 strings matched */
     412             :   return 0;
     413             : }
     414             : 
     415             : utf8_constexpr14_impl int utf8coll(const utf8_int8_t *src1,
     416             :                                    const utf8_int8_t *src2);
     417             : 
     418             : utf8_int8_t *utf8cpy(utf8_int8_t *utf8_restrict dst,
     419             :                      const utf8_int8_t *utf8_restrict src) {
     420             :   utf8_int8_t *d = dst;
     421             : 
     422             :   /* overwriting anything previously in dst, write byte-by-byte
     423             :    * from src */
     424             :   while ('\0' != *src) {
     425             :     *d++ = *src++;
     426             :   }
     427             : 
     428             :   /* append null terminating byte */
     429             :   *d = '\0';
     430             : 
     431             :   return dst;
     432             : }
     433             : 
     434             : utf8_constexpr14_impl size_t utf8cspn(const utf8_int8_t *src,
     435             :                                       const utf8_int8_t *reject) {
     436             :   size_t chars = 0;
     437             : 
     438             :   while ('\0' != *src) {
     439             :     const utf8_int8_t *r = reject;
     440             :     size_t offset = 0;
     441             : 
     442             :     while ('\0' != *r) {
     443             :       /* checking that if *r is the start of a utf8 codepoint
     444             :        * (it is not 0b10xxxxxx) and we have successfully matched
     445             :        * a previous character (0 < offset) - we found a match */
     446             :       if ((0x80 != (0xc0 & *r)) && (0 < offset)) {
     447             :         return chars;
     448             :       } else {
     449             :         if (*r == src[offset]) {
     450             :           /* part of a utf8 codepoint matched, so move our checking
     451             :            * onwards to the next byte */
     452             :           offset++;
     453             :           r++;
     454             :         } else {
     455             :           /* r could be in the middle of an unmatching utf8 code point,
     456             :            * so we need to march it on to the next character beginning, */
     457             : 
     458             :           do {
     459             :             r++;
     460             :           } while (0x80 == (0xc0 & *r));
     461             : 
     462             :           /* reset offset too as we found a mismatch */
     463             :           offset = 0;
     464             :         }
     465             :       }
     466             :     }
     467             : 
     468             :     /* found a match at the end of *r, so didn't get a chance to test it */
     469             :     if (0 < offset) {
     470             :       return chars;
     471             :     }
     472             : 
     473             :     /* the current utf8 codepoint in src did not match reject, but src
     474             :      * could have been partway through a utf8 codepoint, so we need to
     475             :      * march it onto the next utf8 codepoint starting byte */
     476             :     do {
     477             :       src++;
     478             :     } while ((0x80 == (0xc0 & *src)));
     479             :     chars++;
     480             :   }
     481             : 
     482             :   return chars;
     483             : }
     484             : 
     485             : utf8_int8_t *utf8dup(const utf8_int8_t *src) {
     486             :   return utf8dup_ex(src, utf8_null, utf8_null);
     487             : }
     488             : 
     489             : utf8_int8_t *utf8dup_ex(const utf8_int8_t *src,
     490             :                         utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, size_t),
     491             :                         utf8_int8_t *user_data) {
     492             :   utf8_int8_t *n = utf8_null;
     493             : 
     494             :   /* figure out how many bytes (including the terminator) we need to copy first
     495             :    */
     496             :   size_t bytes = utf8size(src);
     497             : 
     498             :   if (alloc_func_ptr) {
     499             :     n = alloc_func_ptr(user_data, bytes);
     500             :   } else {
     501             : #if !defined(UTF8_NO_STD_MALLOC)
     502             :     n = (utf8_int8_t *)malloc(bytes);
     503             : #else
     504             :     return utf8_null;
     505             : #endif
     506             :   }
     507             : 
     508             :   if (utf8_null == n) {
     509             :     /* out of memory so we bail */
     510             :     return utf8_null;
     511             :   } else {
     512             :     bytes = 0;
     513             : 
     514             :     /* copy src byte-by-byte into our new utf8 string */
     515             :     while ('\0' != src[bytes]) {
     516             :       n[bytes] = src[bytes];
     517             :       bytes++;
     518             :     }
     519             : 
     520             :     /* append null terminating byte */
     521             :     n[bytes] = '\0';
     522             :     return n;
     523             :   }
     524             : }
     525             : 
     526             : utf8_constexpr14_impl utf8_int8_t *utf8fry(const utf8_int8_t *str);
     527             : 
     528             : utf8_constexpr14_impl size_t utf8len(const utf8_int8_t *str) {
     529             :   return utf8nlen(str, SIZE_MAX);
     530             : }
     531             : 
     532             : utf8_constexpr14_impl size_t utf8nlen(const utf8_int8_t *str, size_t n) {
     533             :   const utf8_int8_t *t = str;
     534             :   size_t length = 0;
     535             : 
     536             :   while ((size_t)(str - t) < n && '\0' != *str) {
     537             :     if (0xf0 == (0xf8 & *str)) {
     538             :       /* 4-byte utf8 code point (began with 0b11110xxx) */
     539             :       str += 4;
     540             :     } else if (0xe0 == (0xf0 & *str)) {
     541             :       /* 3-byte utf8 code point (began with 0b1110xxxx) */
     542             :       str += 3;
     543             :     } else if (0xc0 == (0xe0 & *str)) {
     544             :       /* 2-byte utf8 code point (began with 0b110xxxxx) */
     545             :       str += 2;
     546             :     } else { /* if (0x00 == (0x80 & *s)) { */
     547             :       /* 1-byte ascii (began with 0b0xxxxxxx) */
     548             :       str += 1;
     549             :     }
     550             : 
     551             :     /* no matter the bytes we marched s forward by, it was
     552             :      * only 1 utf8 codepoint */
     553             :     length++;
     554             :   }
     555             : 
     556             :   if ((size_t)(str - t) > n) {
     557             :     length--;
     558             :   }
     559             :   return length;
     560             : }
     561             : 
     562             : utf8_constexpr14_impl int utf8ncasecmp(const utf8_int8_t *src1,
     563             :                                        const utf8_int8_t *src2, size_t n) {
     564             :   utf8_int32_t src1_lwr_cp = 0, src2_lwr_cp = 0, src1_upr_cp = 0,
     565             :                src2_upr_cp = 0, src1_orig_cp = 0, src2_orig_cp = 0;
     566             : 
     567             :   do {
     568             :     const utf8_int8_t *const s1 = src1;
     569             :     const utf8_int8_t *const s2 = src2;
     570             : 
     571             :     /* first check that we have enough bytes left in n to contain an entire
     572             :      * codepoint */
     573             :     if (0 == n) {
     574             :       return 0;
     575             :     }
     576             : 
     577             :     if ((1 == n) && ((0xc0 == (0xe0 & *s1)) || (0xc0 == (0xe0 & *s2)))) {
     578             :       const utf8_int32_t c1 = (0xe0 & *s1);
     579             :       const utf8_int32_t c2 = (0xe0 & *s2);
     580             : 
     581             :       if (c1 < c2) {
     582             :         return c1 - c2;
     583             :       } else {
     584             :         return 0;
     585             :       }
     586             :     }
     587             : 
     588             :     if ((2 >= n) && ((0xe0 == (0xf0 & *s1)) || (0xe0 == (0xf0 & *s2)))) {
     589             :       const utf8_int32_t c1 = (0xf0 & *s1);
     590             :       const utf8_int32_t c2 = (0xf0 & *s2);
     591             : 
     592             :       if (c1 < c2) {
     593             :         return c1 - c2;
     594             :       } else {
     595             :         return 0;
     596             :       }
     597             :     }
     598             : 
     599             :     if ((3 >= n) && ((0xf0 == (0xf8 & *s1)) || (0xf0 == (0xf8 & *s2)))) {
     600             :       const utf8_int32_t c1 = (0xf8 & *s1);
     601             :       const utf8_int32_t c2 = (0xf8 & *s2);
     602             : 
     603             :       if (c1 < c2) {
     604             :         return c1 - c2;
     605             :       } else {
     606             :         return 0;
     607             :       }
     608             :     }
     609             : 
     610             :     src1 = utf8codepoint(src1, &src1_orig_cp);
     611             :     src2 = utf8codepoint(src2, &src2_orig_cp);
     612             :     n -= utf8codepointsize(src1_orig_cp);
     613             : 
     614             :     src1_lwr_cp = utf8lwrcodepoint(src1_orig_cp);
     615             :     src2_lwr_cp = utf8lwrcodepoint(src2_orig_cp);
     616             : 
     617             :     src1_upr_cp = utf8uprcodepoint(src1_orig_cp);
     618             :     src2_upr_cp = utf8uprcodepoint(src2_orig_cp);
     619             : 
     620             :     /* check if the lowered codepoints match */
     621             :     if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) {
     622             :       return 0;
     623             :     } else if ((src1_lwr_cp == src2_lwr_cp) || (src1_upr_cp == src2_upr_cp)) {
     624             :       continue;
     625             :     }
     626             : 
     627             :     /* if they don't match, then we return the difference between the characters
     628             :      */
     629             :     return src1_lwr_cp - src2_lwr_cp;
     630             :   } while (0 < n);
     631             : 
     632             :   /* both utf8 strings matched */
     633             :   return 0;
     634             : }
     635             : 
     636             : utf8_int8_t *utf8ncat(utf8_int8_t *utf8_restrict dst,
     637             :                       const utf8_int8_t *utf8_restrict src, size_t n) {
     638             :   utf8_int8_t *d = dst;
     639             : 
     640             :   /* find the null terminating byte in dst */
     641             :   while ('\0' != *d) {
     642             :     d++;
     643             :   }
     644             : 
     645             :   /* overwriting the null terminating byte in dst, append src byte-by-byte
     646             :    * stopping if we run out of space */
     647             :   while (('\0' != *src) && (0 != n--)) {
     648             :     *d++ = *src++;
     649             :   }
     650             : 
     651             :   /* write out a new null terminating byte into dst */
     652             :   *d = '\0';
     653             : 
     654             :   return dst;
     655             : }
     656             : 
     657             : utf8_constexpr14_impl int utf8ncmp(const utf8_int8_t *src1,
     658             :                                    const utf8_int8_t *src2, size_t n) {
     659             :   while ((0 != n--) && (('\0' != *src1) || ('\0' != *src2))) {
     660             :     if (*src1 < *src2) {
     661             :       return -1;
     662             :     } else if (*src1 > *src2) {
     663             :       return 1;
     664             :     }
     665             : 
     666             :     src1++;
     667             :     src2++;
     668             :   }
     669             : 
     670             :   /* both utf8 strings matched */
     671             :   return 0;
     672             : }
     673             : 
     674             : utf8_int8_t *utf8ncpy(utf8_int8_t *utf8_restrict dst,
     675             :                       const utf8_int8_t *utf8_restrict src, size_t n) {
     676             :   utf8_int8_t *d = dst;
     677             :   size_t index = 0, check_index = 0;
     678             : 
     679             :   if (n == 0) {
     680             :     return dst;
     681             :   }
     682             : 
     683             :   /* overwriting anything previously in dst, write byte-by-byte
     684             :    * from src */
     685             :   for (index = 0; index < n; index++) {
     686             :     d[index] = src[index];
     687             :     if ('\0' == src[index]) {
     688             :       break;
     689             :     }
     690             :   }
     691             : 
     692             :   for (check_index = index - 1;
     693             :        check_index > 0 && 0x80 == (0xc0 & d[check_index]); check_index--) {
     694             :     /* just moving the index */
     695             :   }
     696             : 
     697             :   if (check_index < index &&
     698             :       ((index - check_index) < utf8codepointcalcsize(&d[check_index]) ||
     699             :        (index - check_index) == n)) {
     700             :     index = check_index;
     701             :   }
     702             : 
     703             :   /* append null terminating byte */
     704             :   for (; index < n; index++) {
     705             :     d[index] = 0;
     706             :   }
     707             : 
     708             :   return dst;
     709             : }
     710             : 
     711             : utf8_int8_t *utf8ndup(const utf8_int8_t *src, size_t n) {
     712             :   return utf8ndup_ex(src, n, utf8_null, utf8_null);
     713             : }
     714             : 
     715             : utf8_int8_t *utf8ndup_ex(const utf8_int8_t *src, size_t n,
     716             :                          utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, size_t),
     717             :                          utf8_int8_t *user_data) {
     718             :   utf8_int8_t *c = utf8_null;
     719             :   size_t bytes = 0;
     720             : 
     721             :   /* Find the end of the string or stop when n is reached */
     722             :   while ('\0' != src[bytes] && bytes < n) {
     723             :     bytes++;
     724             :   }
     725             : 
     726             :   /* In case bytes is actually less than n, we need to set it
     727             :    * to be used later in the copy byte by byte. */
     728             :   n = bytes;
     729             : 
     730             :   if (alloc_func_ptr) {
     731             :     c = alloc_func_ptr(user_data, bytes + 1);
     732             :   } else {
     733             : #if !defined(UTF8_NO_STD_MALLOC)
     734             :     c = (utf8_int8_t *)malloc(bytes + 1);
     735             : #else
     736             :     c = utf8_null;
     737             : #endif
     738             :   }
     739             : 
     740             :   if (utf8_null == c) {
     741             :     /* out of memory so we bail */
     742             :     return utf8_null;
     743             :   }
     744             : 
     745             :   bytes = 0;
     746             : 
     747             :   /* copy src byte-by-byte into our new utf8 string */
     748             :   while ('\0' != src[bytes] && bytes < n) {
     749             :     c[bytes] = src[bytes];
     750             :     bytes++;
     751             :   }
     752             : 
     753             :   /* append null terminating byte */
     754             :   c[bytes] = '\0';
     755             :   return c;
     756             : }
     757             : 
     758             : utf8_constexpr14_impl utf8_int8_t *utf8rchr(const utf8_int8_t *src, int chr) {
     759             : 
     760             :   utf8_int8_t *match = utf8_null;
     761             :   utf8_int8_t c[5] = {'\0', '\0', '\0', '\0', '\0'};
     762             : 
     763             :   if (0 == chr) {
     764             :     /* being asked to return position of null terminating byte, so
     765             :      * just run s to the end, and return! */
     766             :     while ('\0' != *src) {
     767             :       src++;
     768             :     }
     769             :     return (utf8_int8_t *)src;
     770             :   } else if (0 == ((int)0xffffff80 & chr)) {
     771             :     /* 1-byte/7-bit ascii
     772             :      * (0b0xxxxxxx) */
     773             :     c[0] = (utf8_int8_t)chr;
     774             :   } else if (0 == ((int)0xfffff800 & chr)) {
     775             :     /* 2-byte/11-bit utf8 code point
     776             :      * (0b110xxxxx 0b10xxxxxx) */
     777             :     c[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)(chr >> 6));
     778             :     c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
     779             :   } else if (0 == ((int)0xffff0000 & chr)) {
     780             :     /* 3-byte/16-bit utf8 code point
     781             :      * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */
     782             :     c[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)(chr >> 12));
     783             :     c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
     784             :     c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
     785             :   } else { /* if (0 == ((int)0xffe00000 & chr)) { */
     786             :     /* 4-byte/21-bit utf8 code point
     787             :      * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */
     788             :     c[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)(chr >> 18));
     789             :     c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f));
     790             :     c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
     791             :     c[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
     792             :   }
     793             : 
     794             :   /* we've created a 2 utf8 codepoint string in c that is
     795             :    * the utf8 character asked for by chr, and a null
     796             :    * terminating byte */
     797             : 
     798             :   while ('\0' != *src) {
     799             :     size_t offset = 0;
     800             : 
     801             :     while ((src[offset] == c[offset]) && ('\0' != src[offset])) {
     802             :       offset++;
     803             :     }
     804             : 
     805             :     if ('\0' == c[offset]) {
     806             :       /* we found a matching utf8 code point */
     807             :       match = (utf8_int8_t *)src;
     808             :       src += offset;
     809             : 
     810             :       if ('\0' == *src) {
     811             :         break;
     812             :       }
     813             :     } else {
     814             :       src += offset;
     815             : 
     816             :       /* need to march s along to next utf8 codepoint start
     817             :        * (the next byte that doesn't match 0b10xxxxxx) */
     818             :       if ('\0' != *src) {
     819             :         do {
     820             :           src++;
     821             :         } while (0x80 == (0xc0 & *src));
     822             :       }
     823             :     }
     824             :   }
     825             : 
     826             :   /* return the last match we found (or 0 if no match was found) */
     827             :   return match;
     828             : }
     829             : 
     830             : utf8_constexpr14_impl utf8_int8_t *utf8pbrk(const utf8_int8_t *str,
     831             :                                             const utf8_int8_t *accept) {
     832             :   while ('\0' != *str) {
     833             :     const utf8_int8_t *a = accept;
     834             :     size_t offset = 0;
     835             : 
     836             :     while ('\0' != *a) {
     837             :       /* checking that if *a is the start of a utf8 codepoint
     838             :        * (it is not 0b10xxxxxx) and we have successfully matched
     839             :        * a previous character (0 < offset) - we found a match */
     840             :       if ((0x80 != (0xc0 & *a)) && (0 < offset)) {
     841             :         return (utf8_int8_t *)str;
     842             :       } else {
     843             :         if (*a == str[offset]) {
     844             :           /* part of a utf8 codepoint matched, so move our checking
     845             :            * onwards to the next byte */
     846             :           offset++;
     847             :           a++;
     848             :         } else {
     849             :           /* r could be in the middle of an unmatching utf8 code point,
     850             :            * so we need to march it on to the next character beginning, */
     851             : 
     852             :           do {
     853             :             a++;
     854             :           } while (0x80 == (0xc0 & *a));
     855             : 
     856             :           /* reset offset too as we found a mismatch */
     857             :           offset = 0;
     858             :         }
     859             :       }
     860             :     }
     861             : 
     862             :     /* we found a match on the last utf8 codepoint */
     863             :     if (0 < offset) {
     864             :       return (utf8_int8_t *)str;
     865             :     }
     866             : 
     867             :     /* the current utf8 codepoint in src did not match accept, but src
     868             :      * could have been partway through a utf8 codepoint, so we need to
     869             :      * march it onto the next utf8 codepoint starting byte */
     870             :     do {
     871             :       str++;
     872             :     } while ((0x80 == (0xc0 & *str)));
     873             :   }
     874             : 
     875             :   return utf8_null;
     876             : }
     877             : 
     878             : utf8_constexpr14_impl size_t utf8size(const utf8_int8_t *str) {
     879             :   return utf8size_lazy(str) + 1;
     880             : }
     881             : 
     882             : utf8_constexpr14_impl size_t utf8size_lazy(const utf8_int8_t *str) {
     883             :   return utf8nsize_lazy(str, SIZE_MAX);
     884             : }
     885             : 
     886             : utf8_constexpr14_impl size_t utf8nsize_lazy(const utf8_int8_t *str, size_t n) {
     887             :   size_t size = 0;
     888             :   while (size < n && '\0' != str[size]) {
     889             :     size++;
     890             :   }
     891             :   return size;
     892             : }
     893             : 
     894             : utf8_constexpr14_impl size_t utf8spn(const utf8_int8_t *src,
     895             :                                      const utf8_int8_t *accept) {
     896             :   size_t chars = 0;
     897             : 
     898             :   while ('\0' != *src) {
     899             :     const utf8_int8_t *a = accept;
     900             :     size_t offset = 0;
     901             : 
     902             :     while ('\0' != *a) {
     903             :       /* checking that if *r is the start of a utf8 codepoint
     904             :        * (it is not 0b10xxxxxx) and we have successfully matched
     905             :        * a previous character (0 < offset) - we found a match */
     906             :       if ((0x80 != (0xc0 & *a)) && (0 < offset)) {
     907             :         /* found a match, so increment the number of utf8 codepoints
     908             :          * that have matched and stop checking whether any other utf8
     909             :          * codepoints in a match */
     910             :         chars++;
     911             :         src += offset;
     912             :         offset = 0;
     913             :         break;
     914             :       } else {
     915             :         if (*a == src[offset]) {
     916             :           offset++;
     917             :           a++;
     918             :         } else {
     919             :           /* a could be in the middle of an unmatching utf8 codepoint,
     920             :            * so we need to march it on to the next character beginning, */
     921             :           do {
     922             :             a++;
     923             :           } while (0x80 == (0xc0 & *a));
     924             : 
     925             :           /* reset offset too as we found a mismatch */
     926             :           offset = 0;
     927             :         }
     928             :       }
     929             :     }
     930             : 
     931             :     /* found a match at the end of *a, so didn't get a chance to test it */
     932             :     if (0 < offset) {
     933             :       chars++;
     934             :       src += offset;
     935             :       continue;
     936             :     }
     937             : 
     938             :     /* if a got to its terminating null byte, then we didn't find a match.
     939             :      * Return the current number of matched utf8 codepoints */
     940             :     if ('\0' == *a) {
     941             :       return chars;
     942             :     }
     943             :   }
     944             : 
     945             :   return chars;
     946             : }
     947             : 
     948             : utf8_constexpr14_impl utf8_int8_t *utf8str(const utf8_int8_t *haystack,
     949             :                                            const utf8_int8_t *needle) {
     950             :   utf8_int32_t throwaway_codepoint = 0;
     951             : 
     952             :   /* if needle has no utf8 codepoints before the null terminating
     953             :    * byte then return haystack */
     954             :   if ('\0' == *needle) {
     955             :     return (utf8_int8_t *)haystack;
     956             :   }
     957             : 
     958             :   while ('\0' != *haystack) {
     959             :     const utf8_int8_t *maybeMatch = haystack;
     960             :     const utf8_int8_t *n = needle;
     961             : 
     962             :     while (*haystack == *n && (*haystack != '\0' && *n != '\0')) {
     963             :       n++;
     964             :       haystack++;
     965             :     }
     966             : 
     967             :     if ('\0' == *n) {
     968             :       /* we found the whole utf8 string for needle in haystack at
     969             :        * maybeMatch, so return it */
     970             :       return (utf8_int8_t *)maybeMatch;
     971             :     } else {
     972             :       /* h could be in the middle of an unmatching utf8 codepoint,
     973             :        * so we need to march it on to the next character beginning
     974             :        * starting from the current character */
     975             :       haystack = utf8codepoint(maybeMatch, &throwaway_codepoint);
     976             :     }
     977             :   }
     978             : 
     979             :   /* no match */
     980             :   return utf8_null;
     981             : }
     982             : 
     983             : utf8_constexpr14_impl utf8_int8_t *utf8casestr(const utf8_int8_t *haystack,
     984             :                                                const utf8_int8_t *needle) {
     985             :   /* if needle has no utf8 codepoints before the null terminating
     986             :    * byte then return haystack */
     987             :   if ('\0' == *needle) {
     988             :     return (utf8_int8_t *)haystack;
     989             :   }
     990             : 
     991             :   for (;;) {
     992             :     const utf8_int8_t *maybeMatch = haystack;
     993             :     const utf8_int8_t *n = needle;
     994             :     utf8_int32_t h_cp = 0, n_cp = 0;
     995             : 
     996             :     /* Get the next code point and track it */
     997             :     const utf8_int8_t *nextH = haystack = utf8codepoint(haystack, &h_cp);
     998             :     n = utf8codepoint(n, &n_cp);
     999             : 
    1000             :     while ((0 != h_cp) && (0 != n_cp)) {
    1001             :       h_cp = utf8lwrcodepoint(h_cp);
    1002             :       n_cp = utf8lwrcodepoint(n_cp);
    1003             : 
    1004             :       /* if we find a mismatch, bail out! */
    1005             :       if (h_cp != n_cp) {
    1006             :         break;
    1007             :       }
    1008             : 
    1009             :       haystack = utf8codepoint(haystack, &h_cp);
    1010             :       n = utf8codepoint(n, &n_cp);
    1011             :     }
    1012             : 
    1013             :     if (0 == n_cp) {
    1014             :       /* we found the whole utf8 string for needle in haystack at
    1015             :        * maybeMatch, so return it */
    1016             :       return (utf8_int8_t *)maybeMatch;
    1017             :     }
    1018             : 
    1019             :     if (0 == h_cp) {
    1020             :       /* no match */
    1021             :       return utf8_null;
    1022             :     }
    1023             : 
    1024             :     /* Roll back to the next code point in the haystack to test */
    1025             :     haystack = nextH;
    1026             :   }
    1027             : }
    1028             : 
    1029             : utf8_constexpr14_impl utf8_int8_t *utf8valid(const utf8_int8_t *str) {
    1030             :   return utf8nvalid(str, SIZE_MAX);
    1031             : }
    1032             : 
    1033             : utf8_constexpr14_impl utf8_int8_t *utf8nvalid(const utf8_int8_t *str,
    1034             :                                               size_t n) {
    1035             :   const utf8_int8_t *t = str;
    1036             :   size_t consumed = 0;
    1037             : 
    1038             :   while ((void)(consumed = (size_t)(str - t)), consumed < n && '\0' != *str) {
    1039             :     const size_t remaining = n - consumed;
    1040             : 
    1041             :     if (0xf0 == (0xf8 & *str)) {
    1042             :       /* ensure that there's 4 bytes or more remaining */
    1043             :       if (remaining < 4) {
    1044             :         return (utf8_int8_t *)str;
    1045             :       }
    1046             : 
    1047             :       /* ensure each of the 3 following bytes in this 4-byte
    1048             :        * utf8 codepoint began with 0b10xxxxxx */
    1049             :       if ((0x80 != (0xc0 & str[1])) || (0x80 != (0xc0 & str[2])) ||
    1050             :           (0x80 != (0xc0 & str[3]))) {
    1051             :         return (utf8_int8_t *)str;
    1052             :       }
    1053             : 
    1054             :       /* ensure that our utf8 codepoint ended after 4 bytes */
    1055             :       if ((remaining != 4) && (0x80 == (0xc0 & str[4]))) {
    1056             :         return (utf8_int8_t *)str;
    1057             :       }
    1058             : 
    1059             :       /* ensure that the top 5 bits of this 4-byte utf8
    1060             :        * codepoint were not 0, as then we could have used
    1061             :        * one of the smaller encodings */
    1062             :       if ((0 == (0x07 & str[0])) && (0 == (0x30 & str[1]))) {
    1063             :         return (utf8_int8_t *)str;
    1064             :       }
    1065             : 
    1066             :       /* 4-byte utf8 code point (began with 0b11110xxx) */
    1067             :       str += 4;
    1068             :     } else if (0xe0 == (0xf0 & *str)) {
    1069             :       /* ensure that there's 3 bytes or more remaining */
    1070             :       if (remaining < 3) {
    1071             :         return (utf8_int8_t *)str;
    1072             :       }
    1073             : 
    1074             :       /* ensure each of the 2 following bytes in this 3-byte
    1075             :        * utf8 codepoint began with 0b10xxxxxx */
    1076             :       if ((0x80 != (0xc0 & str[1])) || (0x80 != (0xc0 & str[2]))) {
    1077             :         return (utf8_int8_t *)str;
    1078             :       }
    1079             : 
    1080             :       /* ensure that our utf8 codepoint ended after 3 bytes */
    1081             :       if ((remaining != 3) && (0x80 == (0xc0 & str[3]))) {
    1082             :         return (utf8_int8_t *)str;
    1083             :       }
    1084             : 
    1085             :       /* ensure that the top 5 bits of this 3-byte utf8
    1086             :        * codepoint were not 0, as then we could have used
    1087             :        * one of the smaller encodings */
    1088             :       if ((0 == (0x0f & str[0])) && (0 == (0x20 & str[1]))) {
    1089             :         return (utf8_int8_t *)str;
    1090             :       }
    1091             : 
    1092             :       /* 3-byte utf8 code point (began with 0b1110xxxx) */
    1093             :       str += 3;
    1094             :     } else if (0xc0 == (0xe0 & *str)) {
    1095             :       /* ensure that there's 2 bytes or more remaining */
    1096             :       if (remaining < 2) {
    1097             :         return (utf8_int8_t *)str;
    1098             :       }
    1099             : 
    1100             :       /* ensure the 1 following byte in this 2-byte
    1101             :        * utf8 codepoint began with 0b10xxxxxx */
    1102             :       if (0x80 != (0xc0 & str[1])) {
    1103             :         return (utf8_int8_t *)str;
    1104             :       }
    1105             : 
    1106             :       /* ensure that our utf8 codepoint ended after 2 bytes */
    1107             :       if ((remaining != 2) && (0x80 == (0xc0 & str[2]))) {
    1108             :         return (utf8_int8_t *)str;
    1109             :       }
    1110             : 
    1111             :       /* ensure that the top 4 bits of this 2-byte utf8
    1112             :        * codepoint were not 0, as then we could have used
    1113             :        * one of the smaller encodings */
    1114             :       if (0 == (0x1e & str[0])) {
    1115             :         return (utf8_int8_t *)str;
    1116             :       }
    1117             : 
    1118             :       /* 2-byte utf8 code point (began with 0b110xxxxx) */
    1119             :       str += 2;
    1120             :     } else if (0x00 == (0x80 & *str)) {
    1121             :       /* 1-byte ascii (began with 0b0xxxxxxx) */
    1122             :       str += 1;
    1123             :     } else {
    1124             :       /* we have an invalid 0b1xxxxxxx utf8 code point entry */
    1125             :       return (utf8_int8_t *)str;
    1126             :     }
    1127             :   }
    1128             : 
    1129             :   return utf8_null;
    1130             : }
    1131             : 
    1132             : int utf8makevalid(utf8_int8_t *str, const utf8_int32_t replacement) {
    1133             :   utf8_int8_t *read = str;
    1134             :   utf8_int8_t *write = read;
    1135             :   const utf8_int8_t r = (utf8_int8_t)replacement;
    1136             :   utf8_int32_t codepoint = 0;
    1137             : 
    1138             :   if (replacement > 0x7f) {
    1139             :     return -1;
    1140             :   }
    1141             : 
    1142             :   while ('\0' != *read) {
    1143             :     if (0xf0 == (0xf8 & *read)) {
    1144             :       /* ensure each of the 3 following bytes in this 4-byte
    1145             :        * utf8 codepoint began with 0b10xxxxxx */
    1146             :       if ((0x80 != (0xc0 & read[1])) || (0x80 != (0xc0 & read[2])) ||
    1147             :           (0x80 != (0xc0 & read[3]))) {
    1148             :         *write++ = r;
    1149             :         read++;
    1150             :         continue;
    1151             :       }
    1152             : 
    1153             :       /* 4-byte utf8 code point (began with 0b11110xxx) */
    1154             :       read = utf8codepoint(read, &codepoint);
    1155             :       write = utf8catcodepoint(write, codepoint, 4);
    1156             :     } else if (0xe0 == (0xf0 & *read)) {
    1157             :       /* ensure each of the 2 following bytes in this 3-byte
    1158             :        * utf8 codepoint began with 0b10xxxxxx */
    1159             :       if ((0x80 != (0xc0 & read[1])) || (0x80 != (0xc0 & read[2]))) {
    1160             :         *write++ = r;
    1161             :         read++;
    1162             :         continue;
    1163             :       }
    1164             : 
    1165             :       /* 3-byte utf8 code point (began with 0b1110xxxx) */
    1166             :       read = utf8codepoint(read, &codepoint);
    1167             :       write = utf8catcodepoint(write, codepoint, 3);
    1168             :     } else if (0xc0 == (0xe0 & *read)) {
    1169             :       /* ensure the 1 following byte in this 2-byte
    1170             :        * utf8 codepoint began with 0b10xxxxxx */
    1171             :       if (0x80 != (0xc0 & read[1])) {
    1172             :         *write++ = r;
    1173             :         read++;
    1174             :         continue;
    1175             :       }
    1176             : 
    1177             :       /* 2-byte utf8 code point (began with 0b110xxxxx) */
    1178             :       read = utf8codepoint(read, &codepoint);
    1179             :       write = utf8catcodepoint(write, codepoint, 2);
    1180             :     } else if (0x00 == (0x80 & *read)) {
    1181             :       /* 1-byte ascii (began with 0b0xxxxxxx) */
    1182             :       read = utf8codepoint(read, &codepoint);
    1183             :       write = utf8catcodepoint(write, codepoint, 1);
    1184             :     } else {
    1185             :       /* if we got here then we've got a dangling continuation (0b10xxxxxx) */
    1186             :       *write++ = r;
    1187             :       read++;
    1188             :       continue;
    1189             :     }
    1190             :   }
    1191             : 
    1192             :   *write = '\0';
    1193             : 
    1194             :   return 0;
    1195             : }
    1196             : #endif
    1197             : 
    1198             : utf8_constexpr14_impl utf8_int8_t *
    1199   146544188 : utf8codepoint(const utf8_int8_t *utf8_restrict str,
    1200             :               utf8_int32_t *utf8_restrict out_codepoint) {
    1201   146544188 :   if (0xf0 == (0xf8 & str[0])) {
    1202             :     /* 4 byte utf8 codepoint */
    1203           0 :     *out_codepoint = ((0x07 & str[0]) << 18) | ((0x3f & str[1]) << 12) |
    1204           0 :                      ((0x3f & str[2]) << 6) | (0x3f & str[3]);
    1205           0 :     str += 4;
    1206   146544188 :   } else if (0xe0 == (0xf0 & str[0])) {
    1207             :     /* 3 byte utf8 codepoint */
    1208           0 :     *out_codepoint =
    1209           0 :         ((0x0f & str[0]) << 12) | ((0x3f & str[1]) << 6) | (0x3f & str[2]);
    1210           0 :     str += 3;
    1211   146544188 :   } else if (0xc0 == (0xe0 & str[0])) {
    1212             :     /* 2 byte utf8 codepoint */
    1213         229 :     *out_codepoint = ((0x1f & str[0]) << 6) | (0x3f & str[1]);
    1214         229 :     str += 2;
    1215             :   } else {
    1216             :     /* 1 byte utf8 codepoint otherwise */
    1217   146544000 :     *out_codepoint = str[0];
    1218   146544000 :     str += 1;
    1219             :   }
    1220             : 
    1221   146544188 :   return const_cast<utf8_int8_t *>(str);
    1222             : }
    1223             : 
    1224   146544189 : utf8_constexpr14_impl size_t utf8codepointcalcsize(const utf8_int8_t *str) {
    1225   146544189 :   if (0xf0 == (0xf8 & str[0])) {
    1226             :     /* 4 byte utf8 codepoint */
    1227           0 :     return 4;
    1228   146544189 :   } else if (0xe0 == (0xf0 & str[0])) {
    1229             :     /* 3 byte utf8 codepoint */
    1230           0 :     return 3;
    1231   146544189 :   } else if (0xc0 == (0xe0 & str[0])) {
    1232             :     /* 2 byte utf8 codepoint */
    1233         230 :     return 2;
    1234             :   }
    1235             : 
    1236             :   /* 1 byte utf8 codepoint otherwise */
    1237   146544000 :   return 1;
    1238             : }
    1239             : 
    1240             : #if 0
    1241             : utf8_constexpr14_impl size_t utf8codepointsize(utf8_int32_t chr) {
    1242             :   if (0 == ((utf8_int32_t)0xffffff80 & chr)) {
    1243             :     return 1;
    1244             :   } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) {
    1245             :     return 2;
    1246             :   } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) {
    1247             :     return 3;
    1248             :   } else { /* if (0 == ((int)0xffe00000 & chr)) { */
    1249             :     return 4;
    1250             :   }
    1251             : }
    1252             : 
    1253             : utf8_int8_t *utf8catcodepoint(utf8_int8_t *str, utf8_int32_t chr, size_t n) {
    1254             :   if (0 == ((utf8_int32_t)0xffffff80 & chr)) {
    1255             :     /* 1-byte/7-bit ascii
    1256             :      * (0b0xxxxxxx) */
    1257             :     if (n < 1) {
    1258             :       return utf8_null;
    1259             :     }
    1260             :     str[0] = (utf8_int8_t)chr;
    1261             :     str += 1;
    1262             :   } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) {
    1263             :     /* 2-byte/11-bit utf8 code point
    1264             :      * (0b110xxxxx 0b10xxxxxx) */
    1265             :     if (n < 2) {
    1266             :       return utf8_null;
    1267             :     }
    1268             :     str[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)((chr >> 6) & 0x1f));
    1269             :     str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
    1270             :     str += 2;
    1271             :   } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) {
    1272             :     /* 3-byte/16-bit utf8 code point
    1273             :      * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */
    1274             :     if (n < 3) {
    1275             :       return utf8_null;
    1276             :     }
    1277             :     str[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)((chr >> 12) & 0x0f));
    1278             :     str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
    1279             :     str[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
    1280             :     str += 3;
    1281             :   } else { /* if (0 == ((int)0xffe00000 & chr)) { */
    1282             :     /* 4-byte/21-bit utf8 code point
    1283             :      * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */
    1284             :     if (n < 4) {
    1285             :       return utf8_null;
    1286             :     }
    1287             :     str[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)((chr >> 18) & 0x07));
    1288             :     str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f));
    1289             :     str[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
    1290             :     str[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
    1291             :     str += 4;
    1292             :   }
    1293             : 
    1294             :   return str;
    1295             : }
    1296             : 
    1297             : utf8_constexpr14_impl int utf8islower(utf8_int32_t chr) {
    1298             :   return chr != utf8uprcodepoint(chr);
    1299             : }
    1300             : 
    1301             : utf8_constexpr14_impl int utf8isupper(utf8_int32_t chr) {
    1302             :   return chr != utf8lwrcodepoint(chr);
    1303             : }
    1304             : 
    1305             : void utf8lwr(utf8_int8_t *utf8_restrict str) {
    1306             :   utf8_int32_t cp = 0;
    1307             :   utf8_int8_t *pn = utf8codepoint(str, &cp);
    1308             : 
    1309             :   while (cp != 0) {
    1310             :     const utf8_int32_t lwr_cp = utf8lwrcodepoint(cp);
    1311             :     const size_t size = utf8codepointsize(lwr_cp);
    1312             : 
    1313             :     if (lwr_cp != cp) {
    1314             :       utf8catcodepoint(str, lwr_cp, size);
    1315             :     }
    1316             : 
    1317             :     str = pn;
    1318             :     pn = utf8codepoint(str, &cp);
    1319             :   }
    1320             : }
    1321             : 
    1322             : void utf8upr(utf8_int8_t *utf8_restrict str) {
    1323             :   utf8_int32_t cp = 0;
    1324             :   utf8_int8_t *pn = utf8codepoint(str, &cp);
    1325             : 
    1326             :   while (cp != 0) {
    1327             :     const utf8_int32_t lwr_cp = utf8uprcodepoint(cp);
    1328             :     const size_t size = utf8codepointsize(lwr_cp);
    1329             : 
    1330             :     if (lwr_cp != cp) {
    1331             :       utf8catcodepoint(str, lwr_cp, size);
    1332             :     }
    1333             : 
    1334             :     str = pn;
    1335             :     pn = utf8codepoint(str, &cp);
    1336             :   }
    1337             : }
    1338             : #endif
    1339             : 
    1340   136513000 : utf8_constexpr14_impl utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) {
    1341   136513000 :   if (((0x0041 <= cp) && (0x005a >= cp)) ||
    1342    63448800 :       ((0x00c0 <= cp) && (0x00d6 >= cp)) ||
    1343    63448800 :       ((0x00d8 <= cp) && (0x00de >= cp)) ||
    1344    63448800 :       ((0x0391 <= cp) && (0x03a1 >= cp)) ||
    1345    63448800 :       ((0x03a3 <= cp) && (0x03ab >= cp)) ||
    1346           0 :       ((0x0410 <= cp) && (0x042f >= cp))) {
    1347    73064700 :     cp += 32;
    1348    63448800 :   } else if ((0x0400 <= cp) && (0x040f >= cp)) {
    1349           0 :     cp += 80;
    1350    63448800 :   } else if (((0x0100 <= cp) && (0x012f >= cp)) ||
    1351    63448800 :              ((0x0132 <= cp) && (0x0137 >= cp)) ||
    1352    63448800 :              ((0x014a <= cp) && (0x0177 >= cp)) ||
    1353    63448800 :              ((0x0182 <= cp) && (0x0185 >= cp)) ||
    1354    63448800 :              ((0x01a0 <= cp) && (0x01a5 >= cp)) ||
    1355    63448800 :              ((0x01de <= cp) && (0x01ef >= cp)) ||
    1356    63448800 :              ((0x01f8 <= cp) && (0x021f >= cp)) ||
    1357    63448800 :              ((0x0222 <= cp) && (0x0233 >= cp)) ||
    1358    63448800 :              ((0x0246 <= cp) && (0x024f >= cp)) ||
    1359    63448800 :              ((0x03d8 <= cp) && (0x03ef >= cp)) ||
    1360    63448800 :              ((0x0460 <= cp) && (0x0481 >= cp)) ||
    1361           0 :              ((0x048a <= cp) && (0x04ff >= cp))) {
    1362           0 :     cp |= 0x1;
    1363    63448800 :   } else if (((0x0139 <= cp) && (0x0148 >= cp)) ||
    1364    63448800 :              ((0x0179 <= cp) && (0x017e >= cp)) ||
    1365    63448800 :              ((0x01af <= cp) && (0x01b0 >= cp)) ||
    1366    63448800 :              ((0x01b3 <= cp) && (0x01b6 >= cp)) ||
    1367           0 :              ((0x01cd <= cp) && (0x01dc >= cp))) {
    1368           0 :     cp += 1;
    1369           0 :     cp &= ~0x1;
    1370             :   } else {
    1371    63448800 :     switch (cp) {
    1372    63448800 :     default:
    1373    63448800 :       break;
    1374           0 :     case 0x0178:
    1375           0 :       cp = 0x00ff;
    1376           0 :       break;
    1377           0 :     case 0x0243:
    1378           0 :       cp = 0x0180;
    1379           0 :       break;
    1380           0 :     case 0x018e:
    1381           0 :       cp = 0x01dd;
    1382           0 :       break;
    1383           0 :     case 0x023d:
    1384           0 :       cp = 0x019a;
    1385           0 :       break;
    1386           0 :     case 0x0220:
    1387           0 :       cp = 0x019e;
    1388           0 :       break;
    1389           0 :     case 0x01b7:
    1390           0 :       cp = 0x0292;
    1391           0 :       break;
    1392           0 :     case 0x01c4:
    1393           0 :       cp = 0x01c6;
    1394           0 :       break;
    1395           0 :     case 0x01c7:
    1396           0 :       cp = 0x01c9;
    1397           0 :       break;
    1398           0 :     case 0x01ca:
    1399           0 :       cp = 0x01cc;
    1400           0 :       break;
    1401           0 :     case 0x01f1:
    1402           0 :       cp = 0x01f3;
    1403           0 :       break;
    1404           0 :     case 0x01f7:
    1405           0 :       cp = 0x01bf;
    1406           0 :       break;
    1407           0 :     case 0x0187:
    1408           0 :       cp = 0x0188;
    1409           0 :       break;
    1410           0 :     case 0x018b:
    1411           0 :       cp = 0x018c;
    1412           0 :       break;
    1413           0 :     case 0x0191:
    1414           0 :       cp = 0x0192;
    1415           0 :       break;
    1416           0 :     case 0x0198:
    1417           0 :       cp = 0x0199;
    1418           0 :       break;
    1419           0 :     case 0x01a7:
    1420           0 :       cp = 0x01a8;
    1421           0 :       break;
    1422           0 :     case 0x01ac:
    1423           0 :       cp = 0x01ad;
    1424           0 :       break;
    1425           0 :     case 0x01b8:
    1426           0 :       cp = 0x01b9;
    1427           0 :       break;
    1428           0 :     case 0x01bc:
    1429           0 :       cp = 0x01bd;
    1430           0 :       break;
    1431           0 :     case 0x01f4:
    1432           0 :       cp = 0x01f5;
    1433           0 :       break;
    1434           0 :     case 0x023b:
    1435           0 :       cp = 0x023c;
    1436           0 :       break;
    1437           0 :     case 0x0241:
    1438           0 :       cp = 0x0242;
    1439           0 :       break;
    1440           0 :     case 0x03fd:
    1441           0 :       cp = 0x037b;
    1442           0 :       break;
    1443           0 :     case 0x03fe:
    1444           0 :       cp = 0x037c;
    1445           0 :       break;
    1446           0 :     case 0x03ff:
    1447           0 :       cp = 0x037d;
    1448           0 :       break;
    1449           0 :     case 0x037f:
    1450           0 :       cp = 0x03f3;
    1451           0 :       break;
    1452           0 :     case 0x0386:
    1453           0 :       cp = 0x03ac;
    1454           0 :       break;
    1455           0 :     case 0x0388:
    1456           0 :       cp = 0x03ad;
    1457           0 :       break;
    1458           0 :     case 0x0389:
    1459           0 :       cp = 0x03ae;
    1460           0 :       break;
    1461           0 :     case 0x038a:
    1462           0 :       cp = 0x03af;
    1463           0 :       break;
    1464           0 :     case 0x038c:
    1465           0 :       cp = 0x03cc;
    1466           0 :       break;
    1467           0 :     case 0x038e:
    1468           0 :       cp = 0x03cd;
    1469           0 :       break;
    1470           0 :     case 0x038f:
    1471           0 :       cp = 0x03ce;
    1472           0 :       break;
    1473           0 :     case 0x0370:
    1474           0 :       cp = 0x0371;
    1475           0 :       break;
    1476           0 :     case 0x0372:
    1477           0 :       cp = 0x0373;
    1478           0 :       break;
    1479           0 :     case 0x0376:
    1480           0 :       cp = 0x0377;
    1481           0 :       break;
    1482           0 :     case 0x03f4:
    1483           0 :       cp = 0x03b8;
    1484           0 :       break;
    1485           0 :     case 0x03cf:
    1486           0 :       cp = 0x03d7;
    1487           0 :       break;
    1488           0 :     case 0x03f9:
    1489           0 :       cp = 0x03f2;
    1490           0 :       break;
    1491           0 :     case 0x03f7:
    1492           0 :       cp = 0x03f8;
    1493           0 :       break;
    1494           0 :     case 0x03fa:
    1495           0 :       cp = 0x03fb;
    1496           0 :       break;
    1497             :     }
    1498             :   }
    1499             : 
    1500   136513000 :   return cp;
    1501             : }
    1502             : 
    1503   141807000 : utf8_constexpr14_impl utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) {
    1504   141807000 :   if (((0x0061 <= cp) && (0x007a >= cp)) ||
    1505    93277200 :       ((0x00e0 <= cp) && (0x00f6 >= cp)) ||
    1506    93277100 :       ((0x00f8 <= cp) && (0x00fe >= cp)) ||
    1507    93277100 :       ((0x03b1 <= cp) && (0x03c1 >= cp)) ||
    1508    93277100 :       ((0x03c3 <= cp) && (0x03cb >= cp)) ||
    1509           0 :       ((0x0430 <= cp) && (0x044f >= cp))) {
    1510    48529400 :     cp -= 32;
    1511    93277100 :   } else if ((0x0450 <= cp) && (0x045f >= cp)) {
    1512           0 :     cp -= 80;
    1513    93277100 :   } else if (((0x0100 <= cp) && (0x012f >= cp)) ||
    1514    93277100 :              ((0x0132 <= cp) && (0x0137 >= cp)) ||
    1515    93277100 :              ((0x014a <= cp) && (0x0177 >= cp)) ||
    1516    93277100 :              ((0x0182 <= cp) && (0x0185 >= cp)) ||
    1517    93277100 :              ((0x01a0 <= cp) && (0x01a5 >= cp)) ||
    1518    93277100 :              ((0x01de <= cp) && (0x01ef >= cp)) ||
    1519    93277100 :              ((0x01f8 <= cp) && (0x021f >= cp)) ||
    1520    93277100 :              ((0x0222 <= cp) && (0x0233 >= cp)) ||
    1521    93277100 :              ((0x0246 <= cp) && (0x024f >= cp)) ||
    1522    93277100 :              ((0x03d8 <= cp) && (0x03ef >= cp)) ||
    1523    93277100 :              ((0x0460 <= cp) && (0x0481 >= cp)) ||
    1524           0 :              ((0x048a <= cp) && (0x04ff >= cp))) {
    1525           0 :     cp &= ~0x1;
    1526    93277100 :   } else if (((0x0139 <= cp) && (0x0148 >= cp)) ||
    1527    93277100 :              ((0x0179 <= cp) && (0x017e >= cp)) ||
    1528    93277100 :              ((0x01af <= cp) && (0x01b0 >= cp)) ||
    1529    93277100 :              ((0x01b3 <= cp) && (0x01b6 >= cp)) ||
    1530           0 :              ((0x01cd <= cp) && (0x01dc >= cp))) {
    1531           0 :     cp -= 1;
    1532           0 :     cp |= 0x1;
    1533             :   } else {
    1534    93277100 :     switch (cp) {
    1535    93277100 :     default:
    1536    93277100 :       break;
    1537           0 :     case 0x00ff:
    1538           0 :       cp = 0x0178;
    1539           0 :       break;
    1540           0 :     case 0x0180:
    1541           0 :       cp = 0x0243;
    1542           0 :       break;
    1543           0 :     case 0x01dd:
    1544           0 :       cp = 0x018e;
    1545           0 :       break;
    1546           0 :     case 0x019a:
    1547           0 :       cp = 0x023d;
    1548           0 :       break;
    1549           0 :     case 0x019e:
    1550           0 :       cp = 0x0220;
    1551           0 :       break;
    1552           0 :     case 0x0292:
    1553           0 :       cp = 0x01b7;
    1554           0 :       break;
    1555           0 :     case 0x01c6:
    1556           0 :       cp = 0x01c4;
    1557           0 :       break;
    1558           0 :     case 0x01c9:
    1559           0 :       cp = 0x01c7;
    1560           0 :       break;
    1561           0 :     case 0x01cc:
    1562           0 :       cp = 0x01ca;
    1563           0 :       break;
    1564           0 :     case 0x01f3:
    1565           0 :       cp = 0x01f1;
    1566           0 :       break;
    1567           0 :     case 0x01bf:
    1568           0 :       cp = 0x01f7;
    1569           0 :       break;
    1570           0 :     case 0x0188:
    1571           0 :       cp = 0x0187;
    1572           0 :       break;
    1573           0 :     case 0x018c:
    1574           0 :       cp = 0x018b;
    1575           0 :       break;
    1576           0 :     case 0x0192:
    1577           0 :       cp = 0x0191;
    1578           0 :       break;
    1579           0 :     case 0x0199:
    1580           0 :       cp = 0x0198;
    1581           0 :       break;
    1582           0 :     case 0x01a8:
    1583           0 :       cp = 0x01a7;
    1584           0 :       break;
    1585           0 :     case 0x01ad:
    1586           0 :       cp = 0x01ac;
    1587           0 :       break;
    1588           0 :     case 0x01b9:
    1589           0 :       cp = 0x01b8;
    1590           0 :       break;
    1591           0 :     case 0x01bd:
    1592           0 :       cp = 0x01bc;
    1593           0 :       break;
    1594           0 :     case 0x01f5:
    1595           0 :       cp = 0x01f4;
    1596           0 :       break;
    1597           0 :     case 0x023c:
    1598           0 :       cp = 0x023b;
    1599           0 :       break;
    1600           0 :     case 0x0242:
    1601           0 :       cp = 0x0241;
    1602           0 :       break;
    1603           0 :     case 0x037b:
    1604           0 :       cp = 0x03fd;
    1605           0 :       break;
    1606           0 :     case 0x037c:
    1607           0 :       cp = 0x03fe;
    1608           0 :       break;
    1609           0 :     case 0x037d:
    1610           0 :       cp = 0x03ff;
    1611           0 :       break;
    1612           0 :     case 0x03f3:
    1613           0 :       cp = 0x037f;
    1614           0 :       break;
    1615           0 :     case 0x03ac:
    1616           0 :       cp = 0x0386;
    1617           0 :       break;
    1618           0 :     case 0x03ad:
    1619           0 :       cp = 0x0388;
    1620           0 :       break;
    1621           0 :     case 0x03ae:
    1622           0 :       cp = 0x0389;
    1623           0 :       break;
    1624           0 :     case 0x03af:
    1625           0 :       cp = 0x038a;
    1626           0 :       break;
    1627           0 :     case 0x03cc:
    1628           0 :       cp = 0x038c;
    1629           0 :       break;
    1630           0 :     case 0x03cd:
    1631           0 :       cp = 0x038e;
    1632           0 :       break;
    1633           0 :     case 0x03ce:
    1634           0 :       cp = 0x038f;
    1635           0 :       break;
    1636           0 :     case 0x0371:
    1637           0 :       cp = 0x0370;
    1638           0 :       break;
    1639           0 :     case 0x0373:
    1640           0 :       cp = 0x0372;
    1641           0 :       break;
    1642           0 :     case 0x0377:
    1643           0 :       cp = 0x0376;
    1644           0 :       break;
    1645           0 :     case 0x03d1:
    1646           0 :       cp = 0x0398;
    1647           0 :       break;
    1648           0 :     case 0x03d7:
    1649           0 :       cp = 0x03cf;
    1650           0 :       break;
    1651           0 :     case 0x03f2:
    1652           0 :       cp = 0x03f9;
    1653           0 :       break;
    1654           0 :     case 0x03f8:
    1655           0 :       cp = 0x03f7;
    1656           0 :       break;
    1657           0 :     case 0x03fb:
    1658           0 :       cp = 0x03fa;
    1659           0 :       break;
    1660             :     }
    1661             :   }
    1662             : 
    1663   141807000 :   return cp;
    1664             : }
    1665             : 
    1666             : utf8_constexpr14_impl utf8_int8_t *
    1667             : utf8rcodepoint(const utf8_int8_t *utf8_restrict str,
    1668             :                utf8_int32_t *utf8_restrict out_codepoint) {
    1669             :   const utf8_int8_t *s = static_cast<const utf8_int8_t *>(str);
    1670             : 
    1671             :   if (0xf0 == (0xf8 & s[0])) {
    1672             :     /* 4 byte utf8 codepoint */
    1673             :     *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) |
    1674             :                      ((0x3f & s[2]) << 6) | (0x3f & s[3]);
    1675             :   } else if (0xe0 == (0xf0 & s[0])) {
    1676             :     /* 3 byte utf8 codepoint */
    1677             :     *out_codepoint =
    1678             :         ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]);
    1679             :   } else if (0xc0 == (0xe0 & s[0])) {
    1680             :     /* 2 byte utf8 codepoint */
    1681             :     *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]);
    1682             :   } else {
    1683             :     /* 1 byte utf8 codepoint otherwise */
    1684             :     *out_codepoint = s[0];
    1685             :   }
    1686             : 
    1687             :   do {
    1688             :     s--;
    1689             :   } while ((0 != (0x80 & s[0])) && (0x80 == (0xc0 & s[0])));
    1690             : 
    1691             :   return const_cast<utf8_int8_t *>(s);
    1692             : }
    1693             : 
    1694             : #undef utf8_restrict
    1695             : #undef utf8_constexpr14
    1696             : #undef utf8_null
    1697             : 
    1698             : } // namespace
    1699             : 
    1700             : #if defined(__clang__)
    1701             : #pragma clang diagnostic pop
    1702             : #endif
    1703             : 
    1704             : #endif /* SHEREDOM_UTF8_H_INCLUDED */

Generated by: LCOV version 1.14