strlen.c revision 242506
1295041Sbr/*-
2295972Sbr * Copyright (c) 2009, 2010 Xin LI <delphij@FreeBSD.org>
3295041Sbr * All rights reserved.
4295041Sbr *
5295041Sbr * Redistribution and use in source and binary forms, with or without
6295041Sbr * modification, are permitted provided that the following conditions
7295041Sbr * are met:
8295041Sbr * 1. Redistributions of source code must retain the above copyright
9295041Sbr *    notice, this list of conditions and the following disclaimer.
10295041Sbr * 2. Redistributions in binary form must reproduce the above copyright
11295041Sbr *    notice, this list of conditions and the following disclaimer in the
12295041Sbr *    documentation and/or other materials provided with the distribution.
13295041Sbr *
14295041Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15295041Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16295041Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17295041Sbr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18295041Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19295041Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20295041Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21295041Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22295041Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23295041Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24295041Sbr * SUCH DAMAGE.
25295041Sbr */
26295041Sbr
27295041Sbr#include <sys/cdefs.h>
28295041Sbr__FBSDID("$FreeBSD: head/sys/libkern/strlen.c 242506 2012-11-03 04:28:53Z delphij $");
29295041Sbr
30295041Sbr#include <sys/libkern.h>
31295041Sbr#include <sys/limits.h>
32295041Sbr
33295041Sbr/*
34295041Sbr * Portable strlen() for 32-bit and 64-bit systems.
35295041Sbr *
36295041Sbr * Rationale: it is generally much more efficient to do word length
37295041Sbr * operations and avoid branches on modern computer systems, as
38295041Sbr * compared to byte-length operations with a lot of branches.
39295041Sbr *
40295041Sbr * The expression:
41295041Sbr *
42295041Sbr *	((x - 0x01....01) & ~x & 0x80....80)
43295041Sbr *
44295041Sbr * would evaluate to a non-zero value iff any of the bytes in the
45295041Sbr * original word is zero.
46295041Sbr *
47295041Sbr * On multi-issue processors, we can divide the above expression into:
48295041Sbr *	a)  (x - 0x01....01)
49295041Sbr *	b) (~x & 0x80....80)
50295041Sbr *	c) a & b
51295041Sbr *
52295041Sbr * Where, a) and b) can be partially computed in parallel.
53295041Sbr *
54295041Sbr * The algorithm above is found on "Hacker's Delight" by
55295041Sbr * Henry S. Warren, Jr.
56295041Sbr */
57295041Sbr
58295041Sbr/* Magic numbers for the algorithm */
59295041Sbr#if LONG_BIT == 32
60295041Sbrstatic const unsigned long mask01 = 0x01010101;
61295041Sbrstatic const unsigned long mask80 = 0x80808080;
62295041Sbr#elif LONG_BIT == 64
63295041Sbrstatic const unsigned long mask01 = 0x0101010101010101;
64295041Sbrstatic const unsigned long mask80 = 0x8080808080808080;
65295972Sbr#else
66295041Sbr#error Unsupported word size
67295041Sbr#endif
68295041Sbr
69295041Sbr#define	LONGPTR_MASK (sizeof(long) - 1)
70295041Sbr
71295041Sbr/*
72295041Sbr * Helper macro to return string length if we caught the zero
73295041Sbr * byte.
74295041Sbr */
75295041Sbr#define testbyte(x)				\
76295041Sbr	do {					\
77295041Sbr		if (p[x] == '\0')		\
78295041Sbr		    return (p - str + x);	\
79295041Sbr	} while (0)
80295041Sbr
81295041Sbrsize_t
82295041Sbrstrlen(const char *str)
83295041Sbr{
84295041Sbr	const char *p;
85295041Sbr	const unsigned long *lp;
86295041Sbr	long va, vb;
87295041Sbr
88295041Sbr	/*
89295041Sbr	 * Before trying the hard (unaligned byte-by-byte access) way
90295041Sbr	 * to figure out whether there is a nul character, try to see
91295041Sbr	 * if there is a nul character is within this accessible word
92295041Sbr	 * first.
93295041Sbr	 *
94295041Sbr	 * p and (p & ~LONGPTR_MASK) must be equally accessible since
95295041Sbr	 * they always fall in the same memory page, as long as page
96295041Sbr	 * boundaries is integral multiple of word size.
97295041Sbr	 */
98295041Sbr	lp = (const unsigned long *)((uintptr_t)str & ~LONGPTR_MASK);
99295041Sbr	va = (*lp - mask01);
100295041Sbr	vb = ((~*lp) & mask80);
101295041Sbr	lp++;
102295041Sbr	if (va & vb)
103295041Sbr		/* Check if we have \0 in the first part */
104295041Sbr		for (p = str; p < (const char *)lp; p++)
105295041Sbr			if (*p == '\0')
106295041Sbr				return (p - str);
107295041Sbr
108295041Sbr	/* Scan the rest of the string using word sized operation */
109295041Sbr	for (; ; lp++) {
110295041Sbr		va = (*lp - mask01);
111295041Sbr		vb = ((~*lp) & mask80);
112295041Sbr		if (va & vb) {
113295041Sbr			p = (const char *)(lp);
114295041Sbr			testbyte(0);
115295041Sbr			testbyte(1);
116295041Sbr			testbyte(2);
117295041Sbr			testbyte(3);
118295041Sbr#if (LONG_BIT >= 64)
119295041Sbr			testbyte(4);
120295041Sbr			testbyte(5);
121295041Sbr			testbyte(6);
122295041Sbr			testbyte(7);
123295041Sbr#endif
124295041Sbr		}
125295041Sbr	}
126295041Sbr
127295041Sbr	/* NOTREACHED */
128295041Sbr	return (0);
129295972Sbr}
130295972Sbr