-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc][search] implement posix lsearch
function
#114686
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-libc Author: Duncan (duncpro) ChangesChanges
Also, I'm not sure how to specify a function pointer type in the oldhdrgen spec files. If someone could help with that I'd appreciate it. Full diff: https://github.com/llvm/llvm-project/pull/114686.diff 11 Files Affected:
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index b3f94a581c8ad9..51206aa2286392 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -943,6 +943,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.search.hsearch_r
libc.src.search.insque
libc.src.search.remque
+ libc.src.search.lsearch
# threads.h entrypoints
libc.src.threads.call_once
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 5c09edf7cfb266..34628645664f85 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -873,6 +873,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.search.hsearch_r
libc.src.search.insque
libc.src.search.remque
+ libc.src.search.lsearch
# threads.h entrypoints
libc.src.threads.call_once
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a2fb97d04584d5..f885d89c6606ec 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1006,6 +1006,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.search.hsearch_r
libc.src.search.insque
libc.src.search.remque
+ libc.src.search.lsearch
# threads.h entrypoints
libc.src.threads.call_once
diff --git a/libc/docs/libc_search.rst b/libc/docs/libc_search.rst
index 4a7ee288dd43e8..84fc9b18f2786e 100644
--- a/libc/docs/libc_search.rst
+++ b/libc/docs/libc_search.rst
@@ -43,7 +43,7 @@ hdestroy |check|
hsearch |check|
insque |check|
lfind
-lsearch
+lsearch |check|
remque |check|
tdelete
tfind
diff --git a/libc/newhdrgen/yaml/search.yaml b/libc/newhdrgen/yaml/search.yaml
index 37d2650bcf0514..af6dc0fab18594 100644
--- a/libc/newhdrgen/yaml/search.yaml
+++ b/libc/newhdrgen/yaml/search.yaml
@@ -36,6 +36,16 @@ functions:
arguments:
- type: ENTRY
- type: ACTION
+ - name: lsearch
+ standards:
+ - POSIX
+ return_type: void *
+ arguments:
+ - type: void *
+ - type: void *
+ - type: size_t *
+ - type: size_t
+ - type: int(*compar)(const void *, const void *)
- name: hsearch_r
standards: GNUExtensions
return_type: int
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index beede79a38ec24..448d8d2fbf17c7 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -1618,6 +1618,17 @@ def POSIX : StandardSpec<"POSIX"> {
ArgSpec<VoidPtr>
]
>,
+ FunctionSpec<
+ "lsearch",
+ RetValSpec<VoidPtr>,
+ [
+ ArgSpec<VoidPtr>,
+ ArgSpec<VoidPtr>,
+ ArgSpec<SizeTPtr>,
+ ArgSpec<SizeTType>,
+ // TODO: Unsure how to specify int(*compar)(void *, void *)
+ ]
+ >
]
>;
diff --git a/libc/src/search/CMakeLists.txt b/libc/src/search/CMakeLists.txt
index 46ad3e33c02fa9..3208307745adb1 100644
--- a/libc/src/search/CMakeLists.txt
+++ b/libc/src/search/CMakeLists.txt
@@ -27,6 +27,18 @@ add_entrypoint_object(
libc.include.search
)
+add_entrypoint_object(
+ lsearch
+ SRCS
+ lsearch.cpp
+ HDRS
+ lsearch.h
+ DEPENDS
+ libc.include.search
+ libc.src.__support.CPP.cstddef
+ libc.src.string.memory_utils.inline_memcpy
+)
+
add_entrypoint_object(
hsearch
SRCS
diff --git a/libc/src/search/lsearch.cpp b/libc/src/search/lsearch.cpp
new file mode 100644
index 00000000000000..29cc9fde279c46
--- /dev/null
+++ b/libc/src/search/lsearch.cpp
@@ -0,0 +1,33 @@
+//===-- 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/string/memory_utils/inline_memcpy.h" // inline_memcpy
+
+namespace LIBC_NAMESPACE_DECL {
+LLVM_LIBC_FUNCTION(void *, lsearch,
+ (void *key, void *base, size_t *nmemb, size_t size,
+ int (*compar)(void *, void *))) {
+ cpp::byte *next = reinterpret_cast<cpp::byte *>(base);
+ cpp::byte *end = next + (*nmemb * size);
+ while (next < end) {
+ if (compar(key, next) == 0) {
+ return next;
+ }
+ next += size;
+ }
+
+ inline_memcpy(next, key, size);
+ *nmemb += 1;
+ return next;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/search/lsearch.h b/libc/src/search/lsearch.h
new file mode 100644
index 00000000000000..d3902b3a2ebce0
--- /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 <search.h> // size_t
+
+namespace LIBC_NAMESPACE_DECL {
+void *lsearch(void *key, void *base, size_t *nmemb, size_t size,
+ int (*compar)(void *, 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 8a33edc4293ab2..70ac7d5a4fc859 100644
--- a/libc/test/src/search/CMakeLists.txt
+++ b/libc/test/src/search/CMakeLists.txt
@@ -25,3 +25,14 @@ add_libc_unittest(
libc.src.search.insque
libc.src.search.remque
)
+
+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 00000000000000..2717fd6f038439
--- /dev/null
+++ b/libc/test/src/search/lsearch_test.cpp
@@ -0,0 +1,79 @@
+//===-- 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(void *a, void *b) {
+ return *reinterpret_cast<int *>(a) - *reinterpret_cast<int *>(b);
+}
+
+TEST(LlvmLibcLsearchTest, SearchHead) {
+ int list[4] = {1, 2, 3, 4};
+ size_t len = 3; // intentionally 3 and not all 4
+ int key = 1;
+ void *ret = LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), compar);
+
+ ASSERT_TRUE(ret == &list[0]); // head must be returned
+ ASSERT_EQ(key, 1); // `key` must not be changed
+ ASSERT_EQ(len, static_cast<size_t>(3)); // `len` must not be changed
+ // `list` must not be changed
+ ASSERT_EQ(list[0], 1);
+ ASSERT_EQ(list[1], 2);
+ ASSERT_EQ(list[2], 3);
+ ASSERT_EQ(list[3], 4);
+}
+
+TEST(LlvmLibcLsearchTest, SearchMiddle) {
+ int list[4] = {1, 2, 3, 4};
+ size_t len = 3; // intentionally 3 and not all 4
+ int key = 2;
+ void *ret = LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), compar);
+
+ ASSERT_TRUE(ret == &list[1]); // ptr to second element must be returned
+ ASSERT_EQ(key, 2); // `key` must not be changed
+ ASSERT_EQ(len, static_cast<size_t>(3)); // `len` must not be changed
+ // `list` must not be changed
+ ASSERT_EQ(list[0], 1);
+ ASSERT_EQ(list[1], 2);
+ ASSERT_EQ(list[2], 3);
+ ASSERT_EQ(list[3], 4);
+}
+
+TEST(LlvmLibcLsearchTest, SearchTail) {
+ int list[4] = {1, 2, 3, 4};
+ size_t len = 3; // intentionally 3 and not all 4
+ int key = 3;
+ void *ret = LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), compar);
+
+ ASSERT_TRUE(ret == &list[2]); // ptr to last element must be returned
+ ASSERT_EQ(key, 3); // `key` must not be changed
+ ASSERT_EQ(len, static_cast<size_t>(3)); // `len` must not be changed
+ // `list` must not be changed
+ ASSERT_EQ(list[0], 1);
+ ASSERT_EQ(list[1], 2);
+ ASSERT_EQ(list[2], 3);
+ ASSERT_EQ(list[3], 4);
+}
+
+TEST(LlvmLibcLsearchTest, SearchNonExistent) {
+ int list[4] = {1, 2, 3, 4};
+ size_t len = 3; // intentionally 3 and not all 4
+ int key = 5;
+ void *ret = LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), compar);
+
+ ASSERT_TRUE(ret == &list[3]); // ptr past tail must be returned
+ ASSERT_EQ(key, 5); // `key` must not be changed
+ ASSERT_EQ(len, static_cast<size_t>(4)); // `len` must be incremented one
+ // `list` must not be changed
+ ASSERT_EQ(list[0], 1);
+ ASSERT_EQ(list[1], 2);
+ ASSERT_EQ(list[2], 3);
+ // `5` must be appended to list (replacing the dummy 4)
+ ASSERT_EQ(list[3], 5);
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comments apply to #114692 as here. Let's get that reviewed+landed, then revisit this PR.
Changes
Implement the POSIX lsearch function.
Put a checkmark in the posix support table docs next to
lsearch
.Also, I'm not sure how to specify a function pointer type in the oldhdrgen spec files. If someone could help with that I'd appreciate it.