[libc] Implement str{,n}casecmp

Differential Revision: https://reviews.llvm.org/D141236
This commit is contained in:
Alex Brachet 2023-01-11 05:38:33 +00:00
parent fae63a9a22
commit e9d571d3b6
20 changed files with 288 additions and 5 deletions

View File

@ -31,6 +31,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@ -39,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy

View File

@ -31,6 +31,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@ -39,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy

View File

@ -30,6 +30,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@ -38,6 +39,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy

View File

@ -40,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@ -51,6 +52,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy

View File

@ -31,6 +31,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@ -39,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy

View File

@ -40,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@ -52,6 +53,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy

View File

@ -31,6 +31,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@ -39,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy

View File

@ -18,6 +18,25 @@ def BsdExtensions : StandardSpec<"BSDExtensions"> {
]
>;
HeaderSpec Strings = HeaderSpec<
"strings.h",
[], // Macros
[], // Types
[], // Enumerations
[
FunctionSpec<
"strcasecmp",
RetValSpec<IntType>,
[ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>]
>,
FunctionSpec<
"strncasecmp",
RetValSpec<IntType>,
[ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>, ArgSpec<SizeTType>]
>,
]
>;
HeaderSpec SysWait = HeaderSpec<
"sys/wait.h",
[], // Macros
@ -34,6 +53,7 @@ def BsdExtensions : StandardSpec<"BSDExtensions"> {
let Headers = [
String,
Strings,
SysWait,
];
}

View File

@ -36,6 +36,12 @@ static constexpr bool isspace(unsigned ch) {
return ch == ' ' || (ch - '\t') < 5;
}
static constexpr int tolower(int ch) {
if (isupper(ch))
return ch + ('a' - 'A');
return ch;
}
} // namespace internal
} // namespace __llvm_libc

View File

@ -15,10 +15,6 @@ namespace __llvm_libc {
// TODO: Currently restricted to default locale.
// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, tolower, (int c)) {
if (internal::isupper(c))
return c + ('a' - 'A');
return c;
}
LLVM_LIBC_FUNCTION(int, tolower, (int c)) { return internal::tolower(c); }
} // namespace __llvm_libc

View File

