186d7f5d3SJohn Marino /* memrchr -- find the last occurrence of a byte in a memory block
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino Copyright (C) 1991, 1993, 1996, 1997, 1999, 2000, 2003, 2004, 2005
486d7f5d3SJohn Marino Free Software Foundation, Inc.
586d7f5d3SJohn Marino
686d7f5d3SJohn Marino Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
786d7f5d3SJohn Marino with help from Dan Sahlin (dan@sics.se) and
886d7f5d3SJohn Marino commentary by Jim Blandy (jimb@ai.mit.edu);
986d7f5d3SJohn Marino adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
1086d7f5d3SJohn Marino and implemented by Roland McGrath (roland@ai.mit.edu).
1186d7f5d3SJohn Marino
1286d7f5d3SJohn Marino This program is free software; you can redistribute it and/or modify
1386d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
1486d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
1586d7f5d3SJohn Marino any later version.
1686d7f5d3SJohn Marino
1786d7f5d3SJohn Marino This program is distributed in the hope that it will be useful,
1886d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
1986d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2086d7f5d3SJohn Marino GNU General Public License for more details.
2186d7f5d3SJohn Marino
2286d7f5d3SJohn Marino You should have received a copy of the GNU General Public License along
2386d7f5d3SJohn Marino with this program; if not, write to the Free Software Foundation,
2486d7f5d3SJohn Marino Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
2586d7f5d3SJohn Marino
2686d7f5d3SJohn Marino #ifdef HAVE_CONFIG_H
2786d7f5d3SJohn Marino # include <config.h>
2886d7f5d3SJohn Marino #endif
2986d7f5d3SJohn Marino
3086d7f5d3SJohn Marino #if defined _LIBC
3186d7f5d3SJohn Marino # include <string.h>
3286d7f5d3SJohn Marino # include <memcopy.h>
3386d7f5d3SJohn Marino #else
3486d7f5d3SJohn Marino # include "memrchr.h"
3586d7f5d3SJohn Marino # define reg_char char
3686d7f5d3SJohn Marino #endif
3786d7f5d3SJohn Marino
3886d7f5d3SJohn Marino #include <limits.h>
3986d7f5d3SJohn Marino
4086d7f5d3SJohn Marino #undef __memrchr
4186d7f5d3SJohn Marino #undef memrchr
4286d7f5d3SJohn Marino
4386d7f5d3SJohn Marino #ifndef weak_alias
4486d7f5d3SJohn Marino # define __memrchr memrchr
4586d7f5d3SJohn Marino #endif
4686d7f5d3SJohn Marino
4786d7f5d3SJohn Marino /* Search no more than N bytes of S for C. */
4886d7f5d3SJohn Marino void *
__memrchr(void const * s,int c_in,size_t n)4986d7f5d3SJohn Marino __memrchr (void const *s, int c_in, size_t n)
5086d7f5d3SJohn Marino {
5186d7f5d3SJohn Marino const unsigned char *char_ptr;
5286d7f5d3SJohn Marino const unsigned long int *longword_ptr;
5386d7f5d3SJohn Marino unsigned long int longword, magic_bits, charmask;
5486d7f5d3SJohn Marino unsigned reg_char c;
5586d7f5d3SJohn Marino int i;
5686d7f5d3SJohn Marino
5786d7f5d3SJohn Marino c = (unsigned char) c_in;
5886d7f5d3SJohn Marino
5986d7f5d3SJohn Marino /* Handle the last few characters by reading one character at a time.
6086d7f5d3SJohn Marino Do this until CHAR_PTR is aligned on a longword boundary. */
6186d7f5d3SJohn Marino for (char_ptr = (const unsigned char *) s + n;
6286d7f5d3SJohn Marino n > 0 && (size_t) char_ptr % sizeof longword != 0;
6386d7f5d3SJohn Marino --n)
6486d7f5d3SJohn Marino if (*--char_ptr == c)
6586d7f5d3SJohn Marino return (void *) char_ptr;
6686d7f5d3SJohn Marino
6786d7f5d3SJohn Marino /* All these elucidatory comments refer to 4-byte longwords,
6886d7f5d3SJohn Marino but the theory applies equally well to any size longwords. */
6986d7f5d3SJohn Marino
7086d7f5d3SJohn Marino longword_ptr = (const unsigned long int *) char_ptr;
7186d7f5d3SJohn Marino
7286d7f5d3SJohn Marino /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits
7386d7f5d3SJohn Marino the "holes." Note that there is a hole just to the left of
7486d7f5d3SJohn Marino each byte, with an extra at the end:
7586d7f5d3SJohn Marino
7686d7f5d3SJohn Marino bits: 01111110 11111110 11111110 11111111
7786d7f5d3SJohn Marino bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
7886d7f5d3SJohn Marino
7986d7f5d3SJohn Marino The 1-bits make sure that carries propagate to the next 0-bit.
8086d7f5d3SJohn Marino The 0-bits provide holes for carries to fall into. */
8186d7f5d3SJohn Marino
8286d7f5d3SJohn Marino /* Set MAGIC_BITS to be this pattern of 1 and 0 bits.
8386d7f5d3SJohn Marino Set CHARMASK to be a longword, each of whose bytes is C. */
8486d7f5d3SJohn Marino
8586d7f5d3SJohn Marino magic_bits = 0xfefefefe;
8686d7f5d3SJohn Marino charmask = c | (c << 8);
8786d7f5d3SJohn Marino charmask |= charmask << 16;
8886d7f5d3SJohn Marino #if 0xffffffffU < ULONG_MAX
8986d7f5d3SJohn Marino magic_bits |= magic_bits << 32;
9086d7f5d3SJohn Marino charmask |= charmask << 32;
9186d7f5d3SJohn Marino if (8 < sizeof longword)
9286d7f5d3SJohn Marino for (i = 64; i < sizeof longword * 8; i *= 2)
9386d7f5d3SJohn Marino {
9486d7f5d3SJohn Marino magic_bits |= magic_bits << i;
9586d7f5d3SJohn Marino charmask |= charmask << i;
9686d7f5d3SJohn Marino }
9786d7f5d3SJohn Marino #endif
9886d7f5d3SJohn Marino magic_bits = (ULONG_MAX >> 1) & (magic_bits | 1);
9986d7f5d3SJohn Marino
10086d7f5d3SJohn Marino /* Instead of the traditional loop which tests each character,
10186d7f5d3SJohn Marino we will test a longword at a time. The tricky part is testing
10286d7f5d3SJohn Marino if *any of the four* bytes in the longword in question are zero. */
10386d7f5d3SJohn Marino while (n >= sizeof longword)
10486d7f5d3SJohn Marino {
10586d7f5d3SJohn Marino /* We tentatively exit the loop if adding MAGIC_BITS to
10686d7f5d3SJohn Marino LONGWORD fails to change any of the hole bits of LONGWORD.
10786d7f5d3SJohn Marino
10886d7f5d3SJohn Marino 1) Is this safe? Will it catch all the zero bytes?
10986d7f5d3SJohn Marino Suppose there is a byte with all zeros. Any carry bits
11086d7f5d3SJohn Marino propagating from its left will fall into the hole at its
11186d7f5d3SJohn Marino least significant bit and stop. Since there will be no
11286d7f5d3SJohn Marino carry from its most significant bit, the LSB of the
11386d7f5d3SJohn Marino byte to the left will be unchanged, and the zero will be
11486d7f5d3SJohn Marino detected.
11586d7f5d3SJohn Marino
11686d7f5d3SJohn Marino 2) Is this worthwhile? Will it ignore everything except
11786d7f5d3SJohn Marino zero bytes? Suppose every byte of LONGWORD has a bit set
11886d7f5d3SJohn Marino somewhere. There will be a carry into bit 8. If bit 8
11986d7f5d3SJohn Marino is set, this will carry into bit 16. If bit 8 is clear,
12086d7f5d3SJohn Marino one of bits 9-15 must be set, so there will be a carry
12186d7f5d3SJohn Marino into bit 16. Similarly, there will be a carry into bit
12286d7f5d3SJohn Marino 24. If one of bits 24-30 is set, there will be a carry
12386d7f5d3SJohn Marino into bit 31, so all of the hole bits will be changed.
12486d7f5d3SJohn Marino
12586d7f5d3SJohn Marino The one misfire occurs when bits 24-30 are clear and bit
12686d7f5d3SJohn Marino 31 is set; in this case, the hole at bit 31 is not
12786d7f5d3SJohn Marino changed. If we had access to the processor carry flag,
12886d7f5d3SJohn Marino we could close this loophole by putting the fourth hole
12986d7f5d3SJohn Marino at bit 32!
13086d7f5d3SJohn Marino
13186d7f5d3SJohn Marino So it ignores everything except 128's, when they're aligned
13286d7f5d3SJohn Marino properly.
13386d7f5d3SJohn Marino
13486d7f5d3SJohn Marino 3) But wait! Aren't we looking for C, not zero?
13586d7f5d3SJohn Marino Good point. So what we do is XOR LONGWORD with a longword,
13686d7f5d3SJohn Marino each of whose bytes is C. This turns each byte that is C
13786d7f5d3SJohn Marino into a zero. */
13886d7f5d3SJohn Marino
13986d7f5d3SJohn Marino longword = *--longword_ptr ^ charmask;
14086d7f5d3SJohn Marino
14186d7f5d3SJohn Marino /* Add MAGIC_BITS to LONGWORD. */
14286d7f5d3SJohn Marino if ((((longword + magic_bits)
14386d7f5d3SJohn Marino
14486d7f5d3SJohn Marino /* Set those bits that were unchanged by the addition. */
14586d7f5d3SJohn Marino ^ ~longword)
14686d7f5d3SJohn Marino
14786d7f5d3SJohn Marino /* Look at only the hole bits. If any of the hole bits
14886d7f5d3SJohn Marino are unchanged, most likely one of the bytes was a
14986d7f5d3SJohn Marino zero. */
15086d7f5d3SJohn Marino & ~magic_bits) != 0)
15186d7f5d3SJohn Marino {
15286d7f5d3SJohn Marino /* Which of the bytes was C? If none of them were, it was
15386d7f5d3SJohn Marino a misfire; continue the search. */
15486d7f5d3SJohn Marino
15586d7f5d3SJohn Marino const unsigned char *cp = (const unsigned char *) longword_ptr;
15686d7f5d3SJohn Marino
15786d7f5d3SJohn Marino if (8 < sizeof longword)
15886d7f5d3SJohn Marino for (i = sizeof longword - 1; 8 <= i; i--)
15986d7f5d3SJohn Marino if (cp[i] == c)
16086d7f5d3SJohn Marino return (void *) &cp[i];
16186d7f5d3SJohn Marino if (7 < sizeof longword && cp[7] == c)
16286d7f5d3SJohn Marino return (void *) &cp[7];
16386d7f5d3SJohn Marino if (6 < sizeof longword && cp[6] == c)
16486d7f5d3SJohn Marino return (void *) &cp[6];
16586d7f5d3SJohn Marino if (5 < sizeof longword && cp[5] == c)
16686d7f5d3SJohn Marino return (void *) &cp[5];
16786d7f5d3SJohn Marino if (4 < sizeof longword && cp[4] == c)
16886d7f5d3SJohn Marino return (void *) &cp[4];
16986d7f5d3SJohn Marino if (cp[3] == c)
17086d7f5d3SJohn Marino return (void *) &cp[3];
17186d7f5d3SJohn Marino if (cp[2] == c)
17286d7f5d3SJohn Marino return (void *) &cp[2];
17386d7f5d3SJohn Marino if (cp[1] == c)
17486d7f5d3SJohn Marino return (void *) &cp[1];
17586d7f5d3SJohn Marino if (cp[0] == c)
17686d7f5d3SJohn Marino return (void *) cp;
17786d7f5d3SJohn Marino }
17886d7f5d3SJohn Marino
17986d7f5d3SJohn Marino n -= sizeof longword;
18086d7f5d3SJohn Marino }
18186d7f5d3SJohn Marino
18286d7f5d3SJohn Marino char_ptr = (const unsigned char *) longword_ptr;
18386d7f5d3SJohn Marino
18486d7f5d3SJohn Marino while (n-- > 0)
18586d7f5d3SJohn Marino {
18686d7f5d3SJohn Marino if (*--char_ptr == c)
18786d7f5d3SJohn Marino return (void *) char_ptr;
18886d7f5d3SJohn Marino }
18986d7f5d3SJohn Marino
19086d7f5d3SJohn Marino return 0;
19186d7f5d3SJohn Marino }
19286d7f5d3SJohn Marino #ifdef weak_alias
19386d7f5d3SJohn Marino weak_alias (__memrchr, memrchr)
19486d7f5d3SJohn Marino #endif
195