Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ add_subdirectory(hashtbl)
add_subdirectory(heap)
add_subdirectory(hlist)
add_subdirectory(ilist)
add_subdirectory(knuth)
add_subdirectory(levenshtein)
add_subdirectory(list)
add_subdirectory(log)
Expand Down
2 changes: 2 additions & 0 deletions examples/knuth/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-or-later
/knuth-simple
22 changes: 22 additions & 0 deletions examples/knuth/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Copyright(c) 2023 ffashion <helloworldffashion@gmail.com>
#

add_executable(knuth-simple simple.c)
target_link_libraries(knuth-simple bfdev)
add_test(knuth-simple knuth-simple)

if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev")
install(FILES
simple.c
DESTINATION
${CMAKE_INSTALL_DOCDIR}/examples/knuth
)

install(TARGETS
knuth-simple
DESTINATION
${CMAKE_INSTALL_DOCDIR}/bin
)
endif()
32 changes: 32 additions & 0 deletions examples/knuth/simple.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright(c) 2025 John Sanpe <sanpeqf@gmail.com>
*/

#define MODULE_NAME "knuth-simple"
#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt

#include <stdlib.h>
#include <time.h>
#include <bfdev/macro.h>
#include <bfdev/log.h>
#include <bfdev/knuth.h>

static const char *
cards[12] = {
"Ace", "2", "3", "4", "5", "6", "7",
"8", "9", "Jack", "Queen", "King"
};

int
main(int argc, const char *argv[])
{
unsigned int index;

srand(time(NULL));
bfdev_knuth(cards, BFDEV_ARRAY_SIZE(cards), sizeof(*cards));
for (index = 0; index < BFDEV_ARRAY_SIZE(cards); ++index)
bfdev_log_info("card%u: %s\n", index, cards[index]);

return 0;
}
33 changes: 33 additions & 0 deletions include/bfdev/knuth.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/*
* Copyright(c) 2025 John Sanpe <sanpeqf@gmail.com>
*/

#ifndef _BFDEV_KNUTH_H_
#define _BFDEV_KNUTH_H_

#include <bfdev/config.h>
#include <bfdev/types.h>

BFDEV_BEGIN_DECLS

/**
* bfdev_knuth() - Knuth-Shuffle algorithm.
* @base: pointer to data to sort.
* @num: number of elements.
* @cells: size of each element.
*
* The algorithm takes a list of all the elements of the sequence, and
* continually determines the next element in the shuffled sequence
* by randomly drawing an element from the list until no elements remain.
* The algorithm produces an unbiased permutation, every permutation
* is equally likely.
*
* Return 0 on success or a negative error code on failure.
*/
extern int
bfdev_knuth(void *base, bfdev_size_t num, bfdev_size_t cells);

BFDEV_END_DECLS

#endif /* _BFDEV_KNUTH_H_ */
3 changes: 3 additions & 0 deletions include/bfdev/port/stdlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

BFDEV_BEGIN_DECLS

extern int
bfdev_rand(void);

extern __bfdev_noreturn void
bfdev_abort(void);

