LCOV - code coverage report
Current view: top level - source/ps - ConfigDB.h (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 0 11 0.0 %
Date: 2023-01-19 00:18:29 Functions: 0 3 0.0 %

          Line data    Source code
       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             :  */
      46             : enum EConfigNamespace
      47             : {
      48             :     CFG_DEFAULT,
      49             :     CFG_MOD,
      50             :     CFG_SYSTEM,
      51             :     CFG_HWDETECT,
      52             :     CFG_USER,
      53             :     CFG_COMMAND,
      54             :     CFG_LAST
      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             : 
     211             : class CConfigDBHook
     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           0 :     CConfigDBHook(CConfigDBHook&& h) : m_ConfigDB(h.m_ConfigDB)
     220             :     {
     221           0 :         m_Ptr = std::move(h.m_Ptr);
     222           0 :         h.m_Ptr = m_ConfigDB.m_Hooks.end();
     223           0 :     }
     224             :     // Unregisters the hook. Must be called before the original ConfigDB gets deleted.
     225           0 :     ~CConfigDBHook()
     226           0 :     {
     227           0 :         m_ConfigDB.UnregisterHook(std::move(*this));
     228           0 :     }
     229             : private:
     230           0 :     CConfigDBHook(CConfigDB& cdb, std::multimap<CStr, std::function<void()>>::iterator p)
     231           0 :         : m_ConfigDB(cdb), m_Ptr(p)
     232           0 :     {};
     233             : 
     234             :     std::multimap<CStr, std::function<void()>>::iterator m_Ptr;
     235             :     CConfigDB& m_ConfigDB;
     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

Generated by: LCOV version 1.13