Blame gnulib/lib/memchr.c

Packit eba2e2
/* Copyright (C) 1991, 1993, 1996-1997, 1999-2000, 2003-2004, 2006, 2008-2014
Packit eba2e2
   Free Software Foundation, Inc.
Packit eba2e2
Packit eba2e2
   Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
Packit eba2e2
   with help from Dan Sahlin (dan@sics.se) and
Packit eba2e2
   commentary by Jim Blandy (jimb@ai.mit.edu);
Packit eba2e2
   adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
Packit eba2e2
   and implemented by Roland McGrath (roland@ai.mit.edu).
Packit eba2e2
Packit eba2e2
NOTE: The canonical source of this file is maintained with the GNU C Library.
Packit eba2e2
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
Packit eba2e2
Packit eba2e2
This program is free software: you can redistribute it and/or modify it
Packit eba2e2
under the terms of the GNU General Public License as published by the
Packit eba2e2
Free Software Foundation; either version 3 of the License, or any
Packit eba2e2
later version.
Packit eba2e2
Packit eba2e2
This program is distributed in the hope that it will be useful,
Packit eba2e2
but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit eba2e2
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit eba2e2
GNU General Public License for more details.
Packit eba2e2
Packit eba2e2
You should have received a copy of the GNU General Public License
Packit eba2e2
along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit eba2e2
Packit eba2e2
#ifndef _LIBC
Packit eba2e2
# include <config.h>
Packit eba2e2
#endif
Packit eba2e2
Packit eba2e2
#include <string.h>
Packit eba2e2
Packit eba2e2
#include <stddef.h>
Packit eba2e2
Packit eba2e2
#if defined _LIBC
Packit eba2e2
# include <memcopy.h>
Packit eba2e2
#else
Packit eba2e2
# define reg_char char
Packit eba2e2
#endif
Packit eba2e2
Packit eba2e2
#include <limits.h>
Packit eba2e2
Packit eba2e2
#if HAVE_BP_SYM_H || defined _LIBC
Packit eba2e2
# include <bp-sym.h>
Packit eba2e2
#else
Packit eba2e2
# define BP_SYM(sym) sym
Packit eba2e2
#endif
Packit eba2e2
Packit eba2e2
#undef __memchr
Packit eba2e2
#ifdef _LIBC
Packit eba2e2
# undef memchr
Packit eba2e2
#endif
Packit eba2e2
Packit eba2e2
#ifndef weak_alias
Packit eba2e2
# define __memchr memchr
Packit eba2e2
#endif
Packit eba2e2
Packit eba2e2
/* Search no more than N bytes of S for C.  */
Packit eba2e2
void *
Packit eba2e2
__memchr (void const *s, int c_in, size_t n)
Packit eba2e2
{
Packit eba2e2
  /* On 32-bit hardware, choosing longword to be a 32-bit unsigned
Packit eba2e2
     long instead of a 64-bit uintmax_t tends to give better
Packit eba2e2
     performance.  On 64-bit hardware, unsigned long is generally 64
Packit eba2e2
     bits already.  Change this typedef to experiment with
Packit eba2e2
     performance.  */
Packit eba2e2
  typedef unsigned long int longword;
Packit eba2e2
Packit eba2e2
  const unsigned char *char_ptr;
Packit eba2e2
  const longword *longword_ptr;
Packit eba2e2
  longword repeated_one;
Packit eba2e2
  longword repeated_c;
Packit eba2e2
  unsigned reg_char c;
Packit eba2e2
Packit eba2e2
  c = (unsigned char) c_in;
Packit eba2e2
Packit eba2e2
  /* Handle the first few bytes by reading one byte at a time.
Packit eba2e2
     Do this until CHAR_PTR is aligned on a longword boundary.  */
Packit eba2e2
  for (char_ptr = (const unsigned char *) s;
Packit eba2e2
       n > 0 && (size_t) char_ptr % sizeof (longword) != 0;
Packit eba2e2
       --n, ++char_ptr)
Packit eba2e2
    if (*char_ptr == c)
Packit eba2e2
      return (void *) char_ptr;
Packit eba2e2
Packit eba2e2
  longword_ptr = (const longword *) char_ptr;
Packit eba2e2
Packit eba2e2
  /* All these elucidatory comments refer to 4-byte longwords,
Packit eba2e2
     but the theory applies equally well to any size longwords.  */
Packit eba2e2
Packit eba2e2
  /* Compute auxiliary longword values:
Packit eba2e2
     repeated_one is a value which has a 1 in every byte.
Packit eba2e2
     repeated_c has c in every byte.  */
Packit eba2e2
  repeated_one = 0x01010101;
Packit eba2e2
  repeated_c = c | (c << 8);
Packit eba2e2
  repeated_c |= repeated_c << 16;
Packit eba2e2
  if (0xffffffffU < (longword) -1)
Packit eba2e2
    {
Packit eba2e2
      repeated_one |= repeated_one << 31 << 1;
Packit eba2e2
      repeated_c |= repeated_c << 31 << 1;
Packit eba2e2
      if (8 < sizeof (longword))
Packit eba2e2
        {
Packit eba2e2
          size_t i;
Packit eba2e2
Packit eba2e2
          for (i = 64; i < sizeof (longword) * 8; i *= 2)
Packit eba2e2
            {
Packit eba2e2
              repeated_one |= repeated_one << i;
Packit eba2e2
              repeated_c |= repeated_c << i;
Packit eba2e2
            }
Packit eba2e2
        }
Packit eba2e2
    }
Packit eba2e2
Packit eba2e2
  /* Instead of the traditional loop which tests each byte, we will test a
Packit eba2e2
     longword at a time.  The tricky part is testing if *any of the four*
Packit eba2e2
     bytes in the longword in question are equal to c.  We first use an xor
Packit eba2e2
     with repeated_c.  This reduces the task to testing whether *any of the
Packit eba2e2
     four* bytes in longword1 is zero.
Packit eba2e2
Packit eba2e2
     We compute tmp =
Packit eba2e2
       ((longword1 - repeated_one) & ~longword1) & (repeated_one << 7).
Packit eba2e2
     That is, we perform the following operations:
Packit eba2e2
       1. Subtract repeated_one.
Packit eba2e2
       2. & ~longword1.
Packit eba2e2
       3. & a mask consisting of 0x80 in every byte.
Packit eba2e2
     Consider what happens in each byte:
Packit eba2e2
       - If a byte of longword1 is zero, step 1 and 2 transform it into 0xff,
Packit eba2e2
         and step 3 transforms it into 0x80.  A carry can also be propagated
Packit eba2e2
         to more significant bytes.
Packit eba2e2
       - If a byte of longword1 is nonzero, let its lowest 1 bit be at
Packit eba2e2
         position k (0 <= k <= 7); so the lowest k bits are 0.  After step 1,
Packit eba2e2
         the byte ends in a single bit of value 0 and k bits of value 1.
Packit eba2e2
         After step 2, the result is just k bits of value 1: 2^k - 1.  After
Packit eba2e2
         step 3, the result is 0.  And no carry is produced.
Packit eba2e2
     So, if longword1 has only non-zero bytes, tmp is zero.
Packit eba2e2
     Whereas if longword1 has a zero byte, call j the position of the least
Packit eba2e2
     significant zero byte.  Then the result has a zero at positions 0, ...,
Packit eba2e2
     j-1 and a 0x80 at position j.  We cannot predict the result at the more
Packit eba2e2
     significant bytes (positions j+1..3), but it does not matter since we
Packit eba2e2
     already have a non-zero bit at position 8*j+7.
Packit eba2e2
Packit eba2e2
     So, the test whether any byte in longword1 is zero is equivalent to
Packit eba2e2
     testing whether tmp is nonzero.  */
Packit eba2e2
Packit eba2e2
  while (n >= sizeof (longword))
Packit eba2e2
    {
Packit eba2e2
      longword longword1 = *longword_ptr ^ repeated_c;
Packit eba2e2
Packit eba2e2
      if ((((longword1 - repeated_one) & ~longword1)
Packit eba2e2
           & (repeated_one << 7)) != 0)
Packit eba2e2
        break;
Packit eba2e2
      longword_ptr++;
Packit eba2e2
      n -= sizeof (longword);
Packit eba2e2
    }
Packit eba2e2
Packit eba2e2
  char_ptr = (const unsigned char *) longword_ptr;
Packit eba2e2
Packit eba2e2
  /* At this point, we know that either n < sizeof (longword), or one of the
Packit eba2e2
     sizeof (longword) bytes starting at char_ptr is == c.  On little-endian
Packit eba2e2
     machines, we could determine the first such byte without any further
Packit eba2e2
     memory accesses, just by looking at the tmp result from the last loop
Packit eba2e2
     iteration.  But this does not work on big-endian machines.  Choose code
Packit eba2e2
     that works in both cases.  */
Packit eba2e2
Packit eba2e2
  for (; n > 0; --n, ++char_ptr)
Packit eba2e2
    {
Packit eba2e2
      if (*char_ptr == c)
Packit eba2e2
        return (void *) char_ptr;
Packit eba2e2
    }
Packit eba2e2
Packit eba2e2
  return NULL;
Packit eba2e2
}
Packit eba2e2
#ifdef weak_alias
Packit eba2e2
weak_alias (__memchr, BP_SYM (memchr))
Packit eba2e2
#endif