Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/comphelper/source/misc/random.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * Contributor(s):
10
 *   Copyright (C) 2012 Tino Kluge <tino.kluge@hrz.tu-chemnitz.de>
11
 */
12
13
#include <comphelper/random.hxx>
14
#include <assert.h>
15
#include <stdlib.h>
16
#include <time.h>
17
#include <mutex>
18
#include <random>
19
#include <rtl/random.h>
20
#if defined HAVE_VALGRIND_HEADERS
21
#include <valgrind/memcheck.h>
22
#endif
23
24
// this is nothing but a simple wrapper around
25
// the std::random generators
26
27
namespace comphelper::rng
28
{
29
// underlying random number generator
30
// std::mt19937 implements the Mersenne twister algorithm which
31
// is fast and has good statistical properties, it produces integers
32
// in the range of [0, 2^32-1] internally
33
// memory requirement: 625*sizeof(uint32_t)
34
// http://en.wikipedia.org/wiki/Mersenne_twister
35
#define STD_RNG_ALGO std::mt19937
36
37
namespace
38
{
39
struct RandomNumberGenerator
40
{
41
    std::mutex mutex;
42
    STD_RNG_ALGO global_rng;
43
21
    RandomNumberGenerator() { reseed(); }
44
45
    void reseed()
46
21
    {
47
        // make RR easier to use, breaks easily without the RNG being repeatable
48
21
        bool bRepeatable = (getenv("SAL_RAND_REPEATABLE") != nullptr) || (getenv("RR") != nullptr);
49
        // valgrind on some platforms (e.g.Ubuntu16.04) does not support the new Intel RDRAND instructions,
50
        // which leads to "Illegal Opcode" errors, so just turn off randomness.
51
#if defined HAVE_VALGRIND_HEADERS
52
        if (RUNNING_ON_VALGRIND)
53
            bRepeatable = true;
54
#endif
55
21
        if (bRepeatable)
56
0
        {
57
0
            global_rng.seed(42);
58
0
            return;
59
0
        }
60
61
21
        size_t seed = 0;
62
21
        if (rtl_random_getBytes(nullptr, &seed, sizeof(seed)) != rtl_Random_E_None)
63
0
            seed = 0;
64
65
        // initialises the state of the global random number generator
66
        // should only be called once.
67
        // (note, a few std::variate_generator<> (like normal) have their
68
        // own state which would need a reset as well to guarantee identical
69
        // sequence of numbers, e.g. via myrand.distribution().reset())
70
21
        global_rng.seed(seed ^ time(nullptr));
71
21
    }
72
};
73
74
RandomNumberGenerator& GetTheRandomNumberGenerator()
75
1.07M
{
76
1.07M
    static RandomNumberGenerator RANDOM;
77
1.07M
    return RANDOM;
78
1.07M
}
79
}
80
81
0
void reseed() { GetTheRandomNumberGenerator().reseed(); }
82
83
// uniform ints [a,b] distribution
84
int uniform_int_distribution(int a, int b)
85
105k
{
86
105k
    std::uniform_int_distribution<int> dist(a, b);
87
105k
    auto& gen = GetTheRandomNumberGenerator();
88
105k
    std::scoped_lock<std::mutex> g(gen.mutex);
89
105k
    return dist(gen.global_rng);
90
105k
}
91
92
// uniform ints [a,b] distribution
93
unsigned int uniform_uint_distribution(unsigned int a, unsigned int b)
94
967k
{
95
967k
    std::uniform_int_distribution<unsigned int> dist(a, b);
96
967k
    auto& gen = GetTheRandomNumberGenerator();
97
967k
    std::scoped_lock<std::mutex> g(gen.mutex);
98
967k
    return dist(gen.global_rng);
99
967k
}
100
101
// uniform size_t [a,b] distribution
102
size_t uniform_size_distribution(size_t a, size_t b)
103
704
{
104
704
    std::uniform_int_distribution<size_t> dist(a, b);
105
704
    auto& gen = GetTheRandomNumberGenerator();
106
704
    std::scoped_lock<std::mutex> g(gen.mutex);
107
704
    return dist(gen.global_rng);
108
704
}
109
110
// uniform size_t [a,b) distribution
111
double uniform_real_distribution(double a, double b)
112
0
{
113
    assert(a < b);
114
0
    std::uniform_real_distribution<double> dist(a, b);
115
0
    auto& gen = GetTheRandomNumberGenerator();
116
0
    std::scoped_lock<std::mutex> g(gen.mutex);
117
0
    return dist(gen.global_rng);
118
0
}
119
120
} // namespace
121
122
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */