|
|
6e237b |
#pragma once
|
|
|
6e237b |
|
|
|
6e237b |
#ifndef TVARIANT_INCLUDED
|
|
|
6e237b |
#define TVARIANT_INCLUDED
|
|
|
6e237b |
|
|
|
6e237b |
#include <tcommon.h></tcommon.h>
|
|
|
9cf1a4 |
#include <texception.h></texception.h>
|
|
|
6e237b |
#include <tstringid.h></tstringid.h>
|
|
|
6e237b |
|
|
|
9cf1a4 |
#include <iostream></iostream>
|
|
|
6e237b |
#include <string></string>
|
|
|
6e237b |
#include <vector></vector>
|
|
|
6e237b |
#include <map></map>
|
|
|
6e237b |
|
|
|
6e237b |
#undef DVAPI
|
|
|
6e237b |
#undef DVVAR
|
|
|
6e237b |
#ifdef TVARIANT_EXPORTS
|
|
|
6e237b |
#define DVAPI DV_EXPORT_API
|
|
|
6e237b |
#define DVVAR DV_EXPORT_VAR
|
|
|
6e237b |
#else
|
|
|
6e237b |
#define DVAPI DV_IMPORT_API
|
|
|
6e237b |
#define DVVAR DV_IMPORT_VAR
|
|
|
6e237b |
#endif
|
|
|
6e237b |
|
|
|
6e237b |
//-------------------------------------------------------------------
|
|
|
6e237b |
|
|
|
6e237b |
class TVariant;
|
|
|
6e237b |
typedef std::vector<tvariant> TVariantList;</tvariant>
|
|
|
6e237b |
typedef std::map<tstringid, tvariant=""> TVariantMap;</tstringid,>
|
|
|
6e237b |
|
|
|
6e237b |
//-------------------------------------------------------------------
|
|
|
6e237b |
|
|
|
9cf1a4 |
class TVariantSyntaxException final: public TException {
|
|
|
9cf1a4 |
public:
|
|
|
9cf1a4 |
explicit TVariantSyntaxException(
|
|
|
9cf1a4 |
int row = 0,
|
|
|
9cf1a4 |
int col = 0,
|
|
|
9cf1a4 |
const std::string &msg = std::string()
|
|
|
9cf1a4 |
):
|
|
|
9cf1a4 |
TException(std::to_string(row) + ":" + std::to_string(col) + ": " + msg) { }
|
|
|
9cf1a4 |
};
|
|
|
9cf1a4 |
|
|
|
9cf1a4 |
//-------------------------------------------------------------------
|
|
|
9cf1a4 |
|
|
|
6e237b |
class DVAPI TVariantPathEntry {
|
|
|
6e237b |
private:
|
|
|
6e237b |
int m_index;
|
|
|
6e237b |
TStringId m_field;
|
|
|
6e237b |
public:
|
|
|
6e237b |
inline explicit TVariantPathEntry(int index = -1):
|
|
|
6e237b |
m_index(index) { }
|
|
|
6e237b |
inline explicit TVariantPathEntry(const TStringId &field):
|
|
|
6e237b |
m_index(-1), m_field(field) { }
|
|
|
6e237b |
inline explicit TVariantPathEntry(const std::string &fieldName):
|
|
|
6e237b |
m_index(-1), m_field(fieldName) { }
|
|
|
6e237b |
|
|
|
6e237b |
inline bool isIndex() const
|
|
|
6e237b |
{ return m_index >= 0; }
|
|
|
6e237b |
inline bool isField() const
|
|
|
6e237b |
{ return !isIndex(); }
|
|
|
6e237b |
inline int index() const
|
|
|
6e237b |
{ return m_index; }
|
|
|
3bac66 |
inline TStringId field() const
|
|
|
6e237b |
{ return m_field; }
|
|
|
6e237b |
|
|
|
6e237b |
inline bool operator== (const TVariantPathEntry &other) const
|
|
|
6e237b |
{ return m_index == other.m_index && m_field == other.m_field; }
|
|
|
6e237b |
inline bool operator!= (const TVariantPathEntry &other) const
|
|
|
6e237b |
{ return m_index != other.m_index || m_field != other.m_field; }
|
|
|
6e237b |
inline bool operator< (const TVariantPathEntry &other) const
|
|
|
6e237b |
{ return m_index < other.m_index || m_field < other.m_field; }
|
|
|
6e237b |
|
|
|
6e237b |
inline void set(int index)
|
|
|
6e237b |
{ m_index = index; m_field.reset(); }
|
|
|
6e237b |
inline void set(const TStringId &field)
|
|
|
6e237b |
{ m_index = 0; m_field = field; }
|
|
|
6e237b |
inline void set(const std::string &fieldName)
|
|
|
6e237b |
{ m_index = 0; m_field.set(fieldName); }
|
|
|
6e237b |
};
|
|
|
6e237b |
|
|
|
6e237b |
//-------------------------------------------------------------------
|
|
|
6e237b |
|
|
|
6e237b |
class DVAPI TVariantPath: public std::vector<tvariantpathentry> {</tvariantpathentry>
|
|
|
6e237b |
public:
|
|
|
9cf8be |
inline TVariantPath& append(const TVariantPathEntry &x)
|
|
|
9cf8be |
{ push_back(x); return *this; }
|
|
|
9cf8be |
inline TVariantPath& append(const TVariantPath &x)
|
|
|
9cf8be |
{ insert(end(), x.begin(), x.end()); return *this; }
|
|
|
9cf8be |
|
|
|
6e237b |
inline bool isSubPathOf(const TVariantPath &other) const
|
|
|
16421e |
{ return compare(*this, 0, other, 0, (int)size()) == 0; }
|
|
|
6e237b |
inline bool isBasePathOf(const TVariantPath &other) const
|
|
|
6e237b |
{ return other.isSubPathOf(*this); }
|
|
|
6e237b |
inline int compare(const TVariantPath &other) const
|
|
|
6e237b |
{ return compare(*this, 0, other, 0, (int)std::max(size(), other.size())); }
|
|
|
6e237b |
inline bool operator==(const TVariantPath &other) const
|
|
|
6e237b |
{ return compare(other) == 0; }
|
|
|
6e237b |
inline bool operator!=(const TVariantPath &other) const
|
|
|
6e237b |
{ return compare(other) != 0; }
|
|
|
6e237b |
inline bool operator<(const TVariantPath &other) const
|
|
|
6e237b |
{ return compare(other) < 0; }
|
|
|
6e237b |
|
|
|
6e237b |
static int compare(
|
|
|
6e237b |
const TVariantPath &a, int beginA,
|
|
|
6e237b |
const TVariantPath &b, int beginB, int count );
|
|
|
6e237b |
};
|
|
|
6e237b |
|
|
|
6e237b |
//-------------------------------------------------------------------
|
|
|
6e237b |
|
|
|
6e237b |
class DVAPI TVariantOwner {
|
|
|
6e237b |
public:
|
|
|
6e237b |
virtual ~TVariantOwner() { }
|
|
|
ae9154 |
virtual void onVariantChanged(const TVariant &value) { }
|
|
|
6e237b |
};
|
|
|
6e237b |
|
|
|
6e237b |
//-------------------------------------------------------------------
|
|
|
6e237b |
|
|
|
6e237b |
class DVAPI TVariant {
|
|
|
6e237b |
public:
|
|
|
6e237b |
enum Type {
|
|
|
6e237b |
None,
|
|
|
6e237b |
Bool,
|
|
|
6e237b |
Double,
|
|
|
6e237b |
String,
|
|
|
6e237b |
List,
|
|
|
6e237b |
Map
|
|
|
6e237b |
};
|
|
|
6e237b |
|
|
|
6e237b |
private:
|
|
|
6e237b |
Type m_type;
|
|
|
6e237b |
bool m_bool;
|
|
|
6e237b |
double m_double;
|
|
|
6e237b |
std::string m_string;
|
|
|
6e237b |
TVariantList m_list;
|
|
|
6e237b |
TVariantMap m_map;
|
|
|
6e237b |
|
|
|
6e237b |
TVariantOwner* m_owner;
|
|
|
6e237b |
TVariant *m_root;
|
|
|
6e237b |
TVariant *m_parent;
|
|
|
6e237b |
TStringId m_parentField;
|
|
|
6e237b |
|
|
|
6e237b |
void setParentForChilds();
|
|
|
6e237b |
inline void setParent(TVariant &parent, const TStringId &parentField = TStringId()) {
|
|
|
6e237b |
m_root = parent.m_root;
|
|
|
6e237b |
m_parent = &parent;
|
|
|
6e237b |
m_parentField = parentField;
|
|
|
6e237b |
setParentForChilds();
|
|
|
6e237b |
}
|
|
|
6e237b |
|
|
|
6e237b |
public:
|
|
|
6e237b |
static const TVariant& blank();
|
|
|
6e237b |
|
|
|
6e237b |
inline TVariant():
|
|
|
6e237b |
m_type(None),
|
|
|
6e237b |
m_bool(),
|
|
|
6e237b |
m_double(),
|
|
|
6e237b |
m_owner(),
|
|
|
6e237b |
m_root(this),
|
|
|
6e237b |
m_parent() { }
|
|
|
6e237b |
inline TVariant(const TVariant &other):
|
|
|
6e237b |
m_type(None),
|
|
|
6e237b |
m_bool(),
|
|
|
6e237b |
m_double(),
|
|
|
6e237b |
m_owner(),
|
|
|
6e237b |
m_root(this),
|
|
|
6e237b |
m_parent() { *this = other; }
|
|
|
6e237b |
inline explicit TVariant(TVariantOwner &owner, const TVariant &v = TVariant()):
|
|
|
6e237b |
m_type(None),
|
|
|
6e237b |
m_bool(),
|
|
|
6e237b |
m_double(),
|
|
|
6e237b |
m_owner(),
|
|
|
6e237b |
m_root(this),
|
|
|
6e237b |
m_parent() { *this = v; m_owner = &owner; }
|
|
|
6e237b |
inline explicit TVariant(Type t):
|
|
|
6e237b |
m_type(t),
|
|
|
6e237b |
m_bool(),
|
|
|
6e237b |
m_double(),
|
|
|
6e237b |
m_owner(),
|
|
|
6e237b |
m_root(this),
|
|
|
6e237b |
m_parent() { }
|
|
|
6e237b |
inline explicit TVariant(bool v):
|
|
|
6e237b |
m_type(Bool),
|
|
|
6e237b |
m_bool(v),
|
|
|
6e237b |
m_double(),
|
|
|
6e237b |
m_owner(),
|
|
|
6e237b |
m_root(this),
|
|
|
6e237b |
m_parent() { }
|
|
|
6e237b |
inline explicit TVariant(double v):
|
|
|
6e237b |
m_type(Double),
|
|
|
6e237b |
m_bool(),
|
|
|
6e237b |
m_double(v),
|
|
|
6e237b |
m_owner(),
|
|
|
6e237b |
m_root(this),
|
|
|
6e237b |
m_parent() { }
|
|
|
6e237b |
inline explicit TVariant(const std::string &v):
|
|
|
6e237b |
m_type(String),
|
|
|
6e237b |
m_bool(),
|
|
|
6e237b |
m_double(),
|
|
|
6e237b |
m_string(v),
|
|
|
6e237b |
m_owner(),
|
|
|
6e237b |
m_root(this),
|
|
|
6e237b |
m_parent() { }
|
|
|
6e237b |
inline explicit TVariant(const TVariantList &v):
|
|
|
6e237b |
m_type(None),
|
|
|
6e237b |
m_bool(),
|
|
|
6e237b |
m_double(),
|
|
|
6e237b |
m_owner(),
|
|
|
6e237b |
m_root(this),
|
|
|
6e237b |
m_parent() { setList(v); }
|
|
|
6e237b |
inline explicit TVariant(const TVariantMap &v):
|
|
|
6e237b |
m_type(None),
|
|
|
6e237b |
m_bool(),
|
|
|
6e237b |
m_double(),
|
|
|
6e237b |
m_owner(),
|
|
|
6e237b |
m_root(this),
|
|
|
6e237b |
m_parent() { setMap(v); }
|
|
|
6e237b |
|
|
|
6e237b |
inline void touch()
|
|
|
ae9154 |
{ if (m_root->m_owner) m_root->m_owner->onVariantChanged(*this); }
|
|
|
6e237b |
|
|
|
6e237b |
inline TVariant& operator=(const TVariant &other) {
|
|
|
6e237b |
switch(other.m_type) {
|
|
|
6e237b |
case Bool : setBool(other.m_bool); break;
|
|
|
6e237b |
case Double : setDouble(other.m_double); break;
|
|
|
6e237b |
case String : setString(other.m_string); break;
|
|
|
6e237b |
case List : setList(other.m_list); break;
|
|
|
6e237b |
case Map : setMap(other.m_map); break;
|
|
|
6e237b |
default : reset(); break;
|
|
|
6e237b |
}
|
|
|
6e237b |
return *this;
|
|
|
6e237b |
}
|
|
|
6e237b |
|
|
|
6e237b |
inline void clear() {
|
|
|
6e237b |
m_bool = bool();
|
|
|
6e237b |
m_double = double();
|
|
|
6e237b |
m_string.clear();
|
|
|
6e237b |
m_list.clear();
|
|
|
6e237b |
m_map.clear();
|
|
|
6e237b |
touch();
|
|
|
6e237b |
}
|
|
|
6e237b |
inline void setType(Type t)
|
|
|
6e237b |
{ if (m_type != t) { m_type = t; clear(); } }
|
|
|
6e237b |
inline void reset()
|
|
|
6e237b |
{ setType(None); }
|
|
|
6e237b |
|
|
|
6e237b |
inline Type getType() const
|
|
|
6e237b |
{ return m_type; }
|
|
|
6e237b |
inline bool isNone() const
|
|
|
6e237b |
{ return m_type == None; }
|
|
|
6e237b |
inline bool getBool() const
|
|
|
6e237b |
{ return m_bool; }
|
|
|
6e237b |
inline double getDouble() const
|
|
|
6e237b |
{ return m_double; }
|
|
|
6e237b |
inline const std::string& getString() const
|
|
|
6e237b |
{ return m_string; }
|
|
|
6e237b |
inline const TVariantList& getList() const
|
|
|
6e237b |
{ return m_list; }
|
|
|
6e237b |
inline const TVariantMap& getMap() const
|
|
|
6e237b |
{ return m_map; }
|
|
|
6e237b |
|
|
|
6e237b |
inline void setNone()
|
|
|
6e237b |
{ reset(); }
|
|
|
6e237b |
inline void setBool(bool v)
|
|
|
6e237b |
{ setType(Bool); m_bool = v; touch(); }
|
|
|
6e237b |
inline void setDouble(double v)
|
|
|
6e237b |
{ setType(Double); m_double = v; touch(); }
|
|
|
6e237b |
inline void setString(const std::string &v)
|
|
|
6e237b |
{ setType(String); m_string = v; touch(); }
|
|
|
6e237b |
inline void setList(const TVariantList &v)
|
|
|
6e237b |
{ setType(List); m_list = v; setParentForChilds(); touch(); }
|
|
|
6e237b |
inline void setMap(const TVariantMap &v)
|
|
|
6e237b |
{ setType(Map); m_map = v; setParentForChilds(); touch(); }
|
|
|
6e237b |
|
|
|
6e237b |
// list methods
|
|
|
6e237b |
void resize(int size);
|
|
|
6e237b |
void insert(int index, const TVariant &v);
|
|
|
6e237b |
void remove(int index);
|
|
|
6e237b |
TVariant& operator[] (int index);
|
|
|
6e237b |
inline int size() const
|
|
|
6e237b |
{ return (int)(m_type == List ? m_list.size() : m_map.size()); }
|
|
|
6e237b |
inline void clearList()
|
|
|
6e237b |
{ resize(0); }
|
|
|
6e237b |
inline void append(const TVariant &v)
|
|
|
6e237b |
{ insert((int)m_list.size(), v); }
|
|
|
6e237b |
inline const TVariant& operator[] (int index) const {
|
|
|
6e237b |
assert(index >= 0);
|
|
|
6e237b |
return index < (int)m_list.size() ? m_list[index] : blank();
|
|
|
6e237b |
}
|
|
|
6e237b |
|
|
|
6e237b |
// map methods
|
|
|
6e237b |
TVariant& operator[] (const TStringId &field);
|
|
|
6e237b |
bool remove(const TStringId &field);
|
|
|
6e237b |
inline bool contains(const TStringId &field) const
|
|
|
6e237b |
{ return m_type == Map && m_map.count(field); }
|
|
|
6e237b |
inline const TVariant& operator[] (const TStringId &field) const {
|
|
|
6e237b |
TVariantMap::const_iterator i = m_map.find(field);
|
|
|
6e237b |
return i == m_map.end() ? blank() : i->second;
|
|
|
6e237b |
}
|
|
|
6e237b |
inline bool contains(const std::string &field) const
|
|
|
6e237b |
{ return contains(TStringId::find(field)); }
|
|
|
6e237b |
inline const TVariant& operator[] (const std::string &field) const
|
|
|
6e237b |
{ return (*this)[TStringId::find(field)]; }
|
|
|
6e237b |
inline TVariant& operator[] (const std::string &field)
|
|
|
9cf1a4 |
{ return (*this)[TStringId(field)]; }
|
|
|
6e237b |
inline void remove(const std::string &field)
|
|
|
6e237b |
{ remove(TStringId::find(field)); }
|
|
|
6e237b |
|
|
|
6e237b |
// path methods
|
|
|
6e237b |
const TVariant& byPath(const TVariantPath &path, int begin, int end) const;
|
|
|
6e237b |
TVariant& byPath(const TVariantPath &path, int begin, int end);
|
|
|
9cf8be |
inline const TVariant& operator[] (const TVariantPathEntry &entry) const {
|
|
|
6e237b |
return entry.isIndex()
|
|
|
6e237b |
? (m_type == List ? (*this)[entry.index()] : blank())
|
|
|
6e237b |
: (m_type == Map ? (*this)[entry.field()] : blank());
|
|
|
6e237b |
}
|
|
|
9cf8be |
inline TVariant& operator[] (const TVariantPathEntry &entry)
|
|
|
6e237b |
{ return entry.isIndex() ? (*this)[entry.index()] : (*this)[entry.field()]; }
|
|
|
6e237b |
inline const TVariant& byPath(const TVariantPath &path, int begin = 0) const
|
|
|
6e237b |
{ return byPath(path, begin, (int)path.size()); }
|
|
|
6e237b |
inline TVariant& byPath(const TVariantPath &path, int begin = 0)
|
|
|
6e237b |
{ return byPath(path, begin, (int)path.size()); }
|
|
|
6e237b |
inline const TVariant& operator[] (const TVariantPath &path) const
|
|
|
6e237b |
{ return byPath(path); }
|
|
|
6e237b |
inline TVariant& operator[] (const TVariantPath &path)
|
|
|
6e237b |
{ return byPath(path); }
|
|
|
6e237b |
|
|
|
6e237b |
// hierarchy methods
|
|
|
6e237b |
inline const TVariantOwner* owner() const
|
|
|
6e237b |
{ return m_root->m_owner; }
|
|
|
6e237b |
inline TVariantOwner* owner()
|
|
|
6e237b |
{ return m_root->m_owner; }
|
|
|
6e237b |
inline const TVariant& root() const
|
|
|
6e237b |
{ return *m_root; }
|
|
|
6e237b |
inline TVariant& root()
|
|
|
6e237b |
{ return *m_root; }
|
|
|
6e237b |
inline const TVariant* parent() const
|
|
|
6e237b |
{ return m_parent; }
|
|
|
6e237b |
inline TVariant* parent()
|
|
|
6e237b |
{ return m_parent; }
|
|
|
6e237b |
inline int parentIndex() const
|
|
|
6e237b |
{ return m_parent || !m_parentField ? this - &m_parent->m_list.front() : 0; }
|
|
|
6e237b |
inline const TStringId& parentField() const
|
|
|
6e237b |
{ return m_parentField; }
|
|
|
ae9154 |
inline bool isRoot() const
|
|
|
ae9154 |
{ return this == m_root; }
|
|
|
6e237b |
|
|
|
9cf8be |
int getParentPathSize(const TVariant &parent) const;
|
|
|
9cf8be |
bool getParentPath(TVariantPath &outPath, const TVariant &parent) const;
|
|
|
6e237b |
inline TVariantPathEntry parentPathEntry() const {
|
|
|
6e237b |
return !m_parent ? TVariantPathEntry()
|
|
|
6e237b |
: m_parent->m_type == Map ? TVariantPathEntry(m_parentField)
|
|
|
6e237b |
: TVariantPathEntry( this - &m_parent->m_list.front() );
|
|
|
6e237b |
}
|
|
|
9cf8be |
inline int getParentPathSize() const
|
|
|
9cf8be |
{ return getParentPathSize(*m_root); }
|
|
|
9cf8be |
inline bool getParentPath(TVariantPath &outPath) const
|
|
|
9cf8be |
{ return getParentPath(outPath, *m_root); }
|
|
|
9cf8be |
|
|
|
9cf8be |
inline int getChildPathSize(const TVariant &child) const
|
|
|
9cf8be |
{ return child.getParentPathSize(*this); }
|
|
|
9cf8be |
inline bool getChildPath(TVariantPath &outPath, const TVariant &child) const
|
|
|
9cf8be |
{ return child.getParentPath(outPath, *this); }
|
|
|
9cf8be |
bool getChildPathEntry(const TVariant &child, TVariantPathEntry &outEntry) const;
|
|
|
6e237b |
|
|
|
6e237b |
bool isChildOf(const TVariant &other) const;
|
|
|
6e237b |
bool isChildOrEqual(const TVariant &other) const;
|
|
|
6e237b |
inline bool isParentOf(const TVariant &other) const
|
|
|
6e237b |
{ return other.isChildOf(*this); }
|
|
|
6e237b |
inline bool isParentOrEqual(const TVariant &other) const
|
|
|
6e237b |
{ return other.isChildOrEqual(*this); }
|
|
|
6e237b |
inline bool isChildOrParent(const TVariant &other) const
|
|
|
6e237b |
{ return isChildOrEqual(other) || isParentOrEqual(other); }
|
|
|
6e237b |
|
|
|
6e237b |
const TVariant* findCommonParent(const TVariant &other) const;
|
|
|
6e237b |
|
|
|
249386 |
// memory
|
|
|
249386 |
size_t getMemSize() const;
|
|
|
249386 |
|
|
|
6e237b |
// serialization
|
|
|
9cf1a4 |
void toStream(std::ostream &stream, bool pretty = false, int level = 0) const;
|
|
|
9cf1a4 |
void fromStream(std::istream &stream, int *currentRow = 0, int *currentCol = 0);
|
|
|
9cf1a4 |
|
|
|
9cf1a4 |
std::string toString(bool pretty = false, int level = 0) const;
|
|
|
9cf1a4 |
void fromString(const std::string &str, int *currentRow = 0, int *currentCol = 0);
|
|
|
6e237b |
};
|
|
|
6e237b |
|
|
|
6e237b |
#endif
|