Freeciv21
Develop your civilization from humble roots to a global empire
rand.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2021 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
20 // utility
21 #include "log.h"
22 
23 #include "rand.h"
24 #include "shared.h"
25 
26 // Qt
27 #include <QRandomGenerator>
28 
29 #define log_rand log_debug
30 
31 /* A global random state:
32  * Initialized by fc_srand(), updated by fc_rand(),
33  * Can be duplicated/saved/restored via fc_rand_state()
34  * and fc_rand_set_state().
35  */
36 namespace {
37 Q_LOGGING_CATEGORY(random_category, "freeciv.random");
38 static std::mt19937 generator = std::mt19937();
39 bool is_init = false;
40 } // namespace
41 
47 std::uint_fast32_t fc_rand_debug(std::uint_fast32_t size,
48  const char *called_as, int line,
49  const char *file)
50 {
51  // uniform_int_distribution(a, b) is UB if a > b, so protect
52  // against it. Also short-circuit for size == 1 which is always 0
53  // anyway.
54  if (size <= 1) {
55  return 0;
56  }
57 
58  std::uniform_int_distribution<std::uint_fast32_t> uniform(0, size - 1);
59 
60  auto random = uniform(generator);
61  qCDebug(random_category, "%s(%lu) = %lu at %s:%d", called_as,
62  (unsigned long) size, (unsigned long) random, file, line);
63  return random;
64 }
65 
69 void fc_srand(std::uint_fast32_t seed)
70 {
71  generator.seed(seed);
72  fc_rand_set_init(true);
73 }
74 
78 bool fc_rand_is_init() { return is_init; }
79 
83 void fc_rand_set_init(bool init) { is_init = init; }
84 
85 namespace /* anonymous */ {
86 
91 struct random_seed_seq {
95  template <typename It> void generate(It begin, It end)
96  {
97  for (; begin != end; ++begin) {
98  *begin = qgenerator();
99  }
100  }
101 
103  using result_type = decltype(QRandomGenerator64{}.generate());
104 
105 private:
106  QRandomGenerator64 qgenerator = QRandomGenerator64::securelySeeded();
107 };
108 } // anonymous namespace
109 
113 void fc_rand_seed(std::mt19937 &gen)
114 {
115  auto seed = random_seed_seq();
116  gen.seed(seed);
117 }
118 
123 std::mt19937 &fc_rand_state() { return generator; }
124 
129 void fc_rand_set_state(const std::mt19937 &state)
130 {
131  generator = state;
132  fc_rand_set_init(true);
133 }
134 
142 std::uint_fast32_t fc_randomly_debug(std::uint_fast32_t seed,
143  std::uint_fast32_t size,
144  const char *called_as, int line,
145  const char *file)
146 {
147  std::uint_fast32_t result;
148 
149 #define LARGE_PRIME (10007)
150 #define SMALL_PRIME (1009)
151 
152  // Check for overflow and underflow
155  fc_assert_ret_val(size > 0, 0);
156  result = ((seed * LARGE_PRIME) % SMALL_PRIME) % size;
157 
158  log_rand("%s(%lu,%lu) = %lu at %s:%d", called_as, (unsigned long) seed,
159  (unsigned long) size, (unsigned long) result, file, line);
160 
161  return result;
162 }
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
bool init
Definition: mapimg.cpp:328
void fc_rand_set_init(bool init)
Sets whether the current state has been initialized.
Definition: rand.cpp:83
std::mt19937 & fc_rand_state()
Returns a reference to the current random generator state; eg for save/restore.
Definition: rand.cpp:123
#define log_rand
Definition: rand.cpp:29
void fc_rand_set_state(const std::mt19937 &state)
Replace current rand_state with user-supplied; eg for save/restore.
Definition: rand.cpp:129
std::uint_fast32_t fc_randomly_debug(std::uint_fast32_t seed, std::uint_fast32_t size, const char *called_as, int line, const char *file)
Local pseudo-random function for repeatedly reaching the same result, instead of fc_rand().
Definition: rand.cpp:142
bool fc_rand_is_init()
Return whether the current state has been initialized.
Definition: rand.cpp:78
void fc_srand(std::uint_fast32_t seed)
Initialize the generator; see comment at top of file.
Definition: rand.cpp:69
#define LARGE_PRIME
#define SMALL_PRIME
std::uint_fast32_t fc_rand_debug(std::uint_fast32_t size, const char *called_as, int line, const char *file)
Returns a new random value from the sequence, in the interval 0 to (size-1) inclusive,...
Definition: rand.cpp:47
void fc_rand_seed(std::mt19937 &gen)
Seeds the given generator with a random value.
Definition: rand.cpp:113
#define MAX_UINT32
Definition: shared.h:73
size_t size
Definition: specvec.h:64
Q_LOGGING_CATEGORY(tileset_category, "freeciv.tileset")
Functions for handling the tilespec files which describe the files and contents of tilesets.