ultimatepp/uppsrc/Esc/EscValue.cpp

354 lines
7 KiB
C++

#include <Esc/Esc.h>
namespace Upp {
#define LTIMING(x) // RTIMING(x)
String EscTypeName(int sv_type)
{
switch(sv_type)
{
case ESC_VOID: return "void";
case ESC_DOUBLE: return "double";
case ESC_INT64: return "int64";
case ESC_ARRAY: return "array";
case ESC_MAP: return "map";
case ESC_LAMBDA: return "lambda";
default: return Format("unknown(%d)", sv_type);
}
}
void EscValue::Free()
{
LTIMING("Free");
if(type == ESC_ARRAY)
array->Release();
if(type == ESC_MAP)
map->Release();
if(type == ESC_LAMBDA)
lambda->Release();
type = ESC_VOID;
}
EscValue::~EscValue()
{
LTIMING("~EscValue");
Free();
}
void EscValue::Assign(const EscValue& s)
{
LTIMING("Assign");
type = s.type;
switch(type) {
case ESC_ARRAY:
array = s.array;
array->Retain();
break;
case ESC_MAP:
map = s.map;
map->Retain();
break;
case ESC_LAMBDA:
lambda = s.lambda;
lambda->Retain();
break;
case ESC_DOUBLE:
number = s.number;
break;
case ESC_INT64:
i64 = s.i64;
break;
}
}
EscValue& EscValue::operator=(const EscValue& s)
{
LTIMING("Sval=Sval");
Free();
Assign(s);
return *this;
}
EscValue::EscValue(const EscValue& s)
{
LTIMING("Sval(Sval)");
Assign(s);
}
EscLambda& EscValue::CreateLambda()
{
Free();
lambda = new EscLambda;
type = ESC_LAMBDA;
return *lambda;
}
const EscLambda& EscValue::GetLambda() const
{
ASSERT(IsLambda());
return *lambda;
}
int EscValue::GetCount() const
{
switch(type) {
case ESC_VOID:
return 0;
case ESC_ARRAY:
return array->array.GetCount();
case ESC_MAP:
return map->count;
}
return 1;
}
hash_t EscValue::GetHashValue() const
{
LTIMING("GetHashValue");
switch(type) {
case ESC_VOID:
return 1;
case ESC_DOUBLE:
return Upp::GetHashValue(number);
case ESC_INT64:
return Upp::GetHashValue(i64);
case ESC_ARRAY:
if(!array->cached_hash) {
CombineHash h;
for(int i = 0; i < array->array.GetCount(); i++)
h << array->array[i].GetHashValue();
array->cached_hash = h | 0x4000000;
}
return array->cached_hash;
case ESC_MAP:
if(!map->cached_hash) {
CombineHash h;
for(int i = 0; i < map->map.GetCount(); i++)
h << map->map.GetKey(i).GetHashValue() << map->map[i].GetHashValue();
map->cached_hash = h | 0x4000000;
}
return map->cached_hash;
case ESC_LAMBDA:
return Upp::GetHashValue(lambda->code);
}
return 0;
}
template <class T>
bool EqVector(const T& a, const T& b)
{
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 EscValue::operator==(const EscValue& a) const
{
LTIMING("operator==");
int i;
switch(type) {
case ESC_VOID:
return a.type == ESC_VOID;
case ESC_INT64:
if(a.type == ESC_INT64)
return i64 == a.i64;
case ESC_DOUBLE:
return a.IsNumber() && GetNumber() == a.GetNumber();
case ESC_ARRAY:
if(a.type != ESC_ARRAY) return false;
if(array->array.GetCount() != a.array->array.GetCount())
return false;
return EqVector(array->array, a.array->array);
case ESC_MAP: {
if(a.type != ESC_MAP) return false;
const VectorMap<EscValue, EscValue>& x = GetMap();
const VectorMap<EscValue, EscValue>& y = a.GetMap();
for(i = 0; i < x.GetCount(); i++)
if(!x.IsUnlinked(i)) {
int q = y.Find(x.GetKey(i));
if(q < 0)
return false;
if(x[i] != y[q])
return false;
}
for(i = 0; i < y.GetCount(); i++)
if(!y.IsUnlinked(i))
if(x.Find(y.GetKey(i)) < 0)
return false;
return true;
}
case ESC_LAMBDA:
return lambda->code == a.lambda->code &&
EqVector(lambda->arg, a.lambda->arg) && EqVector(lambda->inout, a.lambda->inout);
}
return false;
}
String EscValue::ToString(int maxlen, int indent_step, bool hex, int indent) const
{
String ind(' ', indent);
StringBuffer r;
String s;
int i;
switch(type) {
case ESC_DOUBLE:
{
s = ind;
if((int64)number == number)
s << FormatInt64((int64)number);
else
s << Format("%.8g", number);
if(hex && FitsInInt64(number) && (int64)number == number)
s << " 0x" << Format64Hex((int64)number);
if(hex && number >= 0 && number < 65536 && (int)number == number)
s << ' ' << AsCString(ToUtf8(WString((int)number, 1)));
return s;
}
case ESC_INT64:
{
s = ind;
s << FormatInt64(i64);
if(hex)
s << " 0x" << Format64Hex(i64);
if(hex && i64 >= 0 && i64 < 65536)
s << ' ' << AsCString(ToUtf8(WString((int)i64, 1)));
return s;
}
case ESC_ARRAY:
{
const Vector<EscValue>& a = GetArray();
int i;
int c = min(100, a.GetCount());
for(i = 0; i < a.GetCount(); i++) {
if(!a[i].IsInt())
break;
int c = a[i].GetInt();
if(c >= 32 && c < 256)
s.Cat(c);
else
break;
}
if(i < a.GetCount()) {
r << ind << "[ ";
for(i = 0; i < c; i++) {
if(i)
r << ", ";
r << array->array[i].ToString(maxlen, indent_step, hex, 0);
}
r << " ]";
if(r.GetLength() >= maxlen) {
r.Clear();
r << ind << "[\n";
for(i = 0; i < c; i++) {
if(i)
r << ",\n";
r << array->array[i].ToString(maxlen, indent_step, hex, indent + indent_step);
}
r << '\n' << ind << "]";
}
s = r;
}
else {
r << ind << '\"' << s << '\"';
s = r;
}
if(a.GetCount() > 100)
s << ind << "\n...more than 100 elements";
return s;
}
case ESC_LAMBDA:
r << ind << "@(";
for(i = 0; i < lambda->arg.GetCount(); i++) {
if(i)
r << ", ";
if(lambda->inout[i])
r << "&";
r << lambda->arg[i];
}
r << ")\n" << lambda->code;
return String(r);
case ESC_MAP:
r << ind << "{ ";
int c = min(map->map.GetCount(), 100);
bool q = false;
for(i = 0; i < c; i++) {
if(q)
r << ", ";
if(!map->map.IsUnlinked(i)) {
r << map->map.GetKey(i).ToString(maxlen, indent_step, hex, 0)
<< ":" << map->map[i].ToString(maxlen, indent_step, hex, 0);
q = true;
}
}
r << " }";
if(r.GetLength() >= maxlen) {
r.Clear();
r << ind << "{\n";
q = false;
for(i = 0; i < c; i++) {
if(q)
r << ",\n";
if(!map->map.IsUnlinked(i)) {
r << map->map.GetKey(i).ToString(maxlen, indent_step, hex, indent + indent_step)
<< ":\n" << map->map[i].ToString(maxlen, indent_step, hex, indent + indent_step);
q = true;
}
}
r << '\n' << ind << "}";
}
s = r;
if(map->map.GetCount() > 100)
s << ind << "\n...more than 100 elements";
return s;
}
return "void";
}
double EscValue::GetNumber() const
{
if(type == ESC_INT64)
return (double)i64;
if(type == ESC_DOUBLE)
return number;
return 0;
}
int64 EscValue::GetInt64() const
{
if(type == ESC_INT64)
return i64;
if(type == ESC_DOUBLE && number >= (double)INT64_MIN && number <= (double)INT64_MAX)
return (int64)number;
return 0;
}
bool EscValue::IsInt() const
{
if(IsInt64()) {
int64 n = GetInt64();
return n >= INT_MIN && n <= INT_MAX;
}
if(IsNumber()) {
double n = GetNumber();
return n >= INT_MIN && n <= INT_MAX;
}
return false;
}
int EscValue::GetInt() const
{
return IsInt() ? (int)GetInt64() : 0;
}
bool IsTrue(const EscValue& a)
{
if(a.IsNumber())
return a.GetNumber();
return a.GetCount();
}
}