#include struct SVal::SValMap { Atomic refcount; ArrayMap map; void Retain() { AtomicInc(refcount); } void Release() { if(AtomicDec(refcount) == 0) delete this; } SValMap *Copy(); SValMap *Clone(); SValMap() { AtomicWrite(refcount, 1); } }; struct SVal::SLambdaRef : SLambda { Atomic refcount; void Retain() { AtomicInc(refcount); } void Release() { if(AtomicDec(refcount) == 0) delete this; } SLambdaRef() { refcount = 1; } }; SVal::SValMap *SVal::SValMap::Copy() { SValMap *c = new SValMap; c->map <<= map; return c; } SVal::SValMap *SVal::SValMap::Clone() { if(AtomicRead(refcount) == 1) return this; SValMap *c = Copy(); Release(); return c; } SVal::SVal() { type = SV_VOID; } void SVal::Free() { string.Clear(); if(type == SV_MAP) map->Release(); if(type == SV_LAMBDA) lambda->Release(); } SVal::~SVal() { Free(); } void SVal::Assign(const SVal& s) { type = s.type; if(type == SV_MAP) { map = s.map; ipos = s.ipos; map->Retain(); } else if(type == SV_LAMBDA) { lambda = s.lambda; lambda->Retain(); } else { string = s.string; number = s.number; } } void SVal::operator=(const SVal& s) { Free(); Assign(s); } const ArrayMap& SVal::GetMap() const { ASSERT(IsMap()); return map->map; } void SVal::SetMap() { if(type == SV_MAP) map = map->Clone(); else { map = new SValMap(); ipos = 0; type = SV_MAP; } } SVal::SVal(const SVal& s) { Assign(s); } void SVal::operator=(const Nuller&) { Free(); type = SV_VOID; } void SVal::operator=(double n) { Free(); type = SV_NUMBER; number = n; } void SVal::operator=(const String& s) { Free(); type = SV_STRING; string = s; } SVal::SVal(const String& s) { type = SV_STRING; string = s; } SVal::SVal(const Nuller& s) { type = SV_VOID; } SVal::SVal(double n) { type = SV_NUMBER; number = n; } SLambda& SVal::CreateLambda() { Free(); lambda = new SLambdaRef; type = SV_LAMBDA; return *lambda; } const SLambda& SVal::GetLambda() const { ASSERT(IsLambda()); return *lambda; } SVal& SVal::Set(SVal key) { SetMap(); if(key.IsNumber()) ipos = key.GetNumber() + 1; return map->map.GetAdd(key); } SVal& SVal::Add() { SetMap(); return map->map.GetAdd(ipos++); } unsigned SVal::GetHashValue() const { switch(type) { case SV_NUMBER: return ::GetHashValue(number); case SV_STRING: return ::GetHashValue(string); case SV_MAP: unsigned hash = 0; for(int i = 0; i < map->map.GetCount(); i++) hash ^= ::GetHashValue(map->map.GetKey(i)) ^ ::GetHashValue(map->map[i]); return hash; } return 0; } bool SVal::operator==(const SVal& a) const { switch(type) { case SV_VOID: return a.type == SV_VOID; case SV_NUMBER: return a.type == SV_NUMBER && number == a.number; case SV_STRING: return a.type == SV_STRING && string == a.string; case SV_MAP: if(a.type != SV_MAP) return false; if(map->map.GetCount() != a.map->map.GetCount()) return false; for(int i = 0; i < map->map.GetCount(); i++) { SVal key = map->map.GetKey(i); int q = a.map->map.Find(key); if(q < 0) return false; if(map->map[i] != a.map->map[q]) return false; } return true; } return false; } String SVal::Dump() const { String r; int i; switch(type) { case SV_NUMBER: return Format("%g", number); case SV_STRING: return AsCString(string); case SV_LAMBDA: r = "@("; for(i = 0; i < lambda->arg.GetCount(); i++) { if(i) r << ", "; if(lambda->ref[i]) r << "&"; r << lambda->arg[i]; } r << ")\n" << lambda->code; return r; case SV_MAP: r << "{ "; for(i = 0; i < map->map.GetCount(); i++) { if(i) r << ", "; r << map->map.GetKey(i).Dump() << ":" << map->map[i].Dump(); } r << " }"; return r; } return "void"; } bool IsTrue(const SVal& a) { if(a.IsNumber()) return a.GetNumber(); if(a.IsString()) return a.GetString().GetLength(); if(a.IsMap()) return a.GetMap().GetCount(); return false; }