[libc-commits] [libc] [libc] Implement `search/lsearch` (PR #131431)

Connector Switch via libc-commits libc-commits at lists.llvm.org
Mon Mar 17 10:13:06 PDT 2025


https://github.com/c8ef updated https://github.com/llvm/llvm-project/pull/131431

>From e2a2d3700a79b23f135374e246baecac142371d5 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Sat, 15 Mar 2025 05:38:18 +0000
Subject: [PATCH 1/2] implement lsearch

---
 libc/config/linux/aarch64/entrypoints.txt |  1 +
 libc/config/linux/x86_64/entrypoints.txt  |  1 +
 libc/include/search.yaml                  | 10 +++++
 libc/src/search/CMakeLists.txt            | 13 ++++++
 libc/src/search/lfind.cpp                 |  2 +-
 libc/src/search/lsearch.cpp               | 39 ++++++++++++++++++
 libc/src/search/lsearch.h                 | 20 ++++++++++
 libc/test/src/search/CMakeLists.txt       | 10 +++++
 libc/test/src/search/lsearch_test.cpp     | 48 +++++++++++++++++++++++
 9 files changed, 143 insertions(+), 1 deletion(-)
 create mode 100644 libc/src/search/lsearch.cpp
 create mode 100644 libc/src/search/lsearch.h
 create mode 100644 libc/test/src/search/lsearch_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index ab1917259519b..c1e688ea7e86b 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -999,6 +999,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.search.hsearch_r
     libc.src.search.insque
     libc.src.search.lfind
+    libc.src.search.lsearch
     libc.src.search.remque
 
     # threads.h entrypoints
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a29478898fe70..3cb9ee82752b3 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1113,6 +1113,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.search.hsearch_r
     libc.src.search.insque
     libc.src.search.lfind
+    libc.src.search.lsearch
     libc.src.search.remque
 
     # threads.h entrypoints
diff --git a/libc/include/search.yaml b/libc/include/search.yaml
index b7ce06d48e704..f6f5d6cb062e5 100644
--- a/libc/include/search.yaml
+++ b/libc/include/search.yaml
@@ -69,3 +69,13 @@ functions:
       - type: size_t *
       - type: size_t
       - type: __lsearchcompare_t
+  - name: lsearch
+    standards:
+      - POSIX
+    return_type: void *
+    arguments:
+      - type: const void *
+      - type: void *
+      - type: size_t *
+      - type: size_t
+      - type: __lsearchcompare_t
diff --git a/libc/src/search/CMakeLists.txt b/libc/src/search/CMakeLists.txt
index 497657f40f2f0..d78ea062342a1 100644
--- a/libc/src/search/CMakeLists.txt
+++ b/libc/src/search/CMakeLists.txt
@@ -110,3 +110,16 @@ add_entrypoint_object(
     libc.src.__support.CPP.cstddef
     libc.src.__support.memory_size
 )
+
+add_entrypoint_object(
+  lsearch
+  SRCS
+    lsearch.cpp
+  HDRS
+    lsearch.h
+  DEPENDS
+    libc.include.search
+    libc.src.__support.CPP.cstddef
+    libc.src.__support.memory_size
+    libc.src.string.memory_utils.inline_memcpy
+)
diff --git a/libc/src/search/lfind.cpp b/libc/src/search/lfind.cpp
index c8bf07de0b903..b10065aef2a93 100644
--- a/libc/src/search/lfind.cpp
+++ b/libc/src/search/lfind.cpp
@@ -1,4 +1,4 @@
-//===-- Implementation of lfind   -------------------------------*- C++ -*-===//
+//===-- Implementation of lfind ---------------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/src/search/lsearch.cpp b/libc/src/search/lsearch.cpp
new file mode 100644
index 0000000000000..e28dc3488413d
--- /dev/null
+++ b/libc/src/search/lsearch.cpp
@@ -0,0 +1,39 @@
+//===-- Implementation of lsearch -------------------------------*- 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 "src/search/lsearch.h"
+#include "src/__support/CPP/cstddef.h" // cpp::byte
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/memory_size.h"
+#include "src/string/memory_utils/inline_memcpy.h"
+
+namespace LIBC_NAMESPACE_DECL {
+LLVM_LIBC_FUNCTION(void *, lsearch,
+                   (const void *key, void *base, size_t *nmemb, size_t size,
+                    int (*compar)(const void *, const void *))) {
+  if (key == nullptr || base == nullptr || nmemb == nullptr ||
+      compar == nullptr)
+    return nullptr;
+
+  size_t byte_len = 0;
+  if (internal::mul_overflow(*nmemb, size, &byte_len))
+    return nullptr;
+
+  const cpp::byte *next = reinterpret_cast<const cpp::byte *>(base);
+  const cpp::byte *end = next + byte_len;
+  for (; next < end; next += size)
+    if (compar(key, next) == 0)
+      return const_cast<cpp::byte *>(next);
+
+  *nmemb += 1;
+  inline_memcpy(const_cast<cpp::byte *>(end), key, size);
+  return const_cast<cpp::byte *>(end);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/search/lsearch.h b/libc/src/search/lsearch.h
new file mode 100644
index 0000000000000..c95e01d396cd0
--- /dev/null
+++ b/libc/src/search/lsearch.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for lsearch -----------------------*- 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_SEARCH_LSEARCH_H
+#define LLVM_LIBC_SRC_SEARCH_LSEARCH_H
+
+#include "src/__support/macros/config.h"
+#include <stddef.h> // size_t
+
+namespace LIBC_NAMESPACE_DECL {
+void *lsearch(const void *key, void *base, size_t *nmemb, size_t size,
+              int (*compar)(const void *, const void *));
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SEARCH_LSEARCH_H
diff --git a/libc/test/src/search/CMakeLists.txt b/libc/test/src/search/CMakeLists.txt
index a1f9aac2094c9..9f34d4d3fd259 100644
--- a/libc/test/src/search/CMakeLists.txt
+++ b/libc/test/src/search/CMakeLists.txt
@@ -35,3 +35,13 @@ add_libc_unittest(
   DEPENDS
     libc.src.search.lfind
 )
+
+add_libc_unittest(
+  lsearch_test
+  SUITE
+    libc_search_unittests
+  SRCS
+    lsearch_test.cpp
+  DEPENDS
+    libc.src.search.lsearch
+)
diff --git a/libc/test/src/search/lsearch_test.cpp b/libc/test/src/search/lsearch_test.cpp
new file mode 100644
index 0000000000000..22ac37f18b7bd
--- /dev/null
+++ b/libc/test/src/search/lsearch_test.cpp
@@ -0,0 +1,48 @@
+//===-- Unittests for lsearch ---------------------------------------------===//
+//
+// 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/search/lsearch.h"
+#include "test/UnitTest/Test.h"
+
+int compar(const void *a, const void *b) {
+  return *reinterpret_cast<const int *>(a) != *reinterpret_cast<const int *>(b);
+}
+
+TEST(LlvmLibcLsearchTest, SearchHead) {
+  int list[3] = {1, 2, 3};
+  size_t len = 3;
+  int key = 1;
+  void *ret = LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), compar);
+  ASSERT_TRUE(ret == &list[0]);
+}
+
+TEST(LlvmLibcLsearchTest, SearchMiddle) {
+  int list[3] = {1, 2, 3};
+  size_t len = 3;
+  int key = 2;
+  void *ret = LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), compar);
+  ASSERT_TRUE(ret == &list[1]);
+}
+
+TEST(LlvmLibcLsearchTest, SearchTail) {
+  int list[3] = {1, 2, 3};
+  size_t len = 3;
+  int key = 3;
+  void *ret = LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), compar);
+  ASSERT_TRUE(ret == &list[2]);
+}
+
+TEST(LlvmLibcLsearchTest, SearchNonExistent) {
+  int list[4] = {1, 2, 3, 0};
+  size_t len = 3;
+  int key = 4;
+  void *ret = LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), compar);
+  ASSERT_TRUE(ret == &list[3]);
+  ASSERT_EQ(key, list[3]);
+  ASSERT_EQ(len, 4UL);
+}

