Skip to content

[libc][search] implement posix lfind function #114692

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

Merged
merged 12 commits into from
Nov 11, 2024
Merged
3 changes: 3 additions & 0 deletions libc/config/baremetal/arm/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions libc/config/baremetal/riscv/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions libc/config/darwin/arm/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions libc/config/darwin/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/aarch64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,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
Expand Down
3 changes: 3 additions & 0 deletions libc/config/linux/arm/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/riscv/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,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
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,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
Expand Down
3 changes: 3 additions & 0 deletions libc/config/windows/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion libc/docs/libc_search.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ hcreate |check|
hdestroy |check|
hsearch |check|
insque |check|
lfind
lfind |check|
lsearch
remque |check|
tdelete
Expand Down
1 change: 1 addition & 0 deletions libc/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
1 change: 1 addition & 0 deletions libc/include/llvm-libc-types/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 14 additions & 0 deletions libc/include/llvm-libc-types/__lsearchcompare_t.h
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions libc/newhdrgen/yaml/search.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ types:
- type_name: struct_hsearch_data
- type_name: ENTRY
- type_name: ACTION
- type_name: __lsearchcompare_t
enums: []
objects: []
functions:
Expand Down Expand Up @@ -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
14 changes: 14 additions & 0 deletions libc/spec/posix.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down Expand Up @@ -1618,6 +1621,17 @@ def POSIX : StandardSpec<"POSIX"> {
ArgSpec<VoidPtr>
]
>,
FunctionSpec<
"lfind",
RetValSpec<VoidPtr>,
[
ArgSpec<ConstVoidPtr>,
ArgSpec<ConstVoidPtr>,
ArgSpec<SizeTPtr>,
ArgSpec<SizeTType>,
ArgSpec<LSearchCompareT>
]
>
]
>;

Expand Down
12 changes: 12 additions & 0 deletions libc/src/search/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
36 changes: 36 additions & 0 deletions libc/src/search/lfind.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===-- 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
20 changes: 20 additions & 0 deletions libc/src/search/lfind.h
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions libc/test/src/search/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
46 changes: 46 additions & 0 deletions libc/test/src/search/lfind_test.cpp
Original file line number Diff line number Diff line change
@@ -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);
}