diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 52e746e32a1c..c1ba26008ca9 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -364,6 +364,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.wchar.btowc libc.src.wchar.wcslen libc.src.wchar.wctob + libc.src.wchar.wmemset libc.src.wchar.wcschr # sys/uio.h entrypoints diff --git a/libc/include/wchar.yaml b/libc/include/wchar.yaml index 987bdc0b806d..0342c726146b 100644 --- a/libc/include/wchar.yaml +++ b/libc/include/wchar.yaml @@ -27,6 +27,14 @@ functions: return_type: wint_t arguments: - type: int + - name: wmemset + standards: + - stdc + return_type: wchar_t* + arguments: + - type: wchar_t* + - type: wchar_t + - type: size_t - name: wcschr standards: - stdc diff --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt index 41034cab16d4..caec1a3f3266 100644 --- a/libc/src/wchar/CMakeLists.txt +++ b/libc/src/wchar/CMakeLists.txt @@ -34,6 +34,18 @@ add_entrypoint_object( libc.src.__support.wctype_utils ) +add_entrypoint_object( + wmemset + SRCS + wmemset.cpp + HDRS + wmemset.h + DEPENDS + libc.hdr.types.size_t + libc.hdr.types.wchar_t + libc.src.__support.wctype_utils +) + add_entrypoint_object( wcschr SRCS diff --git a/libc/src/wchar/wmemset.cpp b/libc/src/wchar/wmemset.cpp new file mode 100644 index 000000000000..7c99f5ce98c3 --- /dev/null +++ b/libc/src/wchar/wmemset.cpp @@ -0,0 +1,24 @@ +//===-- Implementation of wmemset -----------------------------------------===// +// +// 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/wmemset.h" + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(wchar_t *, wmemset, (wchar_t * s, wchar_t c, size_t n)) { + for (size_t i = 0; i < n; i++) + s[i] = c; + + return s; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/wchar/wmemset.h b/libc/src/wchar/wmemset.h new file mode 100644 index 000000000000..075a561e0648 --- /dev/null +++ b/libc/src/wchar/wmemset.h @@ -0,0 +1,23 @@ +//===-- Implementation header for wmemset +//----------------------------------===// +// +// 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_WMEMSET_H +#define LLVM_LIBC_SRC_WCHAR_WMEMSET_H + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +wchar_t *wmemset(wchar_t *s, wchar_t c, size_t n); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WMEMSET_H diff --git a/libc/test/src/wchar/CMakeLists.txt b/libc/test/src/wchar/CMakeLists.txt index 7d64dfeb13b6..4c75f070cf40 100644 --- a/libc/test/src/wchar/CMakeLists.txt +++ b/libc/test/src/wchar/CMakeLists.txt @@ -33,6 +33,18 @@ add_libc_test( libc.src.wchar.wctob ) +add_libc_test( + wmemset_test + SUITE + libc_wchar_unittests + SRCS + wmemset_test.cpp + DEPENDS + libc.hdr.types.size_t + libc.hdr.types.wchar_t + libc.src.wchar.wmemset +) + add_libc_test( wcschr_test SUITE diff --git a/libc/test/src/wchar/wmemset_test.cpp b/libc/test/src/wchar/wmemset_test.cpp new file mode 100644 index 000000000000..30e5458c7e72 --- /dev/null +++ b/libc/test/src/wchar/wmemset_test.cpp @@ -0,0 +1,88 @@ +//===-- Unittests for wmemset ---------------------------------------------===// +// +// 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/wmemset.h" +#include "test/UnitTest/Test.h" + +TEST(LlvmLibcWMemsetTest, SmallStringBoundCheck) { + wchar_t str[5]; + for (int i = 0; i < 5; i++) + str[i] = 'A'; + + wchar_t *output = LIBC_NAMESPACE::wmemset(str + 1, 'B', 3); + + EXPECT_EQ(output, str + 1); + + // EXPECT_TRUE being used since there isn't currently support for printing + // wide chars in the future, it would be preferred to switch these to + // EXPECT_EQ + EXPECT_TRUE(str[0] == (wchar_t)'A'); + EXPECT_TRUE(str[1] == (wchar_t)'B'); + EXPECT_TRUE(str[2] == (wchar_t)'B'); + EXPECT_TRUE(str[3] == (wchar_t)'B'); + EXPECT_TRUE(str[4] == (wchar_t)'A'); +} + +TEST(LlvmLibcWMemsetTest, LargeStringBoundCheck) { + constexpr int str_size = 1000; + wchar_t str[str_size]; + for (int i = 0; i < str_size; i++) + str[i] = 'A'; + + wchar_t *output = LIBC_NAMESPACE::wmemset(str + 1, 'B', str_size - 2); + + EXPECT_EQ(output, str + 1); + + EXPECT_TRUE(str[0] == (wchar_t)'A'); + for (int i = 1; i < str_size - 1; i++) + EXPECT_TRUE(str[i] == (wchar_t)'B'); + + EXPECT_TRUE(str[str_size - 1] == (wchar_t)'A'); +} + +TEST(LlvmLibcWMemsetTest, WCharSizeSmallString) { + // ensure we can handle full range of widechars + wchar_t str[5]; + const wchar_t target = WCHAR_MAX; + + for (int i = 0; i < 5; i++) + str[i] = 'A'; + + wchar_t *output = LIBC_NAMESPACE::wmemset(str + 1, target, 3); + + EXPECT_EQ(output, str + 1); + + EXPECT_TRUE(str[0] == (wchar_t)'A'); + EXPECT_TRUE(str[1] == target); + EXPECT_TRUE(str[2] == target); + EXPECT_TRUE(str[3] == target); + EXPECT_TRUE(str[4] == (wchar_t)'A'); +} + +TEST(LlvmLibcWMemsetTest, WCharSizeLargeString) { + // ensure we can handle full range of widechars + constexpr int str_size = 1000; + wchar_t str[str_size]; + + const wchar_t target = WCHAR_MAX; + + for (int i = 0; i < str_size; i++) + str[i] = 'A'; + + wchar_t *output = LIBC_NAMESPACE::wmemset(str + 1, target, str_size - 2); + + EXPECT_EQ(output, str + 1); + + EXPECT_TRUE(str[0] == (wchar_t)'A'); + for (int i = 1; i < str_size - 1; i++) + EXPECT_TRUE(str[i] == target); + + EXPECT_TRUE(str[str_size - 1] == (wchar_t)'A'); +}