Pyrogenesis  trunk
ConfigDB.h
Go to the documentation of this file.
1 /* Copyright (C) 2022 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  CConfigDB - Load, access and store configuration variables
20 
21  TDD : http://www.wildfiregames.com/forum/index.php?showtopic=1125
22  OVERVIEW:
23 
24  JavaScript: Check this documentation: http://trac.wildfiregames.com/wiki/Exposed_ConfigDB_Functions
25 */
26 
27 #ifndef INCLUDED_CONFIGDB
28 #define INCLUDED_CONFIGDB
29 
30 #include "lib/file/vfs/vfs_path.h"
31 #include "ps/CStr.h"
32 
33 #include <array>
34 #include <map>
35 #include <memory>
36 #include <mutex>
37 #include <vector>
38 
39 /**
40  * Namespace priorities:
41  * - Command line args override everything
42  * - User supersedes HWDetect (let the user try crashing his system).
43  * - HWDetect supersedes mods & default -> mods can mod hwdetect itself.
44  * - SYSTEM is used for local.cfg and is basically for setting custom defaults.
45  */
47 {
55 };
56 
57 using CConfigValueSet = std::vector<CStr>;
58 
59 // Opaque data type so that callers that hook into ConfigDB can delete their hooks.
60 // Would be defined in CConfigDB but then it couldn't be forward-declared, which is rather annoying.
61 // Actually defined below - requires access to CConfigDB.
62 class CConfigDBHook;
63 
64 #define g_ConfigDB (*CConfigDB::Instance())
65 
66 class CConfigDB
67 {
68  friend CConfigDBHook;
69 public:
70  CConfigDB();
71  ~CConfigDB();
72  CConfigDB(const CConfigDB&) = delete;
73  CConfigDB(CConfigDB&&) = delete;
74 
75  static void Initialise();
76  static void Shutdown();
77  static bool IsInitialised();
78  static CConfigDB* Instance();
79 
80  /**
81  * Attempt to retrieve the value of a config variable with the given name;
82  * will search CFG_COMMAND first, and then all namespaces from the specified
83  * namespace down.
84  */
85  void GetValue(EConfigNamespace ns, const CStr& name, bool& value);
86  ///@copydoc CConfigDB::GetValue
87  void GetValue(EConfigNamespace ns, const CStr& name, int& value);
88  ///@copydoc CConfigDB::GetValue
89  void GetValue(EConfigNamespace ns, const CStr& name, u32& value);
90  ///@copydoc CConfigDB::GetValue
91  void GetValue(EConfigNamespace ns, const CStr& name, float& value);
92  ///@copydoc CConfigDB::GetValue
93  void GetValue(EConfigNamespace ns, const CStr& name, double& value);
94  ///@copydoc CConfigDB::GetValue
95  void GetValue(EConfigNamespace ns, const CStr& name, std::string& value);
96 
97  /**
98  * Returns true if changed with respect to last write on file
99  */
100  bool HasChanges(EConfigNamespace ns) const;
101 
102  void SetChanges(EConfigNamespace ns, bool value);
103 
104  /**
105  * Attempt to retrieve a vector of values corresponding to the given setting;
106  * will search CFG_COMMAND first, and then all namespaces from the specified
107  * namespace down.
108  */
109  void GetValues(EConfigNamespace ns, const CStr& name, CConfigValueSet& values) const;
110 
111  /**
112  * Returns the namespace that the value returned by GetValues was defined in,
113  * or CFG_LAST if it wasn't defined at all.
114  */
115  EConfigNamespace GetValueNamespace(EConfigNamespace ns, const CStr& name) const;
116 
117  /**
118  * Retrieve a map of values corresponding to settings whose names begin
119  * with the given prefix;
120  * will search all namespaces from default up to the specified namespace.
121  */
122  std::map<CStr, CConfigValueSet> GetValuesWithPrefix(EConfigNamespace ns, const CStr& prefix) const;
123 
124  /**
125  * Save a config value in the specified namespace. If the config variable
126  * existed the value is replaced.
127  */
128  void SetValueString(EConfigNamespace ns, const CStr& name, const CStr& value);
129 
130  void SetValueBool(EConfigNamespace ns, const CStr& name, const bool value);
131 
132  void SetValueList(EConfigNamespace ns, const CStr& name, std::vector<CStr> values);
133 
134  /**
135  * Remove a config value in the specified namespace.
136  */
137  bool RemoveValue(EConfigNamespace ns, const CStr& name);
138 
139  /**
140  * Set the path to the config file used to populate the specified namespace
141  * Note that this function does not actually load the config file. Use
142  * the Reload() method if you want to read the config file at the same time.
143  *
144  * 'path': The path to the config file.
145  */
146  void SetConfigFile(EConfigNamespace ns, const VfsPath& path);
147 
148  /**
149  * Reload the config file associated with the specified config namespace
150  * (the last config file path set with SetConfigFile)
151  *
152  * Returns:
153  * true: if the reload succeeded,
154  * false: if the reload failed
155  */
156  bool Reload(EConfigNamespace);
157 
158  /**
159  * Write the current state of the specified config namespace to the file
160  * specified by 'path'
161  *
162  * Returns:
163  * true: if the config namespace was successfully written to the file
164  * false: if an error occurred
165  */
166  bool WriteFile(EConfigNamespace ns, const VfsPath& path) const;
167 
168  /**
169  * Write the current state of the specified config namespace to the file
170  * it was originally loaded from.
171  *
172  * Returns:
173  * true: if the config namespace was successfully written to the file
174  * false: if an error occurred
175  */
176  bool WriteFile(EConfigNamespace ns) const;
177 
178  /**
179  * Write a config value to the file specified by 'path'
180  *
181  * Returns:
182  * true: if the config value was successfully saved and written to the file
183  * false: if an error occurred
184  */
185  bool WriteValueToFile(EConfigNamespace ns, const CStr& name, const CStr& value, const VfsPath& path);
186 
187  bool WriteValueToFile(EConfigNamespace ns, const CStr& name, const CStr& value);
188 
189  /**
190  * Register a simple lambda that will be called anytime the value changes in any namespace
191  * This is simple on purpose, the hook is responsible for checking if it should do something.
192  * When RegisterHookAndCall is called, the hook is immediately triggered.
193  * NB: CConfigDBHook will auto-unregister the hook when destroyed,
194  * so you can use it to tie the lifetime of the hook to your object.
195  * The hook will be deleted alongside ConfigDB anyways.
196  */
197  [[nodiscard]] CConfigDBHook RegisterHookAndCall(const CStr& name, std::function<void()> hook);
198 
199  void UnregisterHook(CConfigDBHook&& hook);
200  void UnregisterHook(std::unique_ptr<CConfigDBHook> hook);
201 
202 private:
203  std::array<std::map<CStr, CConfigValueSet>, CFG_LAST> m_Map;
204  std::multimap<CStr, std::function<void()>> m_Hooks;
205  std::array<VfsPath, CFG_LAST> m_ConfigFile;
206  std::array<bool, CFG_LAST> m_HasChanges;
207 
208  mutable std::recursive_mutex m_Mutex;
209 };
210 
212 {
213  friend class CConfigDB;
214 public:
215  CConfigDBHook() = delete;
216  CConfigDBHook(const CConfigDBHook&) = delete;
217  // Point the moved-from hook to end, which is checked for in UnregisterHook,
218  // to avoid a double-erase error.
219  CConfigDBHook(CConfigDBHook&& h) : m_ConfigDB(h.m_ConfigDB)
220  {
221  m_Ptr = std::move(h.m_Ptr);
222  h.m_Ptr = m_ConfigDB.m_Hooks.end();
223  }
224  // Unregisters the hook. Must be called before the original ConfigDB gets deleted.
226  {
227  m_ConfigDB.UnregisterHook(std::move(*this));
228  }
229 private:
230  CConfigDBHook(CConfigDB& cdb, std::multimap<CStr, std::function<void()>>::iterator p)
231  : m_ConfigDB(cdb), m_Ptr(p)
232  {};
233 
234  std::multimap<CStr, std::function<void()>>::iterator m_Ptr;
236 };
237 
238 
239 // stores the value of the given key into <destination>. this quasi-template
240 // convenience wrapper on top of GetValue simplifies user code
241 #define CFG_GET_VAL(name, destination)\
242  g_ConfigDB.GetValue(CFG_USER, name, destination)
243 
244 #endif // INCLUDED_CONFIGDB
std::array< bool, CFG_LAST > m_HasChanges
Definition: ConfigDB.h:206
void UnregisterHook(CConfigDBHook &&hook)
Definition: ConfigDB.cpp:524
CConfigDBHook RegisterHookAndCall(const CStr &name, std::function< void()> hook)
Register a simple lambda that will be called anytime the value changes in any namespace This is simpl...
Definition: ConfigDB.cpp:517
void SetValueList(EConfigNamespace ns, const CStr &name, std::vector< CStr > values)
Definition: ConfigDB.cpp:255
static bool IsInitialised()
Definition: ConfigDB.cpp:134
std::array< std::map< CStr, CConfigValueSet >, CFG_LAST > m_Map
Definition: ConfigDB.h:203
CConfigDBHook(CConfigDB &cdb, std::multimap< CStr, std::function< void()>>::iterator p)
Definition: ConfigDB.h:230
~CConfigDB()
Definition: ConfigDB.cpp:149
bool HasChanges(EConfigNamespace ns) const
Returns true if changed with respect to last write on file.
Definition: ConfigDB.cpp:153
static CConfigDB * Instance()
Definition: ConfigDB.cpp:139
static void Shutdown()
Definition: ConfigDB.cpp:129
Definition: ConfigDB.h:50
std::vector< CStr > CConfigValueSet
Definition: ConfigDB.h:57
std::multimap< CStr, std::function< void()> >::iterator m_Ptr
Definition: ConfigDB.h:232
std::recursive_mutex m_Mutex
Definition: ConfigDB.h:208
void GetValues(EConfigNamespace ns, const CStr &name, CConfigValueSet &values) const
Attempt to retrieve a vector of values corresponding to the given setting; will search CFG_COMMAND fi...
Definition: ConfigDB.cpp:169
void GetValue(EConfigNamespace ns, const CStr &name, bool &value)
Attempt to retrieve the value of a config variable with the given name; will search CFG_COMMAND first...
uint32_t u32
Definition: types.h:39
Definition: ConfigDB.h:52
void SetValueString(EConfigNamespace ns, const CStr &name, const CStr &value)
Save a config value in the specified namespace.
Definition: ConfigDB.cpp:232
Definition: path.h:79
CConfigDBHook(CConfigDBHook &&h)
Definition: ConfigDB.h:219
bool Reload(EConfigNamespace)
Reload the config file associated with the specified config namespace (the last config file path set ...
Definition: ConfigDB.cpp:289
Definition: ConfigDB.h:54
EConfigNamespace GetValueNamespace(EConfigNamespace ns, const CStr &name) const
Returns the namespace that the value returned by GetValues was defined in, or CFG_LAST if it wasn&#39;t d...
Definition: ConfigDB.cpp:192
std::map< CStr, CConfigValueSet > GetValuesWithPrefix(EConfigNamespace ns, const CStr &prefix) const
Retrieve a map of values corresponding to settings whose names begin with the given prefix; will sear...
Definition: ConfigDB.cpp:211
void SetChanges(EConfigNamespace ns, bool value)
Definition: ConfigDB.cpp:161
bool WriteFile(EConfigNamespace ns, const VfsPath &path) const
Write the current state of the specified config namespace to the file specified by &#39;path&#39;...
Definition: ConfigDB.cpp:461
friend CConfigDBHook
Definition: ConfigDB.h:68
Definition: ConfigDB.h:48
bool WriteValueToFile(EConfigNamespace ns, const CStr &name, const CStr &value, const VfsPath &path)
Write a config value to the file specified by &#39;path&#39;.
Definition: ConfigDB.cpp:501
std::array< VfsPath, CFG_LAST > m_ConfigFile
Definition: ConfigDB.h:205
static void Initialise()
Definition: ConfigDB.cpp:124
void SetValueBool(EConfigNamespace ns, const CStr &name, const bool value)
Definition: ConfigDB.cpp:249
EConfigNamespace
Namespace priorities:
Definition: ConfigDB.h:46
std::multimap< CStr, std::function< void()> > m_Hooks
Definition: ConfigDB.h:204
void SetConfigFile(EConfigNamespace ns, const VfsPath &path)
Set the path to the config file used to populate the specified namespace Note that this function does...
Definition: ConfigDB.cpp:281
Definition: ConfigDB.h:66
CConfigDB()
Definition: ConfigDB.cpp:144
Definition: ConfigDB.h:53
~CConfigDBHook()
Definition: ConfigDB.h:225
Definition: ConfigDB.h:51
CConfigDB & m_ConfigDB
Definition: ConfigDB.h:235
Definition: ConfigDB.h:49
Definition: ConfigDB.h:211
bool RemoveValue(EConfigNamespace ns, const CStr &name)
Remove a config value in the specified namespace.
Definition: ConfigDB.cpp:267