database.hpp 6.3 KB

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