rathena/src/common/database.hpp
Lemongrass3110 534c5b2edd
Add more Github Actions (#6530)
Renames "build_servers.yml" to "build_servers_gcc.yml"
Removed Pre-Renewal and Renewal from GCC compilation
Added an action for Pre-Renewal and Renewal
Added an action for VIP
Added an action for different packet versions
Added MSVS build
Changed some make server to make all
Added master building
Disabled LTO by default
Added some missing override declarations
Added Clang building
Disabled Clang 12 and 13 for the time being

Thanks to @aleos89 and @Akkarinage for their help and input.
2022-01-19 00:08:28 +01:00

198 lines
5.7 KiB
C++

// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#ifndef DATABASE_HPP
#define DATABASE_HPP
#include <unordered_map>
#include <vector>
#include <yaml-cpp/yaml.h>
#include "../config/core.hpp"
#include "cbasetypes.hpp"
#include "core.hpp"
#include "utilities.hpp"
class YamlDatabase{
// Internal stuff
private:
std::string type;
uint16 version;
uint16 minimumVersion;
std::string currentFile;
bool verifyCompatibility( const YAML::Node& rootNode );
bool load( const std::string& path );
void parse( const YAML::Node& rootNode );
void parseImports( const YAML::Node& rootNode );
template <typename R> bool asType( const YAML::Node& node, const std::string& name, R& out );
// These should be visible/usable by the implementation provider
protected:
// Helper functions
bool nodeExists( const YAML::Node& node, const std::string& name );
bool nodesExist( const YAML::Node& node, std::initializer_list<const std::string> names );
void invalidWarning( const YAML::Node &node, const char* fmt, ... );
std::string getCurrentFile();
// Conversion functions
bool asBool(const YAML::Node &node, const std::string &name, bool &out);
bool asInt16(const YAML::Node& node, const std::string& name, int16& out );
bool asUInt16(const YAML::Node& node, const std::string& name, uint16& out);
bool asInt32(const YAML::Node &node, const std::string &name, int32 &out);
bool asUInt32(const YAML::Node &node, const std::string &name, uint32 &out);
bool asInt64(const YAML::Node &node, const std::string &name, int64 &out);
bool asUInt64(const YAML::Node &node, const std::string &name, uint64 &out);
bool asFloat(const YAML::Node &node, const std::string &name, float &out);
bool asDouble(const YAML::Node &node, const std::string &name, double &out);
bool asString(const YAML::Node &node, const std::string &name, std::string &out);
bool asUInt16Rate(const YAML::Node& node, const std::string& name, uint16& out, uint16 maximum=10000);
bool asUInt32Rate(const YAML::Node& node, const std::string& name, uint32& out, uint32 maximum=10000);
virtual void loadingFinished();
public:
YamlDatabase( const std::string type_, uint16 version_, uint16 minimumVersion_ ){
this->type = type_;
this->version = version_;
this->minimumVersion = minimumVersion_;
}
YamlDatabase( const std::string& type_, uint16 version_ ) : YamlDatabase( type_, version_, version_ ){
// Empty since everything is handled by the real constructor
}
bool load();
bool reload();
// Functions that need to be implemented for each type
virtual void clear() = 0;
virtual const std::string getDefaultLocation() = 0;
virtual uint64 parseBodyNode( const YAML::Node& node ) = 0;
};
template <typename keytype, typename datatype> class TypesafeYamlDatabase : public YamlDatabase{
protected:
std::unordered_map<keytype, std::shared_ptr<datatype>> data;
public:
TypesafeYamlDatabase( const std::string type_, uint16 version_, uint16 minimumVersion_ ) : YamlDatabase( type_, version_, minimumVersion_ ){
}
TypesafeYamlDatabase( const std::string& type_, uint16 version_ ) : YamlDatabase( type_, version_, version_ ){
}
void clear() override{
this->data.clear();
}
bool empty(){
return this->data.empty();
}
bool exists( keytype key ){
return this->find( key ) != nullptr;
}
virtual std::shared_ptr<datatype> find( keytype key ){
auto it = this->data.find( key );
if( it != this->data.end() ){
return it->second;
}else{
return nullptr;
}
}
void put( keytype key, std::shared_ptr<datatype> ptr ){
this->data[key] = ptr;
}
typename std::unordered_map<keytype, std::shared_ptr<datatype>>::iterator begin(){
return this->data.begin();
}
typename std::unordered_map<keytype, std::shared_ptr<datatype>>::iterator end(){
return this->data.end();
}
size_t size(){
return this->data.size();
}
std::shared_ptr<datatype> random(){
if( this->empty() ){
return nullptr;
}
return rathena::util::umap_random( this->data );
}
void erase(keytype key) {
this->data.erase(key);
}
};
template <typename keytype, typename datatype> class TypesafeCachedYamlDatabase : public TypesafeYamlDatabase<keytype, datatype>{
private:
std::vector<std::shared_ptr<datatype>> cache;
public:
TypesafeCachedYamlDatabase( const std::string type_, uint16 version_, uint16 minimumVersion_ ) : TypesafeYamlDatabase<keytype, datatype>( type_, version_, minimumVersion_ ){
}
TypesafeCachedYamlDatabase( const std::string& type_, uint16 version_ ) : TypesafeYamlDatabase<keytype, datatype>( type_, version_, version_ ){
}
void clear() override{
TypesafeYamlDatabase<keytype, datatype>::clear();
// Restore size after clearing
size_t cap = cache.capacity();
cache.clear();
cache.resize(cap, nullptr);
}
std::shared_ptr<datatype> find( keytype key ) override{
if( this->cache.empty() || key >= this->cache.capacity() ){
return TypesafeYamlDatabase<keytype, datatype>::find( key );
}else{
return cache[this->calculateCacheKey( key )];
}
}
virtual size_t calculateCacheKey( keytype key ){
return key;
}
void loadingFinished() override{
// Cache all known values
for (auto &pair : *this) {
// Calculate the key that should be used
size_t key = this->calculateCacheKey(pair.first);
// Check if the key fits into the current cache size
if (this->cache.capacity() < key) {
// Double the current size, so we do not have to resize that often
size_t new_size = key * 2;
// Very important => initialize everything to nullptr
this->cache.resize(new_size, nullptr);
}
// Insert the value into the cache
this->cache[key] = pair.second;
}
// Free the memory that was allocated too much
this->cache.shrink_to_fit();
}
};
#endif /* DATABASE_HPP */