[libc-commits] [libc] 396ed9c - [libc][search] implement posix `lfind` function (#114692)

via libc-commits libc-commits at lists.llvm.org
Mon Nov 11 09:53:25 PST 2024


Author: Duncan
Date: 2024-11-11T09:53:20-08:00
New Revision: 396ed9c2a12daffdb0349c850beb59e891e2a42b

URL: https://github.com/llvm/llvm-project/commit/396ed9c2a12daffdb0349c850beb59e891e2a42b
DIFF: https://github.com/llvm/llvm-project/commit/396ed9c2a12daffdb0349c850beb59e891e2a42b.diff

LOG: [libc][search] implement posix `lfind` function (#114692)

# Changes
- Implement the POSIX
[`lfind`](https://man7.org/linux/man-pages/man3/lsearch.3.html)
function.

- Put a checkmark in the [posix support table
docs](https://libc.llvm.org/libc_search.html) next to `lfind`.

Added: 
    libc/include/llvm-libc-types/__lsearchcompare_t.h
    libc/src/search/lfind.cpp
    libc/src/search/lfind.h
    libc/test/src/search/lfind_test.cpp

Modified: 
    libc/config/baremetal/arm/entrypoints.txt
    libc/config/baremetal/riscv/entrypoints.txt
    libc/config/darwin/arm/entrypoints.txt
    libc/config/darwin/x86_64/entrypoints.txt
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/arm/entrypoints.txt
    libc/config/linux/riscv/entrypoints.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/config/windows/entrypoints.txt
    libc/docs/libc_search.rst
    libc/include/CMakeLists.txt
    libc/include/llvm-libc-types/CMakeLists.txt
    libc/newhdrgen/yaml/search.yaml
    libc/spec/posix.td
    libc/src/search/CMakeLists.txt
    libc/test/src/search/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 68030f7f1775b5..f136711b540966 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -26,6 +26,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     # errno.h entrypoints
     libc.src.errno.errno
 
+    # search.h entrypoints
+    libc.src.search.lfind
+
     # setjmp.h entrypoints
     libc.src.setjmp.longjmp
     libc.src.setjmp.setjmp

diff  --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 5894b591072ef0..08c36ce8396784 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -26,6 +26,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     # errno.h entrypoints
     libc.src.errno.errno
 
+    # search.h entrypoints
+    libc.src.search.lfind
+
     # string.h entrypoints
     libc.src.string.bcmp
     libc.src.string.bcopy

diff  --git a/libc/config/darwin/arm/entrypoints.txt b/libc/config/darwin/arm/entrypoints.txt
index 2d5dbeff485747..13860015ae5841 100644
--- a/libc/config/darwin/arm/entrypoints.txt
+++ b/libc/config/darwin/arm/entrypoints.txt
@@ -20,6 +20,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     # errno.h entrypoints
     libc.src.errno.errno
 
+    # search.h entrypoints
+    libc.src.search.lfind 
+
     # string.h entrypoints
     libc.src.string.bcmp
     libc.src.string.bcopy

diff  --git a/libc/config/darwin/x86_64/entrypoints.txt b/libc/config/darwin/x86_64/entrypoints.txt
index 49c19571ac4192..64eeed18f3819e 100644
--- a/libc/config/darwin/x86_64/entrypoints.txt
+++ b/libc/config/darwin/x86_64/entrypoints.txt
@@ -17,6 +17,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.ctype.tolower
     libc.src.ctype.toupper
 
+    # search.h entrypoints
+    libc.src.search.lfind 
+
     # string.h entrypoints
     libc.src.string.bcmp
     libc.src.string.bzero

diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 571527426de31b..74ca3742977a5f 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -960,6 +960,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.search.hsearch
     libc.src.search.hsearch_r
     libc.src.search.insque
+    libc.src.search.lfind
     libc.src.search.remque
 
     # threads.h entrypoints

diff  --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 383bf8c8e52801..b4f08cde6df48a 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -20,6 +20,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     # errno.h entrypoints
     libc.src.errno.errno
 
+    # search.h entrypoints
+    libc.src.search.lfind  
+
     # string.h entrypoints
     libc.src.string.bcmp
     libc.src.string.bcopy

diff  --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 8108ac55838d3b..d63c5d651cc93b 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -885,6 +885,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.search.hsearch
     libc.src.search.hsearch_r
     libc.src.search.insque
+    libc.src.search.lfind
     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 bc2f7931d3f3fb..d4f552617c279a 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1025,6 +1025,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.search.hsearch
     libc.src.search.hsearch_r
     libc.src.search.insque
+    libc.src.search.lfind
     libc.src.search.remque
 
     # threads.h entrypoints

diff  --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 8f0b50bcc83ea2..5ffd32373148cd 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -17,6 +17,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.ctype.tolower
     libc.src.ctype.toupper
 
+    # search.h entrypoints
+    libc.src.search.lfind
+
     # string.h entrypoints
     libc.src.string.bcmp
     libc.src.string.bcopy

diff  --git a/libc/docs/libc_search.rst b/libc/docs/libc_search.rst
index 4a7ee288dd43e8..774622d1e66c3f 100644
--- a/libc/docs/libc_search.rst
+++ b/libc/docs/libc_search.rst
@@ -42,7 +42,7 @@ hcreate                      |check|
 hdestroy                     |check|
 hsearch                      |check|
 insque                       |check|
-lfind
+lfind                        |check|
 lsearch
 remque                       |check|
 tdelete

diff  --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 5deb5258d532fe..30d0b71d88cc47 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -254,6 +254,7 @@ add_header_macro(
     .llvm-libc-types.ENTRY
     .llvm-libc-types.struct_hsearch_data
     .llvm-libc-types.size_t
+    .llvm-libc-types.__lsearchcompare_t
 )
 
 add_header_macro(

diff  --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 836e8a507bd6f2..a104ab78689606 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -3,6 +3,7 @@ add_header(size_t HDR size_t.h)
 add_header(ssize_t HDR ssize_t.h)
 add_header(__atfork_callback_t HDR __atfork_callback_t.h)
 add_header(__bsearchcompare_t HDR __bsearchcompare_t.h)
+add_header(__lsearchcompare_t HDR __lsearchcompare_t.h)
 add_header(__call_once_func_t HDR __call_once_func_t.h)
 add_header(__exec_argv_t HDR __exec_argv_t.h)
 add_header(__exec_envp_t HDR __exec_envp_t.h)

diff  --git a/libc/include/llvm-libc-types/__lsearchcompare_t.h b/libc/include/llvm-libc-types/__lsearchcompare_t.h
new file mode 100644
index 00000000000000..08dc2db274d0c3
--- /dev/null
+++ b/libc/include/llvm-libc-types/__lsearchcompare_t.h
@@ -0,0 +1,14 @@
+//===-- Definition of type __lsearchcompare_t -----------------------------===//
+//
+// 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_TYPES___LSEARCHCOMPARE_T_H
+#define LLVM_LIBC_TYPES___LSEARCHCOMPARE_T_H
+
+typedef int (*__lsearchcompare_t)(const void *, const void *);
+
+#endif // LLVM_LIBC_TYPES___LSEARCHCOMPARE_T_H

diff  --git a/libc/newhdrgen/yaml/search.yaml b/libc/newhdrgen/yaml/search.yaml
index 37d2650bcf0514..a0c73bc679d819 100644
--- a/libc/newhdrgen/yaml/search.yaml
+++ b/libc/newhdrgen/yaml/search.yaml
@@ -4,6 +4,7 @@ types:
   - type_name: struct_hsearch_data
   - type_name: ENTRY
   - type_name: ACTION
+  - type_name: __lsearchcompare_t
 enums: []
 objects: []
 functions:
@@ -57,3 +58,13 @@ functions:
     return_type: void
     arguments:
       - type: void *
+  - name: lfind
+    standards:
+      - POSIX
+    return_type: void *
+    arguments:
+      - type: const void *
+      - type: const void *
+      - type: size_t *
+      - type: size_t
+      - type: __lsearchcompare_t

diff  --git a/libc/spec/posix.td b/libc/spec/posix.td
index beede79a38ec24..d4712dc0c5d701 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -100,6 +100,9 @@ def StructStatvfs : NamedType<"struct statvfs">;
 def StructStatvfsPtr : PtrType<StructStatvfs>;
 def RestrictedStructStatvfsPtr : RestrictedPtrType<StructStatvfs>;
 
+// The function pointer type for the predicate for lsearch, lfind
+def LSearchCompareT : NamedType<"__lsearchcompare_t">;
+
 def POSIX : StandardSpec<"POSIX"> {
   PtrType CharPtr = PtrType<CharType>;
   RestrictedPtrType RestrictedCharPtr = RestrictedPtrType<CharType>;
@@ -1618,6 +1621,17 @@ def POSIX : StandardSpec<"POSIX"> {
                 ArgSpec<VoidPtr>
             ]
         >,
+        FunctionSpec<
+            "lfind",
+            RetValSpec<VoidPtr>,
+            [
+                ArgSpec<ConstVoidPtr>,
+                ArgSpec<ConstVoidPtr>,
+                ArgSpec<SizeTPtr>,
+                ArgSpec<SizeTType>,
+                ArgSpec<LSearchCompareT>
+            ]
+        >
     ]
   >;
 

diff  --git a/libc/src/search/CMakeLists.txt b/libc/src/search/CMakeLists.txt
index 46ad3e33c02fa9..497657f40f2f02 100644
--- a/libc/src/search/CMakeLists.txt
+++ b/libc/src/search/CMakeLists.txt
@@ -98,3 +98,15 @@ add_entrypoint_object(
     libc.include.search
     libc.src.__support.intrusive_list
 )
+
+add_entrypoint_object(
+  lfind
+  SRCS
+    lfind.cpp
+  HDRS
+    lfind.h
+  DEPENDS
+    libc.include.search
+    libc.src.__support.CPP.cstddef
+    libc.src.__support.memory_size
+)

diff  --git a/libc/src/search/lfind.cpp b/libc/src/search/lfind.cpp
new file mode 100644
index 00000000000000..c8bf07de0b9031
--- /dev/null
+++ b/libc/src/search/lfind.cpp
@@ -0,0 +1,35 @@
+//===-- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/search/lfind.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"
+
+namespace LIBC_NAMESPACE_DECL {
+LLVM_LIBC_FUNCTION(void *, lfind,
+                   (const void *key, const 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);
+  return nullptr;
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/search/lfind.h b/libc/src/search/lfind.h
new file mode 100644
index 00000000000000..2eddb027d885a9
--- /dev/null
+++ b/libc/src/search/lfind.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SEARCH_LFIND_H
+#define LLVM_LIBC_SRC_SEARCH_LFIND_H
+
+#include "src/__support/macros/config.h"
+#include <stddef.h> // size_t
+
+namespace LIBC_NAMESPACE_DECL {
+void *lfind(const void *key, const void *base, size_t *nmemb, size_t size,
+            int (*compar)(const void *, const void *));
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SEARCH_LFIND_H

diff  --git a/libc/test/src/search/CMakeLists.txt b/libc/test/src/search/CMakeLists.txt
index 8a33edc4293ab2..a1f9aac2094c9b 100644
--- a/libc/test/src/search/CMakeLists.txt
+++ b/libc/test/src/search/CMakeLists.txt
@@ -25,3 +25,13 @@ add_libc_unittest(
     libc.src.search.insque
     libc.src.search.remque
 )
+
+add_libc_unittest(
+  lfind_test
+  SUITE
+    libc_search_unittests
+  SRCS
+    lfind_test.cpp
+  DEPENDS
+    libc.src.search.lfind
+)

diff  --git a/libc/test/src/search/lfind_test.cpp b/libc/test/src/search/lfind_test.cpp
new file mode 100644
index 00000000000000..00384f7eec14ea
--- /dev/null
+++ b/libc/test/src/search/lfind_test.cpp
@@ -0,0 +1,46 @@
+//===-- Unittests for lfind -----------------------------------------------===//
+//
+// 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/lfind.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(LlvmLibcLfindTest, SearchHead) {
+  int list[3] = {1, 2, 3};
+  size_t len = 3;
+  int key = 1;
+  void *ret = LIBC_NAMESPACE::lfind(&key, list, &len, sizeof(int), compar);
+  ASSERT_TRUE(ret == &list[0]);
+}
+
+TEST(LlvmLibcLfindTest, SearchMiddle) {
+  int list[3] = {1, 2, 3};
+  size_t len = 3;
+  int key = 2;
+  void *ret = LIBC_NAMESPACE::lfind(&key, list, &len, sizeof(int), compar);
+  ASSERT_TRUE(ret == &list[1]);
+}
+
+TEST(LlvmLibcLfindTest, SearchTail) {
+  int list[3] = {1, 2, 3};
+  size_t len = 3;
+  int key = 3;
+  void *ret = LIBC_NAMESPACE::lfind(&key, list, &len, sizeof(int), compar);
+  ASSERT_TRUE(ret == &list[2]);
+}
+
+TEST(LlvmLibcLfindTest, SearchNonExistent) {
+  int list[3] = {1, 2, 3};
+  size_t len = 3;
+  int key = 5;
+  void *ret = LIBC_NAMESPACE::lfind(&key, list, &len, sizeof(int), compar);
+  ASSERT_TRUE(ret == nullptr);
+}


        


More information about the libc-commits mailing list