struct IdConst { const char *text; mutable int ndx; }; class Value; class Id : Moveable { protected: int ndx; static Index& Ids(); void Set(const String& s); public: int AsNdx() const { return ndx; } String ToString() const; dword GetHashValue() const { return ndx; } bool IsNull() const { return ndx == 0; } void Serialize(Stream& s); operator String() const { return ToString(); } String operator~() const { return ToString(); } bool operator==(Id b) const { return ndx == b.ndx; } bool operator!=(Id b) const { return ndx != b.ndx; } static Id Find(const String& s); static const String& AsString(int n); operator bool() const { return ndx; } Id() { ndx = 0; } Id(const String& s) { Set(s); } Id(const char *s) { Set(s); } explicit Id(int n) { ASSERT(n >= 0 && n < Ids().GetCount()); ndx = n; } Id(const IdConst& cnst); }; const int INT_NULL = INT_MIN; const int64 INT64_NULL = INT64_MIN; const double DOUBLE_NULL = -1.0E+308; const double DOUBLE_NULL_LIM = -1.0E+307; class Nuller { public: operator int() const { return INT_NULL; } operator int64() const { return INT64_NULL; } operator double() const { return DOUBLE_NULL; } operator bool() const { return false; } Nuller() {} }; #ifdef flagSO static const Nuller Null; #else extern const Nuller Null; #endif template<> inline bool IsNull(const int& i) { return i == INT_NULL; } template<> inline bool IsNull(const int64& i) { return i == INT64_NULL; } template<> inline bool IsNull(const double& r) { return r < DOUBLE_NULL_LIM; } template<> inline bool IsNull(const bool& r ) { return false; } template<> inline bool IsNull(const Date& d) { return d.year == -32768; } template<> inline bool IsNull(const Time& t) { return t.year == -32768; } inline const String& Nvl(const String& a, const String& b) { return IsNull(a) ? b : a; } inline int Nvl(int a, int b) { return IsNull(a) ? b : a; } inline int64 Nvl(int64 a, int64 b) { return IsNull(a) ? b : a; } inline double Nvl(double a, double b) { return IsNull(a) ? b : a; } inline Date Nvl(Date a, Date b) { return IsNull(a) ? b : a; } inline Time Nvl(Time a, Time b) { return IsNull(a) ? b : a; } inline int Nvl(int a) { return Nvl(a, 0); } inline int64 Nvl(int64 a) { return Nvl(a, (int64)0); } inline double Nvl(double a) { return Nvl(a, 0.0); } const dword VOID_V = 0; const dword INT_V = 1; const dword DOUBLE_V = 2; const dword STRING_V = 3; const dword DATE_V = 4; const dword TIME_V = 5; const dword ERROR_V = 6; const dword VALUE_V = 7; const dword WSTRING_V = 8; const dword VALUEARRAY_V = 9; const dword INT64_V = 10; const dword BOOL_V = 11; const dword VALUEMAP_V = 12; const dword UNKNOWN_V = (dword)0xffffffff; class Value : Moveable { public: class Void { protected: Atomic refcount; public: void Retain() { AtomicInc(refcount); } void Release() { if(AtomicDec(refcount) == 0) delete this; } virtual dword GetType() const { return VOID_V; } virtual bool IsNull() const { return true; } virtual void Serialize(Stream& s) {} virtual unsigned GetHashValue() const { return 0; } virtual bool IsEqual(const Void *p) { return false; } virtual bool IsPolyEqual(const Value& v) { return false; } virtual String AsString() const { return ""; } Void() { AtomicWrite(refcount, 1); } virtual ~Void() {} friend class Value; }; protected: static VectorMap& Typemap(); Void *ptr; void SetVoidVal(); public: static void Register(dword w, Void* (*c)(Stream& s)) init_; dword GetType() const { return ptr->GetType(); } bool IsError() const { return GetType() == ERROR_V; } bool IsVoid() const { return GetType() == VOID_V || IsError(); } bool IsNull() const { return ptr->IsNull(); } template bool Is() const; operator String() const; operator WString() const; operator Date() const; operator Time() const; operator double() const; operator int() const; operator int64() const; operator bool() const; Value(const String& s); Value(const WString& s); Value(const char *s); Value(int i); Value(int64 i); Value(double d); Value(bool b); Value(Date d); Value(Time t); Value(const Nuller&); bool operator==(const Value& v) const; bool operator!=(const Value& v) const { return !operator==(v); } String ToString() const; void Serialize(Stream& s); unsigned GetHashValue() const; Value& operator=(const Value& v); Value(const Value& v); Value(); ~Value(); Value(Void *p) { ptr = p; } const Void *GetVoidPtr() const { return ptr; } }; #define VALUE_COMPARE(T) \ inline bool operator==(const Value& v, T x) { return (T)v == x; } \ inline bool operator==(T x, const Value& v) { return (T)v == x; } \ inline bool operator!=(const Value& v, T x) { return (T)v != x; } \ inline bool operator!=(T x, const Value& v) { return (T)v != x; } \ VALUE_COMPARE(int) VALUE_COMPARE(int64) VALUE_COMPARE(double) VALUE_COMPARE(bool) VALUE_COMPARE(Date) VALUE_COMPARE(Time) VALUE_COMPARE(String) VALUE_COMPARE(WString) inline bool operator==(const Value& v, const char *x) { return (String)v == x; } inline bool operator==(const char *x, const Value& v) { return (String)v == x; } inline bool operator!=(const Value& v, const char *x) { return (String)v != x; } inline bool operator!=(const char *x, const Value& v) { return (String)v != x; } inline bool operator==(const Value& v, const wchar *x) { return (WString)v == x; } inline bool operator==(const wchar *x, const Value& v) { return (WString)v == x; } inline bool operator!=(const Value& v, const wchar *x) { return (WString)v != x; } inline bool operator!=(const wchar *x, const Value& v) { return (WString)v != x; } inline bool IsVoid(const Value& v) { return v.GetType() == VOID_V; } inline bool IsError(const Value& v) { return v.GetType() == ERROR_V; } inline bool IsString(const Value& v) { return v.GetType() == STRING_V || v.GetType() == WSTRING_V; } inline bool IsNumber(const Value& v) { return v.GetType() == DOUBLE_V || v.GetType() == INT_V || v.GetType() == INT64_V || v.GetType() == BOOL_V; } inline bool IsDateTime(const Value& v) { return v.GetType() == DATE_V || v.GetType() == TIME_V; } int StdValueCompare(const Value& a, const Value& b, int language); int StdValueCompare(const Value& a, const Value& b); int StdValueCompareDesc(const Value& a, const Value& b, int language); int StdValueCompareDesc(const Value& a, const Value& b); struct ValueOrder { virtual bool operator()(const Value& a, const Value& b) const = 0; virtual ~ValueOrder() {} }; struct StdValueOrder : ValueOrder { int language; virtual bool operator()(const Value& a, const Value& b) const; StdValueOrder(int l = -1); virtual ~StdValueOrder(); }; struct FnValueOrder : ValueOrder { int (*fn)(const Value& a, const Value& b); virtual bool operator()(const Value& a, const Value& b) const; FnValueOrder(int (*fn)(const Value& a, const Value& b)); virtual ~FnValueOrder(); }; template inline dword ValueTypeNo(const T&) { return StaticTypeNo() + 0x8000000;; } template<> inline dword ValueTypeNo(const int&) { return INT_V; } template<> inline dword ValueTypeNo(const int64&) { return INT64_V; } template<> inline dword ValueTypeNo(const double&) { return DOUBLE_V; } template<> inline dword ValueTypeNo(const bool&) { return BOOL_V; } template<> inline dword ValueTypeNo(const String&) { return STRING_V; } template<> inline dword ValueTypeNo(const WString&) { return WSTRING_V; } template<> inline dword ValueTypeNo(const Date&) { return DATE_V; } template<> inline dword ValueTypeNo(const Time&) { return TIME_V; } template class AssignValueTypeNo : public B { public: friend dword ValueTypeNo(const T&) { return type; } void operator=(const AssignValueTypeNo&) {} // MSC 6.0 empty base class bug fix }; template bool IsType(const Value& x, T* = 0) { return ValueTypeNo(*(T *)NULL) == x.GetType(); } template inline bool Value::Is() const { return IsType(*this); } template class RawValueRep : public Value::Void { protected: T v; public: virtual dword GetType() const { return ValueTypeNo(v); } virtual bool IsNull() const { return false; } const T& Get() const { return v; } RawValueRep(const T& v) : v(v) {} RawValueRep() {} static const RawValueRep *Cast(const Value::Void *p) { ASSERT_(dynamic_cast(p), String().Cat() << "Invalid value conversion: " << typeid(*p).name() << " -> " << typeid(T).name()); return (const RawValueRep *) p; } }; template bool IsTypeRaw(const Value& value, T * = 0) { return !IsVoid(value) && dynamic_cast *>(value.GetVoidPtr()); } template class RawValue : public Value { protected: typedef RawValueRep Rep; RawValue(Rep *rep) : Value(rep) {} public: RawValue(const T& x) : Value(new Rep(x)) {} static const T& Extract(const Value& v) { return Rep::Cast(v.GetVoidPtr())->Get(); } static const T& Extract(const Value& v, const T& dflt) { return IsTypeRaw(v) ? Rep::Cast(v.GetVoidPtr())->Get() : dflt; } }; template class RawPickValueRep : public RawValueRep { public: RawPickValueRep(pick_ T& _v) { this->v = _v; } RawPickValueRep(const T& _v, int) { this->v <<= _v; } RawPickValueRep() {} }; template class RawPickValue : public RawValue { protected: typedef RawPickValueRep PickRep; public: RawPickValue(pick_ T& x) : RawValue(new PickRep(x)) {} RawPickValue(const T& x, int) : RawValue(new PickRep(x, 0)) {} }; template class RawValueCreateRep : public RawValueRep { public: T& Get() { return this->v; } }; template class RawValueCreate : public RawValue { protected: typedef RawValueCreateRep Rep; public: RawValueCreate() : RawValue(new Rep()) {} T& Get() { return ((Rep *)this->GetVoidPtr())->Get(); } }; template inline Value RawToValue(const T& data) { return RawValue(data); } template inline Value RawPickToValue(pick_ T& data) { return RawPickValue(data); } template inline Value RawDeepToValue(const T& data) { return RawPickValue(data, 0); } template inline T& CreateRawValue(Value& v) { RawValueCreate x; v = x; return x.Get(); } template inline const T& ValueTo(const Value& v, T * = 0) { return RawValue::Extract(v); } template inline const T& ValueTo(const Value& v, const T& dflt) { return RawValue::Extract(v, dflt); } template inline bool IsPolyEqual(const T& x, const Value& v) { return false; } template inline unsigned ValueGetHashValue(const T& x) { return UPP::GetHashValue(x); } inline bool IsPolyEqual(const bool& x, const Value& v) { return v.GetType() == DOUBLE_V && int(x) == double(v) || v.GetType() == INT64_V && int(x) == int64(v) || v.GetType() == INT_V && int(x) == int(v); } inline bool IsPolyEqual(const int& x, const Value& v) { return v.GetType() == DOUBLE_V && x == double(v) || v.GetType() == INT64_V && x == int64(v); } inline bool IsPolyEqual(const int64& x, const Value& v) { return v.GetType() == DOUBLE_V && double(x) == double(v); } inline bool IsPolyEqual(const Date& x, const Value& v) { return v.GetType() == TIME_V && ToTime(x) == Time(v); } inline bool IsPolyEqual(const WString& x, const Value& v) { return v.GetType() == STRING_V && WString(v) == x; } inline unsigned ValueGetHashValue(const bool& x) { return UPP::GetHashValue((double)x); } inline unsigned ValueGetHashValue(const int& x) { return UPP::GetHashValue((double)x); } inline unsigned ValueGetHashValue(const int64& x) { return UPP::GetHashValue((double)x); } inline unsigned ValueGetHashValue(const Date& x) { return UPP::GetHashValue(ToTime(x)); } inline unsigned ValueGetHashValue(const String& x) { // Improve by specialized routines !!! return UPP::GetHashValue((WString)x); } template class RichValueRep : public RawValueRep { public: virtual bool IsNull() const { return UPP::IsNull(this->v); } virtual void Serialize(Stream& s) { s % this->v; } virtual unsigned GetHashValue() const { return UPP::ValueGetHashValue(this->v); } virtual bool IsEqual(const Value::Void *p) { return Cast(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); } RichValueRep(const T& v) : RawValueRep(v) {} RichValueRep(Stream& s) { Serialize(s); } static Value::Void *Create(Stream& s) { return new RichValueRep(s); } static const RichValueRep *Cast(const Value::Void *p) { ASSERT_(dynamic_cast(p), String().Cat() << "Invalid value conversion: " << typeid(*p).name() << " -> " << typeid(T).name()); return (const RichValueRep *) p; } }; template class RichValue : public Value { protected: typedef RichValueRep Rep; static const T& GetNull() { static T *q; ONCELOCK { static T x(Null); q = &x; } return *q; } public: RichValue(const T& x) : Value(new Rep(x)) {} const T& Get(const Value& v) { if(IsNull(v)) return GetNull(); return Rep::Cast(v.GetVoidPtr())->Get(); } static void Register() init_ { Value::Register(ValueTypeNo(*(T *)NULL), Rep::Create); } static const T& Extract(const Value& v) { if(v.IsNull()) return GetNull(); return Rep::Cast(v.GetVoidPtr())->Get(); } }; template inline Value RichToValue(const T& data) { return RichValue(data); } Value ErrorValue(const char *s); Value ErrorValue(const String& s); Value ErrorValue(); String GetErrorText(const Value& v); inline bool IsNull(const Value& v) { return v.IsNull(); } inline const Value& Nvl(const Value& a, const Value& b) { return IsNull(a) ? b : a; } Value Scan(dword stdtype, const String& text); // ----------------------- Ref struct RefManager { virtual int GetType() = 0; virtual Value GetValue(const void *) { return Null; } virtual bool IsNull(const void *) { return false; } virtual void SetValue(void *, const Value& v) { NEVER(); } virtual void SetNull(void *) { NEVER(); } virtual ~RefManager() {} }; template struct RawRef : public RefManager { virtual void SetValue(void *p, const Value& v) { *(T *) p = RawValue::Extract(v); } virtual Value GetValue(const void *p) { return RawValue(*(const T *) p); } virtual int GetType() { return ValueTypeNo(*(T *)NULL); } virtual ~RawRef() {} }; template struct RichRef : public RawRef { virtual Value GetValue(const void *p) { return RichValue(*(T *) p); } virtual bool IsNull(const void *p) { return UPP::IsNull(*(T *) p); } virtual void SetValue(void *p, const Value& v) { *(T *) p = T(v); } virtual void SetNull(void *p) { *(T *) p = T(Null); } }; class Ref : Moveable { protected: RefManager *m; void *ptr; struct ValueRef; public: dword GetType() const { return m ? m->GetType() : VOID_V; } operator Value() const { return m ? m->GetValue(ptr) : Value(); } bool IsNull() const { return m ? m->IsNull(ptr) : true; } void *GetVoidPtr() const { return ptr; } void SetNull() { if(m) m->SetNull(ptr); } void SetValue(const Value& v) { ASSERT(m); m->SetValue(ptr, v); } Ref& operator=(const Value& v) { SetValue(v); return *this; } Ref(String& s); Ref(WString& s); Ref(int& i); Ref(int64& i); Ref(double& d); Ref(Date& d); Ref(Time& t); Ref(Value& v); Ref(void *_ptr, RefManager *_m) { ptr = _ptr, m = _m; } Ref() { ptr = m = NULL; } }; template T& GetRef(Ref r, T *x = NULL) { ASSERT(ValueTypeNo(*x) == r.GetType()); return *(T *) r.GetVoidPtr(); } inline String& RefString(Ref f) { return GetRef(f); } inline WString& RefWString(Ref f) { return GetRef(f); } inline int& RefInt(Ref f) { return GetRef(f); } inline int64& RefInt64(Ref f) { return GetRef(f); } inline double& RefDouble(Ref f) { return GetRef(f); } inline Date& RefDate(Ref f) { return GetRef(f); } inline Time& RefTime(Ref f) { return GetRef