Kawe Mazidjatari 04bee896be Fix string/wstring type conflict
cppkore uses string/wstring as StringBase while we use std::string/std::wstring as string/wstring. Changed all types in cppkore to String/WString instead.
2022-05-21 21:51:35 +02:00

264 lines
5.5 KiB
C++

#pragma once
#include <cstdint>
#include "ListBase.h"
#include "StringBase.h"
#include "ImmutableStringBase.h"
#include "File.h"
#include "BinaryReader.h"
#include "BinaryWriter.h"
namespace System
{
// Represents the type of setting we are using
enum class SettingType : char
{
Boolean = 'B',
Integer = 'I',
Integer64 = 'L',
String = 'S',
ProtectedString = 'P'
};
// Used to store a setting.
class SettingsObject
{
public:
SettingsObject();
SettingsObject(String Key, SettingType Type, uint8_t* Value);
~SettingsObject();
String Key;
SettingType Type;
union ValueUn
{
char* String;
bool Boolean;
uint32_t Integer;
uint64_t Integer64;
} Values;
SettingsObject& operator=(SettingsObject Rhs)
{
Key = Rhs.Key;
Type = Rhs.Type;
if (Type == SettingType::String || Type == SettingType::ProtectedString)
{
if (this->Values.String)
delete[] this->Values.String;
auto Len = strlen(Rhs.Values.String);
this->Values.String = new char[Len + 1]{};
std::memcpy(this->Values.String, Rhs.Values.String, Len);
}
else
{
this->Values.Integer64 = Rhs.Values.Integer64;
}
return *this;
}
bool operator==(SettingsObject Rhs)
{
// yes yes yes i know this is bad but it doesn't cause issues for me so who cares
return Key == Rhs.Key && Type == Rhs.Type;
}
};
// Reads and writes configuration files.
class Settings
{
public:
Settings() = default;
~Settings() = default;
_declspec(noinline) void SetBool(const imstring& Key, bool Value)
{
for (auto& Setting : _Settings)
{
if (Setting.Key == (const char*)Key)
{
Setting.Values.Boolean = Value;
}
}
_Settings.EmplaceBack(Key, SettingType::Boolean, (uint8_t*)&Value);
}
_declspec(noinline) void SetInt(const imstring& Key, uint32_t Value)
{
for (auto& Setting : _Settings)
{
if (Setting.Key == (const char*)Key)
{
Setting.Values.Integer = Value;
}
}
_Settings.EmplaceBack(Key, SettingType::Integer, (uint8_t*)&Value);
}
template<SettingType T, class V>
_declspec(noinline) void Set(const imstring& Key, V && Value)
{
for (auto& Setting : _Settings)
{
if (Setting.Key == (const char*)Key)
{
if constexpr (T == SettingType::Boolean)
Setting.Values.Boolean = Value;
else if constexpr (T == SettingType::Integer)
Setting.Values.Integer = Value;
else if constexpr (T == SettingType::Integer64)
Setting.Values.Integer64 = Value;
else if constexpr (T == SettingType::ProtectedString || T == SettingType::String)
{
if (Setting.Values.String != NULL)
delete[] Setting.Values.String;
if constexpr (std::is_same<V, String>::value)
{
Setting.Values.String = new char[Value.Length() + 1]{};
std::memcpy(Setting.Values.String, (const char*)Value, Value.Length());
}
else
{
auto Len = strlen(Value);
Setting.Values.String = new char[Len + 1]{};
std::memcpy(Setting.Values.String, Value, Len);
}
}
return;
}
}
if constexpr (T == SettingType::String)
_Settings.EmplaceBack(Key, T, (uint8_t*)Value.ToCString());
else
_Settings.EmplaceBack(Key, T, (uint8_t*)&Value);
}
template<const SettingType T>
_declspec(noinline) bool Has(const imstring& Key)
{
SettingsObject* Value = nullptr;
for (auto& Setting : _Settings)
{
if (Setting.Key == (const char*)Key)
{
Value = &Setting;
break;
}
}
return (Value != nullptr);
}
// for some reason the template one doesn't even check the type so what is the point in having it as a template?
bool Has(const imstring& Key)
{
SettingsObject* Value = nullptr;
for (auto& Setting : _Settings)
{
if (Setting.Key == (const char*)Key)
{
Value = &Setting;
break;
}
}
return (Value != nullptr);
}
template<const SettingType T>
_declspec(noinline) void Remove(const imstring& Key)
{
for (SettingsObject& Setting : _Settings)
{
if (Setting.Key == (const char*)Key)
{
Setting = SettingsObject();
break;
}
}
return;
};
_declspec(noinline) bool GetBool(const imstring& Key)
{
SettingsObject* Value = nullptr;
for (auto& Setting : _Settings)
{
if (Setting.Key == (const char*)Key)
{
Value = &Setting;
break;
}
}
if (Value)
return Value->Values.Boolean;
return false;
}
template<const SettingType T>
_declspec(noinline) auto Get(const imstring& Key)
{
SettingsObject* Value = nullptr;
for (auto& Setting : _Settings)
{
if (Setting.Key == (const char*)Key)
{
Value = &Setting;
break;
}
}
if constexpr (T == SettingType::Boolean)
{
if (Value)
return (bool)Value->Values.Boolean;
return (bool)false;
}
else if constexpr (T == SettingType::Integer)
{
if (Value)
return (uint32_t)Value->Values.Integer;
return (uint32_t)0;
}
else if constexpr (T == SettingType::Integer64)
{
if (Value)
return (uint64_t)Value->Values.Integer64;
return (uint64_t)0;
}
else if constexpr (T == SettingType::String || T == SettingType::ProtectedString)
{
if (Value)
return (String)Value->Values.String;
return (String)"";
}
}
// Load the config file from the specified path.
void Load(const String& Path);
// Save the config file to the specified path.
void Save(const String& Path);
private:
// Internal cached settings
List<SettingsObject> _Settings;
};
}