diff --git a/libc/config/gpu/amdgpu/entrypoints.txt b/libc/config/gpu/amdgpu/entrypoints.txt index 7a1982808dfeb..756b2cdc7496e 100644 --- a/libc/config/gpu/amdgpu/entrypoints.txt +++ b/libc/config/gpu/amdgpu/entrypoints.txt @@ -261,6 +261,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.time.nanosleep # wchar.h entrypoints + libc.src.wchar.wcslen libc.src.wchar.wctob # locale.h entrypoints diff --git a/libc/config/gpu/nvptx/entrypoints.txt b/libc/config/gpu/nvptx/entrypoints.txt index 059dc9b20d6dd..6b25dae158cc9 100644 --- a/libc/config/gpu/nvptx/entrypoints.txt +++ b/libc/config/gpu/nvptx/entrypoints.txt @@ -261,6 +261,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.time.nanosleep # wchar.h entrypoints + libc.src.wchar.wcslen libc.src.wchar.wctob # locale.h entrypoints diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index f5ba341411768..8bf47fa952cd9 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -350,6 +350,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.unistd.write # wchar.h entrypoints + libc.src.wchar.wcslen libc.src.wchar.wctob # sys/uio.h entrypoints diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index 49a8d61b93802..f9ab28c2598d5 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -346,6 +346,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.unistd.write # wchar.h entrypoints + libc.src.wchar.wcslen libc.src.wchar.wctob ) diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 0c1ae9561a7e6..3db9a911c59fe 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -349,8 +349,9 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.unistd.write # wchar.h entrypoints - libc.src.wchar.wctob libc.src.wchar.btowc + libc.src.wchar.wcslen + libc.src.wchar.wctob # sys/uio.h entrypoints libc.src.sys.uio.writev diff --git a/libc/include/wchar.yaml b/libc/include/wchar.yaml index 27a5926b57455..5bbf8064c713c 100644 --- a/libc/include/wchar.yaml +++ b/libc/include/wchar.yaml @@ -9,6 +9,12 @@ types: enums: [] objects: [] functions: + - name: wcslen + standards: + - stdc + return_type: size_t + arguments: + - type: const wchar_t * - name: wctob standards: - stdc diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt index e3faa543e630c..2c607bf8ea895 100644 --- a/libc/src/string/CMakeLists.txt +++ b/libc/src/string/CMakeLists.txt @@ -17,9 +17,11 @@ add_header_library( DEPENDS .memory_utils.inline_bzero .memory_utils.inline_memcpy + libc.hdr.types.size_t libc.include.stdlib - libc.src.__support.common libc.src.__support.CPP.bitset + libc.src.__support.CPP.type_traits + libc.src.__support.common ${string_config_options} ) diff --git a/libc/src/string/string_utils.h b/libc/src/string/string_utils.h index fc617bd18e8f6..583d35014d398 100644 --- a/libc/src/string/string_utils.h +++ b/libc/src/string/string_utils.h @@ -14,12 +14,13 @@ #ifndef LLVM_LIBC_SRC_STRING_STRING_UTILS_H #define LLVM_LIBC_SRC_STRING_STRING_UTILS_H +#include "hdr/types/size_t.h" #include "src/__support/CPP/bitset.h" +#include "src/__support/CPP/type_traits.h" // cpp::is_same_v #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY #include "src/string/memory_utils/inline_bzero.h" #include "src/string/memory_utils/inline_memcpy.h" -#include // For size_t namespace LIBC_NAMESPACE_DECL { namespace internal { @@ -79,24 +80,21 @@ LIBC_INLINE size_t string_length_wide_read(const char *src) { return char_ptr - src; } -LIBC_INLINE size_t string_length_byte_read(const char *src) { - size_t length; - for (length = 0; *src; ++src, ++length) - ; - return length; -} - // Returns the length of a string, denoted by the first occurrence // of a null terminator. -LIBC_INLINE size_t string_length(const char *src) { +template LIBC_INLINE size_t string_length(const T *src) { #ifdef LIBC_COPT_STRING_UNSAFE_WIDE_READ // Unsigned int is the default size for most processors, and on x86-64 it // performs better than larger sizes when the src pointer can't be assumed to // be aligned to a word boundary, so it's the size we use for reading the // string a block at a time. - return string_length_wide_read(src); + if constexpr (cpp::is_same_v) + return string_length_wide_read(src); #else - return string_length_byte_read(src); + size_t length; + for (length = 0; *src; ++src, ++length) + ; + return length; #endif } diff --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt index d4c98ea527a8f..703db75b5b194 100644 --- a/libc/src/wchar/CMakeLists.txt +++ b/libc/src/wchar/CMakeLists.txt @@ -1,3 +1,14 @@ +add_entrypoint_object( + wcslen + SRCS + wcslen.cpp + HDRS + wcslen.h + DEPENDS + libc.hdr.types.size_t + libc.hdr.types.wchar_t + libc.src.string.string_utils +) add_entrypoint_object( wctob diff --git a/libc/src/wchar/wcslen.cpp b/libc/src/wchar/wcslen.cpp new file mode 100644 index 0000000000000..5889e27f9729e --- /dev/null +++ b/libc/src/wchar/wcslen.cpp @@ -0,0 +1,23 @@ +//===-- Implementation of wcslen ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/wchar/wcslen.h" + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/string/string_utils.h" // string_length_trivial + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(size_t, wcslen, (const wchar_t *src)) { + return internal::string_length(src); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/wchar/wcslen.h b/libc/src/wchar/wcslen.h new file mode 100644 index 0000000000000..8b2e7f50b007e --- /dev/null +++ b/libc/src/wchar/wcslen.h @@ -0,0 +1,22 @@ +//===-- Implementation header for wcslen ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_WCHAR_WCSLEN_H +#define LLVM_LIBC_SRC_WCHAR_WCSLEN_H + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +size_t wcslen(const wchar_t *src); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCSLEN_H diff --git a/libc/test/src/wchar/CMakeLists.txt b/libc/test/src/wchar/CMakeLists.txt index 3cc404b9c86fc..d41e328fc9d90 100644 --- a/libc/test/src/wchar/CMakeLists.txt +++ b/libc/test/src/wchar/CMakeLists.txt @@ -1,5 +1,17 @@ add_custom_target(libc_wchar_unittests) +add_libc_test( + wcslen_test + SUITE + libc_wchar_unittests + SRCS + wcslen_test.cpp + DEPENDS + libc.hdr.types.size_t + libc.hdr.types.wchar_t + libc.src.wchar.wcslen +) + add_libc_test( btowc_test SUITE diff --git a/libc/test/src/wchar/wcslen_test.cpp b/libc/test/src/wchar/wcslen_test.cpp new file mode 100644 index 0000000000000..9cf446564c07e --- /dev/null +++ b/libc/test/src/wchar/wcslen_test.cpp @@ -0,0 +1,20 @@ +//===-- Unittests for wcslen ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/wchar/wcslen.h" +#include "test/UnitTest/Test.h" + +TEST(LlvmLibcWCSLenTest, EmptyString) { + ASSERT_EQ(size_t{0}, LIBC_NAMESPACE::wcslen(L"")); +} + +TEST(LlvmLibcWCSLenTest, AnyString) { + ASSERT_EQ(size_t{12}, LIBC_NAMESPACE::wcslen(L"Hello World!")); +}