184 lines
4.9 KiB
C++
184 lines
4.9 KiB
C++
#include "assets/settings_document.h"
|
|
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
#include <cmath>
|
|
|
|
namespace pp::assets {
|
|
|
|
namespace {
|
|
|
|
[[nodiscard]] bool is_valid_key_char(char value) noexcept
|
|
{
|
|
const auto ch = static_cast<unsigned char>(value);
|
|
return std::isalnum(ch) != 0 || value == '_' || value == '-' || value == '.';
|
|
}
|
|
|
|
}
|
|
|
|
std::size_t SettingsDocument::size() const noexcept
|
|
{
|
|
return entries_.size();
|
|
}
|
|
|
|
bool SettingsDocument::empty() const noexcept
|
|
{
|
|
return entries_.empty();
|
|
}
|
|
|
|
bool SettingsDocument::has(std::string_view key) const noexcept
|
|
{
|
|
return find_entry(key) != entries_.end();
|
|
}
|
|
|
|
const std::vector<SettingsEntry>& SettingsDocument::entries() const noexcept
|
|
{
|
|
return entries_;
|
|
}
|
|
|
|
pp::foundation::Status SettingsDocument::set(std::string_view key, SettingsValue value)
|
|
{
|
|
const auto key_status = validate_settings_key(key);
|
|
if (!key_status.ok()) {
|
|
return key_status;
|
|
}
|
|
|
|
const auto value_status = validate_settings_value(value);
|
|
if (!value_status.ok()) {
|
|
return value_status;
|
|
}
|
|
|
|
auto found = find_entry(key);
|
|
if (found != entries_.end()) {
|
|
found->value = value;
|
|
return pp::foundation::Status::success();
|
|
}
|
|
|
|
if (entries_.size() >= max_settings_entries) {
|
|
return pp::foundation::Status::out_of_range("settings entry count exceeds the configured limit");
|
|
}
|
|
|
|
entries_.push_back(SettingsEntry {
|
|
.key = std::string(key),
|
|
.value = value,
|
|
});
|
|
return pp::foundation::Status::success();
|
|
}
|
|
|
|
pp::foundation::Result<SettingsValue> SettingsDocument::get(std::string_view key) const
|
|
{
|
|
const auto key_status = validate_settings_key(key);
|
|
if (!key_status.ok()) {
|
|
return pp::foundation::Result<SettingsValue>::failure(key_status);
|
|
}
|
|
|
|
const auto found = find_entry(key);
|
|
if (found == entries_.end()) {
|
|
return pp::foundation::Result<SettingsValue>::failure(
|
|
pp::foundation::Status::out_of_range("settings key was not found"));
|
|
}
|
|
|
|
return pp::foundation::Result<SettingsValue>::success(found->value);
|
|
}
|
|
|
|
pp::foundation::Status SettingsDocument::unset(std::string_view key) noexcept
|
|
{
|
|
const auto key_status = validate_settings_key(key);
|
|
if (!key_status.ok()) {
|
|
return key_status;
|
|
}
|
|
|
|
const auto found = find_entry(key);
|
|
if (found == entries_.end()) {
|
|
return pp::foundation::Status::out_of_range("settings key was not found");
|
|
}
|
|
|
|
entries_.erase(found);
|
|
return pp::foundation::Status::success();
|
|
}
|
|
|
|
void SettingsDocument::clear() noexcept
|
|
{
|
|
entries_.clear();
|
|
}
|
|
|
|
std::vector<SettingsEntry>::iterator SettingsDocument::find_entry(std::string_view key) noexcept
|
|
{
|
|
return std::find_if(
|
|
entries_.begin(),
|
|
entries_.end(),
|
|
[key](const SettingsEntry& entry) {
|
|
return entry.key == key;
|
|
});
|
|
}
|
|
|
|
std::vector<SettingsEntry>::const_iterator SettingsDocument::find_entry(std::string_view key) const noexcept
|
|
{
|
|
return std::find_if(
|
|
entries_.begin(),
|
|
entries_.end(),
|
|
[key](const SettingsEntry& entry) {
|
|
return entry.key == key;
|
|
});
|
|
}
|
|
|
|
pp::foundation::Status validate_settings_key(std::string_view key) noexcept
|
|
{
|
|
if (key.empty()) {
|
|
return pp::foundation::Status::invalid_argument("settings key must not be empty");
|
|
}
|
|
|
|
if (key.size() > max_settings_key_length) {
|
|
return pp::foundation::Status::out_of_range("settings key length exceeds the configured limit");
|
|
}
|
|
|
|
if (key.front() == '.' || key.back() == '.') {
|
|
return pp::foundation::Status::invalid_argument("settings key must not start or end with a dot");
|
|
}
|
|
|
|
for (const auto ch : key) {
|
|
if (!is_valid_key_char(ch)) {
|
|
return pp::foundation::Status::invalid_argument("settings key contains an unsupported character");
|
|
}
|
|
}
|
|
|
|
return pp::foundation::Status::success();
|
|
}
|
|
|
|
pp::foundation::Status validate_settings_value(const SettingsValue& value) noexcept
|
|
{
|
|
if (const auto* string_value = std::get_if<std::string>(&value)) {
|
|
if (string_value->size() > max_settings_string_length) {
|
|
return pp::foundation::Status::out_of_range("settings string length exceeds the configured limit");
|
|
}
|
|
}
|
|
|
|
if (const auto* double_value = std::get_if<double>(&value)) {
|
|
if (!std::isfinite(*double_value)) {
|
|
return pp::foundation::Status::invalid_argument("settings floating point value must be finite");
|
|
}
|
|
}
|
|
|
|
return pp::foundation::Status::success();
|
|
}
|
|
|
|
const char* settings_value_type_name(const SettingsValue& value) noexcept
|
|
{
|
|
if (std::holds_alternative<bool>(value)) {
|
|
return "bool";
|
|
}
|
|
if (std::holds_alternative<std::int64_t>(value)) {
|
|
return "int64";
|
|
}
|
|
if (std::holds_alternative<double>(value)) {
|
|
return "double";
|
|
}
|
|
if (std::holds_alternative<std::string>(value)) {
|
|
return "string";
|
|
}
|
|
|
|
return "unknown";
|
|
}
|
|
|
|
}
|