database.hpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #ifndef DATABASE_HPP
  4. #define DATABASE_HPP
  5. #include <unordered_map>
  6. #include <vector>
  7. #include <ryml_std.hpp>
  8. #include <ryml.hpp>
  9. #include "../config/core.hpp"
  10. #include "cbasetypes.hpp"
  11. #include "core.hpp"
  12. #include "utilities.hpp"
  13. class YamlDatabase{
  14. // Internal stuff
  15. private:
  16. std::string type;
  17. uint16 version;
  18. uint16 minimumVersion;
  19. std::string currentFile;
  20. bool shouldLoadGenerator{false};
  21. bool verifyCompatibility( const ryml::Tree& rootNode );
  22. bool load( const std::string& path );
  23. void parse( const ryml::Tree& rootNode );
  24. void parseImports( const ryml::Tree& rootNode );
  25. template <typename R> bool asType( const ryml::NodeRef& node, const std::string& name, R& out );
  26. // These should be visible/usable by the implementation provider
  27. protected:
  28. ryml::Parser parser;
  29. // Helper functions
  30. bool nodeExists( const ryml::NodeRef& node, const std::string& name );
  31. bool nodesExist( const ryml::NodeRef& node, std::initializer_list<const std::string> names );
  32. int32 getLineNumber(const ryml::NodeRef& node);
  33. int32 getColumnNumber(const ryml::NodeRef& node);
  34. void invalidWarning( const ryml::NodeRef& node, const char* fmt, ... );
  35. std::string getCurrentFile();
  36. // Conversion functions
  37. bool asBool(const ryml::NodeRef& node, const std::string &name, bool &out);
  38. bool asInt16(const ryml::NodeRef& node, const std::string& name, int16& out );
  39. bool asUInt16(const ryml::NodeRef& node, const std::string& name, uint16& out);
  40. bool asInt32(const ryml::NodeRef& node, const std::string &name, int32 &out);
  41. bool asUInt32(const ryml::NodeRef& node, const std::string &name, uint32 &out);
  42. bool asInt64(const ryml::NodeRef& node, const std::string &name, int64 &out);
  43. bool asUInt64(const ryml::NodeRef& node, const std::string &name, uint64 &out);
  44. bool asFloat(const ryml::NodeRef& node, const std::string &name, float &out);
  45. bool asDouble(const ryml::NodeRef& node, const std::string &name, double &out);
  46. bool asString(const ryml::NodeRef& node, const std::string &name, std::string &out);
  47. bool asUInt16Rate(const ryml::NodeRef& node, const std::string& name, uint16& out, uint16 maximum=10000);
  48. bool asUInt32Rate(const ryml::NodeRef& node, const std::string& name, uint32& out, uint32 maximum=10000);
  49. void setGenerator(bool shouldLoad);
  50. virtual void loadingFinished();
  51. public:
  52. YamlDatabase( const std::string& type_, uint16 version_, uint16 minimumVersion_ ){
  53. this->type = type_;
  54. this->version = version_;
  55. this->minimumVersion = minimumVersion_;
  56. }
  57. YamlDatabase( const std::string& type_, uint16 version_ ) : YamlDatabase( type_, version_, version_ ){
  58. // Empty since everything is handled by the real constructor
  59. }
  60. bool load();
  61. bool reload();
  62. // Functions that need to be implemented for each type
  63. virtual void clear() = 0;
  64. virtual const std::string getDefaultLocation() = 0;
  65. virtual uint64 parseBodyNode( const ryml::NodeRef& node ) = 0;
  66. };
  67. template <typename keytype, typename datatype> class TypesafeYamlDatabase : public YamlDatabase{
  68. protected:
  69. std::unordered_map<keytype, std::shared_ptr<datatype>> data;
  70. public:
  71. TypesafeYamlDatabase( const std::string& type_, uint16 version_, uint16 minimumVersion_ ) : YamlDatabase( type_, version_, minimumVersion_ ){
  72. }
  73. TypesafeYamlDatabase( const std::string& type_, uint16 version_ ) : YamlDatabase( type_, version_, version_ ){
  74. }
  75. void clear() override{
  76. this->data.clear();
  77. }
  78. bool empty(){
  79. return this->data.empty();
  80. }
  81. bool exists( keytype key ){
  82. return this->find( key ) != nullptr;
  83. }
  84. virtual std::shared_ptr<datatype> find( keytype key ){
  85. auto it = this->data.find( key );
  86. if( it != this->data.end() ){
  87. return it->second;
  88. }else{
  89. return nullptr;
  90. }
  91. }
  92. virtual void put( keytype key, std::shared_ptr<datatype> ptr ){
  93. this->data[key] = ptr;
  94. }
  95. typename std::unordered_map<keytype, std::shared_ptr<datatype>>::iterator begin(){
  96. return this->data.begin();
  97. }
  98. typename std::unordered_map<keytype, std::shared_ptr<datatype>>::iterator end(){
  99. return this->data.end();
  100. }
  101. size_t size(){
  102. return this->data.size();
  103. }
  104. std::shared_ptr<datatype> random(){
  105. if( this->empty() ){
  106. return nullptr;
  107. }
  108. return rathena::util::umap_random( this->data );
  109. }
  110. virtual void erase(keytype key) {
  111. this->data.erase(key);
  112. }
  113. };
  114. template <typename keytype, typename datatype> class TypesafeCachedYamlDatabase : public TypesafeYamlDatabase<keytype, datatype>{
  115. private:
  116. std::vector<std::shared_ptr<datatype>> cache;
  117. bool loaded;
  118. public:
  119. TypesafeCachedYamlDatabase( const std::string& type_, uint16 version_, uint16 minimumVersion_ ) : TypesafeYamlDatabase<keytype, datatype>( type_, version_, minimumVersion_ ){
  120. this->loaded = false;
  121. }
  122. TypesafeCachedYamlDatabase( const std::string& type_, uint16 version_ ) : TypesafeYamlDatabase<keytype, datatype>( type_, version_, version_ ){
  123. this->loaded = false;
  124. }
  125. void clear() override{
  126. TypesafeYamlDatabase<keytype, datatype>::clear();
  127. cache.clear();
  128. cache.shrink_to_fit();
  129. this->loaded = false;
  130. }
  131. std::shared_ptr<datatype> find( keytype key ) override{
  132. if( this->cache.empty() || key >= this->cache.size() ){
  133. return TypesafeYamlDatabase<keytype, datatype>::find( key );
  134. }else{
  135. return cache[this->calculateCacheKey( key )];
  136. }
  137. }
  138. std::vector<std::shared_ptr<datatype>> getCache() {
  139. return this->cache;
  140. }
  141. virtual size_t calculateCacheKey( keytype key ){
  142. return key;
  143. }
  144. void loadingFinished() override{
  145. // Cache all known values
  146. for (auto &pair : *this) {
  147. // Calculate the key that should be used
  148. size_t key = this->calculateCacheKey(pair.first);
  149. // Check if the key fits into the current cache size
  150. if (this->cache.capacity() <= key) {
  151. // Some keys compute to 0, so we allocate a minimum of 500 (250*2) entries
  152. const static size_t minimum = 250;
  153. // Double the current size, so we do not have to resize that often
  154. size_t new_size = std::max( key, minimum ) * 2;
  155. // Very important => initialize everything to nullptr
  156. this->cache.resize(new_size, nullptr);
  157. }
  158. // Insert the value into the cache
  159. this->cache[key] = pair.second;
  160. }
  161. for( auto it = this->cache.rbegin(); it != this->cache.rend(); it++ ){
  162. if( *it != nullptr ){
  163. // Resize to only fit all existing non null entries
  164. this->cache.resize( this->cache.rend() - it );
  165. // Free the memory that was allocated too much
  166. this->cache.shrink_to_fit();
  167. break;
  168. }
  169. }
  170. this->loaded = true;
  171. }
  172. void erase( keytype key ) override{
  173. TypesafeYamlDatabase<keytype, datatype>::erase( key );
  174. // Prevent excessive usage during loading
  175. if( this->loaded ){
  176. this->cache[this->calculateCacheKey( key )] = nullptr;
  177. }
  178. }
  179. void put( keytype key, std::shared_ptr<datatype> ptr ) override{
  180. TypesafeYamlDatabase<keytype, datatype>::put( key, ptr );
  181. // Prevent excessive usage during loading
  182. if( this->loaded ){
  183. this->cache[this->calculateCacheKey( key )] = ptr;
  184. }
  185. }
  186. };
  187. void do_init_database();
  188. #endif /* DATABASE_HPP */