diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt --- a/libc/src/string/CMakeLists.txt +++ b/libc/src/string/CMakeLists.txt @@ -16,8 +16,7 @@ strcat.h DEPENDS .strcpy - .strlen - libc.include.string + .string_utils ) add_entrypoint_object( @@ -28,8 +27,7 @@ strcpy.h DEPENDS .memcpy - .strlen - libc.include.string + .string_utils ) add_entrypoint_object( @@ -56,6 +54,8 @@ memchr.cpp HDRS memchr.h + DEPENDS + .string_utils ) add_entrypoint_object( @@ -81,7 +81,7 @@ HDRS strnlen.h DEPENDS - .memchr + .string_utils ) add_entrypoint_object( diff --git a/libc/src/string/memchr.cpp b/libc/src/string/memchr.cpp --- a/libc/src/string/memchr.cpp +++ b/libc/src/string/memchr.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "src/string/memchr.h" +#include "src/string/string_utils.h" + #include "src/__support/common.h" #include @@ -14,11 +16,8 @@ // TODO: Look at performance benefits of comparing words. void *LLVM_LIBC_ENTRYPOINT(memchr)(const void *src, int c, size_t n) { - const unsigned char *str = reinterpret_cast(src); - const unsigned char ch = c; - for (; n && *str != ch; --n, ++str) - ; - return n ? const_cast(str) : nullptr; + return internal::find_first_character( + reinterpret_cast(src), c, n); } } // namespace __llvm_libc diff --git a/libc/src/string/strcat.cpp b/libc/src/string/strcat.cpp --- a/libc/src/string/strcat.cpp +++ b/libc/src/string/strcat.cpp @@ -8,7 +8,7 @@ #include "src/string/strcat.h" #include "src/string/strcpy.h" -#include "src/string/strlen.h" +#include "src/string/string_utils.h" #include "src/__support/common.h" @@ -16,7 +16,7 @@ char *LLVM_LIBC_ENTRYPOINT(strcat)(char *__restrict dest, const char *__restrict src) { - __llvm_libc::strcpy(dest + __llvm_libc::strlen(dest), src); + __llvm_libc::strcpy(dest + internal::string_length(dest), src); return dest; } diff --git a/libc/src/string/strcpy.cpp b/libc/src/string/strcpy.cpp --- a/libc/src/string/strcpy.cpp +++ b/libc/src/string/strcpy.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "src/string/strcpy.h" -#include "src/string/strlen.h" #include "src/string/memcpy.h" +#include "src/string/string_utils.h" #include "src/__support/common.h" @@ -17,7 +17,7 @@ char *LLVM_LIBC_ENTRYPOINT(strcpy)(char *__restrict dest, const char *__restrict src) { return reinterpret_cast( - __llvm_libc::memcpy(dest, src, __llvm_libc::strlen(src) + 1)); + __llvm_libc::memcpy(dest, src, internal::string_length(src) + 1)); } } // namespace __llvm_libc diff --git a/libc/src/string/string_utils.h b/libc/src/string/string_utils.h --- a/libc/src/string/string_utils.h +++ b/libc/src/string/string_utils.h @@ -15,6 +15,24 @@ namespace __llvm_libc { namespace internal { +// Returns the length of a string, denoted by the first occurrence +// of a null terminator. +static inline size_t string_length(const char *src) { + size_t length; + for (length = 0; *src; ++src, ++length) + ; + return length; +} + +// Returns the first occurrence of 'ch' within the first 'n' characters of +// 'src'. If 'ch' is not found, returns nullptr. +static inline void *find_first_character(const unsigned char *src, + unsigned char ch, size_t n) { + for (; n && *src != ch; --n, ++src) + ; + return n ? const_cast(src) : nullptr; +} + // Returns the maximum length span that contains only characters not found in // 'segment'. If no characters are found, returns the length of 'src'. static inline size_t complementary_span(const char *src, const char *segment) { diff --git a/libc/src/string/strlen.cpp b/libc/src/string/strlen.cpp --- a/libc/src/string/strlen.cpp +++ b/libc/src/string/strlen.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/string/strlen.h" +#include "src/string/string_utils.h" #include "src/__support/common.h" @@ -15,10 +16,7 @@ // TODO: investigate the performance of this function. // There might be potential for compiler optimization. size_t LLVM_LIBC_ENTRYPOINT(strlen)(const char *src) { - const char *end = src; - while (*end != '\0') - ++end; - return end - src; + return internal::string_length(src); } } // namespace __llvm_libc diff --git a/libc/src/string/strnlen.cpp b/libc/src/string/strnlen.cpp --- a/libc/src/string/strnlen.cpp +++ b/libc/src/string/strnlen.cpp @@ -7,17 +7,17 @@ //===----------------------------------------------------------------------===// #include "src/string/strnlen.h" +#include "src/string/string_utils.h" #include "src/__support/common.h" -#include "src/string/memchr.h" #include namespace __llvm_libc { size_t LLVM_LIBC_ENTRYPOINT(strnlen)(const char *src, size_t n) { - const char *temp = - reinterpret_cast(__llvm_libc::memchr(src, '\0', n)); - return temp ? temp - src : n; + const void *temp = internal::find_first_character( + reinterpret_cast(src), '\0', n); + return temp ? reinterpret_cast(temp) - src : n; } } // namespace __llvm_libc