Generic optimized string functions
[kopensolaris-gnu/glibc.git] / string / bits / string2.h
1 /* Machine-independant string function optimizations.
2    Copyright (C) 1997 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The GNU C Library 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    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #ifndef _BITS_STRING2_H
22 #define _BITS_STRING2_H 1
23
24 /* Unlike the definitions in the header <bits/string.h> the
25    definitions contained here are not optimizing down to assembler
26    level.  These optimizations are not always a good idea since this
27    means the code size increases a lot.  Instead the definitions here
28    optimize some functions in a way which does not dramatically
29    increase the code size and which does not use assembler.  The main
30    trick is to use GNU CC's `__builtin_constant_p' function.
31
32    Every function XXX which has a defined version in
33    <bits/string.h> must be accompanied by a have _HAVE_STRING_ARCH_XXX
34    to make sure we don't get redefinitions.
35
36    We must use here macros instead of inline functions since the
37    trick won't work with the later.  */
38
39 #ifdef __cplusplus
40 # define __STRING_INLINE inline
41 #else
42 # define __STRING_INLINE extern __inline
43 #endif
44
45 /* We need some more types.  */
46 #include <bits/types.h>
47
48
49 /* Copy SRC to DEST.  */
50 #ifndef _HAVE_STRING_ARCH_strcpy
51 # define strcpy(dest, src) \
52   (__extension__ (__builtin_constant_p (src)                                  \
53                   ? (strlen (src) + 1 <= 8                                    \
54                      ? __strcpy_small (dest, src, strlen (src) + 1)           \
55                      : (char *) memcpy (dest, src, strlen (src) + 1))         \
56                   : strcpy (dest, src)))
57
58 __STRING_INLINE char *
59 __strcpy_small (char *__dest, __const char *__src, size_t __srclen)
60 {
61   register char *__tmp = __dest;
62   switch (__srclen)
63     {
64     case 7:
65       *((__uint16_t *) __tmp)++ = *((__uint16_t *) __src)++;
66     case 5:
67       *((__uint32_t *) __tmp)++ = *((__uint32_t *) __src)++;
68       *((unsigned char *) __tmp) = '\0';
69       break;
70
71     case 8:
72       *((__uint32_t *) __tmp)++ = *((__uint32_t *) __src)++;
73     case 4:
74       *((__uint32_t *) __tmp) = *((__uint32_t *) __src);
75       break;
76
77     case 6:
78       *((__uint32_t *) __tmp)++ = *((__uint32_t *) __src)++;
79     case 2:
80       *((__uint16_t *) __tmp) = *((__uint16_t *) __src);
81       break;
82
83     case 3:
84       *((__uint16_t *) __tmp)++ = *((__uint16_t *) __src)++;
85     case 1:
86       *((unsigned char *) __tmp) = '\0';
87       break;
88
89     default:
90       break;
91     }
92   return __dest;
93 }
94 #endif
95
96
97 /* Copy SRC to DEST, returning pointer to final NUL byte.  */
98 #ifdef __USE_GNU
99 # ifndef _HAVE_STRING_ARCH_stpcpy
100 #  define __stpcpy(dest, src) \
101   (__extension__ (__builtin_constant_p (src)                                  \
102                   ? (strlen (src) + 1 <= 8                                    \
103                      ? __stpcpy_small (dest, src, strlen (src) + 1)           \
104                      : ((char *) __mempcpy (dest, src, strlen (src) + 1) - 1))\
105                   : __stpcpy (dest, src)))
106 /* In glibc we use this function frequently but for namespace reasons
107    we have to use the name `__stpcpy'.  */
108 #  define stpcpy(dest, src) __stpcpy (dest, src)
109
110 __STRING_INLINE char *
111 __stpcpy_small (char *__dest, __const char *__src, size_t __srclen)
112 {
113   register char *__tmp = __dest;
114   switch (__srclen)
115     {
116     case 7:
117       *((__uint16_t *) __tmp)++ = *((__uint16_t *) __src)++;
118     case 5:
119       *((__uint32_t *) __tmp)++ = *((__uint32_t *) __src)++;
120       *((unsigned char *) __tmp) = '\0';
121       return __tmp;
122
123     case 8:
124       *((__uint32_t *) __tmp)++ = *((__uint32_t *) __src)++;
125     case 4:
126       *((__uint32_t *) __tmp) = *((__uint32_t *) __src);
127       return __tmp + 3;
128
129     case 6:
130       *((__uint32_t *) __tmp)++ = *((__uint32_t *) __src)++;
131     case 2:
132       *((__uint16_t *) __tmp) = *((__uint16_t *) __src);
133       return __tmp + 1;
134
135     case 3:
136       *((__uint16_t *) __tmp)++ = *((__uint16_t *) __src)++;
137     case 1:
138       *((unsigned char *) __tmp) = '\0';
139       return __tmp;
140
141     default:
142       break;
143     }
144   /* This should never happen.  */
145   return NULL;
146 }
147 # endif
148 #endif
149
150
151 /* Copy no more than N characters of SRC to DEST.  */
152 #ifndef _HAVE_STRING_ARCH_strncpy
153 # if defined _HAVE_STRING_ARCH_memset && defined _HAVE_STRING_ARCH_mempcpy
154 #  define strncpy(dest, src, n) \
155   (__extension__ (__builtin_constant_p (src) && __builtin_constant_p (n)      \
156                   ? (strlen (src) + 1 >= ((size_t) (n))                       \
157                      ? (char *) memcpy (dest, src, n)                         \
158                      : (memset (__mempcpy (dest, src, strlen (src)), '\0',    \
159                                 n - strlen (src)),                            \
160                         dest))                                                \
161                   : strncpy (dest, src, n)))
162 # else
163 #  define strncpy(dest, src, n) \
164   (__extension__ (__builtin_constant_p (src) && __builtin_constant_p (n)      \
165                   ? (strlen (src) + 1 >= ((size_t) (n))                       \
166                      ? (char *) memcpy (dest, src, n)                         \
167                      : strncpy (dest, src, n))                                \
168                   : strncpy (dest, src, n)))
169 # endif
170 #endif
171
172
173 /* Append no more than N characters from SRC onto DEST.  */
174 #ifndef _HAVE_STRING_ARCH_strncat
175 # ifdef _HAVE_STRING_ARCH_strchr
176 #  define strncat(dest, src, n) \
177   (__extension__ (__builtin_constant_p (src) && __builtin_constant_p (n)      \
178                   ? (strlen (src) < ((size_t) (n))                            \
179                      ? strcat (dest, src)                                     \
180                      : (memcpy (strchr (dest, '\0'), src, n), dest))          \
181                   : strncat (dest, src, n)))
182 # else
183 #  define strncat(dest, src, n) \
184   (__extension__ (__builtin_constant_p (src) && __builtin_constant_p (n)      \
185                   ? (strlen (src) < ((size_t) (n))                            \
186                      ? strcat (dest, src)                                     \
187                      : strncat (dest, src, n))                                \
188                   : strncat (dest, src, n)))
189 # endif
190 #endif
191
192
193 /* Compare N characters of S1 and S2.  */
194 #ifndef _HAVE_STRING_ARCH_strncmp
195 # define strncmp(s1, s2, n) \
196   (__extension__ (__builtin_constant_p (s1) && strlen (s1) < ((size_t) (n))   \
197                   ? strcmp (s1, s2)                                           \
198                   : (__builtin_constant_p (s2) && strlen (s2) < ((size_t) (n))\
199                      ? strcmp (s1, s2)                                        \
200                      : strncmp (s1, s2, n))))
201 #endif
202
203
204 /* Return the length of the initial segment of S which
205    consists entirely of characters not in REJECT.  */
206 #ifndef _HAVE_STRING_ARCH_strcspn
207 # define strcspn(s, reject) \
208   (__extension__ (__builtin_constant_p (reject)                               \
209                   ? (((const char *) (reject))[0] == '\0'                     \
210                      ? strlen (s)                                             \
211                      : (((const char *) (reject))[1] == '\0'                  \
212                         ? __strcspn_c1 (s, ((((const char *) (reject))[0]     \
213                                              & 0xff) << 8))                   \
214                         : strcspn (s, reject)))       \
215                   : strcspn (s, reject)))
216
217 __STRING_INLINE size_t
218 __strcspn_c1 (__const char *__s, char __reject)
219 {
220   register size_t __result = 0;
221   while (__s[__result] != '\0' && __s[__result] != __reject)
222     ++__result;
223   return __result;
224 }
225 #endif
226
227
228 /* Return the length of the initial segment of S which
229    consists entirely of characters in ACCEPT.  */
230 #ifndef _HAVE_STRING_ARCH_strspn
231 # define strspn(s, accept) \
232   (__extension__ (__builtin_constant_p (accept)                               \
233                   ? (((const char *) (accept))[0] == '\0'                     \
234                      ? 0                                                      \
235                      : (((const char *) (accept))[1] == '\0'                  \
236                         ? __strspn_c1 (s, ((const char *) (accept))[0])       \
237                         : strspn (s, accept)))                                \
238                   : strspn (s, accept)))
239
240 __STRING_INLINE size_t
241 __strspn_c1 (__const char *__s, char __accept)
242 {
243   register size_t __result = 0;
244   /* Please note that __accept never can be '\0'.  */
245   while (__s[__result] == __accept)
246     ++__result;
247   return __result;
248 }
249 #endif
250
251
252 /* Find the first occurrence in S of any character in ACCEPT.  */
253 #ifndef _HAVE_STRING_ARCH_strpbrk
254 # define strpbrk(s, accept) \
255   (__extension__ (__builtin_constant_p (accept)                               \
256                   ? (((const char *) (accept))[0] == '\0'                     \
257                      ? NULL                                                   \
258                      : (((const char *) (accept))[1] == '\0'                  \
259                         ? strchr (s, ((const char *) (accept))[0])            \
260                         : strpbrk (s, accept)))                               \
261                   : strpbrk (s, accept)))
262 #endif
263
264
265 /* Find the first occurrence of NEEDLE in HAYSTACK.  */
266 #ifndef _HAVE_STRING_ARCH_strstr
267 # define strstr(haystack, needle) \
268   (__extension__ (__builtin_constant_p (needle)                               \
269                   ? (((const char *) (needle))[0] == '\0'                     \
270                      ? haystack                                               \
271                      : (((const char *) (needle))[1] == '\0'                  \
272                         ? strchr (haystack, ((const char *) (needle))[0])     \
273                         : strstr (haystack, needle)))                         \
274                   : strstr (haystack, needle)))
275 #endif
276
277
278 #ifdef __USE_GNU
279 # ifndef _HAVE_STRING_ARCH_strnlen
280 extern __inline size_t
281 strnlen (__const char *__string, size_t __maxlen)
282 {
283   __const char *__end = (__const char *) memchr (__string, '\0', __maxlen);
284   return __end ? __end - __string : __maxlen;
285 }
286 # endif
287 #endif
288
289
290 #undef __STRING_INLINE
291
292 #endif /* bits/string2.h */