Skip to content

Commit b11ed81

Browse files
committed
[libc][search] implement POSIX lsearch function
1 parent def22f4 commit b11ed81

File tree

13 files changed

+193
-2
lines changed

13 files changed

+193
-2
lines changed

libc/config/darwin/x86_64/entrypoints.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ set(TARGET_LIBC_ENTRYPOINTS
1818
libc.src.ctype.toupper
1919

2020
# search.h entrypoints
21-
libc.src.search.lfind
21+
libc.src.search.lfind
22+
libc.src.search.lsearch
2223

2324
# string.h entrypoints
2425
libc.src.string.bcmp

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,7 @@ if(LLVM_LIBC_FULL_BUILD)
961961
libc.src.search.hsearch_r
962962
libc.src.search.insque
963963
libc.src.search.lfind
964+
libc.src.search.lsearch
964965
libc.src.search.remque
965966

966967
# threads.h entrypoints

libc/config/linux/arm/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ if(LLVM_LIBC_FULL_BUILD)
185185
list(APPEND TARGET_LIBC_ENTRYPOINTS
186186
# search.h entrypoints
187187
libc.src.search.lfind
188+
libc.src.search.lsearch
188189

189190
# setjmp.h entrypoints
190191
libc.src.setjmp.longjmp

libc/config/linux/riscv/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,7 @@ if(LLVM_LIBC_FULL_BUILD)
899899
libc.src.search.hsearch_r
900900
libc.src.search.insque
901901
libc.src.search.lfind
902+
libc.src.search.lsearch
902903
libc.src.search.remque
903904

904905
# threads.h entrypoints

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,7 @@ if(LLVM_LIBC_FULL_BUILD)
10441044
libc.src.search.hsearch_r
10451045
libc.src.search.insque
10461046
libc.src.search.lfind
1047+
libc.src.search.lsearch
10471048
libc.src.search.remque
10481049

10491050
# threads.h entrypoints

libc/docs/libc_search.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ hdestroy |check|
4343
hsearch |check|
4444
insque |check|
4545
lfind |check|
46-
lsearch
46+
lsearch |check|
4747
remque |check|
4848
tdelete
4949
tfind

libc/newhdrgen/yaml/search.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,13 @@ functions:
6868
- type: size_t *
6969
- type: size_t
7070
- type: __lsearchcompare_t
71+
- name: lsearch
72+
standards:
73+
- POSIX
74+
return_type: void *
75+
arguments:
76+
- type: const void *
77+
- type: void *
78+
- type: size_t *
79+
- type: size_t
80+
- type: __lsearchcompare_t

libc/spec/posix.td

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,17 @@ def POSIX : StandardSpec<"POSIX"> {
16321632
ArgSpec<SizeTType>,
16331633
ArgSpec<LSearchCompareT>
16341634
]
1635+
>,
1636+
FunctionSpec<
1637+
"lsearch",
1638+
RetValSpec<VoidPtr>,
1639+
[
1640+
ArgSpec<ConstVoidPtr>,
1641+
ArgSpec<VoidPtr>,
1642+
ArgSpec<SizeTPtr>,
1643+
ArgSpec<SizeTType>,
1644+
ArgSpec<LSearchCompareT>
1645+
]
16351646
>
16361647
]
16371648
>;

libc/src/search/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,16 @@ add_entrypoint_object(
110110
libc.src.__support.CPP.cstddef
111111
libc.src.__support.memory_size
112112
)
113+
114+
add_entrypoint_object(
115+
lsearch
116+
SRCS
117+
lsearch.cpp
118+
HDRS
119+
lsearch.h
120+
DEPENDS
121+
libc.include.search
122+
libc.src.__support.CPP.cstddef
123+
libc.src.__support.memory_size
124+
libc.src.string.memory_utils.inline_memcpy
125+
)

libc/src/search/lsearch.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===-- Implementation of lsearch -------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/search/lsearch.h"
10+
#include "src/__support/CPP/cstddef.h" // cpp::byte
11+
#include "src/__support/common.h"
12+
#include "src/__support/macros/config.h"
13+
#include "src/__support/memory_size.h"
14+
#include "src/string/memory_utils/inline_memcpy.h"
15+
16+
namespace LIBC_NAMESPACE_DECL {
17+
LLVM_LIBC_FUNCTION(void *, lsearch,
18+
(const void *key, void *base, size_t *nmemb, size_t size,
19+
int (*compar)(const void *, const void *))) {
20+
if (key == nullptr || base == nullptr || nmemb == nullptr ||
21+
compar == nullptr)
22+
return nullptr;
23+
24+
size_t byte_len = 0;
25+
if (internal::mul_overflow(*nmemb, size, &byte_len))
26+
return nullptr;
27+
28+
cpp::byte *next = reinterpret_cast<cpp::byte *>(const_cast<void *>(base));
29+
const cpp::byte *end = next + byte_len;
30+
31+
for (; next < end; next += size)
32+
if (compar(key, next) == 0)
33+
break;
34+
35+
if (next == end) {
36+
LIBC_NAMESPACE::inline_memcpy(next, key, size);
37+
*nmemb += 1;
38+
}
39+
40+
return next;
41+
}
42+
43+
} // namespace LIBC_NAMESPACE_DECL

libc/src/search/lsearch.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===-- Implementation header for lsearch -----------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_SEARCH_LSEARCH_H
10+
#define LLVM_LIBC_SRC_SEARCH_LSEARCH_H
11+
12+
#include "src/__support/macros/config.h"
13+
#include <stddef.h> // size_t
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
void *lsearch(const void *key, void *base, size_t *nmemb, size_t size,
17+
int (*compar)(const void *, const void *));
18+
} // namespace LIBC_NAMESPACE_DECL
19+
20+
#endif // LLVM_LIBC_SRC_SEARCH_LSEARCH_H

