mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
656 lines
No EOL
13 KiB
C++
656 lines
No EOL
13 KiB
C++
#include "Core.h"
|
|
|
|
namespace Upp {
|
|
|
|
static String sAsString(const Vector<Value>& v);
|
|
|
|
#define LTIMING(x) // RTIMING(x)
|
|
|
|
struct Ref::ValueRef : public RefManager {
|
|
virtual int GetType() { return VALUE_V; }
|
|
virtual Value GetValue(const void *ptr) { return *(Value *) ptr; }
|
|
virtual bool IsNull(const void *ptr) { return UPP::IsNull(*(Value *) ptr); }
|
|
virtual void SetValue(void *ptr, const Value& v) { *(Value *) ptr = v; }
|
|
virtual void SetNull(void *ptr) { *(Value *) ptr = Null; }
|
|
};
|
|
|
|
Ref::Ref(String& s) { ptr = &s; m = &Single< StdRef<String> >(); }
|
|
Ref::Ref(WString& s) { ptr = &s; m = &Single< StdRef<WString> >(); }
|
|
Ref::Ref(int& i) { ptr = &i; m = &Single< StdRef<int> >(); }
|
|
Ref::Ref(int64& i) { ptr = &i; m = &Single< StdRef<int64> >(); }
|
|
Ref::Ref(double& d) { ptr = &d; m = &Single< StdRef<double> >(); }
|
|
Ref::Ref(float& f) { ptr = &f; m = &Single< StdRef<float> >(); }
|
|
Ref::Ref(bool& b) { ptr = &b; m = &Single< StdRef<bool> >(); }
|
|
Ref::Ref(Date& d) { ptr = &d; m = &Single< StdRef<Date> >(); }
|
|
Ref::Ref(Time& t) { ptr = &t; m = &Single< StdRef<Time> >(); }
|
|
Ref::Ref(Value& v) { ptr = &v; m = &Single< ValueRef >(); }
|
|
|
|
// ----------------------------------
|
|
|
|
bool ValueArray::Data::IsNull() const
|
|
{
|
|
return data.IsEmpty();
|
|
}
|
|
|
|
void ValueArray::Data::Serialize(Stream& s)
|
|
{
|
|
s % data;
|
|
}
|
|
|
|
void ValueArray::Data::Jsonize(JsonIO& jio)
|
|
{
|
|
Upp::Jsonize(jio, data);
|
|
}
|
|
|
|
void ValueArray::Data::Xmlize(XmlIO& io)
|
|
{
|
|
Upp::Xmlize(io, data);
|
|
}
|
|
|
|
hash_t ValueArray::Data::GetHashValue() const
|
|
{
|
|
CombineHash w(data.GetCount());
|
|
for(int i = 0; i < data.GetCount(); i++)
|
|
w.Put(data[i].GetHashValue());
|
|
return w;
|
|
}
|
|
|
|
bool ValueArray::Data::IsEqual(const Value::Void *p)
|
|
{
|
|
return ((Data *)p)->data == data;
|
|
}
|
|
|
|
int ValueArray::Data::Compare(const Value::Void *p)
|
|
{
|
|
return data.Compare(((Data *)p)->data);
|
|
}
|
|
|
|
bool ValueArray::operator==(const ValueArray& v) const
|
|
{
|
|
return v.data->data == data->data;
|
|
}
|
|
|
|
int ValueArray::Compare(const ValueArray& b) const
|
|
{
|
|
return data->data.Compare(b.data->data);
|
|
}
|
|
|
|
static String sAsString(const Vector<Value>& v)
|
|
{
|
|
String s;
|
|
s << "[";
|
|
for(int i = 0; i < v.GetCount(); i++) {
|
|
if(i) s << ", ";
|
|
s << v[i];
|
|
}
|
|
s << "]";
|
|
return s;
|
|
}
|
|
|
|
String ValueArray::Data::AsString() const
|
|
{
|
|
return sAsString(data);
|
|
}
|
|
|
|
Vector<Value> ValueArray::VoidData;
|
|
|
|
Vector<Value>& ValueArray::Create()
|
|
{
|
|
data = new Data;
|
|
return data->data;
|
|
}
|
|
|
|
Vector<Value>& ValueArray::Clone() {
|
|
if(data->GetRefCount() != 1) {
|
|
Data *d = new Data;
|
|
d->data = clone(data->data);
|
|
data->Release();
|
|
data = d;
|
|
}
|
|
return data->data;
|
|
}
|
|
|
|
void ValueArray::Init0()
|
|
{
|
|
data = &Single<NullData>();
|
|
data->Retain();
|
|
}
|
|
|
|
ValueArray::ValueArray(const ValueArray& v) {
|
|
data = v.data;
|
|
data->Retain();
|
|
}
|
|
|
|
ValueArray::ValueArray(ValueArray&& v) {
|
|
data = v.data;
|
|
v.Init0();
|
|
}
|
|
|
|
ValueArray::ValueArray(Vector<Value>&& v)
|
|
{
|
|
Create() = pick(v);
|
|
}
|
|
|
|
ValueArray::ValueArray(const Vector<Value>& v, int deep)
|
|
{
|
|
Create() = clone(v);
|
|
}
|
|
|
|
ValueArray::operator Value() const {
|
|
data->Retain();
|
|
return Value(data, VALUEARRAY_V);
|
|
}
|
|
|
|
ValueArray::ValueArray(const Value& src)
|
|
{
|
|
if(!UPP::IsNull(src)) {
|
|
if(src.Is<ValueMap>()) {
|
|
ValueArray v = ValueMap(src);
|
|
data = v.data;
|
|
data->Retain();
|
|
return;
|
|
}
|
|
else {
|
|
if(src.GetType() != VALUEARRAY_V)
|
|
throw ValueTypeError(String().Cat() << "Invalid value conversion: "
|
|
<< src.GetTypeName() << " -> ValueArray",
|
|
src, VALUEARRAY_V);
|
|
data = (ValueArray::Data *)src.GetVoidPtr();
|
|
}
|
|
}
|
|
else
|
|
data = &Single<NullData>();
|
|
data->Retain();
|
|
}
|
|
|
|
void ValueArray::Serialize(Stream& s) {
|
|
if(s.IsLoading()) {
|
|
data->Release();
|
|
Create();
|
|
}
|
|
data->Serialize(s);
|
|
}
|
|
|
|
void ValueArray::Jsonize(JsonIO& jio)
|
|
{
|
|
if(jio.IsLoading()) {
|
|
data->Release();
|
|
Create();
|
|
}
|
|
data->Jsonize(jio);
|
|
}
|
|
|
|
void ValueArray::Xmlize(XmlIO& xio)
|
|
{
|
|
if(xio.IsLoading()) {
|
|
data->Release();
|
|
Create();
|
|
}
|
|
data->Xmlize(xio);
|
|
}
|
|
|
|
String ValueArray::ToString() const
|
|
{
|
|
return sAsString(Get());
|
|
}
|
|
|
|
ValueArray::~ValueArray() {
|
|
ASSERT(data->GetRefCount() > 0);
|
|
data->Release();
|
|
}
|
|
|
|
ValueArray& ValueArray::operator=(const ValueArray& v) {
|
|
v.data->Retain();
|
|
data->Release();
|
|
data = v.data;
|
|
return *this;
|
|
}
|
|
|
|
void ValueArray::SetCount(int n)
|
|
{
|
|
Clone().SetCount(n);
|
|
}
|
|
|
|
void ValueArray::SetCount(int n, const Value& v)
|
|
{
|
|
Clone().SetCount(n, v);
|
|
}
|
|
|
|
void ValueArray::Clear() {
|
|
Clone().Clear();
|
|
}
|
|
|
|
void ValueArray::Add(const Value& v) {
|
|
Clone().Add(v);
|
|
}
|
|
|
|
void ValueArray::Set(int i, const Value& v) {
|
|
#if !defined(_MSC_VER) || _MSC_VER > 1310
|
|
ASSERT(i >= 0);
|
|
Clone().At(i) = v;
|
|
#else
|
|
throw 0;
|
|
#endif
|
|
}
|
|
|
|
Value& ValueArray::At(int i)
|
|
{
|
|
return Clone().At(i);
|
|
}
|
|
|
|
void ValueArray::Remove(int i, int count)
|
|
{
|
|
Clone().Remove(i, count);
|
|
}
|
|
|
|
void ValueArray::Remove(const Vector<int>& ii)
|
|
{
|
|
Clone().Remove(ii);
|
|
}
|
|
|
|
void ValueArray::Insert(int i, const ValueArray& va)
|
|
{
|
|
if(va.data == data) {
|
|
ValueArray va2 = va;
|
|
Clone().Insert(i, va2.Get());
|
|
}
|
|
else
|
|
Clone().Insert(i, va.Get());
|
|
}
|
|
|
|
const Value& ValueArray::Get(int i) const {
|
|
ASSERT(i >= 0 && i < GetCount());
|
|
return data->data[i];
|
|
}
|
|
|
|
Value ValueArray::GetAndClear(int i)
|
|
{
|
|
ASSERT(i >= 0 && i < GetCount());
|
|
Vector<Value>& x = Clone();
|
|
Value v = x[i];
|
|
x[i] = Value();
|
|
return v;
|
|
}
|
|
|
|
Vector<Value> ValueArray::Pick()
|
|
{
|
|
Vector<Value>& x = Clone();
|
|
Vector<Value> r = pick(x);
|
|
x.Clear();
|
|
return r;
|
|
}
|
|
|
|
template<>
|
|
String AsString(const ValueArray& v) {
|
|
return sAsString(v.Get());
|
|
}
|
|
|
|
bool ValueMap::Data::IsNull() const {
|
|
return this == &Single<ValueMap::NullData>();
|
|
}
|
|
|
|
void ValueMap::Data::Serialize(Stream& s) {
|
|
s % key % value;
|
|
if(key.GetCount() != value.GetCount())
|
|
s.LoadError();
|
|
}
|
|
|
|
void ValueMap::Data::Xmlize(XmlIO& xio)
|
|
{
|
|
Upp::Xmlize(xio, key);
|
|
Upp::Xmlize(xio, value);
|
|
}
|
|
|
|
void ValueMap::Data::Jsonize(JsonIO& jio)
|
|
{
|
|
if(jio.IsStoring()) {
|
|
ValueArray va;
|
|
int n = min(value.GetCount(), key.GetCount());
|
|
for(int i = 0; i < n; i++) {
|
|
ValueMap m;
|
|
m.Add("key", StoreAsJsonValue(key[i]));
|
|
m.Add("value", StoreAsJsonValue(value[i]));
|
|
va.Add(m);
|
|
}
|
|
jio.Set(va);
|
|
}
|
|
else {
|
|
Value va = jio.Get();
|
|
key.Clear();
|
|
value.Clear();
|
|
for(int i = 0; i < va.GetCount(); i++) {
|
|
Value k, v;
|
|
LoadFromJsonValue(k, va[i]["key"]);
|
|
LoadFromJsonValue(v, va[i]["value"]);
|
|
key.Add(k);
|
|
value.Add(v);
|
|
}
|
|
}
|
|
}
|
|
|
|
hash_t ValueMap::Data::GetHashValue() const {
|
|
CombineHash w(key.GetCount());
|
|
for(int i = 0; i < key.GetCount(); i++)
|
|
w.Put(key[i].GetHashValue());
|
|
w.Put(value.GetHashValue());
|
|
return w;
|
|
}
|
|
|
|
static bool sIsEqual(const Index<Value>& a, const Index<Value>& b)
|
|
{
|
|
if(&a == &b) return true;
|
|
if(a.GetCount() != b.GetCount()) return false;
|
|
for(int i = 0; i < a.GetCount(); i++)
|
|
if(a[i] != b[i]) return false;
|
|
return true;
|
|
}
|
|
|
|
bool ValueMap::Data::IsEqual(const Value::Void *p)
|
|
{
|
|
return sIsEqual(((Data *)p)->key, key) && ((Data *)p)->value == value;
|
|
}
|
|
|
|
bool ValueMap::operator==(const ValueMap& v) const
|
|
{
|
|
return sIsEqual(data->key, v.data->key) && data->value == v.data->value;
|
|
}
|
|
|
|
int ValueMap::Data::Compare(const Value::Void *p)
|
|
{
|
|
Data *b = (Data *)p;
|
|
int n = min(key.GetCount(), b->key.GetCount());
|
|
for(int i = 0; i < n; i++) {
|
|
int q = SgnCompare(key[i], b->key[i]);
|
|
if(q)
|
|
return q;
|
|
q = SgnCompare(value[i], b->value[i]);
|
|
if(q)
|
|
return q;
|
|
}
|
|
return SgnCompare(key.GetCount(), b->key.GetCount());
|
|
}
|
|
|
|
int ValueMap::Compare(const ValueMap& b) const
|
|
{
|
|
return data->Compare((Value::Void *)b.data);
|
|
}
|
|
|
|
bool ValueMap::IsSame(const ValueMap& b) const
|
|
{
|
|
for(int pass = 0; pass < 2; pass++) {
|
|
const ValueMap& m = pass ? *this : b;
|
|
const ValueMap& n = pass ? b : *this;
|
|
for(int i = 0; i < m.GetCount(); i++)
|
|
if(!n[m.GetKey(i)].IsSame(m.GetValue(i)))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
String ValueMap::Data::AsString() const
|
|
{
|
|
String s;
|
|
s << "{ ";
|
|
for(int i = 0; i < key.GetCount(); i++) {
|
|
if(i) s << ", ";
|
|
s << key[i] << ": " << value[i];
|
|
}
|
|
s << " }";
|
|
return s;
|
|
}
|
|
|
|
ValueMap::Data& ValueMap::Create()
|
|
{
|
|
data = new Data;
|
|
return *data;
|
|
}
|
|
|
|
void ValueMap::Clone(Data *&ptr)
|
|
{
|
|
Data *d = new Data;
|
|
d->key = clone(ptr->key);
|
|
d->value = ptr->value;
|
|
ptr->Release();
|
|
ptr = d;
|
|
}
|
|
|
|
void ValueMap::Init0()
|
|
{
|
|
data = &Single<NullData>();
|
|
data->Retain();
|
|
}
|
|
|
|
ValueMap::ValueMap(const ValueMap& v)
|
|
{
|
|
data = v.data;
|
|
data->Retain();
|
|
}
|
|
|
|
ValueMap::ValueMap(Index<Value>&& k, Vector<Value>&& v)
|
|
{
|
|
Data& d = Create();
|
|
d.key = pick(k);
|
|
d.value = ValueArray(pick(v));
|
|
}
|
|
|
|
ValueMap::ValueMap(VectorMap<Value, Value>&& m)
|
|
{
|
|
Data& d = Create();
|
|
d.key = m.PickKeys();
|
|
d.value = ValueArray(m.PickValues());
|
|
}
|
|
|
|
ValueMap::ValueMap(const Index<Value>& k, const Vector<Value>& v, int deep)
|
|
{
|
|
Data& d = Create();
|
|
d.key = clone(k);
|
|
d.value = ValueArray(v, 0);
|
|
}
|
|
|
|
ValueMap::ValueMap(const VectorMap<Value, Value>& m, int deep)
|
|
{
|
|
Data& d = Create();
|
|
d.key = clone(m.GetKeys());
|
|
d.value = ValueArray(m.GetValues(), 0);
|
|
}
|
|
|
|
VectorMap<Value, Value> ValueMap::Pick()
|
|
{
|
|
Data& d = UnShare();
|
|
VectorMap<Value, Value> m(d.key.PickKeys(), d.value.Pick());
|
|
d.key.Clear();
|
|
return m;
|
|
}
|
|
|
|
ValueMap::operator Value() const {
|
|
data->Retain();
|
|
return Value(data, VALUEMAP_V);
|
|
}
|
|
|
|
void ValueMap::FromArray(const ValueArray& va)
|
|
{
|
|
Init0();
|
|
for(int i = 0; i < va.GetCount(); i++)
|
|
Add(i, va[i]);
|
|
}
|
|
|
|
ValueMap::ValueMap(const Value& src)
|
|
{
|
|
if(!IsNull(src)) {
|
|
if(src.Is<ValueArray>()) {
|
|
FromArray(src);
|
|
return;
|
|
}
|
|
else {
|
|
if(src.GetType() != VALUEMAP_V)
|
|
throw ValueTypeError(String().Cat() << "Invalid value conversion: "
|
|
<< src.GetTypeName() << " -> ValueMap",
|
|
src, VALUEMAP_V);
|
|
data = (ValueMap::Data *)src.GetVoidPtr();
|
|
}
|
|
}
|
|
else
|
|
data = &Single<NullData>();
|
|
data->Retain();
|
|
}
|
|
|
|
void ValueMap::Serialize(Stream& s) {
|
|
if(s.IsLoading()) {
|
|
data->Release();
|
|
Create();
|
|
}
|
|
data->Serialize(s);
|
|
}
|
|
|
|
void ValueMap::Jsonize(JsonIO& jio)
|
|
{
|
|
if(jio.IsLoading()) {
|
|
data->Release();
|
|
Create();
|
|
}
|
|
data->Jsonize(jio);
|
|
}
|
|
|
|
void ValueMap::Xmlize(XmlIO& xio)
|
|
{
|
|
if(xio.IsLoading()) {
|
|
data->Release();
|
|
Create();
|
|
}
|
|
data->Xmlize(xio);
|
|
}
|
|
|
|
ValueMap::~ValueMap() {
|
|
ASSERT(data->GetRefCount() > 0);
|
|
data->Release();
|
|
}
|
|
|
|
ValueMap& ValueMap::operator=(const ValueMap& v) {
|
|
v.data->Retain();
|
|
data->Release();
|
|
data = v.data;
|
|
return *this;
|
|
}
|
|
|
|
void ValueMap::Clear() {
|
|
data->Release();
|
|
Init0();
|
|
}
|
|
|
|
void ValueMap::Set(const Value& key, const Value& value)
|
|
{
|
|
Data& d = UnShare();
|
|
int i = d.key.Find(key);
|
|
if(i >= 0)
|
|
d.value.Set(i, value);
|
|
else {
|
|
d.key.Add(key);
|
|
d.value.Add(value);
|
|
}
|
|
}
|
|
|
|
void ValueMap::SetAt(int i, const Value& v) {
|
|
UnShare().value.Set(i, v);
|
|
}
|
|
|
|
void ValueMap::SetKey(int i, const Value& k) {
|
|
UnShare().key.Set(i, k);
|
|
}
|
|
|
|
int ValueMap::RemoveKey(const Value& key)
|
|
{
|
|
Data& d = UnShare();
|
|
Vector<int> rk;
|
|
int q = d.key.Find(key);
|
|
while(q >= 0) {
|
|
rk.Add(q);
|
|
q = d.key.FindNext(q);
|
|
}
|
|
if(rk.GetCount()) {
|
|
Sort(rk);
|
|
d.key.Remove(rk);
|
|
d.value.Remove(rk);
|
|
}
|
|
return rk.GetCount();
|
|
}
|
|
|
|
void ValueMap::Remove(int i)
|
|
{
|
|
Data& d = UnShare();
|
|
d.key.Remove(i);
|
|
d.value.Remove(i);
|
|
}
|
|
|
|
Value ValueMap::GetAndClear(const Value& key)
|
|
{
|
|
Data& d = UnShare();
|
|
int q = d.key.Find(key);
|
|
return q < 0 ? ErrorValue() : d.value.GetAndClear(q);
|
|
}
|
|
|
|
// ----------------------------------
|
|
|
|
bool StdValuePairOrder::operator()(const Value& k1, const Value& v1, const Value& k2, const Value& v2) const
|
|
{
|
|
int q = StdValueCompare(k1, k2, language);
|
|
if(q) return q < 0;
|
|
return StdValueCompare(v1, v2, language);
|
|
}
|
|
|
|
bool FnValuePairOrder::operator()(const Value& keya, const Value& valuea, const Value& keyb, const Value& valueb) const
|
|
{
|
|
return (*fn)(keya, valuea, keyb, valueb) < 0;
|
|
}
|
|
|
|
int CompareStrings(const Value& a, const Value& b, const LanguageInfo& f)
|
|
{
|
|
return f.Compare(WString(a), WString(b));
|
|
}
|
|
|
|
void Complex::Xmlize(XmlIO& xio)
|
|
{
|
|
double r, i;
|
|
r = real(); i = imag();
|
|
xio.Attr("real", r).Attr("imag", i);
|
|
*this = C(r, i);
|
|
}
|
|
|
|
void Complex::Jsonize(JsonIO& jio)
|
|
{
|
|
double r, i;
|
|
r = real(); i = imag();
|
|
jio("real", r)("imag", i);
|
|
*this = C(r, i);
|
|
}
|
|
|
|
void Complex::Serialize(Stream& s)
|
|
{
|
|
double r, i;
|
|
r = real(); i = imag();
|
|
s % r % i;
|
|
*this = C(r, i);
|
|
}
|
|
|
|
template <class T>
|
|
static void sReg(const char *name)
|
|
{
|
|
if(FitsSvoValue<T>())
|
|
Value::SvoRegister<T>(name);
|
|
else
|
|
Value::Register<T>(name);
|
|
}
|
|
|
|
INITBLOCK
|
|
{
|
|
sReg<Point>("Point");
|
|
sReg<Point64>("Point64");
|
|
sReg<Pointf>("Pointf");
|
|
sReg<Size>("Size");
|
|
sReg<Size64>("Size64");
|
|
sReg<Sizef>("Sizef");
|
|
Value::Register<Rect>("Rect");
|
|
Value::Register<Rect64>("Rect64");
|
|
Value::Register<Rectf>("Rectf");
|
|
}
|
|
|
|
} |