[libc-commits] [libc] 32a5007 - [libc] Add an implementation of bsearch.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Wed Sep 22 09:37:19 PDT 2021


Author: Siva Chandra Reddy
Date: 2021-09-22T16:37:03Z
New Revision: 32a50078657dd8beead327a3478ede4e9d730432

URL: https://github.com/llvm/llvm-project/commit/32a50078657dd8beead327a3478ede4e9d730432
DIFF: https://github.com/llvm/llvm-project/commit/32a50078657dd8beead327a3478ede4e9d730432.diff

LOG: [libc] Add an implementation of bsearch.

Reviewed By: michaelrj

Differential Revision: https://reviews.llvm.org/D110222

Added: 
    libc/src/stdlib/bsearch.cpp
    libc/src/stdlib/bsearch.h
    libc/test/src/stdlib/bsearch_test.cpp

Modified: 
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/api.td
    libc/config/linux/x86_64/entrypoints.txt
    libc/spec/spec.td
    libc/spec/stdc.td
    libc/src/stdlib/CMakeLists.txt
    libc/test/src/stdlib/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 20583ea19dc21..619e628e5d3a7 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -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

diff  --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 757469b0de91a..095f25faa521c 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -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
   ];
 }
 

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 503bd9a9056a2..7c87b6fb81a8f 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -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

diff  --git a/libc/spec/spec.td b/libc/spec/spec.td
index 9bb2925e84651..40ab413c2a939 100644
--- a/libc/spec/spec.td
+++ b/libc/spec/spec.td
@@ -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">;
 

diff  --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 46f56a44068c6..9889436a5fafb 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -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>]>,

diff  --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index c058a936795ce..f46a6b9c6413f 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -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()

diff  --git a/libc/src/stdlib/bsearch.cpp b/libc/src/stdlib/bsearch.cpp
new file mode 100644
index 0000000000000..a298e516ae701
--- /dev/null
+++ b/libc/src/stdlib/bsearch.cpp
@@ -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

diff  --git a/libc/src/stdlib/bsearch.h b/libc/src/stdlib/bsearch.h
new file mode 100644
index 0000000000000..6cab8f736dea0
--- /dev/null
+++ b/libc/src/stdlib/bsearch.h
@@ -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

diff  --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt
index 4eb8526d4e52d..e39130650d433 100644
--- a/libc/test/src/stdlib/CMakeLists.txt
+++ b/libc/test/src/stdlib/CMakeLists.txt
@@ -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
+)

diff  --git a/libc/test/src/stdlib/bsearch_test.cpp b/libc/test/src/stdlib/bsearch_test.cpp
new file mode 100644
index 0000000000000..6076e47f9ab99
--- /dev/null
+++ b/libc/test/src/stdlib/bsearch_test.cpp
@@ -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]);
+}


        


More information about the libc-commits mailing list