Mercurial > hg > octave-kai > gnulib-hg
view lib/memcmp.c @ 16366:bb182ee4a09d
maint: replace FSF snail-mail addresses with URLs
* config/argz.mk, lib/accept4.c, lib/alignof.h, lib/alloca.in.h:
* lib/alphasort.c, lib/arcfour.c, lib/arcfour.h, lib/arctwo.c:
* lib/arctwo.h, lib/argz.c, lib/arpa_inet.in.h, lib/asnprintf.c:
* lib/asprintf.c, lib/assert.in.h, lib/base32.c, lib/base32.h:
* lib/base64.c, lib/base64.h, lib/c-ctype.c, lib/c-ctype.h:
* lib/c-strcase.h, lib/c-strcasecmp.c, lib/c-strncasecmp.c:
* lib/check-version.c, lib/check-version.h, lib/config.charset:
* lib/ctype.in.h, lib/des.c, lib/des.h, lib/dup3.c, lib/errno.in.h:
* lib/float+.h, lib/fnmatch.c, lib/fnmatch.in.h, lib/fnmatch_loop.c:
* lib/fseeko.c, lib/gai_strerror.c, lib/gc-gnulib.c:
* lib/gc-libgcrypt.c, lib/gc-pbkdf2-sha1.c, lib/gc.h:
* lib/getaddrinfo.c, lib/getdelim.c, lib/getfilecon.c, lib/getline.c:
* lib/getlogin_r.c, lib/getpass.c, lib/getpass.h, lib/gettext.h:
* lib/gettimeofday.c, lib/glob.in.h, lib/glthread/cond.c:
* lib/glthread/cond.h, lib/glthread/lock.c, lib/glthread/lock.h:
* lib/glthread/thread.c, lib/glthread/thread.h:
* lib/glthread/threadlib.c, lib/glthread/yield.h, lib/hmac-md5.c:
* lib/hmac-sha1.c, lib/hmac.h, lib/iconv.c, lib/iconv.in.h:
* lib/iconv_close.c, lib/iconv_open.c, lib/inet_ntop.c, lib/isfinite.c:
* lib/isinf.c, lib/iswblank.c, lib/langinfo.in.h, lib/link.c:
* lib/localcharset.c, lib/localcharset.h, lib/lseek.c, lib/malloc.c:
* lib/malloca.c, lib/malloca.h, lib/md2.c, lib/md2.h, lib/md4.c:
* lib/md4.h, lib/md5.c, lib/md5.h, lib/memmem.c, lib/mempcpy.c:
* lib/memset.c, lib/memxor.c, lib/memxor.h, lib/minmax.h, lib/mktime.c:
* lib/msvc-inval.c, lib/msvc-inval.h, lib/msvc-nothrow.c:
* lib/msvc-nothrow.h, lib/netdb.in.h, lib/netinet_in.in.h, lib/nproc.c:
* lib/nproc.h, lib/obstack_printf.c, lib/pathmax.h, lib/pipe.c:
* lib/pipe2.c, lib/poll.c, lib/poll.in.h, lib/printf-args.c:
* lib/printf-args.h, lib/printf-parse.c, lib/printf-parse.h:
* lib/pselect.c, lib/pthread.in.h, lib/pty-private.h, lib/pty.in.h:
* lib/read-file.c, lib/read-file.h, lib/ref-add.sin, lib/ref-del.sin:
* lib/regcomp.c, lib/regex.c, lib/regex.h, lib/regex_internal.c:
* lib/regex_internal.h, lib/regexec.c, lib/rijndael-alg-fst.c:
* lib/rijndael-alg-fst.h, lib/rijndael-api-fst.c:
* lib/rijndael-api-fst.h, lib/rint.c, lib/rintf.c, lib/rintl.c:
* lib/round.c, lib/roundf.c, lib/roundl.c, lib/scandir.c, lib/select.c:
* lib/sha1.c, lib/sha1.h, lib/size_max.h, lib/snprintf.c:
* lib/stdalign.in.h, lib/stdarg.in.h, lib/stdbool.in.h:
* lib/stddef.in.h, lib/stdint.in.h, lib/stdio.in.h, lib/str-kmp.h:
* lib/str-two-way.h, lib/strcasecmp.c, lib/strcasestr.c, lib/strdup.c:
* lib/striconv.c, lib/striconv.h, lib/string.in.h, lib/strings.in.h:
* lib/strncasecmp.c, lib/strndup.c, lib/strnlen.c, lib/strpbrk.c:
* lib/strptime.c, lib/strsep.c, lib/strstr.c, lib/strverscmp.c:
* lib/sys_file.in.h, lib/sys_ioctl.in.h, lib/sys_select.in.h:
* lib/sys_socket.in.h, lib/sys_stat.in.h, lib/sys_time.in.h:
* lib/sys_times.in.h, lib/sys_types.in.h, lib/sys_uio.in.h:
* lib/sys_utsname.in.h, lib/sys_wait.in.h, lib/tcgetsid.c:
* lib/termios.in.h, lib/time.in.h, lib/time_r.c, lib/timegm.c:
* lib/times.c, lib/unictype/3level.h, lib/unictype/3levelbit.h:
* lib/unistd.in.h, lib/vasnprintf.c, lib/vasnprintf.h, lib/vasprintf.c:
* lib/vsnprintf.c, lib/waitpid.c, lib/wchar.in.h, lib/wctype.in.h:
* lib/xsize.h, tests/test-closein.c, tests/test-des.c:
* tests/test-fclose.c, tests/test-fgetc.c, tests/test-filevercmp.c:
* tests/test-fputc.c, tests/test-fread.c, tests/test-fwrite.c:
* tests/test-gc-arcfour.c, tests/test-gc-arctwo.c, tests/test-gc-des.c:
* tests/test-gc-hmac-md5.c, tests/test-gc-hmac-sha1.c:
* tests/test-gc-md2.c, tests/test-gc-md4.c, tests/test-gc-md5.c:
* tests/test-gc-pbkdf2-sha1.c, tests/test-gc-rijndael.c:
* tests/test-gc-sha1.c, tests/test-gc.c, tests/test-getdelim.c:
* tests/test-getline.c, tests/test-getndelim2.c, tests/test-md2.c:
* tests/test-md4.c, tests/test-parse-datetime.c, tests/test-perror.c:
* tests/test-perror2.c, tests/test-pipe.c, tests/test-pipe2.c:
* tests/test-poll.c, tests/test-quotearg-simple.c:
* tests/test-quotearg.c, tests/test-quotearg.h:
* tests/test-round-ieee.c, tests/test-round1.c:
* tests/test-roundf-ieee.c, tests/test-roundf1.c:
* tests/test-roundl-ieee.c, tests/test-roundl.c:
* tests/test-safe-alloc.c, tests/test-sigpipe.c:
* tests/test-spawn-pipe-child.c, tests/test-spawn-pipe-main.c:
* tests/test-strerror.c, tests/test-strerror_r.c:
* tests/test-strsignal.c, tests/test-strverscmp.c:
* tests/test-xmemdup0.c:
Replace FSF snail mail addresses with URLs, as per GNU coding
standards. See glibc bug
<http://sourceware.org/bugzilla/show_bug.cgi?id=13673>.
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Thu, 09 Feb 2012 21:39:05 -0800 |
parents | 18a38c9615f0 |
children | e542fd46ad6f |
line wrap: on
line source
/* Copyright (C) 1991, 1993, 1995, 1997-1998, 2003, 2006, 2009-2012 Free Software Foundation, Inc. Contributed by Torbjorn Granlund (tege@sics.se). NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _LIBC # include <config.h> #endif #include <string.h> #include <stdint.h> #undef memcmp #ifdef _LIBC # include <memcopy.h> # include <endian.h> # if __BYTE_ORDER == __BIG_ENDIAN # define WORDS_BIGENDIAN # endif #else /* Not in the GNU C library. */ # include <sys/types.h> /* Type to use for aligned memory operations. This should normally be the biggest type supported by a single load and store. Must be an unsigned type. */ # define op_t unsigned long int # define OPSIZ (sizeof(op_t)) /* Threshold value for when to enter the unrolled loops. */ # define OP_T_THRES 16 /* Type to use for unaligned operations. */ typedef unsigned char byte; # ifndef WORDS_BIGENDIAN # define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2))) # else # define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2))) # endif #endif /* In the GNU C library. */ #ifdef WORDS_BIGENDIAN # define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1) #else # define CMP_LT_OR_GT(a, b) memcmp_bytes (a, b) #endif /* BE VERY CAREFUL IF YOU CHANGE THIS CODE! */ /* The strategy of this memcmp is: 1. Compare bytes until one of the block pointers is aligned. 2. Compare using memcmp_common_alignment or memcmp_not_common_alignment, regarding the alignment of the other block after the initial byte operations. The maximum number of full words (of type op_t) are compared in this way. 3. Compare the few remaining bytes. */ #ifndef WORDS_BIGENDIAN /* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine. A and B are known to be different. This is needed only on little-endian machines. */ # ifdef __GNUC__ __inline # endif static int memcmp_bytes (op_t a, op_t b) { const byte *srcp1 = (const byte *) &a; const byte *srcp2 = (const byte *) &b; op_t a0, b0; do { a0 = srcp1[0]; b0 = srcp2[0]; srcp1 += 1; srcp2 += 1; } while (a0 == b0); return a0 - b0; } #endif /* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN 'op_t' objects (not LEN bytes!). Both SRCP1 and SRCP2 should be aligned for memory operations on 'op_t's. */ #ifdef __GNUC__ __inline #endif static int memcmp_common_alignment (uintptr_t srcp1, uintptr_t srcp2, size_t len) { op_t a0, a1; op_t b0, b1; switch (len % 4) { default: /* Avoid warning about uninitialized local variables. */ case 2: a0 = ((op_t *) srcp1)[0]; b0 = ((op_t *) srcp2)[0]; srcp1 -= 2 * OPSIZ; srcp2 -= 2 * OPSIZ; len += 2; goto do1; case 3: a1 = ((op_t *) srcp1)[0]; b1 = ((op_t *) srcp2)[0]; srcp1 -= OPSIZ; srcp2 -= OPSIZ; len += 1; goto do2; case 0: if (OP_T_THRES <= 3 * OPSIZ && len == 0) return 0; a0 = ((op_t *) srcp1)[0]; b0 = ((op_t *) srcp2)[0]; goto do3; case 1: a1 = ((op_t *) srcp1)[0]; b1 = ((op_t *) srcp2)[0]; srcp1 += OPSIZ; srcp2 += OPSIZ; len -= 1; if (OP_T_THRES <= 3 * OPSIZ && len == 0) goto do0; /* Fall through. */ } do { a0 = ((op_t *) srcp1)[0]; b0 = ((op_t *) srcp2)[0]; if (a1 != b1) return CMP_LT_OR_GT (a1, b1); do3: a1 = ((op_t *) srcp1)[1]; b1 = ((op_t *) srcp2)[1]; if (a0 != b0) return CMP_LT_OR_GT (a0, b0); do2: a0 = ((op_t *) srcp1)[2]; b0 = ((op_t *) srcp2)[2]; if (a1 != b1) return CMP_LT_OR_GT (a1, b1); do1: a1 = ((op_t *) srcp1)[3]; b1 = ((op_t *) srcp2)[3]; if (a0 != b0) return CMP_LT_OR_GT (a0, b0); srcp1 += 4 * OPSIZ; srcp2 += 4 * OPSIZ; len -= 4; } while (len != 0); /* This is the right position for do0. Please don't move it into the loop. */ do0: if (a1 != b1) return CMP_LT_OR_GT (a1, b1); return 0; } /* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN 'op_t' objects (not LEN bytes!). SRCP2 should be aligned for memory operations on 'op_t', but SRCP1 *should be unaligned*. */ #ifdef __GNUC__ __inline #endif static int memcmp_not_common_alignment (uintptr_t srcp1, uintptr_t srcp2, size_t len) { op_t a0, a1, a2, a3; op_t b0, b1, b2, b3; op_t x; int shl, shr; /* Calculate how to shift a word read at the memory operation aligned srcp1 to make it aligned for comparison. */ shl = 8 * (srcp1 % OPSIZ); shr = 8 * OPSIZ - shl; /* Make SRCP1 aligned by rounding it down to the beginning of the 'op_t' it points in the middle of. */ srcp1 &= -OPSIZ; switch (len % 4) { default: /* Avoid warning about uninitialized local variables. */ case 2: a1 = ((op_t *) srcp1)[0]; a2 = ((op_t *) srcp1)[1]; b2 = ((op_t *) srcp2)[0]; srcp1 -= 1 * OPSIZ; srcp2 -= 2 * OPSIZ; len += 2; goto do1; case 3: a0 = ((op_t *) srcp1)[0]; a1 = ((op_t *) srcp1)[1]; b1 = ((op_t *) srcp2)[0]; srcp2 -= 1 * OPSIZ; len += 1; goto do2; case 0: if (OP_T_THRES <= 3 * OPSIZ && len == 0) return 0; a3 = ((op_t *) srcp1)[0]; a0 = ((op_t *) srcp1)[1]; b0 = ((op_t *) srcp2)[0]; srcp1 += 1 * OPSIZ; goto do3; case 1: a2 = ((op_t *) srcp1)[0]; a3 = ((op_t *) srcp1)[1]; b3 = ((op_t *) srcp2)[0]; srcp1 += 2 * OPSIZ; srcp2 += 1 * OPSIZ; len -= 1; if (OP_T_THRES <= 3 * OPSIZ && len == 0) goto do0; /* Fall through. */ } do { a0 = ((op_t *) srcp1)[0]; b0 = ((op_t *) srcp2)[0]; x = MERGE (a2, shl, a3, shr); if (x != b3) return CMP_LT_OR_GT (x, b3); do3: a1 = ((op_t *) srcp1)[1]; b1 = ((op_t *) srcp2)[1]; x = MERGE (a3, shl, a0, shr); if (x != b0) return CMP_LT_OR_GT (x, b0); do2: a2 = ((op_t *) srcp1)[2]; b2 = ((op_t *) srcp2)[2]; x = MERGE (a0, shl, a1, shr); if (x != b1) return CMP_LT_OR_GT (x, b1); do1: a3 = ((op_t *) srcp1)[3]; b3 = ((op_t *) srcp2)[3]; x = MERGE (a1, shl, a2, shr); if (x != b2) return CMP_LT_OR_GT (x, b2); srcp1 += 4 * OPSIZ; srcp2 += 4 * OPSIZ; len -= 4; } while (len != 0); /* This is the right position for do0. Please don't move it into the loop. */ do0: x = MERGE (a2, shl, a3, shr); if (x != b3) return CMP_LT_OR_GT (x, b3); return 0; } int rpl_memcmp (const void *s1, const void *s2, size_t len) { op_t a0; op_t b0; uintptr_t srcp1 = (uintptr_t) s1; uintptr_t srcp2 = (uintptr_t) s2; op_t res; if (len >= OP_T_THRES) { /* There are at least some bytes to compare. No need to test for LEN == 0 in this alignment loop. */ while (srcp2 % OPSIZ != 0) { a0 = ((byte *) srcp1)[0]; b0 = ((byte *) srcp2)[0]; srcp1 += 1; srcp2 += 1; res = a0 - b0; if (res != 0) return res; len -= 1; } /* SRCP2 is now aligned for memory operations on 'op_t'. SRCP1 alignment determines if we can do a simple, aligned compare or need to shuffle bits. */ if (srcp1 % OPSIZ == 0) res = memcmp_common_alignment (srcp1, srcp2, len / OPSIZ); else res = memcmp_not_common_alignment (srcp1, srcp2, len / OPSIZ); if (res != 0) return res; /* Number of bytes remaining in the interval [0..OPSIZ-1]. */ srcp1 += len & -OPSIZ; srcp2 += len & -OPSIZ; len %= OPSIZ; } /* There are just a few bytes to compare. Use byte memory operations. */ while (len != 0) { a0 = ((byte *) srcp1)[0]; b0 = ((byte *) srcp2)[0]; srcp1 += 1; srcp2 += 1; res = a0 - b0; if (res != 0) return res; len -= 1; } return 0; } #ifdef weak_alias # undef bcmp weak_alias (memcmp, bcmp) #endif