refactor: enable compile-time D-Bus signature generation (#425)

Since sdbus-c++ knows types of D-Bus call/signal/property input/output parameters at compile time, why not assemble the D-Bus signature strings at compile time, too, instead of assembling them at run time as std::string with likely cost of (unnecessary) heap allocations...

std::array is well supported constexpr type in C++20, so we harness it to build the D-Bus signature string and store it into the binary at compile time.
This commit is contained in:
Stanislav Angelovič
2024-04-24 20:20:29 +02:00
parent 32a97f214f
commit d856969051
9 changed files with 294 additions and 319 deletions
+106 -42
View File
@@ -161,22 +161,38 @@ namespace sdbus {
template <typename... _ValueTypes>
Message& operator>>(std::tuple<_ValueTypes...>& item);
Message& openContainer(const std::string& signature);
template <typename _ElementType>
Message& openContainer();
Message& openContainer(const char* signature);
Message& closeContainer();
Message& openDictEntry(const std::string& signature);
template <typename _KeyType, typename _ValueType>
Message& openDictEntry();
Message& openDictEntry(const char* signature);
Message& closeDictEntry();
Message& openVariant(const std::string& signature);
template <typename _ValueType>
Message& openVariant();
Message& openVariant(const char* signature);
Message& closeVariant();
Message& openStruct(const std::string& signature);
template <typename... _ValueTypes>
Message& openStruct();
Message& openStruct(const char* signature);
Message& closeStruct();
Message& enterContainer(const std::string& signature);
template <typename _ElementType>
Message& enterContainer();
Message& enterContainer(const char* signature);
Message& exitContainer();
Message& enterDictEntry(const std::string& signature);
template <typename _KeyType, typename _ValueType>
Message& enterDictEntry();
Message& enterDictEntry(const char* signature);
Message& exitDictEntry();
Message& enterVariant(const std::string& signature);
template <typename _ValueType>
Message& enterVariant();
Message& enterVariant(const char* signature);
Message& exitVariant();
Message& enterStruct(const std::string& signature);
template <typename... _ValueTypes>
Message& enterStruct();
Message& enterStruct(const char* signature);
Message& exitStruct();
Message& appendArray(char type, const void *ptr, size_t size);
@@ -320,8 +336,9 @@ namespace sdbus {
template <typename ...Elements>
inline Message& Message::operator<<(const std::variant<Elements...>& value)
{
std::visit([this](const auto& inner){
openVariant(signature_of<decltype(inner)>::str());
std::visit([this](const auto& inner)
{
openVariant<decltype(inner)>();
*this << inner;
closeVariant();
}, value);
@@ -370,11 +387,12 @@ namespace sdbus {
// otherwise use step-by-step serialization of individual elements.
if constexpr (signature_of<ElementType>::is_trivial_dbus_type && !std::is_same_v<ElementType, bool>)
{
appendArray(*signature_of<ElementType>::str().c_str(), items.data(), items.size() * sizeof(ElementType));
constexpr auto signature = as_null_terminated(signature_of_v<ElementType>);
appendArray(*signature.data(), items.data(), items.size() * sizeof(ElementType));
}
else
{
openContainer(signature_of<ElementType>::str());
openContainer<ElementType>();
for (const auto& item : items)
*this << item;
@@ -403,16 +421,13 @@ namespace sdbus {
inline void Message::serializeDictionary(const _Dictionary& items)
{
using KeyType = typename _Dictionary::key_type;
using ValueType = typename _Dictionary::mapped_type;
using MappedType = typename _Dictionary::mapped_type;
const std::string dictEntrySignature = signature_of<KeyType>::str() + signature_of<ValueType>::str();
const std::string arraySignature = "{" + dictEntrySignature + "}";
openContainer(arraySignature);
openContainer<DictEntry<KeyType, MappedType>>();
for (const auto& item : items)
{
openDictEntry(dictEntrySignature);
openDictEntry<KeyType, MappedType>();
*this << item.first;
*this << item.second;
closeDictEntry();
@@ -441,12 +456,7 @@ namespace sdbus {
template <typename... _ValueTypes>
inline Message& Message::operator<<(const Struct<_ValueTypes...>& item)
{
auto structSignature = signature_of<Struct<_ValueTypes...>>::str();
assert(structSignature.size() > 2);
// Remove opening and closing parenthesis from the struct signature to get contents signature
auto structContentSignature = structSignature.substr(1, structSignature.size() - 2);
openStruct(structContentSignature);
openStruct<_ValueTypes...>();
detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
closeStruct();
@@ -465,11 +475,13 @@ namespace sdbus {
template <typename _Element, typename... _Elements>
bool deserialize_variant(Message& msg, std::variant<_Elements...>& value, const std::string& signature)
{
if (signature != signature_of<_Element>::str())
constexpr auto elemSignature = sdbus::signature_of_v<_Element>;
// TODO: Try to optimize
if (signature != std::string(elemSignature.begin(), elemSignature.end()))
return false;
_Element temp;
msg.enterVariant(signature);
msg.enterVariant(signature.c_str());
msg >> temp;
msg.exitVariant();
value = std::move(temp);
@@ -482,6 +494,7 @@ namespace sdbus {
{
std::string type;
std::string contentType;
// TODO: Refactor ppekType prior to release/v2.0 to return pair of const char* or string_view...
peekType(type, contentType);
bool result = (detail::deserialize_variant<Elements>(*this, value, contentType) || ...);
SDBUS_THROW_ERROR_IF(!result, "Failed to deserialize variant: signature did not match any of the variant types", EINVAL);
@@ -548,7 +561,8 @@ namespace sdbus {
size_t arraySize{};
const ElementType* arrayPtr{};
readArray(*signature_of<ElementType>::str().c_str(), (const void**)&arrayPtr, &arraySize);
constexpr auto signature = as_null_terminated(sdbus::signature_of_v<ElementType>);
readArray(*signature.data(), (const void**)&arrayPtr, &arraySize);
size_t elementsInMsg = arraySize / sizeof(ElementType);
bool notEnoughSpace = items.size() < elementsInMsg;
@@ -563,7 +577,8 @@ namespace sdbus {
size_t arraySize{};
const _Element* arrayPtr{};
readArray(*signature_of<_Element>::str().c_str(), (const void**)&arrayPtr, &arraySize);
constexpr auto signature = as_null_terminated(sdbus::signature_of_v<_Element>);
readArray(*signature.data(), (const void**)&arrayPtr, &arraySize);
items.insert(items.end(), arrayPtr, arrayPtr + (arraySize / sizeof(_Element)));
}
@@ -573,7 +588,7 @@ namespace sdbus {
{
using ElementType = typename _Array::value_type;
if(!enterContainer(signature_of<ElementType>::str()))
if(!enterContainer<ElementType>())
return;
for (auto& elem : items)
@@ -590,7 +605,7 @@ namespace sdbus {
template <typename _Element, typename _Allocator>
void Message::deserializeArraySlow(std::vector<_Element, _Allocator>& items)
{
if(!enterContainer(signature_of<_Element>::str()))
if(!enterContainer<_Element>())
return;
while (true)
@@ -627,21 +642,18 @@ namespace sdbus {
inline void Message::deserializeDictionary(_Dictionary& items)
{
using KeyType = typename _Dictionary::key_type;
using ValueType = typename _Dictionary::mapped_type;
using MappedType = typename _Dictionary::mapped_type;
const std::string dictEntrySignature = signature_of<KeyType>::str() + signature_of<ValueType>::str();
const std::string arraySignature = "{" + dictEntrySignature + "}";
if (!enterContainer(arraySignature))
if (!enterContainer<DictEntry<KeyType, MappedType>>())
return;
while (true)
{
if (!enterDictEntry(dictEntrySignature))
if (!enterDictEntry<KeyType, MappedType>())
break;
KeyType key;
ValueType value;
MappedType value;
*this >> key >> value;
items.emplace(std::move(key), std::move(value));
@@ -674,11 +686,7 @@ namespace sdbus {
template <typename... _ValueTypes>
inline Message& Message::operator>>(Struct<_ValueTypes...>& item)
{
auto structSignature = signature_of<Struct<_ValueTypes...>>::str();
// Remove opening and closing parenthesis from the struct signature to get contents signature
auto structContentSignature = structSignature.substr(1, structSignature.size()-2);
if (!enterStruct(structContentSignature))
if (!enterStruct<_ValueTypes...>())
return *this;
detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
@@ -695,6 +703,62 @@ namespace sdbus {
return *this;
}
template <typename _ElementType>
inline Message& Message::openContainer()
{
constexpr auto signature = as_null_terminated(signature_of_v<_ElementType>);
return openContainer(signature.data());
}
template <typename _KeyType, typename _ValueType>
inline Message& Message::openDictEntry()
{
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_KeyType, _ValueType>>);
return openDictEntry(signature.data());
}
template <typename _ValueType>
inline Message& Message::openVariant()
{
constexpr auto signature = as_null_terminated(signature_of_v<_ValueType>);
return openVariant(signature.data());
}
template <typename... _ValueTypes>
inline Message& Message::openStruct()
{
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_ValueTypes...>>);
return openStruct(signature.data());
}
template <typename _ElementType>
inline Message& Message::enterContainer()
{
constexpr auto signature = as_null_terminated(signature_of_v<_ElementType>);
return enterContainer(signature.data());
}
template <typename _KeyType, typename _ValueType>
inline Message& Message::enterDictEntry()
{
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_KeyType, _ValueType>>);
return enterDictEntry(signature.data());
}
template <typename _ValueType>
inline Message& Message::enterVariant()
{
constexpr auto signature = as_null_terminated(signature_of_v<_ValueType>);
return enterVariant(signature.data());
}
template <typename... _ValueTypes>
inline Message& Message::enterStruct()
{
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_ValueTypes...>>);
return enterStruct(signature.data());
}
}
#endif /* SDBUS_CXX_MESSAGE_H_ */
+132 -234
View File
@@ -44,6 +44,7 @@
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <variant>
#include <vector>
@@ -54,6 +55,7 @@ namespace sdbus {
class ObjectPath;
class Signature;
class UnixFd;
template<typename _T1, typename _T2> using DictEntry = std::pair<_T1, _T2>;
class BusName;
class InterfaceName;
class MemberName;
@@ -65,6 +67,7 @@ namespace sdbus {
class PropertyGetReply;
template <typename... _Results> class Result;
class Error;
template <typename _T, typename _Enable = void> struct signature_of;
}
namespace sdbus {
@@ -106,253 +109,171 @@ namespace sdbus {
// Helper for static assert
template <class... _T> constexpr bool always_false = false;
// Helper operator+ for concatenation of `std::array`s
template <typename _T, std::size_t _N1, std::size_t _N2>
constexpr std::array<_T, _N1 + _N2> operator+(std::array<_T, _N1> lhs, std::array<_T, _N2> rhs);
// Template specializations for getting D-Bus signatures from C++ types
template <typename _T, typename _Enable = void>
template <typename _T>
constexpr auto signature_of_v = signature_of<_T>::value;
template <typename _T, typename _Enable>
struct signature_of
{
static constexpr bool is_valid = false;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
static constexpr void* value = []
{
// See using-sdbus-c++.md, section "Extending sdbus-c++ type system",
// on how to teach sdbus-c++ about your custom types
static_assert(always_false<_T>, "Unsupported DBus type (template specializations are needed for your custom types)");
return "";
}
static_assert(always_false<_T>, "Unsupported D-Bus type (specialize `signature_of` for your custom types)");
};
};
template <typename _T>
struct signature_of<const _T>
: public signature_of<_T>
struct signature_of<const _T> : signature_of<_T>
{};
template <typename _T>
struct signature_of<_T&>
: public signature_of<_T>
struct signature_of<volatile _T> : signature_of<_T>
{};
template <typename _T>
struct signature_of<_T&> : signature_of<_T>
{};
template <>
struct signature_of<void>
{
static constexpr std::array<char, 0> value{};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "";
}
};
template <>
struct signature_of<bool>
{
static constexpr std::array value{'b'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
return "b";
}
};
template <>
struct signature_of<uint8_t>
{
static constexpr std::array value{'y'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
return "y";
}
};
template <>
struct signature_of<int16_t>
{
static constexpr std::array value{'n'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
return "n";
}
};
template <>
struct signature_of<uint16_t>
{
static constexpr std::array value{'q'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
return "q";
}
};
template <>
struct signature_of<int32_t>
{
static constexpr std::array value{'i'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
return "i";
}
};
template <>
struct signature_of<uint32_t>
{
static constexpr std::array value{'u'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
return "u";
}
};
template <>
struct signature_of<int64_t>
{
static constexpr std::array value{'x'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
return "x";
}
};
template <>
struct signature_of<uint64_t>
{
static constexpr std::array value{'t'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
return "t";
}
};
template <>
struct signature_of<double>
{
static constexpr std::array value{'d'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
return "d";
}
};
template <>
struct signature_of<char*>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "s";
}
};
template <>
struct signature_of<const char*>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "s";
}
};
template <std::size_t _N>
struct signature_of<char[_N]>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "s";
}
};
template <std::size_t _N>
struct signature_of<const char[_N]>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "s";
}
};
template <>
struct signature_of<std::string>
{
static constexpr std::array value{'s'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "s";
}
};
template <>
struct signature_of<char*> : signature_of<std::string>
{};
template <>
struct signature_of<const char*> : signature_of<std::string>
{};
template <std::size_t _N>
struct signature_of<char[_N]> : signature_of<std::string>
{};
template <std::size_t _N>
struct signature_of<const char[_N]> : signature_of<std::string>
{};
template <>
struct signature_of<BusName> : signature_of<std::string>
{
};
{};
template <>
struct signature_of<InterfaceName> : signature_of<std::string>
{
};
{};
template <>
struct signature_of<MemberName> : signature_of<std::string>
{
};
{};
template <typename... _ValueTypes>
struct signature_of<Struct<_ValueTypes...>>
{
static constexpr std::array contents = (signature_of_v<_ValueTypes> + ...);
static constexpr std::array value = std::array{'('} + contents + std::array{')'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
std::string signature;
signature += "(";
(signature += ... += signature_of<_ValueTypes>::str());
signature += ")";
return signature;
}
};
template <>
struct signature_of<Variant>
{
static constexpr std::array value{'v'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "v";
}
};
template <typename... Elements>
@@ -362,74 +283,52 @@ namespace sdbus {
template <>
struct signature_of<ObjectPath>
{
static constexpr std::array value{'o'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "o";
}
};
template <>
struct signature_of<Signature>
{
static constexpr std::array value{'g'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "g";
}
};
template <>
struct signature_of<UnixFd>
{
static constexpr std::array value{'h'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
};
static const std::string str()
{
return "h";
}
template <typename _T1, typename _T2>
struct signature_of<DictEntry<_T1, _T2>>
{
static constexpr std::array value = std::array{'{'} + signature_of_v<std::tuple<_T1, _T2>> + std::array{'}'};
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
};
template <typename _Element, typename _Allocator>
struct signature_of<std::vector<_Element, _Allocator>>
{
static constexpr std::array value = std::array{'a'} + signature_of_v<_Element>;
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "a" + signature_of<_Element>::str();
}
};
template <typename _Element, std::size_t _Size>
struct signature_of<std::array<_Element, _Size>>
struct signature_of<std::array<_Element, _Size>> : signature_of<std::vector<_Element>>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "a" + signature_of<_Element>::str();
}
};
#ifdef __cpp_lib_span
template <typename _Element, std::size_t _Extent>
struct signature_of<std::span<_Element, _Extent>>
struct signature_of<std::span<_Element, _Extent>> : signature_of<std::vector<_Element>>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "a" + signature_of<_Element>::str();
}
};
#endif
@@ -438,46 +337,49 @@ namespace sdbus {
: public signature_of<std::underlying_type_t<_Enum>>
{};
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
struct signature_of<std::map<_Key, _Value, _Compare, _Allocator>>
{
static constexpr std::array contents = signature_of_v<std::tuple<_Key, _Value>>;
static constexpr std::array dict_entry = std::array{'{'} + contents + std::array{'}'};
static constexpr std::array value = std::array{'a'} + dict_entry;
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "a{" + signature_of<_Key>::str() + signature_of<_Value>::str() + "}";
}
};
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
struct signature_of<std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>>
: signature_of<std::map<_Key, _Value>>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "a{" + signature_of<_Key>::str() + signature_of<_Value>::str() + "}";
}
};
template <typename... _Types>
struct signature_of<std::tuple<_Types...>> // A simple concatenation of signatures of _Types
{
static constexpr std::array value = (std::array<char, 0>{} + ... + signature_of_v<_Types>);
static constexpr bool is_valid = false;
static constexpr bool is_trivial_dbus_type = false;
};
// To simplify conversions of arrays to C strings
template <typename _T, std::size_t _N>
constexpr auto as_null_terminated(std::array<_T, _N> arr)
{
return arr + std::array<_T, 1>{0};
}
// Function traits implementation inspired by (c) kennytm,
// https://github.com/kennytm/utils/blob/master/traits.hpp
template <typename _Type>
struct function_traits
: public function_traits<decltype(&_Type::operator())>
struct function_traits : function_traits<decltype(&_Type::operator())>
{};
template <typename _Type>
struct function_traits<const _Type>
: public function_traits<_Type>
struct function_traits<const _Type> : function_traits<_Type>
{};
template <typename _Type>
struct function_traits<_Type&>
: public function_traits<_Type>
struct function_traits<_Type&> : function_traits<_Type>
{};
template <typename _ReturnType, typename... _Args>
@@ -517,72 +419,62 @@ namespace sdbus {
};
template <typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_Args...)>
: public function_traits_base<_ReturnType, _Args...>
struct function_traits<_ReturnType(_Args...)> : function_traits_base<_ReturnType, _Args...>
{
static constexpr bool is_async = false;
static constexpr bool has_error_param = false;
};
template <typename... _Args>
struct function_traits<void(std::optional<Error>, _Args...)>
: public function_traits_base<void, _Args...>
struct function_traits<void(std::optional<Error>, _Args...)> : function_traits_base<void, _Args...>
{
static constexpr bool has_error_param = true;
};
template <typename... _Args, typename... _Results>
struct function_traits<void(Result<_Results...>, _Args...)>
: public function_traits_base<std::tuple<_Results...>, _Args...>
struct function_traits<void(Result<_Results...>, _Args...)> : function_traits_base<std::tuple<_Results...>, _Args...>
{
static constexpr bool is_async = true;
using async_result_t = Result<_Results...>;
};
template <typename... _Args, typename... _Results>
struct function_traits<void(Result<_Results...>&&, _Args...)>
: public function_traits_base<std::tuple<_Results...>, _Args...>
struct function_traits<void(Result<_Results...>&&, _Args...)> : function_traits_base<std::tuple<_Results...>, _Args...>
{
static constexpr bool is_async = true;
using async_result_t = Result<_Results...>;
};
template <typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(*)(_Args...)>
: public function_traits<_ReturnType(_Args...)>
struct function_traits<_ReturnType(*)(_Args...)> : function_traits<_ReturnType(_Args...)>
{};
template <typename _ClassType, typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_ClassType::*)(_Args...)>
: public function_traits<_ReturnType(_Args...)>
struct function_traits<_ReturnType(_ClassType::*)(_Args...)> : function_traits<_ReturnType(_Args...)>
{
typedef _ClassType& owner_type;
};
template <typename _ClassType, typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_ClassType::*)(_Args...) const>
: public function_traits<_ReturnType(_Args...)>
struct function_traits<_ReturnType(_ClassType::*)(_Args...) const> : function_traits<_ReturnType(_Args...)>
{
typedef const _ClassType& owner_type;
};
template <typename _ClassType, typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_ClassType::*)(_Args...) volatile>
: public function_traits<_ReturnType(_Args...)>
struct function_traits<_ReturnType(_ClassType::*)(_Args...) volatile> : function_traits<_ReturnType(_Args...)>
{
typedef volatile _ClassType& owner_type;
};
template <typename _ClassType, typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_ClassType::*)(_Args...) const volatile>
: public function_traits<_ReturnType(_Args...)>
struct function_traits<_ReturnType(_ClassType::*)(_Args...) const volatile> : function_traits<_ReturnType(_Args...)>
{
typedef const volatile _ClassType& owner_type;
};
template <typename FunctionType>
struct function_traits<std::function<FunctionType>>
: public function_traits<FunctionType>
struct function_traits<std::function<FunctionType>> : function_traits<FunctionType>
{};
template <class _Function>
@@ -621,45 +513,33 @@ namespace sdbus {
template <typename _Function>
using tuple_of_function_output_arg_types_t = typename tuple_of_function_output_arg_types<_Function>::type;
template <typename _Type>
struct aggregate_signature
template <typename _Function>
struct signature_of_function_input_arguments : signature_of<tuple_of_function_input_arg_types_t<_Function>>
{
static const std::string str()
static std::string value_as_string()
{
return signature_of<std::decay_t<_Type>>::str();
}
};
template <typename... _Types>
struct aggregate_signature<std::tuple<_Types...>>
{
static const std::string str()
{
std::string signature;
(void)(signature += ... += signature_of<std::decay_t<_Types>>::str());
return signature;
constexpr auto signature = as_null_terminated(signature_of_v<tuple_of_function_input_arg_types_t<_Function>>);
return signature.data();
}
};
template <typename _Function>
struct signature_of_function_input_arguments
inline auto signature_of_function_input_arguments_v = signature_of_function_input_arguments<_Function>::value_as_string();
template <typename _Function>
struct signature_of_function_output_arguments : signature_of<tuple_of_function_output_arg_types_t<_Function>>
{
static const std::string str()
static std::string value_as_string()
{
return aggregate_signature<tuple_of_function_input_arg_types_t<_Function>>::str();
constexpr auto signature = as_null_terminated(signature_of_v<tuple_of_function_output_arg_types_t<_Function>>);
return signature.data();
}
};
template <typename _Function>
struct signature_of_function_output_arguments
{
static const std::string str()
{
return aggregate_signature<tuple_of_function_output_arg_types_t<_Function>>::str();
}
};
inline auto signature_of_function_output_arguments_v = signature_of_function_output_arguments<_Function>::value_as_string();
// std::future stuff for return values of async calls
template <typename... _Args> struct future_return
{
typedef std::tuple<_Args...> type;
@@ -678,7 +558,6 @@ namespace sdbus {
template <typename... _Args>
using future_return_t = typename future_return<_Args...>::type;
// Credit: Piotr Skotnicki (https://stackoverflow.com/a/57639506)
template <typename, typename>
constexpr bool is_one_of_variants_types = false;
@@ -687,7 +566,6 @@ namespace sdbus {
constexpr bool is_one_of_variants_types<std::variant<_VariantTypes...>, _QueriedType>
= (std::is_same_v<_QueriedType, _VariantTypes> || ...);
namespace detail
{
template <class _Function, class _Tuple, typename... _Args, std::size_t... _I>
@@ -753,6 +631,26 @@ namespace sdbus {
, std::forward<_Tuple>(t)
, std::make_index_sequence<std::tuple_size<std::decay_t<_Tuple>>::value>{} );
}
// Convenient concatenation of arrays
template <typename _T, std::size_t _N1, std::size_t _N2>
constexpr std::array<_T, _N1 + _N2> operator+(std::array<_T, _N1> lhs, std::array<_T, _N2> rhs)
{
std::array<_T, _N1 + _N2> result{};
std::size_t index = 0;
for (auto& el : lhs) {
result[index] = std::move(el);
++index;
}
for (auto& el : rhs) {
result[index] = std::move(el);
++index;
}
return result;
}
}
#endif /* SDBUS_CXX_TYPETRAITS_H_ */
+16 -8
View File
@@ -57,10 +57,9 @@ namespace sdbus {
Variant();
template <typename _ValueType>
explicit Variant(const _ValueType& value)
: Variant()
explicit Variant(const _ValueType& value) : Variant()
{
msg_.openVariant(signature_of<_ValueType>::str());
msg_.openVariant<_ValueType>();
msg_ << value;
msg_.closeVariant();
msg_.seal();
@@ -79,7 +78,8 @@ namespace sdbus {
{
_ValueType val;
msg_.rewind(false);
msg_.enterVariant(signature_of<_ValueType>::str());
msg_.enterVariant<_ValueType>();
msg_ >> val;
msg_.exitVariant();
return val;
@@ -104,7 +104,8 @@ namespace sdbus {
template <typename _Type>
bool containsValueOfType() const
{
return signature_of<_Type>::str() == peekValueType();
constexpr auto signature = as_null_terminated(signature_of_v<_Type>);
return signature.data() == peekValueType();
}
bool isEmpty() const;
@@ -134,15 +135,12 @@ namespace sdbus {
public:
using std::tuple<_ValueTypes...>::tuple;
// Disable constructor if an older then 7.1.0 version of GCC is used
#if !((defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__) && !(__GNUC__ > 7 || (__GNUC__ == 7 && (__GNUC_MINOR__ > 1 || (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ > 0)))))
Struct() = default;
explicit Struct(const std::tuple<_ValueTypes...>& t)
: std::tuple<_ValueTypes...>(t)
{
}
#endif
template <std::size_t _I>
auto& get()
@@ -374,6 +372,16 @@ namespace sdbus {
int fd_ = -1;
};
/********************************************//**
* @typedef DictEntry
*
* DictEntry is implemented as std::pair, a standard
* value_type in STL(-like) associative containers.
*
***********************************************/
template<typename _T1, typename _T2>
using DictEntry = std::pair<_T1, _T2>;
}
template <size_t _I, typename... _ValueTypes>
+5 -5
View File
@@ -42,8 +42,8 @@ namespace sdbus {
template <typename _Function>
MethodVTableItem& MethodVTableItem::implementedAs(_Function&& callback)
{
inputSignature = signature_of_function_input_arguments<_Function>::str();
outputSignature = signature_of_function_output_arguments<_Function>::str();
inputSignature = signature_of_function_input_arguments_v<_Function>;
outputSignature = signature_of_function_output_arguments_v<_Function>;
callbackHandler = [callback = std::forward<_Function>(callback)](MethodCall call)
{
// Create a tuple of callback input arguments' types, which will be used
@@ -142,7 +142,7 @@ namespace sdbus {
template <typename... _Args>
inline SignalVTableItem& SignalVTableItem::withParameters()
{
signature = signature_of_function_input_arguments<void(_Args...)>::str();
signature = signature_of_function_input_arguments_v<void(_Args...)>;
return *this;
}
@@ -192,7 +192,7 @@ namespace sdbus {
static_assert(!std::is_void<function_result_t<_Function>>::value, "Property getter function must return property value");
if (signature.empty())
signature = signature_of_function_output_arguments<_Function>::str();
signature = signature_of_function_output_arguments_v<_Function>;
getter = [callback = std::forward<_Function>(callback)](PropertyGetReply& reply)
{
@@ -210,7 +210,7 @@ namespace sdbus {
static_assert(std::is_void<function_result_t<_Function>>::value, "Property setter function must not return any value");
if (signature.empty())
signature = signature_of_function_input_arguments<_Function>::str();
signature = signature_of_function_input_arguments_v<_Function>;
setter = [callback = std::forward<_Function>(callback)](PropertySetCall call)
{