Skip to content

Instantly share code, notes, and snippets.

@nstansbury
Last active September 21, 2023 09:29
Show Gist options
  • Select an option

  • Save nstansbury/6d627a447ca3b4ebbcf2c49ae37922c5 to your computer and use it in GitHub Desktop.

Select an option

Save nstansbury/6d627a447ca3b4ebbcf2c49ae37922c5 to your computer and use it in GitHub Desktop.
C++ KeyValue pair property variant
/*
A KeyValue pair property variant in C++ for the RaspberryPi RP2040/Arduino/PlatformIO
PropertyType is the base class that describes the underlying property type
PropertyDescriptor is the variant value for that property name
PropertySet is the unique Key/Value set itself
Internally the PropertyDescriptors are stored as std:shared_ptrs so should be thread-safe
To build in PlatformIO add to platformio.ini:
build_unflags = -fno-rtti
For inspiration and sample code credit to:
https://stackoverflow.com/users/2068573/neil-kirk
For: https://stackoverflow.com/a/24702400/2897944
Andrew Anderson
for: https://dev.to/aka_dude/let-s-write-tagged-union-in-c-1chf
and: https://gist.github.com/Mr-Andersen/cd5f9d8740e03b3a779bd49da281652d
*/
#include <memory>
#include <string>
#include <map>
template<class T>
class PropertyDescriptor;
class PropertyType {
protected:
std::type_info* type;
public:
template<typename T>
bool typeOf(){
const std::type_info& typeInfo = *this->type;
return typeid(T) == typeInfo;
}
virtual ~PropertyType() = 0;
};
inline PropertyType::~PropertyType() {}
template<class T>
class PropertyDescriptor : public PropertyType {
private:
T _value;
public:
explicit PropertyDescriptor(const T value){
this->type = const_cast<std::type_info*>(&typeid(value));
this->_value = value;
}
PropertyDescriptor(){}
T value(){
return this->_value;
}
};
class PropertySet {
protected:
std::map<std::string, Unique<PropertyType>> _properties;
public:
template<typename T>
void setProperty(std::string name, T value){
this->_properties[name].reset(new PropertyDescriptor<T>(value));
}
template<typename T>
const T getProperty(std::string name) const {
auto iter = this->_properties.find(name);
if(iter != this->_properties.end()){
if(iter->second->typeOf<T>()){
PropertyDescriptor<T> propertyDesc = dynamic_cast<PropertyDescriptor<T>&>(*iter->second);
return propertyDesc.value();
}
}
return T();
}
bool hasProperty(std::string name) const {
auto iter = this->_properties.find(name);
if(iter != this->_properties.end()){
return true;
}
return false;
}
template<typename T>
bool hasProperty(std::string name) const {
auto iter = this->_properties.find(name);
if(iter != this->_properties.end()){
if(iter->second->typeOf<T>()){
return true;
}
}
return false;
}
int size() const {
return this->_properties.size();
}
};
int main() {
PropertySet props = PropertySet();
// Set the property key/value pair
props.setProperty("IntProp", 12345);
props.setProperty("StrProp", std::string("A string property"));
props.setProperty("ArrProp", std::array<int, 5>({1,2,3,4,5}));
// Get the property values based on the key
auto intProp = props.getProperty<int>("IntProp");
auto strProp = props.getProperty<std::string>("StrProp");
auto arrProp = props.getProperty<std::array<int, 5>>("ArrProp");
// Has property "name" of <type>
if(props.hasProperty<int>("IntProp")){
// ....
}
// Has property "name" of any type
if(props.hasProperty("ArrProp")){
// ....
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment