Skip to content

Commit f26c0d0

Browse files
authored
[libc] Implemented wcsdup libc function (#150453)
Implemented wcsdup by templating internal strdup function
1 parent 4f2686e commit f26c0d0

File tree

8 files changed

+130
-3
lines changed

8 files changed

+130
-3
lines changed

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ set(TARGET_LIBC_ENTRYPOINTS
377377
libc.src.wchar.wcsrchr
378378
libc.src.wchar.wcsspn
379379
libc.src.wchar.wcscspn
380+
libc.src.wchar.wcsdup
380381
libc.src.wchar.wmemcmp
381382
libc.src.wchar.wmempcpy
382383
libc.src.wchar.wmemcpy

libc/include/wchar.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,12 @@ functions:
226226
arguments:
227227
- type: wchar_t *__restrict
228228
- type: const wchar_t *__restrict
229+
- name: wcsdup
230+
standards:
231+
- stdc
232+
return_type: wchar_t *
233+
arguments:
234+
- type: const wchar_t *
229235
- name: wcslcpy
230236
standards:
231237
- stdc

libc/src/string/allocating_string_utils.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@
2020
namespace LIBC_NAMESPACE_DECL {
2121
namespace internal {
2222

23-
LIBC_INLINE cpp::optional<char *> strdup(const char *src) {
23+
template <typename T> LIBC_INLINE cpp::optional<T *> strdup(const T *src) {
2424
if (src == nullptr)
2525
return cpp::nullopt;
2626
size_t len = string_length(src) + 1;
2727
AllocChecker ac;
28-
char *newstr = new (ac) char[len];
28+
T *newstr = new (ac) T[len];
2929
if (!ac)
3030
return cpp::nullopt;
31-
inline_memcpy(newstr, src, len);
31+
inline_memcpy(newstr, src, len * sizeof(T));
3232
return newstr;
3333
}
3434

libc/src/wchar/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,19 @@ add_entrypoint_object(
255255
libc.hdr.wchar_macros
256256
)
257257

258+
add_entrypoint_object(
259+
wcsdup
260+
SRCS
261+
wcsdup.cpp
262+
HDRS
263+
wcsdup.h
264+
DEPENDS
265+
libc.hdr.types.wchar_t
266+
libc.src.__support.libc_errno
267+
libc.src.__support.macros.config
268+
libc.src.string.allocating_string_utils
269+
)
270+
258271
add_entrypoint_object(
259272
wcspbrk
260273
SRCS

libc/src/wchar/wcsdup.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===-- Implementation of wcsdup -----------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/wchar/wcsdup.h"
10+
#include "hdr/types/wchar_t.h"
11+
#include "src/__support/common.h"
12+
#include "src/__support/libc_errno.h"
13+
#include "src/__support/macros/config.h"
14+
#include "src/string/allocating_string_utils.h"
15+
16+
namespace LIBC_NAMESPACE_DECL {
17+
18+
LLVM_LIBC_FUNCTION(wchar_t *, wcsdup, (const wchar_t *wcs)) {
19+
auto dup = internal::strdup(wcs);
20+
if (dup)
21+
return *dup;
22+
if (wcs != nullptr)
23+
libc_errno = ENOMEM;
24+
return nullptr;
25+
}
26+
27+
} // namespace LIBC_NAMESPACE_DECL

libc/src/wchar/wcsdup.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===-- Implementation header for wcsdup ----------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_WCHAR_WCSDUP_H
10+
#define LLVM_LIBC_SRC_WCHAR_WCSDUP_H
11+
12+
#include "hdr/types/wchar_t.h"
13+
#include "src/__support/macros/config.h"
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
wchar_t *wcsdup(const wchar_t *wcs);
18+
19+
} // namespace LIBC_NAMESPACE_DECL
20+
21+
#endif // LLVM_LIBC_SRC_WCHAR_WCSDUP_H

libc/test/src/wchar/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ add_libc_test(
2424
libc.src.wchar.wcsnlen
2525
)
2626

27+
add_libc_test(
28+
wcsdup_test
29+
SUITE
30+
libc_wchar_unittests
31+
SRCS
32+
wcsdup_test.cpp
33+
DEPENDS
34+
libc.hdr.types.wchar_t
35+
libc.src.wchar.wcsdup
36+
)
37+
2738
add_libc_test(
2839
btowc_test
2940
SUITE

libc/test/src/wchar/wcsdup_test.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//===-- Unittests for wcsdup ----------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "hdr/types/wchar_t.h"
10+
#include "src/wchar/wcsdup.h"
11+
#include "test/UnitTest/ErrnoCheckingTest.h"
12+
#include "test/UnitTest/Test.h"
13+
14+
using LlvmLibcWcsDupTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
15+
16+
TEST_F(LlvmLibcWcsDupTest, EmptyString) {
17+
const wchar_t *empty = L"";
18+
19+
wchar_t *result = LIBC_NAMESPACE::wcsdup(empty);
20+
ASSERT_ERRNO_SUCCESS();
21+
22+
ASSERT_NE(result, static_cast<wchar_t *>(nullptr));
23+
ASSERT_NE(empty, const_cast<const wchar_t *>(result));
24+
ASSERT_TRUE(empty[0] == result[0]);
25+
::free(result);
26+
}
27+
28+
TEST_F(LlvmLibcWcsDupTest, AnyString) {
29+
const wchar_t *abc = L"abc";
30+
31+
wchar_t *result = LIBC_NAMESPACE::wcsdup(abc);
32+
ASSERT_ERRNO_SUCCESS();
33+
34+
ASSERT_NE(result, static_cast<wchar_t *>(nullptr));
35+
ASSERT_NE(abc, const_cast<const wchar_t *>(result));
36+
ASSERT_TRUE(abc[0] == result[0]);
37+
ASSERT_TRUE(abc[1] == result[1]);
38+
ASSERT_TRUE(abc[2] == result[2]);
39+
ASSERT_TRUE(abc[3] == result[3]);
40+
::free(result);
41+
}
42+
43+
TEST_F(LlvmLibcWcsDupTest, NullPtr) {
44+
wchar_t *result = LIBC_NAMESPACE::wcsdup(nullptr);
45+
ASSERT_ERRNO_SUCCESS();
46+
47+
ASSERT_EQ(result, static_cast<wchar_t *>(nullptr));
48+
}

0 commit comments

Comments
 (0)