CVarSet.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Util/List.h>
  7. #include <AnKi/Util/String.h>
  8. #include <AnKi/Util/Singleton.h>
  9. #include <AnKi/Util/WeakArray.h>
  10. namespace anki {
  11. /// @addtogroup util_other
  12. /// @{
  13. /// Define a global CVAR.
  14. #define ANKI_CVAR(type, namespace, name, ...) inline type g_cvar##namespace##name(ANKI_STRINGIZE(namespace) "." ANKI_STRINGIZE(name), __VA_ARGS__);
  15. /// Same as ANKI_CVAR but you can define 2 namespaces.
  16. #define ANKI_CVAR2(type, namespaceA, namespaceB, name, ...) \
  17. inline type g_cvar##namespaceA##namespaceB##name(ANKI_STRINGIZE(namespaceA) "." ANKI_STRINGIZE(namespaceB) "." ANKI_STRINGIZE(name), __VA_ARGS__);
  18. enum class CVarValueType : U32
  19. {
  20. kString,
  21. kBool,
  22. kNumericU8,
  23. kNumericU16,
  24. kNumericU32,
  25. kNumericPtrSize,
  26. kNumericF32,
  27. kNumericF64
  28. };
  29. /// ConfigSet variable base.
  30. class CVar : public IntrusiveListEnabled<CVar>
  31. {
  32. friend class CVarSet;
  33. public:
  34. CVar(const CVar&) = delete;
  35. CVar& operator=(const CVar&) = delete;
  36. CString getName() const
  37. {
  38. return m_name;
  39. }
  40. CVarValueType getValueType() const
  41. {
  42. return m_type;
  43. }
  44. protected:
  45. CString m_name;
  46. CString m_descr;
  47. CVarValueType m_type;
  48. CVar(CVarValueType type, CString name, CString descr = {})
  49. : m_name(name)
  50. , m_descr((!descr.isEmpty()) ? descr : "No description")
  51. , m_type(type)
  52. {
  53. registerSelf();
  54. }
  55. void validateSetValue() const
  56. #if ANKI_ASSERTIONS_ENABLED
  57. ;
  58. #else
  59. {
  60. }
  61. #endif
  62. private:
  63. void registerSelf();
  64. };
  65. /// Numeric config variable.
  66. template<typename TNumber>
  67. class NumericCVar : public CVar
  68. {
  69. public:
  70. using CheckValueCallback = Bool (*)(TNumber);
  71. /// Initialize using a custom callback the checks the correctness of the value.
  72. NumericCVar(CString name, TNumber defaultVal, CheckValueCallback checkValueCallback, CString descr = CString())
  73. : CVar(getCVarType(), name, descr)
  74. , m_value(defaultVal)
  75. , m_checkValueCallback(checkValueCallback)
  76. {
  77. ANKI_ASSERT(checkValueCallback);
  78. ANKI_ASSERT(checkValueCallback(defaultVal));
  79. }
  80. /// Initialize using a min max range.
  81. NumericCVar(CString name, TNumber defaultVal, TNumber min = getMinNumericLimit<TNumber>(), TNumber max = getMaxNumericLimit<TNumber>(),
  82. CString descr = CString())
  83. : CVar(getCVarType(), name, descr)
  84. , m_value(defaultVal)
  85. , m_min(min)
  86. , m_max(max)
  87. {
  88. ANKI_ASSERT(min <= max);
  89. ANKI_ASSERT(defaultVal >= min && defaultVal <= max);
  90. }
  91. NumericCVar& operator=(TNumber val)
  92. {
  93. validateSetValue();
  94. Bool ok = true;
  95. if(!m_checkValueCallback)
  96. {
  97. const TNumber newVal = clamp(val, m_min, m_max);
  98. ok = (newVal == val);
  99. m_value = newVal;
  100. }
  101. else
  102. {
  103. ok = m_checkValueCallback(val);
  104. if(ok)
  105. {
  106. m_value = val;
  107. }
  108. }
  109. if(!ok)
  110. {
  111. ANKI_UTIL_LOGW("Wrong value set for config var: %s", m_name.cstr());
  112. }
  113. return *this;
  114. }
  115. operator TNumber() const
  116. {
  117. return m_value;
  118. }
  119. private:
  120. TNumber m_value;
  121. TNumber m_min = getMinNumericLimit<TNumber>();
  122. TNumber m_max = getMaxNumericLimit<TNumber>();
  123. CheckValueCallback m_checkValueCallback = nullptr;
  124. static CVarValueType getCVarType();
  125. };
  126. #define ANKI_CVAR_NUMERIC_TYPE(type) \
  127. template<> \
  128. inline CVarValueType NumericCVar<type>::getCVarType() \
  129. { \
  130. return CVarValueType::kNumeric##type; \
  131. }
  132. ANKI_CVAR_NUMERIC_TYPE(U8)
  133. ANKI_CVAR_NUMERIC_TYPE(U16)
  134. ANKI_CVAR_NUMERIC_TYPE(U32)
  135. ANKI_CVAR_NUMERIC_TYPE(PtrSize)
  136. ANKI_CVAR_NUMERIC_TYPE(F32)
  137. ANKI_CVAR_NUMERIC_TYPE(F64)
  138. #undef ANKI_CVAR_NUMERIC_TYPE
  139. /// String config variable.
  140. class StringCVar : public CVar
  141. {
  142. public:
  143. StringCVar(CString name, CString value, CString descr = CString())
  144. : CVar(CVarValueType::kString, name, descr)
  145. {
  146. *this = value;
  147. }
  148. ~StringCVar()
  149. {
  150. if(m_str)
  151. {
  152. free(m_str);
  153. }
  154. }
  155. StringCVar& operator=(CString name)
  156. {
  157. validateSetValue();
  158. if(m_str)
  159. {
  160. free(m_str);
  161. }
  162. const U len = name.getLength();
  163. m_str = static_cast<Char*>(malloc(len + 1));
  164. if(len == 0)
  165. {
  166. m_str[0] = '\0';
  167. }
  168. else
  169. {
  170. memcpy(m_str, name.cstr(), len + 1);
  171. }
  172. return *this;
  173. }
  174. operator CString() const
  175. {
  176. return m_str;
  177. }
  178. private:
  179. Char* m_str;
  180. };
  181. /// Boolean config variable.
  182. class BoolCVar : public CVar
  183. {
  184. public:
  185. explicit BoolCVar(CString name, Bool defaultVal, CString descr = CString())
  186. : CVar(CVarValueType::kBool, name, descr)
  187. , m_val(defaultVal)
  188. {
  189. }
  190. BoolCVar& operator=(Bool val)
  191. {
  192. validateSetValue();
  193. m_val = val;
  194. return *this;
  195. }
  196. operator Bool() const
  197. {
  198. return m_val;
  199. }
  200. private:
  201. Bool m_val;
  202. };
  203. /// Access all configuration variables.
  204. class CVarSet : public MakeSingletonLazyInit<CVarSet>
  205. {
  206. friend class CVar;
  207. public:
  208. CVarSet() = default;
  209. CVarSet(const CVarSet& b) = delete; // Non-copyable
  210. CVarSet& operator=(const CVarSet& b) = delete; // Non-copyable
  211. Error loadFromFile(CString filename);
  212. Error saveToFile(CString filename) const;
  213. Error setFromCommandLineArguments(U32 cmdLineArgsCount, Char* cmdLineArgs[])
  214. {
  215. ConstWeakArray<const Char*> arr(cmdLineArgs, cmdLineArgsCount);
  216. return setMultiple(arr);
  217. }
  218. template<U32 kTCount>
  219. Error setMultiple(Array<const Char*, kTCount> arr)
  220. {
  221. return setMultiple(ConstWeakArray<const Char*>(arr.getBegin(), kTCount));
  222. }
  223. Error setMultiple(ConstWeakArray<const Char*> arr);
  224. template<typename TFunc>
  225. void iterateCVars(TFunc func)
  226. {
  227. for(CVar& cvar : m_cvars)
  228. {
  229. if(func(cvar) == FunctorContinue::kStop)
  230. {
  231. return;
  232. }
  233. }
  234. }
  235. private:
  236. IntrusiveList<CVar> m_cvars;
  237. #if ANKI_ASSERTIONS_ENABLED
  238. U64 m_mainThreadHandle = 0;
  239. #endif
  240. void registerCVar(CVar* var);
  241. };
  242. inline void CVar::registerSelf()
  243. {
  244. CVarSet::getSingleton().registerCVar(this);
  245. }
  246. /// @}
  247. } // end namespace anki