Program Listing for File variant.hpp
↰ Return to documentation for file (include/hsmcpp/variant.hpp
)
// Copyright (C) 2021 Igor Krechetov
// Distributed under MIT license. See file LICENSE for details
#ifndef HSMCPP_VARIANT_HPP
#define HSMCPP_VARIANT_HPP
#include <functional>
#include <list>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
namespace hsmcpp {
class Variant;
using ByteArray_t = std::vector<unsigned char>;
using VariantVector_t = std::vector<Variant>;
using VariantList_t = std::list<Variant>;
using VariantMap_t = std::map<Variant, Variant>;
using VariantPair_t = std::pair<Variant, Variant>;
// cppcheck-suppress misra-c2012-20.7 ; parentheses are not needed
#define DEF_CONSTRUCTOR(_val_type, _internal_type) \
\
explicit Variant(const _val_type v);
// cppcheck-suppress misra-c2012-20.7 ; parentheses are not needed
#define DEF_OPERATOR_ASSIGN(_val_type, _internal_type) \
\
Variant& operator=(const _val_type v);
#define DEF_MAKE_DOC(_internal_type) \
\
\
// cppcheck-suppress misra-c2012-20.7 ; parentheses are not needed
#define DEF_MAKE(_val_type, _internal_type) \
DEF_MAKE_DOC(_internal_type) \
static Variant make(const _val_type v);
class Variant {
private:
// using MemoryHandlerFunc_t = std::function<void*(void*, const bool)>;
using MemoryAllocatorFunc_t = std::function<std::shared_ptr<void>(const void*)>;
using CompareFunc_t = std::function<int(const void*, const void*)>;
public:
enum class Type {
UNKNOWN,
BYTE_1,
BYTE_2,
BYTE_4,
BYTE_8,
UBYTE_1,
UBYTE_2,
UBYTE_4,
UBYTE_8,
DOUBLE,
BOOL,
STRING,
BYTEARRAY,
LIST,
VECTOR,
MAP,
PAIR,
CUSTOM
};
public:
DEF_MAKE(int8_t, Type::BYTE_1);
DEF_MAKE(int16_t, Type::BYTE_2);
DEF_MAKE(int32_t, Type::BYTE_4);
DEF_MAKE(int64_t, Type::BYTE_8);
DEF_MAKE(uint8_t, Type::UBYTE_1);
DEF_MAKE(uint16_t, Type::UBYTE_2);
DEF_MAKE(uint32_t, Type::UBYTE_4);
DEF_MAKE(uint64_t, Type::UBYTE_8);
DEF_MAKE(double, Type::DOUBLE);
DEF_MAKE(bool, Type::BOOL);
DEF_MAKE(std::string&, Type::STRING);
DEF_MAKE(char*, Type::STRING);
DEF_MAKE(ByteArray_t&, Type::VECTOR);
static Variant make(const char* binaryData, const size_t bytesCount);
DEF_MAKE(VariantVector_t&, Type::VECTOR);
template <typename T>
DEF_MAKE(std::vector<T>&, Type::VECTOR);
DEF_MAKE(VariantList_t&, Type::LIST);
template <typename T>
DEF_MAKE(std::list<T>&, Type::LIST);
DEF_MAKE(VariantMap_t&, Type::MAP);
DEF_MAKE_DOC(Type::MAP)
template <typename K, typename V>
static Variant make(const std::map<K, V>& v);
DEF_MAKE(VariantPair_t&, Type::PAIR);
template <typename TFirst, typename TSecond>
static Variant make(const TFirst& first, const TSecond& second);
DEF_MAKE_DOC(Type::CUSTOM)
template <typename T>
static Variant make(const T& v);
DEF_MAKE_DOC(Type::CUSTOM)
template <typename T>
static Variant makeCustom(const T& v);
static Variant make(const Variant& v);
public:
Variant() = default;
Variant(const Variant& v);
Variant(Variant&& v) noexcept;
~Variant();
DEF_CONSTRUCTOR(int8_t, Type::BYTE_1)
DEF_CONSTRUCTOR(int16_t, Type::BYTE_2)
DEF_CONSTRUCTOR(int32_t, Type::BYTE_4)
DEF_CONSTRUCTOR(int64_t, Type::BYTE_8)
DEF_CONSTRUCTOR(uint8_t, Type::UBYTE_1)
DEF_CONSTRUCTOR(uint16_t, Type::UBYTE_2)
DEF_CONSTRUCTOR(uint32_t, Type::UBYTE_4)
DEF_CONSTRUCTOR(uint64_t, Type::UBYTE_8)
DEF_CONSTRUCTOR(double, Type::DOUBLE)
DEF_CONSTRUCTOR(bool, Type::BOOL)
DEF_CONSTRUCTOR(std::string&, Type::STRING)
explicit Variant(const char* v);
DEF_CONSTRUCTOR(ByteArray_t&, Type::BYTEARRAY)
explicit Variant(const char* binaryData, const size_t bytesCount);
DEF_CONSTRUCTOR(VariantVector_t&, Type::VECTOR)
DEF_CONSTRUCTOR(VariantList_t&, Type::LIST)
DEF_CONSTRUCTOR(VariantMap_t&, Type::MAP)
DEF_CONSTRUCTOR(VariantPair_t&, Type::PAIR)
template <typename T>
DEF_CONSTRUCTOR(std::vector<T>&, Type::VECTOR);
template <typename T>
DEF_CONSTRUCTOR(std::list<T>&, Type::LIST);
template <typename K, typename V>
explicit Variant(const std::map<K, V>& v);
template <typename TFirst, typename TSecond>
explicit Variant(const TFirst& first, const TSecond& second);
template <typename T>
explicit Variant(const T& v);
Variant& operator=(const Variant& v);
Variant& operator=(Variant&& v) noexcept;
DEF_OPERATOR_ASSIGN(int8_t, Type::BYTE_1)
DEF_OPERATOR_ASSIGN(int16_t, Type::BYTE_2)
DEF_OPERATOR_ASSIGN(int32_t, Type::BYTE_4)
DEF_OPERATOR_ASSIGN(int64_t, Type::BYTE_8)
DEF_OPERATOR_ASSIGN(uint8_t, Type::UBYTE_1)
DEF_OPERATOR_ASSIGN(uint16_t, Type::UBYTE_2)
DEF_OPERATOR_ASSIGN(uint32_t, Type::UBYTE_4)
DEF_OPERATOR_ASSIGN(uint64_t, Type::UBYTE_8)
DEF_OPERATOR_ASSIGN(double, Type::DOUBLE)
DEF_OPERATOR_ASSIGN(bool, Type::BOOL)
DEF_OPERATOR_ASSIGN(std::string&, Type::STRING)
DEF_OPERATOR_ASSIGN(char*, Type::STRING)
DEF_OPERATOR_ASSIGN(ByteArray_t&, Type::BYTEARRAY)
DEF_OPERATOR_ASSIGN(VariantVector_t&, Type::VECTOR)
DEF_OPERATOR_ASSIGN(VariantList_t&, Type::LIST)
DEF_OPERATOR_ASSIGN(VariantMap_t&, Type::MAP)
DEF_OPERATOR_ASSIGN(VariantPair_t&, Type::PAIR)
template <typename T>
DEF_OPERATOR_ASSIGN(T&, Type::CUSTOM)
void clear();
inline Type getType() const;
operator bool() const;
bool isEmpty() const;
bool isNumeric() const;
bool isSignedNumeric() const;
bool isUnsignedNumeric() const;
bool isBool() const;
bool isString() const;
bool isByteArray() const;
bool isVector() const;
bool isList() const;
bool isMap() const;
bool isPair() const;
bool isCustomType() const;
int64_t toInt64() const;
uint64_t toUInt64() const;
double toDouble() const;
bool toBool() const;
std::string toString() const;
ByteArray_t toByteArray() const;
std::shared_ptr<ByteArray_t> getByteArray() const;
std::shared_ptr<VariantVector_t> getVector() const;
template <typename T>
std::vector<T> toVector(const std::function<T(const Variant&)>& converter) const;
std::shared_ptr<VariantList_t> getList() const;
template <typename T>
std::list<T> toList(const std::function<T(const Variant&)>& converter) const;
std::shared_ptr<VariantMap_t> getMap() const;
template <typename K, typename V>
std::map<K, V> toMap(const std::function<K(const Variant&)>& converterKey,
const std::function<V(const Variant&)>& converterValue) const;
std::shared_ptr<VariantPair_t> getPair() const;
template <typename TFirst, typename TSecond>
std::pair<TFirst, TSecond> toPair(const std::function<TFirst(const Variant&)>& converterFirst,
const std::function<TSecond(const Variant&)>& converterSecond) const;
template <typename T>
std::shared_ptr<T> getCustomType() const;
bool operator==(const Variant& val) const;
bool operator!=(const Variant& val) const;
bool operator>(const Variant& val) const;
bool operator>=(const Variant& val) const;
bool operator<(const Variant& val) const;
bool operator<=(const Variant& val) const;
private:
Variant(std::shared_ptr<void> d, const Type t);
template <typename T>
Variant(const T& v, const Type t);
bool isSameObject(const Variant& val) const;
template <typename T>
void assign(const T& v, const Type t);
template <typename T>
inline std::shared_ptr<T> value() const;
template <typename T>
void createMemoryAllocator();
void freeMemory();
private:
Type type = Type::UNKNOWN;
std::shared_ptr<void> data;
MemoryAllocatorFunc_t memoryAllocator;
CompareFunc_t compareOperator;
};
template <typename T>
Variant Variant::make(const std::vector<T>& v) {
return Variant(v);
}
template <typename T>
Variant Variant::make(const std::list<T>& v) {
return Variant(v);
}
template <typename K, typename V>
Variant Variant::make(const std::map<K, V>& v) {
return Variant(v);
}
template <typename TFirst, typename TSecond>
Variant Variant::make(const TFirst& first, const TSecond& second) {
return Variant(first, second);
}
template <typename T>
Variant Variant::make(const T& v) {
return makeCustom(v);
}
template <typename T>
Variant Variant::makeCustom(const T& v) {
return Variant(v, Type::CUSTOM);
}
template <typename T>
Variant::Variant(const std::vector<T>& v) {
std::shared_ptr<VariantVector_t> dest = std::shared_ptr<VariantVector_t>(new VariantVector_t(), [](void* ptr) {
delete reinterpret_cast<VariantVector_t*>(ptr);
});
dest->reserve(v.size());
for (auto it = v.begin(); it != v.end(); ++it) {
dest->emplace_back(*it);
}
data = std::static_pointer_cast<void>(dest);
type = Type::VECTOR;
createMemoryAllocator<VariantVector_t>();
}
template <typename T>
Variant::Variant(const std::list<T>& v) {
std::shared_ptr<VariantList_t> dest =
std::shared_ptr<VariantList_t>(new VariantList_t(), [](void* ptr) { delete reinterpret_cast<VariantList_t*>(ptr); });
for (auto it = v.begin(); it != v.end(); ++it) {
dest->emplace_back(*it);
}
data = std::static_pointer_cast<void>(dest);
type = Type::LIST;
createMemoryAllocator<VariantList_t>();
}
template <typename K, typename V>
Variant::Variant(const std::map<K, V>& v) {
std::shared_ptr<VariantMap_t> dest =
std::shared_ptr<VariantMap_t>(new VariantMap_t(), [](void* ptr) { delete reinterpret_cast<VariantMap_t*>(ptr); });
for (auto it = v.begin(); it != v.end(); ++it) {
dest->emplace(it->first, it->second);
}
data = std::static_pointer_cast<void>(dest);
type = Type::MAP;
createMemoryAllocator<VariantMap_t>();
}
template <typename TFirst, typename TSecond>
Variant::Variant(const TFirst& first, const TSecond& second)
// cppcheck-suppress misra-c2012-10.4 : false-positive. thinks that ':' is arithmetic operation
: Variant(std::make_pair(Variant(first), Variant(second))) {}
template <typename T>
Variant::Variant(const T& v) {
assign(v, Type::CUSTOM);
}
template <typename T>
Variant& Variant::operator=(const T& v) {
assign(v, Type::CUSTOM);
return *this;
}
Variant::Type Variant::getType() const {
return type;
}
template <typename T>
std::shared_ptr<T> Variant::getCustomType() const {
std::shared_ptr<T> result;
if (true == isCustomType()) {
result = value<T>();
}
return result;
}
template <typename T>
std::vector<T> Variant::toVector(const std::function<T(const Variant&)>& converter) const {
std::vector<T> res;
if (isVector()) {
std::shared_ptr<VariantVector_t> vectorData = getVector();
// cppcheck-suppress misra-c2012-14.4 ; false-positive. std::shared_ptr has a bool() operator
if (vectorData) {
res.reserve(vectorData->size());
for (const Variant& curItem : *vectorData) {
res.emplace_back(converter(curItem));
}
}
}
return res;
}
template <typename T>
std::list<T> Variant::toList(const std::function<T(const Variant&)>& converter) const {
std::list<T> res;
if (isList()) {
std::shared_ptr<VariantList_t> listData = getList();
// cppcheck-suppress misra-c2012-14.4 ; false-positive. std::shared_ptr has a bool() operator
if (listData) {
for (const Variant& curItem : *listData) {
res.emplace_back(converter(curItem));
}
}
}
return res;
}
template <typename K, typename V>
std::map<K, V> Variant::toMap(const std::function<K(const Variant&)>& converterKey,
const std::function<V(const Variant&)>& converterValue) const {
std::map<K, V> res;
if (isMap()) {
std::shared_ptr<VariantMap_t> mapData = getMap();
// cppcheck-suppress misra-c2012-14.4 ; false-positive. std::shared_ptr has a bool() operator
if (mapData) {
for (const auto& curItem : *mapData) {
res.insert(std::make_pair(converterKey(curItem.first), converterValue(curItem.second)));
}
}
}
return res;
}
template <typename TFirst, typename TSecond>
std::pair<TFirst, TSecond> Variant::toPair(const std::function<TFirst(const Variant&)>& converterFirst,
const std::function<TSecond(const Variant&)>& converterSecond) const {
std::pair<TFirst, TSecond> res;
if (isPair()) {
std::shared_ptr<VariantPair_t> pairData = getPair();
// cppcheck-suppress misra-c2012-14.4 ; false-positive. std::shared_ptr has a bool() operator
if (pairData) {
res = std::make_pair(converterFirst(pairData->first), converterSecond(pairData->second));
}
}
return res;
}
template <typename T>
Variant::Variant(const T& v, const Type t) {
assign(v, t);
}
template <typename T>
void Variant::assign(const T& v, const Type t) {
freeMemory();
createMemoryAllocator<T>();
type = t;
data = memoryAllocator(&v);
}
template <typename T>
inline std::shared_ptr<T> Variant::value() const {
return std::static_pointer_cast<T>(data);
}
template <typename T>
void Variant::createMemoryAllocator() {
memoryAllocator = [](const void* ptr) {
// NOTE: false-positive. "return" statement belongs to lambda function, not parent function
// cppcheck-suppress misra-c2012-15.5
return ((nullptr != ptr) ? (std::shared_ptr<void>(new T(*reinterpret_cast<const T*>(ptr)),
[](void* ptr) { delete reinterpret_cast<const T*>(ptr); }))
: nullptr);
};
// cppcheck-suppress misra-c2012-13.1 ; false-positive. this is a functor, not initializer list
compareOperator = [](const void* left, const void* right) {
int res = -1;
if (*reinterpret_cast<const T*>(left) == *reinterpret_cast<const T*>(right)) {
res = 0;
} else if (*reinterpret_cast<const T*>(left) > *reinterpret_cast<const T*>(right)) {
res = 1;
} else {
// do nothing
}
// NOTE: false-positive. "return" statement belongs to lambda function, not parent function
// cppcheck-suppress misra-c2012-15.5
return res;
};
}
} // namespace hsmcpp
#endif // HSMCPP_VARIANT_HPP