Skip to content

Commit e3d1a33

Browse files
sribee8Sriya Pratipati
andauthored
[libc] wcsstr implementation (llvm#142440)
Implemented wcsstr and tests. fixes llvm#124348 --------- Co-authored-by: Sriya Pratipati <[email protected]>
1 parent 883130e commit e3d1a33

File tree

7 files changed

+202
-0
lines changed

7 files changed

+202
-0
lines changed

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ set(TARGET_LIBC_ENTRYPOINTS
373373
libc.src.wchar.wmemcmp
374374
libc.src.wchar.wmempcpy
375375
libc.src.wchar.wmemcpy
376+
libc.src.wchar.wcsstr
376377
libc.src.wchar.wcsncat
377378
libc.src.wchar.wcscpy
378379

libc/include/wchar.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ functions:
9494
- type: __restrict wchar_t *
9595
- type: const __restrict wchar_t *
9696
- type: size_t
97+
- name: wcsstr
98+
standards:
99+
- stdc
100+
return_type: const wchar_t *
101+
arguments:
102+
- type: const wchar_t *
103+
- type: const wchar_t *
97104
- name: wcsncat
98105
standards:
99106
- stdc

libc/src/wchar/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,18 @@ add_entrypoint_object(
126126
libc.src.__support.wctype_utils
127127
)
128128

129+
add_entrypoint_object(
130+
wcsstr
131+
SRCS
132+
wcsstr.cpp
133+
HDRS
134+
wcsstr.h
135+
DEPENDS
136+
libc.hdr.types.size_t
137+
libc.hdr.wchar_macros
138+
libc.src.string.string_utils
139+
)
140+
129141
add_entrypoint_object(
130142
wcsncat
131143
SRCS

libc/src/wchar/wcsstr.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===-- Implementation of wcsstr ------------------------------------------===//
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/wcsstr.h"
10+
11+
#include "hdr/types/size_t.h"
12+
#include "hdr/types/wchar_t.h"
13+
#include "src/__support/common.h"
14+
#include "src/__support/macros/config.h"
15+
#include "src/string/string_utils.h"
16+
17+
namespace LIBC_NAMESPACE_DECL {
18+
19+
LLVM_LIBC_FUNCTION(const wchar_t *, wcsstr,
20+
(const wchar_t *s1, const wchar_t *s2)) {
21+
size_t s1_len = internal::string_length(s1);
22+
size_t s2_len = internal::string_length(s2);
23+
if (s2_len == 0)
24+
return s1;
25+
if (s2_len > s1_len)
26+
return nullptr;
27+
for (size_t i = 0; i <= (s1_len - s2_len); ++i) {
28+
size_t j = 0;
29+
// j will increment until the characters don't match or end of string.
30+
for (; j < s2_len && s1[i + j] == s2[j]; ++j)
31+
;
32+
if (j == s2_len)
33+
return (s1 + i);
34+
}
35+
return nullptr;
36+
}
37+
38+
} // namespace LIBC_NAMESPACE_DECL

libc/src/wchar/wcsstr.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===-- Implementation header for wcsstr ----------------------------------===//
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_WCSSTR_H
10+
#define LLVM_LIBC_SRC_WCHAR_WCSSTR_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 *wcsstr(const wchar_t *s1, const wchar_t *s2);
18+
19+
} // namespace LIBC_NAMESPACE_DECL
20+
21+
#endif // LLVM_LIBC_SRC_WCHAR_WCSSTR_H

libc/test/src/wchar/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,16 @@ add_libc_test(
125125
libc.src.wchar.wmemcpy
126126
)
127127

128+
add_libc_test(
129+
wcsstr_test
130+
SUITE
131+
libc_wchar_unittests
132+
SRCS
133+
wcsstr_test.cpp
134+
DEPENDS
135+
libc.src.wchar.wcsstr
136+
)
137+
128138
add_libc_test(
129139
wcsncat_test
130140
SUITE

libc/test/src/wchar/wcsstr_test.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//===-- Unittests for wcsstr ----------------------------------------------===//
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/wcsstr.h"
11+
#include "test/UnitTest/Test.h"
12+
13+
TEST(LlvmLibcWCSStrTest, NeedleNotInHaystack) {
14+
// Should return nullptr if string is not found.
15+
const wchar_t *haystack = L"12345";
16+
const wchar_t *needle = L"a";
17+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), nullptr);
18+
}
19+
20+
TEST(LlvmLibcWCSStrTest, NeedleIsEmptyString) {
21+
// Should return pointer to first character if needle is empty.
22+
const wchar_t *haystack = L"12345";
23+
const wchar_t *needle = L"";
24+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack);
25+
}
26+
27+
TEST(LlvmLibcWCSStrTest, HaystackIsEmptyString) {
28+
// Should return nullptr since haystack is empty.
29+
const wchar_t *needle = L"12345";
30+
const wchar_t *haystack = L"";
31+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), nullptr);
32+
}
33+
34+
TEST(LlvmLibcWCSStrTest, HaystackAndNeedleAreEmptyStrings) {
35+
// Should point to haystack since needle is empty.
36+
const wchar_t *needle = L"";
37+
const wchar_t *haystack = L"";
38+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack);
39+
}
40+
41+
TEST(LlvmLibcWCSStrTest, HaystackAndNeedleAreSingleCharacters) {
42+
const wchar_t *haystack = L"a";
43+
// Should point to haystack.
44+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"a"), haystack);
45+
// Should return nullptr.
46+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"b"), nullptr);
47+
}
48+
49+
TEST(LlvmLibcWCSStrTest, NeedleEqualToHaystack) {
50+
const wchar_t *haystack = L"12345";
51+
// Should point to haystack.
52+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"12345"), haystack);
53+
}
54+
55+
TEST(LlvmLibcWCSStrTest, NeedleLargerThanHaystack) {
56+
const wchar_t *haystack = L"123";
57+
// Should return nullptr.
58+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"12345"), nullptr);
59+
}
60+
61+
TEST(LlvmLibcWCSStrTest, NeedleAtBeginning) {
62+
const wchar_t *haystack = L"12345";
63+
const wchar_t *needle = L"12";
64+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack);
65+
}
66+
67+
TEST(LlvmLibcWCSStrTest, NeedleInMiddle) {
68+
const wchar_t *haystack = L"abcdefghi";
69+
const wchar_t *needle = L"def";
70+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack + 3);
71+
}
72+
73+
TEST(LlvmLibcWCSStrTest, NeedleDirectlyBeforeNullTerminator) {
74+
const wchar_t *haystack = L"abcdefghi";
75+
const wchar_t *needle = L"ghi";
76+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack + 6);
77+
}
78+
79+
TEST(LlvmLibcWCSStrTest, NeedlePastNullTerminator) {
80+
const wchar_t haystack[5] = {L'1', L'2', L'\0', L'3', L'4'};
81+
// Shouldn't find anything after the null terminator.
82+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, /*needle=*/L"3"), nullptr);
83+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, /*needle=*/L"4"), nullptr);
84+
}
85+
86+
TEST(LlvmLibcWCSStrTest, PartialNeedle) {
87+
const wchar_t *haystack = L"la_ap_lap";
88+
const wchar_t *needle = L"lap";
89+
// Shouldn't find la or ap.
90+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack + 6);
91+
}
92+
93+
TEST(LlvmLibcWCSStrTest, MisspelledNeedle) {
94+
const wchar_t *haystack = L"atalloftwocities...wait, tale";
95+
const wchar_t *needle = L"tale";
96+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack + 25);
97+
}
98+
99+
TEST(LlvmLibcWCSStrTest, AnagramNeedle) {
100+
const wchar_t *haystack = L"dgo_ogd_god_odg_gdo_dog";
101+
const wchar_t *needle = L"dog";
102+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack + 20);
103+
}
104+
105+
TEST(LlvmLibcWCSStrTest, MorphedNeedle) {
106+
// Changes a single letter in the needle to mismatch with the haystack.
107+
const wchar_t *haystack = L"once upon a time";
108+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"time"), haystack + 12);
109+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"lime"), nullptr);
110+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"tome"), nullptr);
111+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"tire"), nullptr);
112+
ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"timo"), nullptr);
113+
}

0 commit comments

Comments
 (0)