Expand Down
1 change: 1 addition & 0 deletions src/build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ set(BFDEV_SOURCE
${CMAKE_CURRENT_LIST_DIR}/heap.c
${CMAKE_CURRENT_LIST_DIR}/ilist.c
${CMAKE_CURRENT_LIST_DIR}/jhash.c
${CMAKE_CURRENT_LIST_DIR}/knuth.c
${CMAKE_CURRENT_LIST_DIR}/levenshtein.c
${CMAKE_CURRENT_LIST_DIR}/list-sort.c
${CMAKE_CURRENT_LIST_DIR}/llist.c
Expand Down
40 changes: 40 additions & 0 deletions src/knuth.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/*
* Copyright(c) 2023 John Sanpe <sanpeqf@gmail.com>
*/

#include <base.h>
#include <bfdev/knuth.h>
#include <bfdev/stdlib.h>
#include <export.h>

static __bfdev_noinline void
knuth_swap(bfdev_size_t cells, void *cel1, void *cel2)
{
void *buff;

/* alloca hates inline */
buff = bfdev_alloca(cells);

bfdev_memcpy(buff, cel1, cells);
bfdev_memcpy(cel1, cel2, cells);
bfdev_memcpy(cel2, buff, cells);
}

export int
bfdev_knuth(void *base, bfdev_size_t num, bfdev_size_t cells)
{
bfdev_size_t idx1, idx2;

if (bfdev_unlikely(!base || !num || !cells))
return -BFDEV_EINVAL;

for (idx1 = num - 1; idx1; --idx1) {
idx2 = bfdev_rand() % (idx1 + 1);
if (bfdev_unlikely(idx1 == idx2))
continue;
knuth_swap(cells, base + idx1 * cells, base + idx2 * cells);
}

return -BFDEV_ENOERR;
}
6 changes: 6 additions & 0 deletions src/port/stdlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
#include <port/stdlib.h>
#include <export.h>

export int
bfdev_rand(void)
{
return bfport_rand();
}

export __bfdev_noreturn void
bfdev_abort(void)
{
Expand Down
4 changes: 2 additions & 2 deletions src/skiplist.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*/

#include <base.h>
#include <bfdev/stdlib.h>
#include <bfdev/skiplist.h>
#include <port/stdlib.h>
#include <export.h>

static unsigned int
Expand All @@ -15,7 +15,7 @@ random_level(bfdev_skip_head_t *head)

level = 1;
while (level < head->levels) {
if ((bfport_rand() & 0xffff) > 0xffff >> 2)
if ((bfdev_rand() & 0xffff) > 0xffff >> 2)
break;
level++;
}
Expand Down
56 changes: 17 additions & 39 deletions testsuite/memalloc/fuzzy.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
#include <bfdev/log.h>
#include <bfdev/errno.h>
#include <bfdev/memalloc.h>
#include <bfdev/knuth.h>
#include <bfdev/size.h>
#include <testsuite.h>
#include <randpool.h>

#define POOL_SIZE BFDEV_SZ_32MiB
#define TEST_SIZE BFDEV_SZ_16MiB
Expand All @@ -25,70 +25,48 @@ static int
test_memalloc(bfdev_memalloc_head_t *pool)
{
bfdev_memalloc_chunk_t *node;
void *result, *data;
void *result[TEST_LOOP];
unsigned int count;
size_t size;
int retval;

DEFINE_RANDPOOL(rpool1);
DEFINE_RANDPOOL(rpool2);
retval = -BFDEV_ENOERR;

srand(time(NULL));

for (count = 0; count < TEST_LOOP; ++count) {
size = (unsigned int)rand() % (TEST_SIZE / TEST_LOOP);
result = bfdev_memalloc_alloc(pool, size);
if (!result) {
retval = BFDEV_ENOMEM;
goto failed;
}

retval = randpool_put(&rpool1, result);
if (retval)
goto failed;

memset(result, 0, size);
result[count] = bfdev_memalloc_alloc(pool, size);
if (!result[count])
return -BFDEV_ENOMEM;
memset(result[count], 0, size);
}

bfdev_knuth(result, TEST_LOOP, sizeof(*result));
for (count = 0; count < TEST_LOOP; ++count) {
data = randpool_get(&rpool1);
size = (unsigned int)rand() % (TEST_SIZE / TEST_LOOP);
result = bfdev_memalloc_realloc(pool, data, size);
if (!result) {
retval = BFDEV_ENOMEM;
goto failed;
}

retval = randpool_put(&rpool2, result);
if (retval)
goto failed;

memset(result, 0, size);
result[count] = bfdev_memalloc_realloc(pool, result[count], size);
if (!result[count])
return -BFDEV_ENOMEM;
memset(result[count], 0, size);
}

for (count = 0; count < TEST_LOOP; ++count) {
data = randpool_get(&rpool2);
bfdev_memalloc_free(pool, data);
}
bfdev_knuth(result, TEST_LOOP, sizeof(*result));
for (count = 0; count < TEST_LOOP; ++count)
bfdev_memalloc_free(pool, result[count]);

node = bfdev_list_first_entry(&pool->block_list, bfdev_memalloc_chunk_t, block);
if (node->usize != POOL_SIZE - sizeof(bfdev_memalloc_chunk_t)) {
bfdev_log_err("free node size leak %#lx -> %#lx\n", (unsigned long)POOL_SIZE -
sizeof(bfdev_memalloc_chunk_t), (unsigned long)node->usize);
retval = -BFDEV_EFAULT;
goto failed;
return -BFDEV_EFAULT;
}

if (pool->avail != POOL_SIZE - sizeof(bfdev_memalloc_chunk_t)) {
bfdev_log_err("total available leak %#lx -> %#lx\n", (unsigned long)POOL_SIZE -
sizeof(bfdev_memalloc_chunk_t), (unsigned long)pool->avail);
retval = -BFDEV_EFAULT;
goto failed;
return -BFDEV_EFAULT;
}

failed:
randpool_release(&rpool1, NULL, NULL);
randpool_release(&rpool2, NULL, NULL);
return retval;
}

Expand Down
92 changes: 0 additions & 92 deletions testsuite/randpool.h

This file was deleted.

Loading