Skip to content

Commit 9fee55f

Browse files
authored
Merge pull request #690 from sanpeqf/feat-knuth
Feat knuth
2 parents c2cd940 + a2fdbea commit 9fee55f

File tree

12 files changed

+159
-133
lines changed

12 files changed

+159
-133
lines changed

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ add_subdirectory(hashtbl)
2828
add_subdirectory(heap)
2929
add_subdirectory(hlist)
3030
add_subdirectory(ilist)
31+
add_subdirectory(knuth)
3132
add_subdirectory(levenshtein)
3233
add_subdirectory(list)
3334
add_subdirectory(log)

examples/knuth/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# SPDX-License-Identifier: GPL-2.0-or-later
2+
/knuth-simple

examples/knuth/CMakeLists.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# SPDX-License-Identifier: GPL-2.0-or-later
2+
#
3+
# Copyright(c) 2023 ffashion <[email protected]>
4+
#
5+
6+
add_executable(knuth-simple simple.c)
7+
target_link_libraries(knuth-simple bfdev)
8+
add_test(knuth-simple knuth-simple)
9+
10+
if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev")
11+
install(FILES
12+
simple.c
13+
DESTINATION
14+
${CMAKE_INSTALL_DOCDIR}/examples/knuth
15+
)
16+
17+
install(TARGETS
18+
knuth-simple
19+
DESTINATION
20+
${CMAKE_INSTALL_DOCDIR}/bin
21+
)
22+
endif()

examples/knuth/simple.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/*
3+
* Copyright(c) 2025 John Sanpe <[email protected]>
4+
*/
5+
6+
#define MODULE_NAME "knuth-simple"
7+
#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt
8+
9+
#include <stdlib.h>
10+
#include <time.h>
11+
#include <bfdev/macro.h>
12+
#include <bfdev/log.h>
13+
#include <bfdev/knuth.h>
14+
15+
static const char *
16+
cards[12] = {
17+
"Ace", "2", "3", "4", "5", "6", "7",
18+
"8", "9", "Jack", "Queen", "King"
19+
};
20+
21+
int
22+
main(int argc, const char *argv[])
23+
{
24+
unsigned int index;
25+
26+
srand(time(NULL));
27+
bfdev_knuth(cards, BFDEV_ARRAY_SIZE(cards), sizeof(*cards));
28+
for (index = 0; index < BFDEV_ARRAY_SIZE(cards); ++index)
29+
bfdev_log_info("card%u: %s\n", index, cards[index]);
30+
31+
return 0;
32+
}

include/bfdev/knuth.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/* SPDX-License-Identifier: LGPL-3.0-or-later */
2+
/*
3+
* Copyright(c) 2025 John Sanpe <[email protected]>
4+
*/
5+
6+
#ifndef _BFDEV_KNUTH_H_
7+
#define _BFDEV_KNUTH_H_
8+
9+
#include <bfdev/config.h>
10+
#include <bfdev/types.h>
11+
12+
BFDEV_BEGIN_DECLS
13+
14+
/**
15+
* bfdev_knuth() - Knuth-Shuffle algorithm.
16+
* @base: pointer to data to sort.
17+
* @num: number of elements.
18+
* @cells: size of each element.
19+
*
20+
* The algorithm takes a list of all the elements of the sequence, and
21+
* continually determines the next element in the shuffled sequence
22+
* by randomly drawing an element from the list until no elements remain.
23+
* The algorithm produces an unbiased permutation, every permutation
24+
* is equally likely.
25+
*
26+
* Return 0 on success or a negative error code on failure.
27+
*/
28+
extern int
29+
bfdev_knuth(void *base, bfdev_size_t num, bfdev_size_t cells);
30+
31+
BFDEV_END_DECLS
32+
33+
#endif /* _BFDEV_KNUTH_H_ */

include/bfdev/port/stdlib.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
BFDEV_BEGIN_DECLS
1212

13+
extern int
14+
bfdev_rand(void);
15+
1316
extern __bfdev_noreturn void
1417
bfdev_abort(void);
1518

