Skip to content

Commit dabe983

Browse files
authored
[libc] Implemented wcsrchr (llvm#142436)
fixes llvm#124347 Implemented wcsrchr and added tests
1 parent 62af2a5 commit dabe983

File tree

7 files changed

+148
-0
lines changed

7 files changed

+148
-0
lines changed

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ set(TARGET_LIBC_ENTRYPOINTS
368368
libc.src.wchar.wcschr
369369
libc.src.wchar.wcscmp
370370
libc.src.wchar.wcspbrk
371+
libc.src.wchar.wcsrchr
371372
libc.src.wchar.wcsspn
372373
libc.src.wchar.wmemcmp
373374
libc.src.wchar.wmempcpy

libc/include/wchar.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ functions:
5656
arguments:
5757
- type: const wchar_t *
5858
- type: const wchar_t *
59+
- name: wcsrchr
60+
standards:
61+
- stdc
62+
return_type: const wchar_t *
63+
arguments:
64+
- type: const wchar_t *
65+
- type: wchar_t
5966
- name: wcsspn
6067
standards:
6168
- stdc

libc/src/wchar/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,16 @@ add_entrypoint_object(
7878
libc.src.__support.wctype_utils
7979
)
8080

81+
add_entrypoint_object(
82+
wcsrchr
83+
SRCS
84+
wcsrchr.cpp
85+
HDRS
86+
wcsrchr.h
87+
DEPENDS
88+
libc.hdr.wchar_macros
89+
)
90+
8191
add_entrypoint_object(
8292
wcsspn
8393
SRCS

libc/src/wchar/wcsrchr.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===-- Implementation of wcsrchr -----------------------------------------===//
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/wcsrchr.h"
10+
11+
#include "hdr/types/wchar_t.h"
12+
#include "src/__support/common.h"
13+
#include "src/__support/macros/config.h"
14+
#include "src/__support/macros/null_check.h"
15+
16+
namespace LIBC_NAMESPACE_DECL {
17+
18+
LLVM_LIBC_FUNCTION(const wchar_t *, wcsrchr, (const wchar_t *s, wchar_t c)) {
19+
LIBC_CRASH_ON_NULLPTR(s);
20+
21+
const wchar_t *last_occurrence = nullptr;
22+
while (true) {
23+
if (*s == c)
24+
last_occurrence = s;
25+
if (*s == L'\0')
26+
return last_occurrence;
27+
++s;
28+
}
29+
}
30+
31+
} // namespace LIBC_NAMESPACE_DECL

libc/src/wchar/wcsrchr.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===-- Implementation header for wcsrchr ---------------------------------===//
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_WCSRCHR_H
10+
#define LLVM_LIBC_SRC_WCHAR_WCSRCHR_H
11+
12+
#include "hdr/types/wchar_t.h"
13+
#include "src/__support/macros/config.h"
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
const wchar_t *wcsrchr(const wchar_t *s, wchar_t c);
18+
19+
} // namespace LIBC_NAMESPACE_DECL
20+
21+
#endif // LLVM_LIBC_SRC_WCHAR_WCSRCHR_H

libc/test/src/wchar/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ add_libc_test(
7575
libc.src.wchar.wcspbrk
7676
)
7777

78+
add_libc_test(
79+
wcsrchr_test
80+
SUITE
81+
libc_wchar_unittests
82+
SRCS
83+
wcsrchr_test.cpp
84+
DEPENDS
85+
libc.src.wchar.wcsrchr
86+
)
87+
7888
add_libc_test(
7989
wcsspn_test
8090
SUITE

libc/test/src/wchar/wcsrchr_test.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//===-- Unittests for wcsrchr ---------------------------------------------===//
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/wcsrchr.h"
11+
#include "test/UnitTest/Test.h"
12+
13+
TEST(LlvmLibcWCSRChrTest, FindsFirstCharacter) {
14+
// Should return pointer to original string since 'a' is the first character.
15+
const wchar_t *src = L"abcde";
16+
ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'a'), src);
17+
}
18+
19+
TEST(LlvmLibcWCSRChrTest, FindsMiddleCharacter) {
20+
// Should return pointer to 'c'.
21+
const wchar_t *src = L"abcde";
22+
ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'c'), (src + 2));
23+
}
24+
25+
TEST(LlvmLibcWCSRChrTest, FindsLastCharacterThatIsNotNullTerminator) {
26+
// Should return pointer to 'e'.
27+
const wchar_t *src = L"abcde";
28+
ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'e'), (src + 4));
29+
}
30+
31+
TEST(LlvmLibcWCSRChrTest, FindsNullTerminator) {
32+
// Should return pointer to null terminator.
33+
const wchar_t *src = L"abcde";
34+
ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'\0'), (src + 5));
35+
}
36+
37+
TEST(LlvmLibcWCSRChrTest, CharacterNotWithinStringShouldReturnNullptr) {
38+
// Since 'z' is not within the string, should return nullptr.
39+
const wchar_t *src = L"abcde";
40+
ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'z'), nullptr);
41+
}
42+
43+
TEST(LlvmLibcWCSRChrTest, ShouldFindLastOfDuplicates) {
44+
// Should return pointer to the last '1'.
45+
const wchar_t *src = L"abc1def1ghi";
46+
ASSERT_EQ((int)(LIBC_NAMESPACE::wcsrchr(src, L'1') - src), 7);
47+
48+
// Should return pointer to the last 'X'
49+
const wchar_t *dups = L"XXXXX";
50+
ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(dups, L'X'), dups + 4);
51+
}
52+
53+
TEST(LlvmLibcWCSRChrTest, EmptyStringShouldOnlyMatchNullTerminator) {
54+
// Null terminator should match
55+
const wchar_t *src = L"";
56+
ASSERT_EQ(src, LIBC_NAMESPACE::wcsrchr(src, L'\0'));
57+
// All other characters should not match
58+
ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'Z'), nullptr);
59+
ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'3'), nullptr);
60+
ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'*'), nullptr);
61+
}
62+
63+
#if defined(LIBC_ADD_NULL_CHECKS) && !defined(LIBC_HAS_SANITIZER)
64+
TEST(LlvmLibcWCSRChrTest, NullptrCrash) {
65+
// Passing in a nullptr should crash the program.
66+
EXPECT_DEATH([] { LIBC_NAMESPACE::wcsrchr(nullptr, L'a'); }, WITH_SIGNAL(-1));
67+
}
68+
#endif // LIBC_HAS_ADDRESS_SANITIZER

0 commit comments

Comments
 (0)