/src/serenity/AK/Random.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <AK/Platform.h> |
10 | | #include <AK/Span.h> |
11 | | #include <AK/StdLibExtras.h> |
12 | | #include <AK/Types.h> |
13 | | #include <stdlib.h> |
14 | | |
15 | | #if defined(__unix__) |
16 | | # include <unistd.h> |
17 | | #endif |
18 | | |
19 | | namespace AK { |
20 | | |
21 | | inline void fill_with_random([[maybe_unused]] Bytes bytes) |
22 | 0 | { |
23 | 0 | #if defined(AK_OS_SERENITY) || defined(AK_OS_BSD_GENERIC) || defined(AK_OS_HAIKU) || AK_LIBC_GLIBC_PREREQ(2, 36) |
24 | 0 | arc4random_buf(bytes.data(), bytes.size()); |
25 | | #elif defined(OSS_FUZZ) |
26 | | #else |
27 | | auto fill_with_random_fallback = [&]() { |
28 | | for (auto& byte : bytes) |
29 | | byte = rand(); |
30 | | }; |
31 | | |
32 | | # if defined(__unix__) |
33 | | // The maximum permitted value for the getentropy length argument. |
34 | | static constexpr size_t getentropy_length_limit = 256; |
35 | | auto iterations = bytes.size() / getentropy_length_limit; |
36 | | |
37 | | for (size_t i = 0; i < iterations; ++i) { |
38 | | if (getentropy(bytes.data(), getentropy_length_limit) != 0) { |
39 | | fill_with_random_fallback(); |
40 | | return; |
41 | | } |
42 | | |
43 | | bytes = bytes.slice(getentropy_length_limit); |
44 | | } |
45 | | |
46 | | if (bytes.is_empty() || getentropy(bytes.data(), bytes.size()) == 0) |
47 | | return; |
48 | | # endif |
49 | | |
50 | | fill_with_random_fallback(); |
51 | | #endif |
52 | 0 | } |
53 | | |
54 | | template<typename T> |
55 | | inline T get_random() |
56 | 0 | { |
57 | 0 | T t; |
58 | 0 | fill_with_random({ &t, sizeof(T) }); |
59 | 0 | return t; |
60 | 0 | } Unexecuted instantiation: unsigned int AK::get_random<unsigned int>() Unexecuted instantiation: unsigned long AK::get_random<unsigned long>() Unexecuted instantiation: unsigned char AK::get_random<unsigned char>() |
61 | | |
62 | | u32 get_random_uniform(u32 max_bounds); |
63 | | u64 get_random_uniform_64(u64 max_bounds); |
64 | | |
65 | | template<typename Collection> |
66 | | inline void shuffle(Collection& collection) |
67 | | { |
68 | | // Fisher-Yates shuffle |
69 | | for (size_t i = collection.size() - 1; i >= 1; --i) { |
70 | | size_t j = get_random_uniform(i + 1); |
71 | | AK::swap(collection[i], collection[j]); |
72 | | } |
73 | | } |
74 | | |
75 | | } |
76 | | |
77 | | #if USING_AK_GLOBALLY |
78 | | using AK::fill_with_random; |
79 | | using AK::get_random; |
80 | | using AK::get_random_uniform; |
81 | | using AK::shuffle; |
82 | | #endif |