src/build.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ set(BFDEV_SOURCE
2626
${CMAKE_CURRENT_LIST_DIR}/heap.c
2727
${CMAKE_CURRENT_LIST_DIR}/ilist.c
2828
${CMAKE_CURRENT_LIST_DIR}/jhash.c
29+
${CMAKE_CURRENT_LIST_DIR}/knuth.c
2930
${CMAKE_CURRENT_LIST_DIR}/levenshtein.c
3031
${CMAKE_CURRENT_LIST_DIR}/list-sort.c
3132
${CMAKE_CURRENT_LIST_DIR}/llist.c

src/knuth.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* SPDX-License-Identifier: LGPL-3.0-or-later */
2+
/*
3+
* Copyright(c) 2023 John Sanpe <[email protected]>
4+
*/
5+
6+
#include <base.h>
7+
#include <bfdev/knuth.h>
8+
#include <bfdev/stdlib.h>
9+
#include <export.h>
10+
11+
static __bfdev_noinline void
12+
knuth_swap(bfdev_size_t cells, void *cel1, void *cel2)
13+
{
14+
void *buff;
15+
16+
/* alloca hates inline */
17+
buff = bfdev_alloca(cells);
18+
19+
bfdev_memcpy(buff, cel1, cells);
20+
bfdev_memcpy(cel1, cel2, cells);
21+
bfdev_memcpy(cel2, buff, cells);
22+
}
23+
24+
export int
25+
bfdev_knuth(void *base, bfdev_size_t num, bfdev_size_t cells)
26+
{
27+
bfdev_size_t idx1, idx2;
28+
29+
if (bfdev_unlikely(!base || !num || !cells))
30+
return -BFDEV_EINVAL;
31+
32+
for (idx1 = num - 1; idx1; --idx1) {
33+
idx2 = bfdev_rand() % (idx1 + 1);
34+
if (bfdev_unlikely(idx1 == idx2))
35+
continue;
36+
knuth_swap(cells, base + idx1 * cells, base + idx2 * cells);
37+
}
38+
39+
return -BFDEV_ENOERR;
40+
}

src/port/stdlib.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
#include <port/stdlib.h>
88
#include <export.h>
99

10+
export int
11+
bfdev_rand(void)
12+
{
13+
return bfport_rand();
14+
}
15+
1016
export __bfdev_noreturn void
1117
bfdev_abort(void)
1218
{

src/skiplist.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
*/
55

66
#include <base.h>
7+
#include <bfdev/stdlib.h>
78
#include <bfdev/skiplist.h>
8-
#include <port/stdlib.h>
99
#include <export.h>
1010

1111
static unsigned int
@@ -15,7 +15,7 @@ random_level(bfdev_skip_head_t *head)
1515

1616
level = 1;
1717
while (level < head->levels) {
18-
if ((bfport_rand() & 0xffff) > 0xffff >> 2)
18+
if ((bfdev_rand() & 0xffff) > 0xffff >> 2)
1919
break;
2020
level++;
2121
}

testsuite/memalloc/fuzzy.c

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
#include <bfdev/log.h>
1414
#include <bfdev/errno.h>
1515
#include <bfdev/memalloc.h>
16+
#include <bfdev/knuth.h>
1617
#include <bfdev/size.h>
1718
#include <testsuite.h>
18-
#include <randpool.h>
1919

2020
#define POOL_SIZE BFDEV_SZ_32MiB
2121
#define TEST_SIZE BFDEV_SZ_16MiB
@@ -25,70 +25,48 @@ static int
2525
test_memalloc(bfdev_memalloc_head_t *pool)
2626
{
2727
bfdev_memalloc_chunk_t *node;
28-
void *result, *data;
28+
void *result[TEST_LOOP];
2929
unsigned int count;
3030
size_t size;
3131
int retval;
3232

33-
DEFINE_RANDPOOL(rpool1);
34-
DEFINE_RANDPOOL(rpool2);
3533
retval = -BFDEV_ENOERR;
36-
3734
srand(time(NULL));
35+
3836
for (count = 0; count < TEST_LOOP; ++count) {
3937
size = (unsigned int)rand() % (TEST_SIZE / TEST_LOOP);
40-
result = bfdev_memalloc_alloc(pool, size);
41-
if (!result) {
42-
retval = BFDEV_ENOMEM;
43-
goto failed;
44-
}
45-
46-
retval = randpool_put(&rpool1, result);
47-
if (retval)
48-
goto failed;
49-
50-
memset(result, 0, size);
38+
result[count] = bfdev_memalloc_alloc(pool, size);
39+
if (!result[count])
40+
return -BFDEV_ENOMEM;
41+
memset(result[count], 0, size);
5142
}
5243

44+
bfdev_knuth(result, TEST_LOOP, sizeof(*result));
5345
for (count = 0; count < TEST_LOOP; ++count) {
54-
data = randpool_get(&rpool1);
5546
size = (unsigned int)rand() % (TEST_SIZE / TEST_LOOP);
56-
result = bfdev_memalloc_realloc(pool, data, size);
57-
if (!result) {
58-
retval = BFDEV_ENOMEM;
59-
goto failed;
60-
}
61-
62-
retval = randpool_put(&rpool2, result);
63-
if (retval)
64-
goto failed;
65-
66-
memset(result, 0, size);
47+
result[count] = bfdev_memalloc_realloc(pool, result[count], size);
48+
if (!result[count])
49+
return -BFDEV_ENOMEM;
50+
memset(result[count], 0, size);
6751
}
6852

69-
for (count = 0; count < TEST_LOOP; ++count) {
70-
data = randpool_get(&rpool2);
71-
bfdev_memalloc_free(pool, data);
72-
}
53+
bfdev_knuth(result, TEST_LOOP, sizeof(*result));
54+
for (count = 0; count < TEST_LOOP; ++count)
55+
bfdev_memalloc_free(pool, result[count]);
7356

7457
node = bfdev_list_first_entry(&pool->block_list, bfdev_memalloc_chunk_t, block);
7558
if (node->usize != POOL_SIZE - sizeof(bfdev_memalloc_chunk_t)) {
7659
bfdev_log_err("free node size leak %#lx -> %#lx\n", (unsigned long)POOL_SIZE -
7760
sizeof(bfdev_memalloc_chunk_t), (unsigned long)node->usize);
78-
retval = -BFDEV_EFAULT;
79-
goto failed;
61+
return -BFDEV_EFAULT;
8062
}
8163

8264
if (pool->avail != POOL_SIZE - sizeof(bfdev_memalloc_chunk_t)) {
8365
bfdev_log_err("total available leak %#lx -> %#lx\n", (unsigned long)POOL_SIZE -
8466
sizeof(bfdev_memalloc_chunk_t), (unsigned long)pool->avail);
85-
retval = -BFDEV_EFAULT;
86-
goto failed;
67+
return -BFDEV_EFAULT;
8768
}
8869

89-
failed:
90-
randpool_release(&rpool1, NULL, NULL);
91-
randpool_release(&rpool2, NULL, NULL);
9270
return retval;
9371
}
9472

testsuite/randpool.h

Lines changed: 0 additions & 92 deletions
This file was deleted.

0 commit comments

Comments
 (0)