Fix compiler warnings on Ubuntu and code cleanup

Fixes some compiler warnings, avoids using anonymous namespaces as much
and removes manual inlining for config.
This commit is contained in:
pixl 2023-05-03 21:31:05 -04:00
parent 5e436a2bdf
commit a96036c97d
No known key found for this signature in database
GPG Key ID: 1866C148CD593B6E
7 changed files with 487 additions and 512 deletions

@ -1 +1 @@
Subproject commit 745329ed9d41051ddb6e4010229d4b54d868e1a4
Subproject commit 4f22a43e3380dc1e9c0a490201f4d745390b623f

View File

@ -38,24 +38,25 @@ namespace logid::backend::hidpp10 {
namespace logid::backend::hidpp {
struct DeviceConnectionEvent;
namespace {
template <typename T>
class DeviceWrapper : public T {
friend class Device;
public:
template <typename... Args>
explicit DeviceWrapper(Args... args) : T(std::forward<Args>(args)...) { }
template<typename T>
class _deviceWrapper : public T {
friend class Device;
template <typename... Args>
static std::shared_ptr<T> make(Args... args) {
return std::make_shared<DeviceWrapper>(std::forward<Args>(args)...);
}
};
}
public:
template<typename... Args>
explicit _deviceWrapper(Args... args) : T(std::forward<Args>(args)...) {}
template<typename... Args>
static std::shared_ptr<T> make(Args... args) {
return std::make_shared<_deviceWrapper>(std::forward<Args>(args)...);
}
};
class Device {
template <typename T>
friend class DeviceWrapper;
template<typename T>
friend
class _deviceWrapper;
public:
struct EventHandler {
std::function<bool(Report&)> condition;
@ -102,7 +103,9 @@ namespace logid::backend::hidpp {
[[nodiscard]] const std::shared_ptr<raw::RawDevice>& rawDevice() const;
Device(const Device&) = delete;
Device(Device&&) = delete;
virtual ~Device() = default;
protected:
@ -161,16 +164,16 @@ namespace logid::backend::hidpp {
std::weak_ptr<Device> _self;
protected:
template <typename T, typename... Args>
template<typename T, typename... Args>
static std::shared_ptr<T> makeDerived(Args... args) {
auto device = DeviceWrapper<T>::make(std::forward<Args>(args)...);
auto device = _deviceWrapper<T>::make(std::forward<Args>(args)...);
device->_self = device;
device->_setupReportsAndInit();
return device;
}
public:
template <typename... Args>
template<typename... Args>
static std::shared_ptr<Device> make(Args... args) {
return makeDerived<Device>(std::forward<Args>(args)...);
}

View File

@ -26,20 +26,19 @@
namespace logid::backend::hidpp10 {
namespace {
template <typename T>
class ReceiverMonitorWrapper : public T {
friend class ReceiverMonitor;
public:
template <typename... Args>
explicit ReceiverMonitorWrapper(Args... args) : T(std::forward<Args>(args)...) { }
template<typename T>
class _receiverMonitorWrapper : public T {
friend class ReceiverMonitor;
template <typename... Args>
static std::shared_ptr<T> make(Args... args) {
return std::make_shared<ReceiverMonitorWrapper>(std::forward<Args>(args)...);
}
};
}
public:
template<typename... Args>
explicit _receiverMonitorWrapper(Args... args) : T(std::forward<Args>(args)...) {}
template<typename... Args>
static std::shared_ptr<T> make(Args... args) {
return std::make_shared<_receiverMonitorWrapper>(std::forward<Args>(args)...);
}
};
static constexpr int max_tries = 5;
static constexpr int ready_backoff = 250;
@ -50,7 +49,9 @@ namespace logid::backend::hidpp10 {
void enumerate();
ReceiverMonitor(const ReceiverMonitor&) = delete;
ReceiverMonitor(ReceiverMonitor&&) = delete;
protected:
ReceiverMonitor(const std::string& path,
const std::shared_ptr<raw::DeviceMonitor>& monitor,
@ -101,9 +102,9 @@ namespace logid::backend::hidpp10 {
std::weak_ptr<ReceiverMonitor> _self;
public:
template <typename T, typename... Args>
template<typename T, typename... Args>
static std::shared_ptr<T> make(Args... args) {
auto receiver_monitor = ReceiverMonitorWrapper<T>::make(std::forward<Args>(args)...);
auto receiver_monitor = _receiverMonitorWrapper<T>::make(std::forward<Args>(args)...);
receiver_monitor->_self = receiver_monitor;
receiver_monitor->_ready();
return receiver_monitor;

View File

@ -36,21 +36,19 @@ namespace logid::backend::raw {
static constexpr int max_tries = 5;
static constexpr int ready_backoff = 500;
namespace {
template<typename T>
class DeviceMonitorWrapper : public T {
friend class Device;
template<typename T>
class _deviceMonitorWrapper : public T {
friend class Device;
public:
template<typename... Args>
explicit DeviceMonitorWrapper(Args... args) : T(std::forward<Args>(args)...) {}
public:
template<typename... Args>
explicit _deviceMonitorWrapper(Args... args) : T(std::forward<Args>(args)...) {}
template<typename... Args>
static std::shared_ptr<T> make(Args... args) {
return std::make_shared<DeviceMonitorWrapper>(std::forward<Args>(args)...);
}
};
}
template<typename... Args>
static std::shared_ptr<T> make(Args... args) {
return std::make_shared<_deviceMonitorWrapper>(std::forward<Args>(args)...);
}
};
class DeviceMonitor {
public:
@ -62,7 +60,7 @@ namespace logid::backend::raw {
template<typename T, typename... Args>
static std::shared_ptr<T> make(Args... args) {
auto device_monitor = DeviceMonitorWrapper<T>::make(std::forward<Args>(args)...);
auto device_monitor = _deviceMonitorWrapper<T>::make(std::forward<Args>(args)...);
device_monitor->_self = device_monitor;
device_monitor->ready();
@ -79,7 +77,7 @@ namespace logid::backend::raw {
virtual void removeDevice(std::string device) = 0;
template <typename T>
template<typename T>
[[nodiscard]] std::weak_ptr<T> self() const {
return std::dynamic_pointer_cast<T>(_self.lock());
}

View File

@ -38,55 +38,45 @@ namespace logid::config {
template<typename T>
void append(libconfig::Setting& list, const T& t);
namespace {
template<typename T, typename... M>
struct group_io {
};
template<typename T, typename... M>
struct group_io {
};
template<typename T>
struct group_io<T> {
static inline void get(
[[maybe_unused]] const libconfig::Setting& s,
[[maybe_unused]] T* t,
[[maybe_unused]] const std::vector<std::string>& names,
[[maybe_unused]] const std::size_t index) {}
template<typename T>
struct group_io<T> {
static void get(const libconfig::Setting&, T*,
const std::vector<std::string>&, const std::size_t) {}
static inline void set(
[[maybe_unused]] libconfig::Setting& s,
[[maybe_unused]] const T* t,
[[maybe_unused]] const std::vector<std::string>& names,
[[maybe_unused]] const std::size_t index) {}
};
static void set(libconfig::Setting&, const T*,
const std::vector<std::string>&, const std::size_t) {}
};
template<typename T, typename A, typename... M>
struct group_io<T, A, M...> {
static inline void get(
const libconfig::Setting& s, T* t,
const std::vector<std::string>& names,
const std::size_t index, A T::* arg, M T::*... rest) {
auto& x = t->*(arg);
A old{x};
try {
x = config::get<A>(s, names[index]);
group_io<T, M...>::get(s, t, names, index + 1, rest...);
} catch (libconfig::SettingTypeException& e) {
x = old;
throw;
} catch (libconfig::SettingException& e) {
x = old;
throw libconfig::SettingTypeException(s);
}
template<typename T, typename A, typename... M>
struct group_io<T, A, M...> {
static void get(const libconfig::Setting& s, T* t,
const std::vector<std::string>& names,
const std::size_t index, A T::* arg, M T::*... rest) {
auto& x = t->*(arg);
A old{x};
try {
x = config::get<A>(s, names[index]);
group_io<T, M...>::get(s, t, names, index + 1, rest...);
} catch (libconfig::SettingTypeException& e) {
x = old;
throw;
} catch (libconfig::SettingException& e) {
x = old;
throw libconfig::SettingTypeException(s);
}
}
static inline void set(
libconfig::Setting& s, const T* t,
const std::vector<std::string>& names,
const std::size_t index, A T::* arg, M T::*... rest) {
config::set(s, names[index], t->*(arg));
group_io<T, M...>::set(s, t, names, index + 1, rest...);
}
};
}
static void set(libconfig::Setting& s, const T* t,
const std::vector<std::string>& names,
const std::size_t index, A T::* arg, M T::*... rest) {
config::set(s, names[index], t->*(arg));
group_io<T, M...>::set(s, t, names, index + 1, rest...);
}
};
template<typename Sign>
struct signed_group;
@ -149,22 +139,19 @@ namespace logid::config {
}
};
namespace {
template<typename T>
struct normalize_signature {
static inline const T& make(const T& ret) { return ret; }
};
template<typename T>
struct normalize_signature {
static const T& make(const T& ret) { return ret; }
};
template<>
struct normalize_signature<std::string> {
static inline std::string make(const std::string& data) {
std::string ret = data;
std::transform(ret.begin(), ret.end(),
ret.begin(), ::tolower);
return ret;
}
};
}
template<>
struct normalize_signature<std::string> {
static std::string make(const std::string& data) {
std::string ret = data;
std::transform(ret.begin(), ret.end(), ret.begin(), ::tolower);
return ret;
}
};
template<typename Sign>
struct signed_group : public group {

View File

@ -33,416 +33,402 @@
namespace logid::config {
void logError(const libconfig::Setting& setting, std::exception& e);
namespace {
template<typename T>
struct config_io {
static_assert(std::is_base_of<group, T>::value);
template<typename T>
struct config_io {
static_assert(std::is_base_of<group, T>::value);
static inline T get(const libconfig::Setting& parent,
const std::string& name) {
T t{};
t._load(parent.lookup(name));
return t;
static T get(const libconfig::Setting& parent,
const std::string& name) {
T t{};
t._load(parent.lookup(name));
return t;
}
static T get(const libconfig::Setting& setting) {
T t{};
t._load(setting);
return t;
}
static void set(libconfig::Setting& parent,
const std::string& name,
const T& t) {
if (!parent.exists(name)) {
parent.add(name, libconfig::Setting::TypeGroup);
} else if (parent.lookup(name).getType()
!= libconfig::Setting::TypeGroup) {
parent.remove(name);
parent.add(name, libconfig::Setting::TypeGroup);
}
t._save(parent.lookup(name));
}
static inline T get(const libconfig::Setting& setting) {
T t{};
t._load(setting);
return t;
static void set(libconfig::Setting& setting, const T& t) {
t._save(setting);
}
static void append(libconfig::Setting& list, const T& t) {
auto& x = list.add(libconfig::Setting::TypeGroup);
set(x, t);
}
};
template<typename T>
struct config_io<ipcgull::property<T>> : public config_io<T> {
};
template<typename T, libconfig::Setting::Type TypeEnum>
struct primitive_io {
static T get(const libconfig::Setting& parent,
const std::string& name) {
return parent.lookup(name);
}
static T get(const libconfig::Setting& setting) {
return setting;
}
static void set(libconfig::Setting& parent,
const std::string& name,
const T& t) {
if (!parent.exists(name)) {
parent.add(name, TypeEnum);
} else if (parent.lookup(name).getType() != TypeEnum) {
parent.remove(name);
parent.add(name, TypeEnum);
}
set(parent.lookup(name), t);
}
static inline void set(libconfig::Setting& parent,
const std::string& name,
const T& t) {
if (!parent.exists(name)) {
parent.add(name, libconfig::Setting::TypeGroup);
} else if (parent.lookup(name).getType()
!= libconfig::Setting::TypeGroup) {
parent.remove(name);
parent.add(name, libconfig::Setting::TypeGroup);
}
t._save(parent.lookup(name));
static void set(libconfig::Setting& setting, const T& t) {
setting = t;
}
static void append(libconfig::Setting& list, const T& t) {
auto& x = list.add(TypeEnum);
set(x, t);
}
};
template<typename T, typename O, libconfig::Setting::Type TypeEnum>
struct reinterpret_io {
static T get(const libconfig::Setting& parent,
const std::string& name) {
return static_cast<T>(primitive_io<O, TypeEnum>::get(parent, name));
}
static T get(const libconfig::Setting& setting) {
return static_cast<T>(primitive_io<O, TypeEnum>::get(setting));
}
static void set(libconfig::Setting& parent,
const std::string& name,
const T& t) {
primitive_io<O, TypeEnum>::set(parent, name,
static_cast<O>(t));
}
static void set(libconfig::Setting& setting, const T& t) {
primitive_io<O, TypeEnum>::set(setting,
static_cast<O>(t));
}
[[maybe_unused]]
static void append(libconfig::Setting& list, const T& t) {
primitive_io<O, TypeEnum>::append(list,
static_cast<O>(t));
}
};
template<>
struct config_io<bool> : public primitive_io<bool,
libconfig::Setting::TypeBoolean> {
};
template<>
struct config_io<int8_t> : public reinterpret_io<int8_t, int,
libconfig::Setting::TypeInt> {
};
template<>
struct config_io<uint8_t> : public reinterpret_io<uint8_t, int,
libconfig::Setting::TypeInt> {
};
template<>
struct config_io<short> : public reinterpret_io<short, int,
libconfig::Setting::TypeInt> {
};
template<>
struct config_io<unsigned short> : public reinterpret_io<unsigned short,
int, libconfig::Setting::TypeInt> {
};
template<>
struct config_io<int> : public primitive_io<int,
libconfig::Setting::TypeInt> {
};
template<>
struct config_io<unsigned int> : public reinterpret_io<unsigned int,
int, libconfig::Setting::TypeInt> {
};
template<>
struct config_io<long> : public reinterpret_io<long, long long,
libconfig::Setting::TypeInt64> {
};
template<>
struct config_io<unsigned long> : public reinterpret_io<unsigned long,
long long, libconfig::Setting::TypeInt64> {
};
template<>
struct config_io<long long> : public primitive_io<long long,
libconfig::Setting::TypeInt64> {
};
template<>
struct config_io<unsigned long long> :
public reinterpret_io<unsigned long long, long long,
libconfig::Setting::TypeInt64> {
};
template<>
struct config_io<float> : public primitive_io<float,
libconfig::Setting::TypeFloat> {
};
template<>
struct config_io<double> : public primitive_io<double,
libconfig::Setting::TypeFloat> {
};
template<>
struct config_io<std::string> : public primitive_io<std::string,
libconfig::Setting::TypeString> {
};
template<typename... T>
struct config_io<std::variant<T...>> {
private:
template<typename Singleton>
static std::variant<T...> try_each(const libconfig::Setting& setting) {
return config_io<Singleton>::get(setting);
}
template<typename First, typename Next, typename... Rest>
static std::variant<T...> try_each(const libconfig::Setting& setting) {
try {
return config_io<First>::get(setting);
} catch (libconfig::SettingException& e) {
return try_each<Next, Rest...>(setting);
}
}
static inline void set(libconfig::Setting& setting, const T& t) {
t._save(setting);
}
public:
static std::variant<T...> get(const libconfig::Setting& setting) {
return try_each<T...>(setting);
}
static inline void append(libconfig::Setting& list, const T& t) {
auto& x = list.add(libconfig::Setting::TypeGroup);
set(x, t);
}
};
static std::variant<T...> get(const libconfig::Setting& parent,
const std::string& name) {
return get(parent.lookup(name));
}
template<typename T>
struct config_io<ipcgull::property<T>> : public config_io<T> {
};
static void set(libconfig::Setting& setting,
const std::variant<T...>& t) {
std::visit([&setting](auto&& arg) {
config::set(setting, arg);
}, t);
}
template<typename T, libconfig::Setting::Type TypeEnum>
struct primitive_io {
static inline T get(const libconfig::Setting& parent,
const std::string& name) {
return parent.lookup(name);
}
static void set(libconfig::Setting& parent,
const std::string& name,
const std::variant<T...>& t) {
std::visit([&parent, &name](auto&& arg) {
config::set(parent, name, arg);
}, t);
}
static inline T get(const libconfig::Setting& setting) {
return setting;
}
[[maybe_unused]]
static void append(libconfig::Setting& list, const std::variant<T...>& t) {
std::visit([&list](auto&& arg) {
config::append(list, arg);
}, t);
}
};
static inline void set(libconfig::Setting& parent,
const std::string& name,
const T& t) {
if (!parent.exists(name)) {
parent.add(name, TypeEnum);
} else if (parent.lookup(name).getType() != TypeEnum) {
parent.remove(name);
parent.add(name, TypeEnum);
}
set(parent.lookup(name), t);
}
static inline void set(libconfig::Setting& setting, const T& t) {
setting = t;
}
static inline void append(libconfig::Setting& list, const T& t) {
auto& x = list.add(TypeEnum);
set(x, t);
}
};
template<typename T, typename O, libconfig::Setting::Type TypeEnum>
struct reinterpret_io {
static inline T get(const libconfig::Setting& parent,
const std::string& name) {
return static_cast<T>(primitive_io<O, TypeEnum>::get(parent, name));
}
static inline T get(const libconfig::Setting& setting) {
return static_cast<T>(primitive_io<O, TypeEnum>::get(setting));
}
static inline void set(libconfig::Setting& parent,
const std::string& name,
const T& t) {
primitive_io<O, TypeEnum>::set(parent, name,
static_cast<O>(t));
}
static inline void set(libconfig::Setting& setting, const T& t) {
primitive_io<O, TypeEnum>::set(setting,
static_cast<O>(t));
}
[[maybe_unused]]
static inline void append(libconfig::Setting& list, const T& t) {
primitive_io<O, TypeEnum>::append(list,
static_cast<O>(t));
}
};
template<>
struct config_io<bool> : public primitive_io<bool,
libconfig::Setting::TypeBoolean> {
};
template<>
struct config_io<int8_t> : public reinterpret_io<int8_t, int,
libconfig::Setting::TypeInt> {
};
template<>
struct config_io<uint8_t> : public reinterpret_io<uint8_t, int,
libconfig::Setting::TypeInt> {
};
template<>
struct config_io<short> : public reinterpret_io<short, int,
libconfig::Setting::TypeInt> {
};
template<>
struct config_io<unsigned short> : public reinterpret_io<unsigned short,
int, libconfig::Setting::TypeInt> {
};
template<>
struct config_io<int> : public primitive_io<int,
libconfig::Setting::TypeInt> {
};
template<>
struct config_io<unsigned int> : public reinterpret_io<unsigned int,
int, libconfig::Setting::TypeInt> {
};
template<>
struct config_io<long> : public reinterpret_io<long, long long,
libconfig::Setting::TypeInt64> {
};
template<>
struct config_io<unsigned long> : public reinterpret_io<unsigned long,
long long, libconfig::Setting::TypeInt64> {
};
template<>
struct config_io<long long> : public primitive_io<long long,
libconfig::Setting::TypeInt64> {
};
template<>
struct config_io<unsigned long long> :
public reinterpret_io<unsigned long long, long long,
libconfig::Setting::TypeInt64> {
};
template<>
struct config_io<float> : public primitive_io<float,
libconfig::Setting::TypeFloat> {
};
template<>
struct config_io<double> : public primitive_io<double,
libconfig::Setting::TypeFloat> {
};
template<>
struct config_io<std::string> : public primitive_io<std::string,
libconfig::Setting::TypeString> {
};
template<typename... T>
struct config_io<std::variant<T...>> {
private:
template<typename Singleton>
static inline std::variant<T...> try_each(
const libconfig::Setting& setting) {
return config_io<Singleton>::get(setting);
}
template<typename First, typename Next, typename... Rest>
static inline std::variant<T...> try_each(
const libconfig::Setting& setting) {
template<typename T>
struct config_io<std::list<T>> {
static std::list<T> get(const libconfig::Setting& setting) {
const auto size = setting.getLength();
std::list<T> t{};
for (int i = 0; i < size; ++i) {
try {
return config_io<First>::get(setting);
t.emplace_back(config_io<T>::get(setting[i]));
} catch (libconfig::SettingException& e) {}
}
return t;
}
static std::list<T> get(const libconfig::Setting& parent, const std::string& name) {
return get(parent.lookup(name));
}
static void set(libconfig::Setting& setting, const std::list<T>& t) {
while (setting.getLength() != 0)
setting.remove((int) 0);
for (auto& x: t) {
config_io<T>::append(setting, x);
}
}
static void set(libconfig::Setting& parent,
const std::string& name,
const std::list<T>& t) {
if (!parent.exists(name)) {
parent.add(name, libconfig::Setting::TypeList);
} else if (!parent.lookup(name).isList()) {
parent.remove(name);
parent.add(name, libconfig::Setting::TypeList);
}
set(parent.lookup(name), t);
}
[[maybe_unused]]
static void append(libconfig::Setting& list, const std::list<T>& t) {
auto& s = list.add(libconfig::Setting::TypeList);
set(s, t);
}
};
template<typename T>
struct config_io<std::set<T>> {
static std::set<T> get(const libconfig::Setting& setting) {
const auto size = setting.getLength();
std::set<T> t;
for (int i = 0; i < size; ++i) {
try {
t.emplace(config_io<T>::get(setting[i]));
} catch (libconfig::SettingException& e) {}
}
return t;
}
static std::set<T> get(const libconfig::Setting& parent, const std::string& name) {
return get(parent.lookup(name));
}
static void set(libconfig::Setting& setting, const std::set<T>& t) {
while (setting.getLength() != 0)
setting.remove((int) 0);
for (auto& x: t) {
auto& s = setting.add(libconfig::Setting::TypeGroup);
config_io<T>::set(s, x);
}
}
static void set(libconfig::Setting& parent,
const std::string& name,
const std::set<T>& t) {
if (!parent.exists(name)) {
parent.add(name, libconfig::Setting::TypeList);
} else if (!parent.lookup(name).isArray()) {
parent.remove(name);
parent.add(name, libconfig::Setting::TypeList);
}
set(parent.lookup(name), t);
}
[[maybe_unused]]
static void append(libconfig::Setting& list,
const std::set<T>& t) {
auto& s = list.add(libconfig::Setting::TypeList);
set(s, t);
}
};
template<typename K, typename V, typename KeyName,
typename Cmp, typename Alloc>
struct config_io<map<K, V, KeyName, Cmp, Alloc>> {
static map<K, V, KeyName, Cmp, Alloc> get(const libconfig::Setting& setting) {
const auto size = setting.getLength();
map<K, V, KeyName, Cmp, Alloc> t;
for (int i = 0; i < size; ++i) {
auto& s = setting[i];
try {
t.emplace(config_io<K>::get(s.lookup(KeyName::value)),
config_io<V>::get(s));
} catch (libconfig::SettingException& e) {}
}
return t;
}
static map<K, V, KeyName, Cmp, Alloc> get(
const libconfig::Setting& parent, const std::string& name) {
return get(parent.lookup(name));
}
static void set(libconfig::Setting& setting,
const map<K, V, KeyName, Cmp, Alloc>& t) {
while (setting.getLength() != 0)
setting.remove((int) 0);
for (auto& x: t) {
auto& s = setting.add(libconfig::Setting::TypeGroup);
config_io<V>::set(s, x.second);
config_io<K>::set(s, KeyName::value, x.first);
}
}
static void set(libconfig::Setting& parent,
const std::string& name,
const map<K, V, KeyName, Cmp, Alloc>& t) {
if (!parent.exists(name)) {
parent.add(name, libconfig::Setting::TypeList);
} else if (!parent.lookup(name).isArray()) {
parent.remove(name);
parent.add(name, libconfig::Setting::TypeList);
}
set(parent.lookup(name), t);
}
[[maybe_unused]]
static void append(libconfig::Setting& list, const map<K, V, KeyName, Cmp, Alloc>& t) {
auto& s = list.add(libconfig::Setting::TypeList);
set(s, t);
}
};
template<typename T>
struct config_io<std::optional<T>> {
static std::optional<T> get(const libconfig::Setting& parent,
const std::string& name) {
if (parent.exists(name)) {
auto& setting = parent.lookup(name);
try {
return config_io<T>::get(setting);
} catch (libconfig::SettingException& e) {
return try_each<Next, Rest...>(setting);
logError(setting, e);
return std::nullopt;
}
} else {
return std::nullopt;
}
}
public:
static inline std::variant<T...> get(
const libconfig::Setting& setting) {
return try_each<T...>(setting);
}
static void set(libconfig::Setting& parent,
const std::string& name,
const std::optional<T>& t) {
if (t.has_value())
config_io<T>::set(parent, name, t.value());
}
};
static inline std::variant<T...> get(
const libconfig::Setting& parent,
const std::string& name) {
return get(parent.lookup(name));
}
// Optionals may not appear as part of a list or array
template<typename T, typename... Rest>
struct config_io<std::variant<std::optional<T>, Rest...>> {
static_assert(!sizeof(std::optional<T>), "Invalid type");
};
static inline void set(libconfig::Setting& setting,
const std::variant<T...>& t) {
std::visit([&setting](auto&& arg) {
config::set(setting, arg);
}, t);
}
template<typename T>
struct config_io<std::list<std::optional<T>>> {
static_assert(!sizeof(std::optional<T>), "Invalid type");
};
static inline void set(libconfig::Setting& parent,
const std::string& name,
const std::variant<T...>& t) {
std::visit([&parent, &name](auto&& arg) {
config::set(parent, name, arg);
}, t);
}
[[maybe_unused]]
static inline void append(libconfig::Setting& list,
const std::variant<T...>& t) {
std::visit([&list](auto&& arg) {
config::append(list, arg);
}, t);
}
};
template<typename T>
struct config_io<std::list<T>> {
static inline std::list<T> get(const libconfig::Setting& setting) {
const auto size = setting.getLength();
std::list<T> t{};
for (int i = 0; i < size; ++i) {
try {
t.emplace_back(config_io<T>::get(setting[i]));
} catch (libconfig::SettingException& e) {}
}
return t;
}
static inline std::list<T> get(const libconfig::Setting& parent,
const std::string& name) {
return get(parent.lookup(name));
}
static inline void set(libconfig::Setting& setting,
const std::list<T>& t) {
while (setting.getLength() != 0)
setting.remove((int) 0);
for (auto& x: t) {
config_io<T>::append(setting, x);
}
}
static inline void set(libconfig::Setting& parent,
const std::string& name,
const std::list<T>& t) {
if (!parent.exists(name)) {
parent.add(name, libconfig::Setting::TypeList);
} else if (!parent.lookup(name).isList()) {
parent.remove(name);
parent.add(name, libconfig::Setting::TypeList);
}
set(parent.lookup(name), t);
}
[[maybe_unused]]
static inline void append(libconfig::Setting& list,
const std::list<T>& t) {
auto& s = list.add(libconfig::Setting::TypeList);
set(s, t);
}
};
template<typename T>
struct config_io<std::set<T>> {
static inline std::set<T> get(const libconfig::Setting& setting) {
const auto size = setting.getLength();
std::set<T> t;
for (int i = 0; i < size; ++i) {
try {
t.emplace(config_io<T>::get(setting[i]));
} catch (libconfig::SettingException& e) {}
}
return t;
}
static inline std::set<T> get(const libconfig::Setting& parent,
const std::string& name) {
return get(parent.lookup(name));
}
static inline void set(libconfig::Setting& setting,
const std::set<T>& t) {
while (setting.getLength() != 0)
setting.remove((int) 0);
for (auto& x: t) {
auto& s = setting.add(libconfig::Setting::TypeGroup);
config_io<T>::set(s, x);
}
}
static inline void set(libconfig::Setting& parent,
const std::string& name,
const std::set<T>& t) {
if (!parent.exists(name)) {
parent.add(name, libconfig::Setting::TypeList);
} else if (!parent.lookup(name).isArray()) {
parent.remove(name);
parent.add(name, libconfig::Setting::TypeList);
}
set(parent.lookup(name), t);
}
[[maybe_unused]]
static inline void append(libconfig::Setting& list,
const std::set<T>& t) {
auto& s = list.add(libconfig::Setting::TypeList);
set(s, t);
}
};
template<typename K, typename V, typename KeyName,
typename Cmp, typename Alloc>
struct config_io<map<K, V, KeyName, Cmp, Alloc>> {
static inline map<K, V, KeyName, Cmp, Alloc> get(
const libconfig::Setting& setting) {
const auto size = setting.getLength();
map<K, V, KeyName, Cmp, Alloc> t;
for (int i = 0; i < size; ++i) {
auto& s = setting[i];
try {
t.emplace(config_io<K>::get(s.lookup(KeyName::value)),
config_io<V>::get(s));
} catch (libconfig::SettingException& e) {}
}
return t;
}
static inline map<K, V, KeyName, Cmp, Alloc> get(
const libconfig::Setting& parent, const std::string& name) {
return get(parent.lookup(name));
}
static inline void set(libconfig::Setting& setting,
const map<K, V, KeyName, Cmp, Alloc>& t) {
while (setting.getLength() != 0)
setting.remove((int) 0);
for (auto& x: t) {
auto& s = setting.add(libconfig::Setting::TypeGroup);
config_io<V>::set(s, x.second);
config_io<K>::set(s, KeyName::value, x.first);
}
}
static inline void set(libconfig::Setting& parent,
const std::string& name,
const map<K, V, KeyName, Cmp, Alloc>& t) {
if (!parent.exists(name)) {
parent.add(name, libconfig::Setting::TypeList);
} else if (!parent.lookup(name).isArray()) {
parent.remove(name);
parent.add(name, libconfig::Setting::TypeList);
}
set(parent.lookup(name), t);
}
[[maybe_unused]]
static inline void append(libconfig::Setting& list,
const map<K, V, KeyName, Cmp, Alloc>& t) {
auto& s = list.add(libconfig::Setting::TypeList);
set(s, t);
}
};
template<typename T>
struct config_io<std::optional<T>> {
static inline std::optional<T> get(const libconfig::Setting& parent,
const std::string& name) {
if (parent.exists(name)) {
auto& setting = parent.lookup(name);
try {
return config_io<T>::get(setting);
} catch (libconfig::SettingException& e) {
logError(setting, e);
return {};
}
} else {
return {};
}
}
static inline void set(libconfig::Setting& parent,
const std::string& name,
const std::optional<T>& t) {
if (t.has_value())
config_io<T>::set(parent, name, t.value());
}
};
// Optionals may not appear as part of a list or array
template<typename T, typename... Rest>
struct config_io<std::variant<std::optional<T>, Rest...>> {
static_assert(!sizeof(std::optional<T>), "Invalid type");
};
template<typename T>
struct config_io<std::list<std::optional<T>>> {
static_assert(!sizeof(std::optional<T>), "Invalid type");
};
template<typename T>
struct config_io<std::optional<std::optional<T>>> {
static_assert(!sizeof(std::optional<T>), "Invalid type");
};
}
template<typename T>
struct config_io<std::optional<std::optional<T>>> {
static_assert(!sizeof(std::optional<T>), "Invalid type");
};
template<typename T>
void set(libconfig::Setting& parent,

View File

@ -40,21 +40,19 @@ namespace logid::features {
}
};
namespace {
template<typename T>
class FeatureWrapper : public T {
friend class DeviceFeature;
template<typename T>
class _featureWrapper : public T {
friend class DeviceFeature;
public:
template<typename... Args>
explicit FeatureWrapper(Args... args) : T(std::forward<Args>(args)...) {}
public:
template<typename... Args>
explicit _featureWrapper(Args... args) : T(std::forward<Args>(args)...) {}
template<typename... Args>
static std::shared_ptr<T> make(Args... args) {
return std::make_shared<FeatureWrapper>(std::forward<Args>(args)...);
}
};
}
template<typename... Args>
static std::shared_ptr<T> make(Args... args) {
return std::make_shared<_featureWrapper>(std::forward<Args>(args)...);
}
};
class DeviceFeature {
std::weak_ptr<DeviceFeature> _self;
@ -68,7 +66,9 @@ namespace logid::features {
virtual ~DeviceFeature() = default;
DeviceFeature(const DeviceFeature&) = delete;
DeviceFeature(DeviceFeature&&) = delete;
protected:
explicit DeviceFeature(Device* dev) : _device(dev) {}
@ -82,7 +82,7 @@ namespace logid::features {
public:
template<typename T, typename... Args>
static std::shared_ptr<T> make(Args... args) {
auto feature = FeatureWrapper<T>::make(std::forward<Args>(args)...);
auto feature = _featureWrapper<T>::make(std::forward<Args>(args)...);
feature->_self = feature;
return feature;