forked from OSchip/llvm-project
[libc] Add an implementation of bsearch.
Reviewed By: michaelrj Differential Revision: https://reviews.llvm.org/D110222
This commit is contained in:
parent
1aedf77ece
commit
32a5007865
|
@ -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
|
||||
|
|
|
@ -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
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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">;
|
||||
|
||||
|
|
|
@ -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>]>,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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]);
|
||||
}
|
Loading…
Reference in New Issue