strlen.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /*-
  2. * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  3. *
  4. * Copyright (c) 2009, 2010 Xin LI <delphij@FreeBSD.org>
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  16. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. * SUCH DAMAGE.
  26. */
  27. #include <sys/cdefs.h>
  28. __FBSDID("$FreeBSD$");
  29. #include <sys/libkern.h>
  30. #include <sys/limits.h>
  31. /*
  32. * Portable strlen() for 32-bit and 64-bit systems.
  33. *
  34. * Rationale: it is generally much more efficient to do word length
  35. * operations and avoid branches on modern computer systems, as
  36. * compared to byte-length operations with a lot of branches.
  37. *
  38. * The expression:
  39. *
  40. * ((x - 0x01....01) & ~x & 0x80....80)
  41. *
  42. * would evaluate to a non-zero value iff any of the bytes in the
  43. * original word is zero.
  44. *
  45. * On multi-issue processors, we can divide the above expression into:
  46. * a) (x - 0x01....01)
  47. * b) (~x & 0x80....80)
  48. * c) a & b
  49. *
  50. * Where, a) and b) can be partially computed in parallel.
  51. *
  52. * The algorithm above is found on "Hacker's Delight" by
  53. * Henry S. Warren, Jr.
  54. */
  55. /* Magic numbers for the algorithm */
  56. #if LONG_BIT == 32
  57. static const unsigned long mask01 = 0x01010101;
  58. static const unsigned long mask80 = 0x80808080;
  59. #elif LONG_BIT == 64
  60. static const unsigned long mask01 = 0x0101010101010101;
  61. static const unsigned long mask80 = 0x8080808080808080;
  62. #else
  63. #error Unsupported word size
  64. #endif
  65. #define LONGPTR_MASK (sizeof(long) - 1)
  66. /*
  67. * Helper macro to return string length if we caught the zero
  68. * byte.
  69. */
  70. #define testbyte(x) \
  71. do { \
  72. if (p[x] == '\0') \
  73. return (p - str + x); \
  74. } while (0)
  75. size_t
  76. (strlen)(const char *str)
  77. {
  78. const char *p;
  79. const unsigned long *lp;
  80. long va, vb;
  81. /*
  82. * Before trying the hard (unaligned byte-by-byte access) way
  83. * to figure out whether there is a nul character, try to see
  84. * if there is a nul character is within this accessible word
  85. * first.
  86. *
  87. * p and (p & ~LONGPTR_MASK) must be equally accessible since
  88. * they always fall in the same memory page, as long as page
  89. * boundaries is integral multiple of word size.
  90. */
  91. lp = (const unsigned long *)((uintptr_t)str & ~LONGPTR_MASK);
  92. va = (*lp - mask01);
  93. vb = ((~*lp) & mask80);
  94. lp++;
  95. if (va & vb)
  96. /* Check if we have \0 in the first part */
  97. for (p = str; p < (const char *)lp; p++)
  98. if (*p == '\0')
  99. return (p - str);
  100. /* Scan the rest of the string using word sized operation */
  101. for (; ; lp++) {
  102. va = (*lp - mask01);
  103. vb = ((~*lp) & mask80);
  104. if (va & vb) {
  105. p = (const char *)(lp);
  106. testbyte(0);
  107. testbyte(1);
  108. testbyte(2);
  109. testbyte(3);
  110. #if (LONG_BIT >= 64)
  111. testbyte(4);
  112. testbyte(5);
  113. testbyte(6);
  114. testbyte(7);
  115. #endif
  116. }
  117. }
  118. /* NOTREACHED */
  119. return (0);
  120. }