[libc] Add an implementation of bsearch.

Reviewed By: michaelrj

Differential Revision: https://reviews.llvm.org/D110222
This commit is contained in:
Siva Chandra Reddy 2021-09-21 23:53:30 +00:00
parent 1aedf77ece
commit 32a5007865
10 changed files with 178 additions and 0 deletions

View File

@ -55,6 +55,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdlib.atoi
libc.src.stdlib.atol
libc.src.stdlib.atoll
libc.src.stdlib.bsearch
libc.src.stdlib.div
libc.src.stdlib.labs
libc.src.stdlib.ldiv

View File

@ -281,11 +281,19 @@ def LLDivT : TypeDecl<"lldiv_t"> {
}];
}
def BSearchCompareTDefn : TypeDecl<"__bsearchcompare_t"> {
let Decl = [{
typedef int(*__bsearchcompare_t)(const void *, const void *);
}];
}
def StdlibAPI : PublicAPI<"stdlib.h"> {
let TypeDeclarations = [
DivT,
LDivT,
LLDivT,
SizeT,
BSearchCompareTDefn
];
}

View File

@ -55,6 +55,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdlib.atoi
libc.src.stdlib.atol
libc.src.stdlib.atoll
libc.src.stdlib.bsearch
libc.src.stdlib.div
libc.src.stdlib.labs
libc.src.stdlib.ldiv

View File

@ -91,6 +91,8 @@ def SigHandlerT : NamedType<"__sighandler_t">;
def TimeTType : NamedType<"time_t">;
def BSearchCompareT : NamedType<"__bsearchcompare_t">;
//added because __assert_fail needs it.
def UnsignedType : NamedType<"unsigned">;

View File

@ -479,11 +479,15 @@ def StdC : StandardSpec<"stdc"> {
DivTType,
LDivTType,
LLDivTType,
SizeTType,
BSearchCompareT,
], // Types
[], // Enumerations
[
FunctionSpec<"abort", RetValSpec<NoReturn>, [ArgSpec<VoidType>]>,
FunctionSpec<"bsearch", RetValSpec<VoidPtr>, [ArgSpec<ConstVoidPtr>, ArgSpec<ConstVoidPtr>, ArgSpec<SizeTType>, ArgSpec<SizeTType>, ArgSpec<BSearchCompareT>]>,
FunctionSpec<"abs", RetValSpec<IntType>, [ArgSpec<IntType>]>,
FunctionSpec<"labs", RetValSpec<LongType>, [ArgSpec<LongType>]>,
FunctionSpec<"llabs", RetValSpec<LongLongType>, [ArgSpec<LongLongType>]>,

View File

@ -131,6 +131,16 @@ add_entrypoint_object(
libc.src.__support.integer_operations
)
add_entrypoint_object(
bsearch
SRCS
bsearch.cpp
HDRS
bsearch.h
DEPENDS
libc.include.stdlib
)
if(NOT LLVM_LIBC_FULL_BUILD)
return()
endif()

View File

@ -0,0 +1,47 @@
//===-- Implementation of bsearch -----------------------------------------===//
//
// 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/stdlib/bsearch.h"
#include "src/__support/common.h"
#include <stdint.h>
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(void *, bsearch,
(const void *key, const void *array, size_t array_size,
size_t elem_size,
int (*compare)(const void *, const void *))) {
if (key == nullptr || array == nullptr || array_size == 0 || elem_size == 0)
return nullptr;
while (array_size > 0) {
size_t mid = array_size / 2;
const void *elem =
reinterpret_cast<const uint8_t *>(array) + mid * elem_size;
int compare_result = compare(key, elem);
if (compare_result == 0)
return const_cast<void *>(elem);
if (compare_result < 0) {
// This means that key is less than the element at |mid|.
// So, in the next iteration, we only compare elements less
// than mid.
array_size = mid;
} else {
// |mid| is strictly less than |array_size|. So, the below
// decrement in |array_size| will not lead to a wrap around.
array_size -= (mid + 1);
array = reinterpret_cast<const uint8_t *>(elem) + elem_size;
}
}
return nullptr;
}
} // namespace __llvm_libc

