ultimatepp/uppsrc/Esc/EscValue.cpp
mdelfede 263ff5f895 changed svn layout
git-svn-id: svn://ultimatepp.org/upp/trunk@281 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2008-06-07 22:31:27 +00:00

318 lines
6.3 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_NUMBER: return "number";
case ESC_ARRAY: return "array";
case ESC_MAP: return "map";
case ESC_LAMBDA: return "lambda";
default: return NFormat("unknown(%d)", sv_type);
}
}
int EscValue::total;
int EscValue::max_total = 1000000;
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;
hash = 0;
}
EscValue::~EscValue()
{
LTIMING("~EscValue");
total--;
Free();
}
void EscValue::Assign(const EscValue& s)
{
LTIMING("Assign");
type = s.type;
hash = s.hash;
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_NUMBER:
number = s.number;
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);
total++;
}
EscLambda& EscValue::CreateLambda()
{
Free();
lambda = new EscLambda;
type = ESC_LAMBDA;
hash = 0;
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;
}
unsigned EscValue::GetHashValue() const
{
LTIMING("GetHashValue");
if(hash == 0) {
switch(type) {
case ESC_VOID:
hash = 1;
break;
case ESC_NUMBER:
hash = UPP::GetHashValue(number) | 0x80000;
break;
case ESC_ARRAY:
for(int i = 0; i < array->array.GetCount(); i++)
hash = hash ^ array->array[i].GetHashValue();
hash |= 0x40000;
break;
case ESC_MAP:
for(int i = 0; i < map->map.GetCount(); i++)
if(!map->map[i].IsVoid())
hash ^= map->map.GetKey(i).GetHashValue() ^ map->map[i].GetHashValue();
hash |= 0x8000000;
break;
case ESC_LAMBDA:
hash = UPP::GetHashValue(lambda->code) | 0x4000000;
break;
}
}
return hash;
}
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_NUMBER:
return a.type == ESC_NUMBER && number == a.number;
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_NUMBER:
{
s = ind;
if((int64)number == number)
s << FormatInt64((int64)number);
else
s << Format("%.8g", number);
if(hex && number >= INT64_MIN && number <= INT64_MAX && (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_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 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";
}
bool EscValue::IsInt() const
{
return IsNumber() && number >= (double)INT_MIN && number <= (double)INT_MAX;
}
int EscValue::GetInt() const
{
return (int)minmax(GetNumber(), (double)INT_MIN, (double)INT_MAX);
}
bool IsTrue(const EscValue& a)
{
if(a.IsNumber())
return a.GetNumber();
return a.GetCount();
}
END_UPP_NAMESPACE