>From 009a3e94bc49d25931374f5bf52b8a3f18f59ab5 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Mon, 17 Mar 2025 17:12:56 +0000
Subject: [PATCH 2/2] address review comments

---
 libc/test/src/search/lsearch_test.cpp | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/libc/test/src/search/lsearch_test.cpp b/libc/test/src/search/lsearch_test.cpp
index 22ac37f18b7bd..a02ff6d9685db 100644
--- a/libc/test/src/search/lsearch_test.cpp
+++ b/libc/test/src/search/lsearch_test.cpp
@@ -46,3 +46,25 @@ TEST(LlvmLibcLsearchTest, SearchNonExistent) {
   ASSERT_EQ(key, list[3]);
   ASSERT_EQ(len, 4UL);
 }
+
+TEST(LlvmLibcLsearchTest, SearchExceptional) {
+  int list[3] = {1, 2, 3};
+  size_t len = 3;
+  size_t max_len = ~0;
+  int key = 3;
+  void *ret_key =
+      LIBC_NAMESPACE::lsearch(nullptr, list, &len, sizeof(int), compar);
+  ASSERT_TRUE(ret_key == nullptr);
+  void *ret_base =
+      LIBC_NAMESPACE::lsearch(&key, nullptr, &len, sizeof(int), compar);
+  ASSERT_TRUE(ret_base == nullptr);
+  void *ret_nmemb =
+      LIBC_NAMESPACE::lsearch(&key, list, nullptr, sizeof(int), compar);
+  ASSERT_TRUE(ret_nmemb == nullptr);
+  void *ret_size =
+      LIBC_NAMESPACE::lsearch(&key, list, &max_len, sizeof(int), compar);
+  ASSERT_TRUE(ret_size == nullptr);
+  void *ret_compar =
+      LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), nullptr);
+  ASSERT_TRUE(ret_compar == nullptr);
+}



More information about the libc-commits mailing list