16
libc/src/stdlib/bsearch.h Normal file
View File

@ -0,0 +1,16 @@
//===-- Implementation header for bsearch -----------------------*- 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
//
//===----------------------------------------------------------------------===//
#include <stdlib.h>
namespace __llvm_libc {
void *bsearch(const void *key, const void *array, size_t array_size,
size_t elem_size, int (*compare)(const void *, const void *));
} // namespace __llvm_libc

View File

@ -167,3 +167,14 @@ add_libc_unittest(
libc.include.stdlib
libc.src.stdlib.lldiv
)
add_libc_unittest(
bsearch_test
SUITE
libc_stdlib_unittests
SRCS
bsearch_test.cpp
DEPENDS
libc.include.stdlib
libc.src.stdlib.bsearch
)

View File

@ -0,0 +1,78 @@
//===-- Unittests for bsearch ---------------------------------------------===//
//
// 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/stdlib/bsearch.h"
#include "utils/UnitTest/Test.h"
#include <stdlib.h>
static int int_compare(const void *l, const void *r) {
int li = *reinterpret_cast<const int *>(l);
int ri = *reinterpret_cast<const int *>(r);
if (li == ri)
return 0;
else if (li > ri)
return 1;
else
return -1;
}
TEST(LlvmLibcBsearchTest, ErrorInputs) {
int val = 123;
EXPECT_TRUE(__llvm_libc::bsearch(nullptr, &val, 1, sizeof(int),
int_compare) == nullptr);
EXPECT_TRUE(__llvm_libc::bsearch(&val, nullptr, 1, sizeof(int),
int_compare) == nullptr);
EXPECT_TRUE(__llvm_libc::bsearch(&val, &val, 0, sizeof(int), int_compare) ==
nullptr);
EXPECT_TRUE(__llvm_libc::bsearch(&val, &val, 1, 0, int_compare) == nullptr);
}
TEST(LlvmLibcBsearchTest, IntegerArray) {
constexpr int array[25] = {10, 23, 33, 35, 55, 70, 71,
100, 110, 123, 133, 135, 155, 170,
171, 1100, 1110, 1123, 1133, 1135, 1155,
1170, 1171, 11100, 12310};
constexpr size_t array_size = sizeof(array) / sizeof(int);
for (size_t s = 1; s <= array_size; ++s) {
for (size_t i = 0; i < s; ++i) {
int key = array[i];
void *elem =
__llvm_libc::bsearch(&key, array, s, sizeof(int), int_compare);
ASSERT_EQ(*reinterpret_cast<int *>(elem), key);
}
}
// Non existent keys
for (size_t s = 1; s <= array_size; ++s) {
int key = 5;
ASSERT_TRUE(__llvm_libc::bsearch(&key, &array, s, sizeof(int),
int_compare) == nullptr);
key = 125;
ASSERT_TRUE(__llvm_libc::bsearch(&key, &array, s, sizeof(int),
int_compare) == nullptr);
key = 136;
ASSERT_TRUE(__llvm_libc::bsearch(&key, &array, s, sizeof(int),
int_compare) == nullptr);
key = 12345;
ASSERT_TRUE(__llvm_libc::bsearch(&key, &array, s, sizeof(int),
int_compare) == nullptr);
}
}
TEST(LlvmLibcBsearchTest, SameKeyAndArray) {
constexpr int array[5] = {1, 2, 3, 4, 5};
constexpr size_t array_size = sizeof(array) / sizeof(int);
void *elem =
__llvm_libc::bsearch(array, array, array_size, sizeof(int), int_compare);
EXPECT_EQ(*reinterpret_cast<int *>(elem), array[0]);
}