ultimatepp/uppsrc/Core/Value.hpp
2023-10-29 20:58:52 +01:00

426 lines
No EOL
12 KiB
C++

inline
Value::Value(const Value& v)
: data(String::SPECIAL)
{
if(v.IsRef() || v.data.IsLarge())
SetLarge(v);
else
data.SetSmall(v.data);
Magic();
}
template<>
inline bool IsPolyEqual(const bool& x, const Value& v) {
return v.Is<double>() && int(x) == double(v)
|| v.Is<float>() && int(x) == float(v)
|| v.Is<int64>() && int(x) == int64(v)
|| v.Is<int>() && int(x) == int(v);
}
template<>
inline bool IsPolyEqual(const int& x, const Value& v) {
return v.Is<double>() && x == double(v)
|| v.Is<float>() && x == float(v)
|| v.Is<int64>() && x == int64(v);
}
template<>
inline bool IsPolyEqual(const int64& x, const Value& v) {
return v.Is<double>() && double(x) == double(v);
}
template<>
inline bool IsPolyEqual(const Date& x, const Value& v) {
return v.Is<Time>() && ToTime(x) == Time(v);
}
template<>
inline bool IsPolyEqual(const WString& x, const Value& v) {
return v.GetType() == STRING_V && WString(v) == x;
}
template<class T>
inline int PolyCompare(const T& a, const Value& b)
{
return a.PolyCompare(b);
}
template<>
inline int PolyCompare(const WString& x, const Value& v) {
return IsString(v) && SgnCompare(x, WString(v));
}
template<>
inline int PolyCompare(const String& x, const Value& v) {
return IsString(v) && SgnCompare((WString)x, (WString)v);
}
template<>
inline int PolyCompare(const bool& x, const Value& v) {
return v.Is<int64>() ? SgnCompare((int64)x, (int64)v)
: IsNumber(v) ? SgnCompare((double)x, (double)v)
: 0;
}
template<>
inline int PolyCompare(const int& x, const Value& v) {
return v.Is<int64>() ? SgnCompare((int64)x, (int64)v)
: IsNumber(v) ? SgnCompare((double)x, (double)v)
: 0;
}
template<>
inline int PolyCompare(const int64& x, const Value& v) {
return v.Is<double>() ? SgnCompare((double)x, (double)v)
: IsNumber(v) ? SgnCompare((int64)x, (int64)v)
: 0;
}
template<>
inline int PolyCompare(const double& x, const Value& v) {
return IsNumber(v) ? SgnCompare((double)x, (double)v) : 0;
}
template<>
inline int PolyCompare(const float& x, const Value& v) {
return IsNumber(v) ? SgnCompare((double)x, (double)v) : 0;
}
template<>
inline int PolyCompare(const Date& x, const Value& v) {
return v.Is<Time>() && SgnCompare(ToTime(x), Time(v));
}
template<>
inline int PolyCompare(const Time& x, const Value& v) {
return v.Is<Date>() && SgnCompare(ToTime(x), Time(v));
}
template<>
inline hash_t ValueGetHashValue(const bool& x) {
return UPP::GetHashValue((int64)x);
}
template<>
inline hash_t ValueGetHashValue(const int& x) {
return UPP::GetHashValue((int64)x);
}
template<>
inline hash_t ValueGetHashValue(const double& x) {
if(x >= (double)INT64_MIN && x <= (double)INT64_MAX && (int64)x == x)
return UPP::GetHashValue((int64)x); // we want this to be equal to other number types
return UPP::GetHashValue(x);
}
template<>
inline hash_t ValueGetHashValue(const float& x) {
if(x >= (float)INT64_MIN && x <= (float)INT64_MAX && (int64)x == x)
return UPP::GetHashValue((int64)x); // we want this to be equal to other number types
return UPP::GetHashValue(x);
}
template<>
inline hash_t ValueGetHashValue(const Date& x) {
return UPP::GetHashValue(ToTime(x));
}
template<>
inline hash_t ValueGetHashValue(const WString& x) {
return UPP::GetHashValue(x.ToString());
}
template <class T>
class RawValueRep : public Value::Void {
public:
virtual bool IsNull() const { return false; }
T v;
enum VPICK { PICK };
enum VDEEP { DEEP };
const T& Get() const { return v; }
T& Get() { return v; }
RawValueRep(const T& v) : v(v) {}
RawValueRep(T&& v, VPICK) : v(pick(v)) {}
RawValueRep(const T& v, VDEEP) : v(v, 1) {}
RawValueRep() {}
};
template <class T>
class RichValueRep : public RawValueRep<T> {
public:
virtual bool IsNull() const { return UPP::IsNull(this->v); }
virtual void Serialize(Stream& s) { s % this->v; }
virtual void Xmlize(XmlIO& xio) { Upp::Xmlize(xio, this->v); }
virtual void Jsonize(JsonIO& jio) { Upp::Jsonize(jio, this->v); }
virtual hash_t GetHashValue() const { return UPP::ValueGetHashValue(this->v); }
virtual bool IsEqual(const Value::Void *p) { ASSERT(dynamic_cast<const RawValueRep<T> *>(p));
return static_cast<const RawValueRep<T> *>(p)->Get() == this->v; }
virtual bool IsPolyEqual(const Value& b) { return UPP::IsPolyEqual(this->v, b); }
virtual String AsString() const { return UPP::AsString(this->v); }
virtual int Compare(const Value::Void *p) { ASSERT(dynamic_cast<const RawValueRep<T> *>(p));
return SgnCompare(this->v, static_cast<const RawValueRep<T> *>(p)->Get()); }
virtual int PolyCompare(const Value& b) { return Upp::PolyCompare(this->v, b); }
RichValueRep(const T& v) : RawValueRep<T>(v) {}
RichValueRep() {}
static Value::Void *Create() { return new RichValueRep; }
};
template <class T>
struct SvoFn {
static bool IsNull(const void *p) { return UPP::IsNull(*(T *)p); }
static void Serialize(void *p, Stream& s) { s % *(T*)p; }
static void Xmlize(void *p, XmlIO& xio) { Upp::Xmlize(xio, *(T*)p); }
static void Jsonize(void *p, JsonIO& jio) { Upp::Jsonize(jio, *(T*)p); }
static hash_t GetHashValue(const void *p) { return UPP::ValueGetHashValue(*(T*)p); }
static bool IsEqual(const void *p1, const void *p2) { return *(T*)p1 == *(T*)p2; }
static bool IsPolyEqual(const void *p, const Value& v) { return UPP::IsPolyEqual(*(T*)p, v); }
static String AsString(const void *p) { return UPP::AsString(*(T*)p); }
static int Compare(const void *p1, const void *p2) { return SgnCompare(*(T*)p1, *(T*)p2); }
static int PolyCompare(const void *p1, const Value& p2) { return UPP::PolyCompare(*(T*)p1, p2); }
};
#define SVO_FN(id, T) \
static Value::Sval id = { \
SvoFn<T>::IsNull, SvoFn<T>::Serialize, SvoFn<T>::Xmlize, SvoFn<T>::Jsonize, \
SvoFn<T>::GetHashValue, SvoFn<T>::IsEqual, \
SvoFn<T>::IsPolyEqual, SvoFn<T>::AsString, \
SvoFn<T>::Compare, SvoFn<T>::PolyCompare \
};
template <class T>
void Value::InitSmall(const T& init)
{
ASSERT(sizeof(T) <= 8);
SVO_FN(sval, T)
int typeno = GetValueTypeNo<T>();
ASSERT(typeno >= 0 && typeno < 256);
svo[typeno] = &sval;
data.SetSpecial(typeno);
new(&data) T(init);
}
template <class T>
inline T& Value::GetSmallRaw() const
{
return *(T*)&data; // Silence compiler warning
}
template <class T>
T& Value::GetSmall() const
{
dword t = GetValueTypeNo<T>();
ASSERT(t < 255);
if(Is((byte)t))
return GetSmallRaw<T>();
String h = String() << "Invalid value conversion: "
<< GetName() << " -> " << typeid(T).name();
throw ValueTypeError(h, *this, t);
return *(T*)&data; // Silence compiler warning
}
template <class T>
void Value::SvoRegister(const char *name)
{
dword t = GetValueTypeNo<T>();
ASSERT(t < 255);
SVO_FN(sval, T)
svo[t] = &sval;
AddName(t, name);
}
template <class T>
inline const T& Value::To() const
{
dword t = GetValueTypeNo<T>();
ASSERT(t != VALUEARRAY_V && t != VALUEMAP_V);
#ifndef _DEBUG
if(t == VALUEARRAY_V) {
ASSERT(ptr()->GetType() == VALUEARRAY_V);
return *(T*)this; // Illegal, but works -> better than crash in release mode
}
if(t == VALUEMAP_V) {
ASSERT(ptr()->GetType() == VALUEMAP_V);
return *(T*)this; // Illegal, but works -> better than crash in release mode
}
#endif
if(IsRef()) {
const RawValueRep<T> *x = dynamic_cast<const RawValueRep<T>*>(ptr());
if(x)
return x->Get();
}
else
if(t == STRING_V) {
ASSERT(IsString());
return *reinterpret_cast<const T*>(&data); // Only active when T is String
}
else
if(t < 255 && Is((byte)t))
return GetSmallRaw<T>();
// DLOG(String().Cat() << "Invalid value conversion: " << GetName() << " -> " << typeid(T).name());
throw ValueTypeError(String().Cat() << "Invalid value conversion: "
<< GetName() << " -> " << typeid(T).name(),
*this, t);
}
template <class T>
inline bool Value::Is() const
{
dword t = GetValueTypeNo<T>();
if(IsRef() && GetRefType() == t)
return true;
if(t == STRING_V)
return IsString();
if(t == VOID_V)
return IsVoid();
return t < 255 && Is((byte)t);
}
inline
int Value::Compare(const Value& v) const
{
if(Is(INT_V) && v.Is(INT_V))
return SgnCompare(GetSmallRaw<int>(), v.GetSmallRaw<int>());
if(Is(DOUBLE_V) && v.Is(DOUBLE_V))
return SgnCompare(GetSmallRaw<double>(), v.GetSmallRaw<double>());
if(Is(FLOAT_V) && v.Is(FLOAT_V))
return SgnCompare(GetSmallRaw<float>(), v.GetSmallRaw<float>());
return Compare2(v);
}
template <class T>
const T& GetStaticNull()
{
static T *q;
ONCELOCK {
static T x;
SetNull(x);
q = &x;
}
return *q;
}
template <class T>
inline const T& Value::Get() const
{
#ifndef _DEBUG
dword t = GetValueTypeNo<T>();
if(t == VALUEARRAY_V) {
ASSERT(ptr()->GetType() == VALUEARRAY_V);
return *(T*)this; // Illegal, but works -> better than crash in release mode
}
if(t == VALUEMAP_V) {
ASSERT(ptr()->GetType() == VALUEMAP_V);
return *(T*)this; // Illegal, but works -> better than crash in release mode
}
#endif
if(IsNull())
return GetStaticNull<T>();
return To<T>();
}
template <class T>
Value::Value(const T& x, VSMALL)
{
InitSmall(x);
}
inline
hash_t Value::GetHashValue() const
{
return IsString() ? data.GetCount() ? data.GetHashValue() : 0
: GetOtherHashValue();
}
template <class T>
void Value::Register(const char *name)
{
dword t = GetValueTypeNo<T>();
Value::Register(t, RichValueRep<T>::Create, name);
}
inline
const Value& Value::operator[](const char *key) const
{
return operator[](String(key));
}
inline
const Value& Value::operator[](const Id& key) const
{
return operator[](~key);
}
template <class T>
inline Value RawToValue(const T& data)
{
return Value(new RawValueRep<T>(data), GetValueTypeNo<T>());
}
template <class T>
inline Value RawPickToValue(T&& data)
{
typedef RawValueRep<T> R;
return Value(new R(pick(data), R::PICK), GetValueTypeNo<T>());
}
template <class T>
inline Value RawDeepToValue(const T& data)
{
typedef RawValueRep<T> R;
return Value(new R(data, R::DEEP), GetValueTypeNo<T>());
}
template <class T>
inline T& CreateRawValue(Value& v) {
typedef RawValueRep<T> R;
R *r = new R;
v = Value(r, GetValueTypeNo<T>());
return r->Get();
}
template <class T>
inline Value RichToValue(const T& data)
{
return Value(new RichValueRep<T>(data), GetValueTypeNo<T>());
}
template <>
inline Value RichToValue(const String& data)
{
return Value(data);
}
#ifdef DEPRECATED
template <class T> // use Value::Is
bool IsTypeRaw(const Value& value, T * = 0) { return value.Is<T>(); }
template <class T> // use Value::Is
bool IsType(const Value& x, T* = 0) { return x.Is<T>(); }
template <class T>
struct RawValue : public Value { // use RawToValue and Value::To
RawValue(const T& x) : Value(RawToValue(x)) {}
static const T& Extract(const Value& v) { return v.To<T>(); }
static const T& Extract(const Value& v, const T& dflt) { return v.Is<T>() ? v.To<T>() : dflt; }
};
template <class T>
struct RichValue : public Value { // use RichToValue and Value::To
public:
RichValue(const T& x) : Value(RichToValue<T>(x)) {}
static void Register() init_ { Value::Register<T>(); }
static const T& Extract(const Value& v) { return v.Get<T>(); }
};
template <class T> // use Value::To
inline const T& ValueTo(const Value& v) { return v.To<T>(); }
template <class T> // use Value::To
inline const T& ValueTo(const Value& v, const T& dflt) { return v.Is<T>() ? v.To<T>() : dflt; }
#endif