xref: /dflybsd-src/contrib/cvs-1.12/lib/memrchr.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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