libc/test/src/search/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,13 @@ add_libc_unittest(
3535
DEPENDS
3636
libc.src.search.lfind
3737
)
38+
39+
add_libc_unittest(
40+
lsearch_test
41+
SUITE
42+
libc_search_unittests
43+
SRCS
44+
lsearch_test.cpp
45+
DEPENDS
46+
libc.src.search.lsearch
47+
)

libc/test/src/search/lsearch_test.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//===-- Unittests for lsearch ---------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/search/lsearch.h"
10+
#include "test/UnitTest/Test.h"
11+
12+
int compar(const void *a, const void *b) {
13+
return *reinterpret_cast<const int *>(a) != *reinterpret_cast<const int *>(b);
14+
}
15+
16+
TEST(LlvmLibcLsearchTest, SearchHead) {
17+
int list[4] = {1, 2, 3, 4};
18+
size_t len = 3;
19+
int key = 1;
20+
void *ret = LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), compar);
21+
22+
ASSERT_EQ(static_cast<int *>(ret), &list[0]);
23+
ASSERT_EQ(len, static_cast<size_t>(3));
24+
ASSERT_EQ(list[1], 2);
25+
ASSERT_EQ(list[2], 3);
26+
ASSERT_EQ(list[3], 4);
27+
ASSERT_EQ(list[3], 4);
28+
}
29+
30+
TEST(LlvmLibcLsearchTest, SearchMiddle) {
31+
int list[4] = {1, 2, 3, 4};
32+
size_t len = 3;
33+
int key = 2;
34+
void *ret = LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), compar);
35+
ASSERT_EQ(static_cast<int *>(ret), &list[1]);
36+
ASSERT_EQ(len, static_cast<size_t>(3));
37+
ASSERT_EQ(list[0], 1);
38+
ASSERT_EQ(list[1], 2);
39+
ASSERT_EQ(list[2], 3);
40+
ASSERT_EQ(list[3], 4);
41+
}
42+
43+
TEST(LlvmLibcLsearchTest, SearchTail) {
44+
int list[4] = {1, 2, 3, 4};
45+
size_t len = 3;
46+
int key = 3;
47+
void *ret = LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), compar);
48+
ASSERT_EQ(static_cast<int *>(ret), &list[2]);
49+
ASSERT_EQ(len, static_cast<size_t>(3));
50+
ASSERT_EQ(list[0], 1);
51+
ASSERT_EQ(list[1], 2);
52+
ASSERT_EQ(list[2], 3);
53+
ASSERT_EQ(list[3], 4);
54+
}
55+
56+
TEST(LlvmLibcLsearchTest, SearchNonExistent) {
57+
int list[4] = {1, 2, 3, 4};
58+
size_t len = 3;
59+
int key = 5;
60+
void *ret = LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), compar);
61+
62+
ASSERT_EQ(static_cast<int *>(ret), &list[3]);
63+
ASSERT_EQ(len, static_cast<size_t>(4));
64+
ASSERT_EQ(list[0], 1);
65+
ASSERT_EQ(list[1], 2);
66+
ASSERT_EQ(list[2], 3);
67+
ASSERT_EQ(list[3], 5);
68+
}
69+
70+
TEST(LlvmLibcLsearchTest, SearchNonExistentEmpty) {
71+
int list[1] = {1};
72+
size_t len = 0;
73+
int key = 0;
74+
void *ret = LIBC_NAMESPACE::lsearch(&key, list, &len, sizeof(int), compar);
75+
76+
ASSERT_EQ(static_cast<int *>(ret), &list[0]);
77+
ASSERT_EQ(len, static_cast<size_t>(1));
78+
ASSERT_EQ(list[0], 0);
79+
}

0 commit comments

Comments
 (0)