Skip to content

Commit c6d03b5

Browse files
[libc] add strncmp to strings
Add strncmp as a function to strings.h. Also adds unit tests, and adds strncmp as an entrypoint for all current platforms. Reviewed By: sivachandra Differential Revision: https://reviews.llvm.org/D106901
1 parent 87aa318 commit c6d03b5

File tree

8 files changed

+231
-0
lines changed

8 files changed

+231
-0
lines changed

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ set(TARGET_LIBC_ENTRYPOINTS
3434
libc.src.string.strcmp
3535
libc.src.string.strcspn
3636
libc.src.string.strlen
37+
libc.src.string.strncmp
3738
libc.src.string.strncpy
3839
libc.src.string.strnlen
3940
libc.src.string.strpbrk

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ set(TARGET_LIBC_ENTRYPOINTS
3434
libc.src.string.strcpy
3535
libc.src.string.strcspn
3636
libc.src.string.strlen
37+
libc.src.string.strncmp
3738
libc.src.string.strncpy
3839
libc.src.string.strnlen
3940
libc.src.string.strpbrk

libc/config/windows/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ set(TARGET_LIBC_ENTRYPOINTS
3030
libc.src.string.strcmp
3131
libc.src.string.strcspn
3232
libc.src.string.strlen
33+
libc.src.string.strncmp
3334
libc.src.string.strncpy
3435
libc.src.string.strnlen
3536
libc.src.string.strpbrk

libc/src/string/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ add_entrypoint_object(
4848
strcmp.h
4949
)
5050

51+
add_entrypoint_object(
52+
strncmp
53+
SRCS
54+
strncmp.cpp
55+
HDRS
56+
strncmp.h
57+
)
58+
5159
add_entrypoint_object(
5260
memchr
5361
SRCS

libc/src/string/strncmp.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//===-- Implementation of strncmp -----------------------------------------===//
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/string/strncmp.h"
10+
11+
#include "src/__support/common.h"
12+
#include <stddef.h>
13+
14+
namespace __llvm_libc {
15+
16+
// TODO: Look at benefits for comparing words at a time.
17+
LLVM_LIBC_FUNCTION(int, strncmp,
18+
(const char *left, const char *right, size_t n)) {
19+
20+
if (n == 0)
21+
return 0;
22+
23+
for (; n > 1; --n, ++left, ++right) {
24+
char lc = *left;
25+
if (lc == '\0' || lc != *right)
26+
break;
27+
}
28+
return *reinterpret_cast<const unsigned char *>(left) -
29+
*reinterpret_cast<const unsigned char *>(right);
30+
}
31+
32+
} // namespace __llvm_libc

libc/src/string/strncmp.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===-- Implementation header for strncmp -----------------------*- C++ -*-===//
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_STRING_STRNCMP_H
10+
#define LLVM_LIBC_SRC_STRING_STRNCMP_H
11+
12+
#include <stddef.h>
13+
14+
namespace __llvm_libc {
15+
16+
int strncmp(const char *left, const char *right, size_t n);
17+
18+
} // namespace __llvm_libc
19+
20+
#endif // LLVM_LIBC_SRC_STRING_STRNCMP_H

libc/test/src/string/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ add_libc_unittest(
4242
libc.src.string.strcmp
4343
)
4444

45+
add_libc_unittest(
46+
strncmp_test
47+
SUITE
48+
libc_string_unittests
49+
SRCS
50+
strncmp_test.cpp
51+
DEPENDS
52+
libc.src.string.strncmp
53+
)
54+
4555
add_libc_unittest(
4656
memchr_test
4757
SUITE

libc/test/src/string/strncmp_test.cpp

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
//===-- Unittests for strncmp ---------------------------------------------===//
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/string/strncmp.h"
10+
#include "utils/UnitTest/Test.h"
11+
12+
// This group is just copies of the strcmp tests, since all the same cases still
13+
// need to be tested.
14+
15+
TEST(LlvmLibcStrNCmpTest, EmptyStringsShouldReturnZeroWithSufficientLength) {
16+
const char *s1 = "";
17+
const char *s2 = "";
18+
int result = __llvm_libc::strncmp(s1, s2, 1);
19+
ASSERT_EQ(result, 0);
20+
21+
// Verify operands reversed.
22+
result = __llvm_libc::strncmp(s2, s1, 1);
23+
ASSERT_EQ(result, 0);
24+
}
25+
26+
TEST(LlvmLibcStrNCmpTest,
27+
EmptyStringShouldNotEqualNonEmptyStringWithSufficientLength) {
28+
const char *empty = "";
29+
const char *s2 = "abc";
30+
int result = __llvm_libc::strncmp(empty, s2, 3);
31+
// This should be '\0' - 'a' = -97
32+
ASSERT_EQ(result, -97);
33+
34+
// Similar case if empty string is second argument.
35+
const char *s3 = "123";
36+
result = __llvm_libc::strncmp(s3, empty, 3);
37+
// This should be '1' - '\0' = 49
38+
ASSERT_EQ(result, 49);
39+
}
40+
41+
TEST(LlvmLibcStrNCmpTest, EqualStringsShouldReturnZeroWithSufficientLength) {
42+
const char *s1 = "abc";
43+
const char *s2 = "abc";
44+
int result = __llvm_libc::strncmp(s1, s2, 3);
45+
ASSERT_EQ(result, 0);
46+
47+
// Verify operands reversed.
48+
result = __llvm_libc::strncmp(s2, s1, 3);
49+
ASSERT_EQ(result, 0);
50+
}
51+
52+
TEST(LlvmLibcStrNCmpTest,
53+
ShouldReturnResultOfFirstDifferenceWithSufficientLength) {
54+
const char *s1 = "___B42__";
55+
const char *s2 = "___C55__";
56+
int result = __llvm_libc::strncmp(s1, s2, 8);
57+
// This should return 'B' - 'C' = -1.
58+
ASSERT_EQ(result, -1);
59+
60+
// Verify operands reversed.
61+
result = __llvm_libc::strncmp(s2, s1, 8);
62+
// This should return 'C' - 'B' = 1.
63+
ASSERT_EQ(result, 1);
64+
}
65+
66+
TEST(LlvmLibcStrNCmpTest,
67+
CapitalizedLetterShouldNotBeEqualWithSufficientLength) {
68+
const char *s1 = "abcd";
69+
const char *s2 = "abCd";
70+
int result = __llvm_libc::strncmp(s1, s2, 4);
71+
// 'c' - 'C' = 32.
72+
ASSERT_EQ(result, 32);
73+
74+
// Verify operands reversed.
75+
result = __llvm_libc::strncmp(s2, s1, 4);
76+
// 'C' - 'c' = -32.
77+
ASSERT_EQ(result, -32);
78+
}
79+
80+
TEST(LlvmLibcStrNCmpTest,
81+
UnequalLengthStringsShouldNotReturnZeroWithSufficientLength) {
82+
const char *s1 = "abc";
83+
const char *s2 = "abcd";
84+
int result = __llvm_libc::strncmp(s1, s2, 4);
85+
// '\0' - 'd' = -100.
86+
ASSERT_EQ(result, -100);
87+
88+
// Verify operands reversed.
89+
result = __llvm_libc::strncmp(s2, s1, 4);
90+
// 'd' - '\0' = 100.
91+
ASSERT_EQ(result, 100);
92+
}
93+
94+
TEST(LlvmLibcStrNCmpTest, StringArgumentSwapChangesSignWithSufficientLength) {
95+
const char *a = "a";
96+
const char *b = "b";
97+
int result = __llvm_libc::strncmp(b, a, 1);
98+
// 'b' - 'a' = 1.
99+
ASSERT_EQ(result, 1);
100+
101+
result = __llvm_libc::strncmp(a, b, 1);
102+
// 'a' - 'b' = -1.
103+
ASSERT_EQ(result, -1);
104+
}
105+
106+
// This group is actually testing strncmp functionality
107+
108+
TEST(LlvmLibcStrNCmpTest, NonEqualStringsEqualWithLengthZero) {
109+
const char *s1 = "abc";
110+
const char *s2 = "def";
111+
int result = __llvm_libc::strncmp(s1, s2, 0);
112+
ASSERT_EQ(result, 0);
113+
114+
// Verify operands reversed.
115+
result = __llvm_libc::strncmp(s2, s1, 0);
116+
ASSERT_EQ(result, 0);
117+
}
118+
119+
TEST(LlvmLibcStrNCmpTest, NonEqualStringsNotEqualWithLengthOne) {
120+
const char *s1 = "abc";
121+
const char *s2 = "def";
122+
int result = __llvm_libc::strncmp(s1, s2, 1);
123+
ASSERT_EQ(result, -3);
124+
125+
// Verify operands reversed.
126+
result = __llvm_libc::strncmp(s2, s1, 1);
127+
ASSERT_EQ(result, 3);
128+
}
129+
130+
TEST(LlvmLibcStrNCmpTest, NonEqualStringsEqualWithShorterLength) {
131+
const char *s1 = "___B42__";
132+
const char *s2 = "___C55__";
133+
int result = __llvm_libc::strncmp(s1, s2, 3);
134+
ASSERT_EQ(result, 0);
135+
136+
// This should return 'B' - 'C' = -1.
137+
result = __llvm_libc::strncmp(s1, s2, 4);
138+
ASSERT_EQ(result, -1);
139+
140+
// Verify operands reversed.
141+
result = __llvm_libc::strncmp(s2, s1, 3);
142+
ASSERT_EQ(result, 0);
143+
144+
// This should return 'C' - 'B' = 1.
145+
result = __llvm_libc::strncmp(s2, s1, 4);
146+
ASSERT_EQ(result, 1);
147+
}
148+
149+
TEST(LlvmLibcStrNCmpTest, StringComparisonEndsOnNullByteEvenWithLongerLength) {
150+
const char *s1 = "abc\0def";
151+
const char *s2 = "abc\0abc";
152+
int result = __llvm_libc::strncmp(s1, s2, 7);
153+
ASSERT_EQ(result, 0);
154+
155+
// Verify operands reversed.
156+
result = __llvm_libc::strncmp(s2, s1, 7);
157+
ASSERT_EQ(result, 0);
158+
}

0 commit comments

Comments
 (0)