mirror of
https://github.com/ARMSX2/ARMSX3.git
synced 2026-08-24 16:58:52 -07:00
Adds an Android build of the RPCS3 core plus a Compose UI, and fixes several things that stopped it working on ARM64. Renderer: - Emit concrete bounds for runtime sized arrays in uniform blocks when VK_EXT_shader_uniform_buffer_unsized_array is missing. Adreno does not have the extension, so every game pipeline failed with VK_ERROR_UNKNOWN and only overlays drew. - Probe and request that extension properly instead of chaining its feature struct unconditionally. - Hand VMA the Vulkan function pointers it needs under VK_NO_PROTOTYPES. - Rebuild the surface and swapchain when the window is lost instead of killing the RSX thread. - Only create a GLES context when the GL renderer is actually selected. SPU: - Sum instead of taking an absolute difference in the ARM64 block verification checksum. The difference collides on the near identical job binaries an SPU job manager streams through one local store address, so a cached block could run against another job's code. Threading: - Implement thread affinity on Android using sched_setaffinity. - Add an ARM big.LITTLE core arrangement so SPU and RSX threads land on the fast cores. Misc: - Detect the host CPU for the LLVM JIT instead of pinning cortex-a34. - Fall back to the default audio device when cubeb cannot enumerate.
927 lines
18 KiB
C++
927 lines
18 KiB
C++
#pragma once
|
|
|
|
#include "util/types.hpp"
|
|
#include "Utilities/StrUtil.h"
|
|
#include "util/logs.hpp"
|
|
#include "util/atomic.hpp"
|
|
#include "util/shared_ptr.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <utility>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <set>
|
|
#include <map>
|
|
|
|
namespace cfg
|
|
{
|
|
// Format min and max values
|
|
std::vector<std::string> make_int_range(s64 min, s64 max);
|
|
|
|
// Format min and max unsigned values
|
|
std::vector<std::string> make_uint_range(u64 min, u64 max);
|
|
|
|
// Format min and max float values
|
|
std::vector<std::string> make_float_range(f64 min, f64 max);
|
|
|
|
// Internal hack
|
|
bool try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, std::string_view value, std::string_view name = {});
|
|
|
|
// Internal hack
|
|
std::vector<std::string> try_to_enum_list(decltype(&fmt_class_string<int>::format) func);
|
|
|
|
// Internal hack
|
|
size_t try_to_enum_size(decltype(&fmt_class_string<int>::format) func);
|
|
|
|
// Config tree entry type.
|
|
enum class type : unsigned
|
|
{
|
|
node = 0, // cfg::node type
|
|
_bool, // cfg::_bool type
|
|
_enum, // cfg::_enum type
|
|
_int, // cfg::_int type
|
|
uint, // cfg::uint type
|
|
uint128, // cfg::uint128 type
|
|
string, // cfg::string type
|
|
set, // cfg::set_entry type
|
|
map, // cfg::map_entry type
|
|
node_map, // cfg::node_map_entry type
|
|
log, // cfg::log_entry type
|
|
device, // cfg::device_entry type
|
|
};
|
|
|
|
// Config tree entry abstract base class
|
|
class _base
|
|
{
|
|
const type m_type{};
|
|
|
|
protected:
|
|
_base* m_parent = nullptr;
|
|
bool m_dynamic = true;
|
|
const std::string m_name{};
|
|
|
|
static u32 id_counter;
|
|
u32 m_id = 0;
|
|
|
|
// Ownerless entry constructor
|
|
_base(type _type);
|
|
|
|
// Owned entry constructor
|
|
_base(type _type, class node* owner, std::string name, bool dynamic);
|
|
|
|
public:
|
|
_base(const _base&) = delete;
|
|
|
|
_base& operator=(const _base&) = delete;
|
|
|
|
virtual ~_base() = default;
|
|
|
|
// Get unique ID
|
|
u32 get_id() const { return m_id; }
|
|
|
|
// Get parent
|
|
_base* get_parent() const { return m_parent; }
|
|
|
|
// Get type
|
|
type get_type() const { return m_type; }
|
|
|
|
// Get name
|
|
const std::string& get_name() const { return m_name; }
|
|
|
|
// Get dynamic property for reloading configs during games
|
|
bool get_is_dynamic() const { return m_dynamic; }
|
|
|
|
// Reset defaults
|
|
virtual void from_default() = 0;
|
|
|
|
// Restore default members
|
|
virtual void restore_defaults() = 0;
|
|
|
|
// Convert to string (optional)
|
|
virtual std::string to_string() const
|
|
{
|
|
return {};
|
|
}
|
|
|
|
// Convert default to string (optional)
|
|
virtual std::string def_to_string() const
|
|
{
|
|
return {};
|
|
}
|
|
|
|
// ARMSX3: expose the numeric range through the base interface.
|
|
// _int/_float/uint carry Min/Max as static constexpr TEMPLATE parameters,
|
|
// which are unreachable from a _base* -- so a generic settings UI cannot
|
|
// tell a slider from a free-text field without these. Mirrors the
|
|
// to_string/def_to_string pattern; empty means "not a bounded numeric".
|
|
virtual std::string min_to_string() const
|
|
{
|
|
return {};
|
|
}
|
|
|
|
virtual std::string max_to_string() const
|
|
{
|
|
return {};
|
|
}
|
|
|
|
// Try to convert from string (optional)
|
|
virtual bool from_string(std::string_view value, bool dynamic = false);
|
|
|
|
// Get string list (optional)
|
|
virtual std::vector<std::string> to_list() const
|
|
{
|
|
return {};
|
|
}
|
|
|
|
// Set multiple values. Implementation-specific, optional.
|
|
virtual bool from_list(std::vector<std::string>&&);
|
|
|
|
bool save(std::string_view cfg_name) const;
|
|
};
|
|
|
|
// Config tree node which contains another nodes
|
|
class node : public _base
|
|
{
|
|
std::vector<_base*> m_nodes{};
|
|
|
|
friend class _base;
|
|
|
|
public:
|
|
// Root node constructor
|
|
node()
|
|
: _base(type::node)
|
|
{
|
|
}
|
|
|
|
// Registered node constructor
|
|
node(node* owner, std::string name, bool dynamic = true)
|
|
: _base(type::node, owner, std::move(name), dynamic)
|
|
{
|
|
}
|
|
|
|
// Get child nodes
|
|
const auto& get_nodes() const
|
|
{
|
|
return m_nodes;
|
|
}
|
|
|
|
// Serialize node
|
|
std::string to_string() const override;
|
|
|
|
// Deserialize node
|
|
bool from_string(std::string_view value, bool dynamic = false) override;
|
|
|
|
// Set default values
|
|
void from_default() override;
|
|
|
|
// Restore default members
|
|
void restore_defaults() override;
|
|
|
|
// Try to convert from string and validate
|
|
bool validate(std::string_view value);
|
|
};
|
|
|
|
class _bool final : public _base
|
|
{
|
|
atomic_t<bool> m_value;
|
|
bool original_def;
|
|
|
|
public:
|
|
bool def;
|
|
|
|
_bool(node* owner, std::string name, bool def = false, bool dynamic = false)
|
|
: _base(type::_bool, owner, std::move(name), dynamic)
|
|
, m_value(def)
|
|
, original_def(def)
|
|
, def(def)
|
|
{
|
|
}
|
|
|
|
explicit operator bool() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
bool get() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
void from_default() override
|
|
{
|
|
m_value = def;
|
|
}
|
|
|
|
void restore_defaults() override
|
|
{
|
|
def = original_def;
|
|
}
|
|
|
|
std::string to_string() const override
|
|
{
|
|
return m_value ? "true" : "false";
|
|
}
|
|
|
|
std::string def_to_string() const override
|
|
{
|
|
return def ? "true" : "false";
|
|
}
|
|
|
|
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
|
|
{
|
|
if (value.size() != 4 && value.size() != 5)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
char copy[5];
|
|
std::transform(value.begin(), value.end(), std::begin(copy), ::tolower);
|
|
|
|
if (value.size() == 5 && std::string_view{copy, 5} == "false")
|
|
m_value = false;
|
|
else if (value.size() == 4 && std::string_view{copy, 4} == "true")
|
|
m_value = true;
|
|
else
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void set(const bool& value)
|
|
{
|
|
m_value = value;
|
|
}
|
|
};
|
|
|
|
// Value node with fixed set of possible values, each maps to an enum value of type T.
|
|
template <typename T>
|
|
class _enum : public _base
|
|
{
|
|
atomic_t<T> m_value;
|
|
T original_def;
|
|
|
|
public:
|
|
T def;
|
|
|
|
_enum(node* owner, const std::string& name, T def = {}, bool dynamic = false)
|
|
: _base(type::_enum, owner, name, dynamic)
|
|
, m_value(def)
|
|
, original_def(def)
|
|
, def(def)
|
|
{
|
|
}
|
|
|
|
operator T() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
T get() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
T get_default() const
|
|
{
|
|
return def;
|
|
}
|
|
|
|
void set(T value)
|
|
{
|
|
m_value = value;
|
|
}
|
|
|
|
void from_default() override
|
|
{
|
|
m_value = def;
|
|
}
|
|
|
|
void restore_defaults() override
|
|
{
|
|
def = original_def;
|
|
}
|
|
|
|
std::string to_string() const override
|
|
{
|
|
std::string result;
|
|
fmt_class_string<T>::format(result, fmt_unveil<T>::get(m_value.load()));
|
|
return result; // TODO: ???
|
|
}
|
|
|
|
std::string def_to_string() const override
|
|
{
|
|
std::string result;
|
|
fmt_class_string<T>::format(result, fmt_unveil<T>::get(def));
|
|
return result; // TODO: ???
|
|
}
|
|
|
|
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
|
|
{
|
|
u64 result;
|
|
|
|
if (try_to_enum_value(&result, &fmt_class_string<T>::format, value, m_name))
|
|
{
|
|
// No narrowing check, it's hard to do right there
|
|
m_value = static_cast<T>(static_cast<std::underlying_type_t<T>>(result));
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
std::vector<std::string> to_list() const override
|
|
{
|
|
return try_to_enum_list(&fmt_class_string<T>::format);
|
|
}
|
|
|
|
size_t size() const
|
|
{
|
|
return try_to_enum_size(&fmt_class_string<T>::format);
|
|
}
|
|
};
|
|
|
|
// Signed 32/64-bit integer entry with custom Min/Max range.
|
|
template <s64 Min, s64 Max>
|
|
class _int final : public _base
|
|
{
|
|
static_assert(Min < Max, "Invalid cfg::_int range");
|
|
|
|
// Prefer 32 bit type if possible
|
|
using int_type = std::conditional_t<Min >= s32{smin} && Max <= s32{smax}, s32, s64>;
|
|
|
|
atomic_t<int_type> m_value;
|
|
int_type original_def;
|
|
|
|
public:
|
|
int_type def;
|
|
|
|
// Expose range
|
|
static constexpr s64 max = Max;
|
|
static constexpr s64 min = Min;
|
|
|
|
_int(node* owner, const std::string& name, int_type def = std::min<int_type>(Max, std::max<int_type>(Min, 0)), bool dynamic = false)
|
|
: _base(type::_int, owner, name, dynamic)
|
|
, m_value(def)
|
|
, original_def(def)
|
|
, def(def)
|
|
{
|
|
}
|
|
|
|
operator int_type() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
int_type get() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
void from_default() override
|
|
{
|
|
m_value = def;
|
|
}
|
|
|
|
void restore_defaults() override
|
|
{
|
|
def = original_def;
|
|
}
|
|
|
|
std::string to_string() const override
|
|
{
|
|
return std::to_string(m_value);
|
|
}
|
|
|
|
std::string def_to_string() const override
|
|
{
|
|
return std::to_string(def);
|
|
}
|
|
|
|
std::string min_to_string() const override
|
|
{
|
|
return std::to_string(min);
|
|
}
|
|
|
|
std::string max_to_string() const override
|
|
{
|
|
return std::to_string(max);
|
|
}
|
|
|
|
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
|
|
{
|
|
s64 result;
|
|
if (try_to_int64(&result, value, Min, Max, m_name))
|
|
{
|
|
m_value = static_cast<int_type>(result);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void set(const s64& value)
|
|
{
|
|
if (value < Min || value > Max) fmt::throw_exception("'%s': value %d out of bounds (min=%d, max=%d)", m_name, value, Min, Max);
|
|
m_value = static_cast<int_type>(value);
|
|
}
|
|
|
|
std::vector<std::string> to_list() const override
|
|
{
|
|
return make_int_range(Min, Max);
|
|
}
|
|
};
|
|
|
|
// Float entry with custom Min/Max range.
|
|
template <s32 Min, s32 Max>
|
|
class _float final : public _base
|
|
{
|
|
static_assert(Min < Max, "Invalid cfg::_float range");
|
|
|
|
using float_type = f64;
|
|
atomic_t<float_type> m_value;
|
|
float_type original_def;
|
|
|
|
public:
|
|
float_type def;
|
|
|
|
// Expose range
|
|
static constexpr float_type max = Max;
|
|
static constexpr float_type min = Min;
|
|
|
|
_float(node* owner, const std::string& name, float_type def = std::min<float_type>(Max, std::max<float_type>(Min, 0)), bool dynamic = false)
|
|
: _base(type::_int, owner, name, dynamic)
|
|
, m_value(def)
|
|
, original_def(def)
|
|
, def(def)
|
|
{
|
|
}
|
|
|
|
operator float_type() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
float_type get() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
void from_default() override
|
|
{
|
|
m_value = def;
|
|
}
|
|
|
|
void restore_defaults() override
|
|
{
|
|
def = original_def;
|
|
}
|
|
|
|
std::string to_string() const override
|
|
{
|
|
std::string result;
|
|
if (try_to_string(&result, m_value, m_name))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
return "0.0";
|
|
}
|
|
|
|
std::string def_to_string() const override
|
|
{
|
|
std::string result;
|
|
if (try_to_string(&result, def, m_name))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
return "0.0";
|
|
}
|
|
|
|
std::string min_to_string() const override
|
|
{
|
|
return std::to_string(min);
|
|
}
|
|
|
|
std::string max_to_string() const override
|
|
{
|
|
return std::to_string(max);
|
|
}
|
|
|
|
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
|
|
{
|
|
f64 result;
|
|
if (try_to_float(&result, value, Min, Max, m_name))
|
|
{
|
|
m_value = static_cast<float_type>(result);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void set(const f64& value)
|
|
{
|
|
if (value < Min || value > Max) fmt::throw_exception("'%s': value %d out of bounds (min=%d, max=%d)", m_name, value, Min, Max);
|
|
m_value = static_cast<float_type>(value);
|
|
}
|
|
|
|
std::vector<std::string> to_list() const override
|
|
{
|
|
return make_float_range(Min, Max);
|
|
}
|
|
};
|
|
|
|
// Alias for 32 bit int
|
|
using int32 = _int<s32{smin}, s32{smax}>;
|
|
|
|
// Alias for 64 bit int
|
|
using int64 = _int<s64{smin}, s64{smax}>;
|
|
|
|
// Unsigned 32/64-bit integer entry with custom Min/Max range.
|
|
template <u64 Min, u64 Max>
|
|
class uint final : public _base
|
|
{
|
|
static_assert(Min < Max, "Invalid cfg::uint range");
|
|
|
|
// Prefer 32 bit type if possible
|
|
using int_type = std::conditional_t<Max <= u32{umax}, u32, u64>;
|
|
|
|
atomic_t<int_type> m_value;
|
|
int_type original_def;
|
|
|
|
public:
|
|
int_type def;
|
|
|
|
// Expose range
|
|
static constexpr u64 max = Max;
|
|
static constexpr u64 min = Min;
|
|
|
|
uint(node* owner, const std::string& name, int_type def = std::max<int_type>(Min, 0), bool dynamic = false)
|
|
: _base(type::uint, owner, name, dynamic)
|
|
, m_value(def)
|
|
, original_def(def)
|
|
, def(def)
|
|
{
|
|
}
|
|
|
|
operator int_type() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
int_type get() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
void from_default() override
|
|
{
|
|
m_value = def;
|
|
}
|
|
|
|
void restore_defaults() override
|
|
{
|
|
def = original_def;
|
|
}
|
|
|
|
std::string to_string() const override
|
|
{
|
|
return std::to_string(m_value);
|
|
}
|
|
|
|
std::string def_to_string() const override
|
|
{
|
|
return std::to_string(def);
|
|
}
|
|
|
|
std::string min_to_string() const override
|
|
{
|
|
return std::to_string(min);
|
|
}
|
|
|
|
std::string max_to_string() const override
|
|
{
|
|
return std::to_string(max);
|
|
}
|
|
|
|
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
|
|
{
|
|
u64 result;
|
|
if (try_to_uint64(&result, value, Min, Max, m_name))
|
|
{
|
|
m_value = static_cast<int_type>(result);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void set(const u64& value)
|
|
{
|
|
if (value < Min || value > Max) fmt::throw_exception("'%s': value %d out of bounds (min=%d, max=%d)", m_name, value, Min, Max);
|
|
m_value = static_cast<int_type>(value);
|
|
}
|
|
|
|
std::vector<std::string> to_list() const override
|
|
{
|
|
return make_uint_range(Min, Max);
|
|
}
|
|
};
|
|
|
|
// Alias for 32 bit uint
|
|
using uint32 = uint<0, u32{umax}>;
|
|
|
|
// Alias for 64 bit int
|
|
using uint64 = uint<0, u64{umax}>;
|
|
|
|
// Unsigned 128-bit integer entry.
|
|
class uint128 final : public _base
|
|
{
|
|
using int_type = u128;
|
|
|
|
atomic_t<int_type> m_value{};
|
|
int_type original_def = 0;
|
|
|
|
public:
|
|
int_type def;
|
|
|
|
uint128(node* owner, const std::string& name, int_type def = 0, bool dynamic = false)
|
|
: _base(type::uint128, owner, name, dynamic)
|
|
, m_value(def)
|
|
, original_def(def)
|
|
, def(def)
|
|
{
|
|
}
|
|
|
|
operator int_type() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
operator ullong() const
|
|
{
|
|
return static_cast<ullong>(m_value.load());
|
|
}
|
|
|
|
int_type get() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
void from_default() override
|
|
{
|
|
m_value = def;
|
|
}
|
|
|
|
void restore_defaults() override
|
|
{
|
|
def = original_def;
|
|
}
|
|
|
|
static std::string to_string(u128 value) noexcept;
|
|
|
|
std::string to_string() const override
|
|
{
|
|
return to_string(m_value.load());
|
|
}
|
|
|
|
std::string def_to_string() const override
|
|
{
|
|
return to_string(def);
|
|
}
|
|
|
|
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
|
|
{
|
|
u128 result;
|
|
if (try_to_uint128(&result, value, m_name))
|
|
{
|
|
m_value = result;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void set(u128 value)
|
|
{
|
|
m_value = value;
|
|
}
|
|
|
|
std::vector<std::string> to_list() const override
|
|
{
|
|
// Should not be used
|
|
return make_uint_range(0, 1);
|
|
}
|
|
};
|
|
|
|
// Simple string entry with mutex
|
|
class string : public _base
|
|
{
|
|
atomic_ptr<std::string> m_value;
|
|
std::string original_def;
|
|
|
|
public:
|
|
std::string def;
|
|
|
|
string(node* owner, std::string name, std::string def = {}, bool dynamic = false)
|
|
: _base(type::string, owner, std::move(name), dynamic)
|
|
, m_value(def)
|
|
, original_def(def)
|
|
, def(std::move(def))
|
|
{
|
|
}
|
|
|
|
operator std::string() const
|
|
{
|
|
return *m_value.load().get();
|
|
}
|
|
|
|
void from_default() override
|
|
{
|
|
m_value = def;
|
|
}
|
|
|
|
void restore_defaults() override
|
|
{
|
|
def = original_def;
|
|
}
|
|
|
|
std::string to_string() const override
|
|
{
|
|
return *m_value.load().get();
|
|
}
|
|
|
|
std::string get() const
|
|
{
|
|
return *m_value.load().get();
|
|
}
|
|
|
|
std::string def_to_string() const override
|
|
{
|
|
return def;
|
|
}
|
|
|
|
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
|
|
{
|
|
m_value = std::string(value);
|
|
return true;
|
|
}
|
|
|
|
void set(std::string_view value)
|
|
{
|
|
m_value = std::string(value);
|
|
}
|
|
};
|
|
|
|
// Simple set entry (TODO: template for various types)
|
|
class set_entry final : public _base
|
|
{
|
|
std::set<std::string> m_set{};
|
|
|
|
public:
|
|
// Default value is empty list in current implementation
|
|
set_entry(node* owner, const std::string& name)
|
|
: _base(type::set, owner, name, false)
|
|
{
|
|
}
|
|
|
|
const std::set<std::string>& get_set() const
|
|
{
|
|
return m_set;
|
|
}
|
|
|
|
void set_set(std::set<std::string>&& set)
|
|
{
|
|
m_set = std::move(set);
|
|
}
|
|
|
|
void from_default() override
|
|
{
|
|
m_set = {};
|
|
}
|
|
|
|
void restore_defaults() override
|
|
{
|
|
}
|
|
|
|
std::vector<std::string> to_list() const override
|
|
{
|
|
return { m_set.begin(), m_set.end() };
|
|
}
|
|
|
|
bool from_list(std::vector<std::string>&& list) override
|
|
{
|
|
m_set = { std::make_move_iterator(list.begin()), std::make_move_iterator(list.end()) };
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
using map_of_type = std::map<std::string, T, std::less<>>;
|
|
|
|
class map_entry : public _base
|
|
{
|
|
map_of_type<std::string> m_map{};
|
|
|
|
public:
|
|
map_entry(node* owner, const std::string& name, type _type = type::map)
|
|
: _base(_type, owner, name, true)
|
|
{
|
|
}
|
|
|
|
const map_of_type<std::string>& get_map() const
|
|
{
|
|
return m_map;
|
|
}
|
|
|
|
std::string get_value(std::string_view key);
|
|
|
|
void set_value(std::string key, std::string value);
|
|
void set_map(map_of_type<std::string>&& map);
|
|
|
|
void erase(std::string_view key);
|
|
|
|
void from_default() override;
|
|
|
|
void restore_defaults() override
|
|
{
|
|
}
|
|
};
|
|
|
|
class node_map_entry final : public map_entry
|
|
{
|
|
public:
|
|
node_map_entry(node* owner, const std::string& name)
|
|
: map_entry(owner, name, type::node_map)
|
|
{
|
|
}
|
|
};
|
|
|
|
class log_entry final : public _base
|
|
{
|
|
map_of_type<logs::level> m_map{};
|
|
|
|
public:
|
|
log_entry(node* owner, const std::string& name)
|
|
: _base(type::log, owner, name, true)
|
|
{
|
|
}
|
|
|
|
const map_of_type<logs::level>& get_map() const
|
|
{
|
|
return m_map;
|
|
}
|
|
|
|
void set_map(map_of_type<logs::level>&& map);
|
|
|
|
void from_default() override;
|
|
|
|
void restore_defaults() override
|
|
{
|
|
}
|
|
};
|
|
|
|
struct device_info
|
|
{
|
|
std::string path;
|
|
std::string serial;
|
|
std::string vid;
|
|
std::string pid;
|
|
std::pair<u16, u16> get_usb_ids() const;
|
|
};
|
|
|
|
class device_entry final : public _base
|
|
{
|
|
map_of_type<device_info> m_map{};
|
|
map_of_type<device_info> m_default{};
|
|
|
|
public:
|
|
device_entry(node* owner, const std::string& name, map_of_type<device_info> def = {})
|
|
: _base(type::device, owner, name, true)
|
|
, m_map(std::move(def))
|
|
{
|
|
m_default = m_map;
|
|
}
|
|
|
|
const map_of_type<device_info>& get_map() const
|
|
{
|
|
return m_map;
|
|
}
|
|
|
|
const map_of_type<device_info>& get_default() const
|
|
{
|
|
return m_default;
|
|
}
|
|
|
|
void set_map(map_of_type<device_info>&& map);
|
|
|
|
void from_default() override;
|
|
|
|
void restore_defaults() override
|
|
{
|
|
}
|
|
};
|
|
}
|