SQLamarr
The stand-alone ultra-fast simulation option for the LHCb experiment
GlobalPRNG.h
1 // (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration.
2 //
3 // This software is distributed under the terms of the GNU General Public
4 // Licence version 3 (GPL Version 3), copied verbatim in the file "LICENCE".
5 //
6 // In applying this licence, CERN does not waive the privileges and immunities
7 // granted to it by virtue of its status as an Intergovernmental Organization
8 // or submit itself to any jurisdiction.
9 
10 
11 #pragma once
12 
13 #include <unordered_map>
14 #include <algorithm>
15 #include <random>
16 #include <memory>
17 #include <iostream>
18 #include <mutex>
19 
20 #include "sqlite3.h"
21 
22 namespace SQLamarr
23 {
80  template <class PRNG>
82  {
83  public: // static methods
86  static constexpr uint64_t no_seed = 0xBAD0000000000000L;
87 
88 
91  static T_GlobalPRNG& handle()
92  {
93  static T_GlobalPRNG instance;
94  return instance;
95  }
96 
97 
99  static PRNG* get_or_create (
100  const sqlite3_context* db,
101  uint64_t seed = no_seed
102  )
103  {
104  sqlite3_context* db_ = const_cast<sqlite3_context*> (db);
105  return get_or_create(sqlite3_context_db_handle(db_), seed);
106  }
107 
108 
110  static PRNG* get_or_create (
111  const sqlite3* db,
112  uint64_t seed = no_seed
113  )
114  {
115  // Gets the singleton handle
117  std::lock_guard<std::mutex>(h.m_mutex); // Forbids multithreading
118 
119  // Looks for the DB in the hash table
120  auto gen_it = h.m_generators.find(db);
121 
122  // If initialized return it, possibly after re-seeding.
123  if (gen_it != h.m_generators.end())
124  {
125  if (seed == no_seed)
126  return gen_it->second.get();
127 
128  // Reseeding
129  gen_it->second->seed(static_cast<uint32_t>(0xFFFFFFFFL & seed));
130  return gen_it->second.get();
131  }
132 
133  // If it is a new instance:
134  // - if no seed is passed, use random_device for seeding or throw
135  if (seed == no_seed)
136  {
137 #ifndef ALLOW_RANDOM_DEVICE_FOR_SEEDING
138  std::cerr << "Trying to use unseeded generator. "
139  << "Compile with -DALLOW_RANDOM_DEVICE_FOR_SEEDING to ignore."
140  << std::endl;
141  throw std::logic_error("Random seeding disabled.");
142 #endif
143  std::random_device seeder;
144  h.m_generators[db] = std::unique_ptr<PRNG>(new PRNG(seeder()));
145  return h.m_generators[db].get();
146  }
147 
148  // - if a seed is provided, create a new generator
149  h.m_generators[db] = std::unique_ptr<PRNG>(new PRNG(
150  static_cast<uint32_t>(0xFFFFFFFFL & seed)
151  ));
152 
153  return h.m_generators[db].get();
154  }
155 
157  static bool release (const sqlite3* db)
158  {
160  std::lock_guard<std::mutex>(h.m_mutex); // Forbids multithreading
161 
162  auto it = h.m_generators.find(db);
163  bool releasing_unexisting = (it == h.m_generators.end());
164  h.m_generators.erase(db);
165  return releasing_unexisting;
166  }
167 
168 
169  private:
170  T_GlobalPRNG() {}
171 
172  std::unordered_map<const sqlite3*, std::unique_ptr<PRNG> > m_generators;
173 
174  std::mutex m_mutex;
175 
176  public:
178  T_GlobalPRNG(T_GlobalPRNG const&) = delete;
179 
181  void operator=(T_GlobalPRNG const&) = delete;
182  };
183 
186 
189 }
Singleton handler of Pseudo-Random Number Generator(s)
Definition: GlobalPRNG.h:82
static PRNG * get_or_create(const sqlite3_context *db, uint64_t seed=no_seed)
Return a pointer to an initialized generator.
Definition: GlobalPRNG.h:99
static T_GlobalPRNG & handle()
Return a handle to the hash table, not to the single generator (see below).
Definition: GlobalPRNG.h:91
static bool release(const sqlite3 *db)
Releases a generator (delete). May require re-seeding.
Definition: GlobalPRNG.h:157
static PRNG * get_or_create(const sqlite3 *db, uint64_t seed=no_seed)
Return a pointer to an initialized generator.
Definition: GlobalPRNG.h:110
static constexpr uint64_t no_seed
Higher part of the int64 is used to identify missing or invalid seed.
Definition: GlobalPRNG.h:86
void operator=(T_GlobalPRNG const &)=delete
Copy operator disabled as per singleton pattern.
T_GlobalPRNG(T_GlobalPRNG const &)=delete
Copy constructor disabled as per singleton pattern.
T_GlobalPRNG< std::ranlux48 > GlobalPRNG
Default specialization using RANLUX48.
Definition: GlobalPRNG.h:185
T_GlobalPRNG< std::mt19937 > GlobalPRNG_MT
An additional specialization for testing purpose using Marsenne Twister.
Definition: GlobalPRNG.h:188