@ -115,6 +115,17 @@ add_entrypoint_object(
.memory_utils.strcmp_implementation
)
add_entrypoint_object(
strcasecmp
SRCS
strcasecmp.cpp
HDRS
strcasecmp.h
DEPENDS
.memory_utils.strcmp_implementation
libc.src.__support.ctype_utils
)
add_entrypoint_object(
strcoll
SRCS
@ -232,6 +243,17 @@ add_entrypoint_object(
.memory_utils.strcmp_implementation
)
add_entrypoint_object(
strncasecmp
SRCS
strncasecmp.cpp
HDRS
strncasecmp.h
DEPENDS
.memory_utils.strcmp_implementation
libc.src.__support.ctype_utils
)
add_entrypoint_object(
strncpy
SRCS

View File

@ -0,0 +1,25 @@
//===-- Implementation of strcasecmp --------------------------------------===//
//
// 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/string/strcasecmp.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/string/memory_utils/strcmp_implementations.h"
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(int, strcasecmp, (const char *left, const char *right)) {
auto case_cmp = [](char a, char b) {
return __llvm_libc::internal::tolower(a) -
__llvm_libc::internal::tolower(b);
};
return strcmp_implementation(left, right, case_cmp);
}
} // namespace __llvm_libc

View File

@ -0,0 +1,18 @@
//===-- Implementation header for strcasecmp --------------------*- C++ -*-===//
//
// 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_STRING_STRCASECMP_H
#define LLVM_LIBC_SRC_STRING_STRCASECMP_H
namespace __llvm_libc {
int strcasecmp(const char *left, const char *right);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_STRING_STRCASECMP_H

View File

@ -0,0 +1,26 @@
//===-- Implementation of strncasecmp -------------------------------------===//
//
// 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/string/strncasecmp.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/string/memory_utils/strcmp_implementations.h"
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(int, strncasecmp,
(const char *left, const char *right, size_t n)) {
auto case_cmp = [](char a, char b) {
return __llvm_libc::internal::tolower(a) -
__llvm_libc::internal::tolower(b);
};
return strncmp_implementation(left, right, n, case_cmp);
}
} // namespace __llvm_libc

View File

@ -0,0 +1,20 @@
//===-- Implementation header for strcasecmp --------------------*- C++ -*-===//
//
// 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_STRING_STRCASECMP_H
#define LLVM_LIBC_SRC_STRING_STRCASECMP_H
#include <stddef.h>
namespace __llvm_libc {
int strncasecmp(const char *left, const char *right, size_t n);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_STRING_STRCASECMP_H

View File

@ -104,6 +104,16 @@ add_libc_unittest(
libc.src.string.strcmp
)
add_libc_unittest(
strcasecmp_test
SUITE
libc_string_unittests
SRCS
strcasecmp_test.cpp
DEPENDS
libc.src.string.strcasecmp
)
add_libc_unittest(
strcoll_test
SUITE
@ -218,6 +228,16 @@ add_libc_unittest(
libc.src.string.strncmp
)
add_libc_unittest(
strncasecmp_test
SUITE
libc_string_unittests
SRCS
strncasecmp_test.cpp
DEPENDS
libc.src.string.strncasecmp
)
add_libc_unittest(
strncpy_test
SUITE

View File

@ -0,0 +1,46 @@
//===-- Unittests for strcasecmp ------------------------------------------===//
//
// 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/string/strcasecmp.h"
#include "utils/UnitTest/Test.h"
TEST(LlvmLibcStrCaseCmpTest, EmptyStringsShouldReturnZero) {
const char *s1 = "";
const char *s2 = "";
int result = __llvm_libc::strcasecmp(s1, s2);
ASSERT_EQ(result, 0);
// Verify operands reversed.
result = __llvm_libc::strcasecmp(s2, s1);
ASSERT_EQ(result, 0);
}
TEST(LlvmLibcStrCaseCmpTest, EmptyStringShouldNotEqualNonEmptyString) {
const char *empty = "";
const char *s2 = "abc";
int result = __llvm_libc::strcasecmp(empty, s2);
// This should be '\0' - 'a' = -97
ASSERT_LT(result, 0);
// Similar case if empty string is second argument.
const char *s3 = "123";
result = __llvm_libc::strcasecmp(s3, empty);
// This should be '1' - '\0' = 49
ASSERT_GT(result, 0);
}
TEST(LlvmLibcStrCaseCmpTest, Case) {
const char *s1 = "aB";
const char *s2 = "ab";
int result = __llvm_libc::strcasecmp(s1, s2);
ASSERT_EQ(result, 0);
// Verify operands reversed.
result = __llvm_libc::strcasecmp(s2, s1);
ASSERT_EQ(result, 0);
}

View File

@ -95,3 +95,14 @@ TEST(LlvmLibcStrCmpTest, StringArgumentSwapChangesSign) {
// 'a' - 'b' = -1.
ASSERT_EQ(result, -1);
}
TEST(LlvmLibcStrCmpTest, Case) {
const char *s1 = "aB";
const char *s2 = "ab";
int result = __llvm_libc::strcmp(s1, s2);
ASSERT_LT(result, 0);
// Verify operands reversed.
result = __llvm_libc::strcmp(s2, s1);
ASSERT_GT(result, 0);
}

View File

@ -0,0 +1,48 @@
//===-- Unittests for strncasecmp -----------------------------------------===//
//
// 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/string/strncasecmp.h"
#include "utils/UnitTest/Test.h"
TEST(LlvmLibcStrNCaseCmpTest,
EmptyStringsShouldReturnZeroWithSufficientLength) {
const char *s1 = "";
const char *s2 = "";
int result = __llvm_libc::strncasecmp(s1, s2, 1);
ASSERT_EQ(result, 0);
// Verify operands reversed.
result = __llvm_libc::strncasecmp(s2, s1, 1);
ASSERT_EQ(result, 0);
}
TEST(LlvmLibcStrNCaseCmpTest,
EmptyStringShouldNotEqualNonEmptyStringWithSufficientLength) {
const char *empty = "";
const char *s2 = "abc";
int result = __llvm_libc::strncasecmp(empty, s2, 3);
// This should be '\0' - 'a' = -97
ASSERT_LT(result, 0);
// Similar case if empty string is second argument.
const char *s3 = "123";
result = __llvm_libc::strncasecmp(s3, empty, 3);
// This should be '1' - '\0' = 49
ASSERT_GT(result, 0);
}
TEST(LlvmLibcStrNCaseCmpTest, Case) {
const char *s1 = "aB";
const char *s2 = "ab";
int result = __llvm_libc::strncasecmp(s1, s2, 2);
ASSERT_EQ(result, 0);
// Verify operands reversed.
result = __llvm_libc::strncasecmp(s2, s1, 2);
ASSERT_EQ(result, 0);
}

View File

@ -156,3 +156,14 @@ TEST(LlvmLibcStrNCmpTest, StringComparisonEndsOnNullByteEvenWithLongerLength) {
result = __llvm_libc::strncmp(s2, s1, 7);
ASSERT_EQ(result, 0);
}
TEST(LlvmLibcStrNCmpTest, Case) {
const char *s1 = "aB";
const char *s2 = "ab";
int result = __llvm_libc::strncmp(s1, s2, 2);
ASSERT_LT(result, 0);
// Verify operands reversed.
result = __llvm_libc::strncmp(s2, s1, 2);
ASSERT_GT(result, 0);
}