unistr/u8-strchr: Optimize non-ASCII argument case.
[gnulib.git] / lib / unistr / u8-strchr.c
1 /* Search character in UTF-8 string.
2    Copyright (C) 1999, 2002, 2006-2007, 2009-2010 Free Software Foundation,
3    Inc.
4    Written by Bruno Haible <bruno@clisp.org>, 2002.
5
6    This program is free software: you can redistribute it and/or modify it
7    under the terms of the GNU Lesser General Public License as published
8    by the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 #include <config.h>
20
21 /* Specification.  */
22 #include "unistr.h"
23
24 #include <string.h>
25
26 uint8_t *
27 u8_strchr (const uint8_t *s, ucs4_t uc)
28 {
29   uint8_t c[6];
30
31   if (uc < 0x80)
32     {
33       uint8_t c0 = uc;
34
35       if (false)
36         {
37           /* Unoptimized code.  */
38           for (;; s++)
39             {
40               if (*s == c0)
41                 break;
42               if (*s == 0)
43                 goto notfound;
44             }
45           return (uint8_t *) s;
46         }
47       else
48         {
49           /* Optimized code.
50              strchr() is often so well optimized, that it's worth the
51              added function call.  */
52           return (uint8_t *) strchr ((const char *) s, c0);
53         }
54     }
55   else
56     switch (u8_uctomb_aux (c, uc, 6))
57       {
58       /* Loops equivalent to strstr, optimized for a specific length (2, 3, 4)
59          of the needle.  */
60       case 2:
61         if (*s == 0)
62           goto notfound;
63         {
64           uint8_t c0 = c[0];
65           uint8_t c1 = c[1];
66
67           for (;; s++)
68             {
69               if (s[1] == 0)
70                 goto notfound;
71               if (s[1] == c1 && *s == c0)
72                 break;
73             }
74           return (uint8_t *) s;
75         }
76
77       case 3:
78         if (*s == 0 || s[1] == 0)
79           goto notfound;
80         {
81           uint8_t c0 = c[0];
82           uint8_t c1 = c[1];
83           uint8_t c2 = c[2];
84
85           for (;; s++)
86             {
87               if (s[2] == 0)
88                 goto notfound;
89               if (s[2] == c2 && s[1] == c1 && *s == c0)
90                 break;
91             }
92           return (uint8_t *) s;
93         }
94
95       case 4:
96         if (*s == 0 || s[1] == 0 || s[2] == 0)
97           goto notfound;
98         {
99           uint8_t c0 = c[0];
100           uint8_t c1 = c[1];
101           uint8_t c2 = c[2];
102           uint8_t c3 = c[3];
103
104           for (;; s++)
105             {
106               if (s[3] == 0)
107                 goto notfound;
108               if (s[3] == c3 && s[2] == c2 && s[1] == c1 && *s == c0)
109                 break;
110             }
111           return (uint8_t *) s;
112         }
113       }
114 notfound:
115   return NULL;
116 }