/* Web Polygraph http://www.web-polygraph.org/ * (C) 2003-2006 The Measurement Factory * Licensed under the Apache License, Version 2.0 */ #include "pgl/pgl.h" #include "xstd/StrIdentifier.h" #include "xstd/TblDistr.h" #include "pgl/PglCtx.h" #include "pgl/PglRec.h" #include "pgl/PglRecSym.h" #include "pgl/PglBoolSym.h" #include "pgl/PglIntSym.h" #include "pgl/PglNumSym.h" #include "pgl/PglSizeSym.h" #include "pgl/PglRateSym.h" #include "pgl/PglBwidthSym.h" #include "pgl/PglDistrSym.h" #include "pgl/PglStringSym.h" #include "pgl/PglNetAddrSym.h" #include "pgl/PglTimeSym.h" #include "pgl/PglArraySym.h" String RecSym::TheType = "Rec"; static String strDistr = "Distr"; RecSym::~RecSym() { delete theRec; } bool RecSym::isA(const String &type) const { return ExpressionSym::isA(type) || type == TheType; } SynSym *RecSym::dupe(const String &type) const { Assert(theRec); if (isA(type)) return new RecSym(this->type(), theRec->clone()); else return ExpressionSym::dupe(type); } bool RecSym::empty() const { const int symCount = theRec->count(); for (int i = 0; i < symCount; ++i) { if (const SynSym *ss = theRec->valAt(i)->sym()) { // empty() is recursive for items that are records if (ss->isA(TheType) && ((const RecSym&)ss->cast(TheType)).empty()) continue; return false; } } return true; } SynSymTblItem **RecSym::memberItem(const String &name) { return rec()->valp(name); } ostream &RecSym::print(ostream &os, const String &pfx) const { os << '{' << endl; if (theRec) theRec->report(os, pfx + " "); os << pfx << '}'; return os; } bool RecSym::getBool(const String &name, bool &set) const { SynSymTblItem *bi = 0; Assert(theRec); Assert(theRec->find(name, bi)); if (bi->sym()) set = ((const BoolSym&)bi->sym()->cast(BoolSym::TheType)).val(); return bi->sym() != 0; } bool RecSym::getInt(const String &name, int &n) const { SynSymTblItem *ii = 0; Assert(theRec); Assert(theRec->find(name, ii)); if (ii->sym()) n = ((const IntSym&)ii->sym()->cast(IntSym::TheType)).val(); return ii->sym() != 0; } bool RecSym::getDouble(const String &name, double &n) const { SynSymTblItem *di = 0; Assert(theRec); Assert(theRec->find(name, di)); if (di->sym()) n = ((const NumSym&)di->sym()->cast(NumSym::TheType)).val(); return di->sym() != 0; } Time RecSym::getTime(const String &name) const { SynSymTblItem *ti = 0; Assert(theRec); Assert(theRec->find(name, ti)); return ti->sym() ? ((const TimeSym&)ti->sym()->cast(TimeSym::TheType)).val() : Time(); } RndDistr *RecSym::getDistr(const String &name) const { const String typeName = strDistr; SynSymTblItem *di = 0; Assert(theRec); Assert(theRec->find(name, di)); return di->sym() ? ((const DistrSym&)di->sym()->cast(typeName)).val() : 0; } String RecSym::getString(const String &name) const { SynSymTblItem *ni = 0; Assert(theRec->find(name, ni)); return ni->sym() ? ((const StringSym&)ni->sym()->cast(StringSym::TheType)).val() : String(); } NetAddr RecSym::getNetAddr(const String &name) const { SynSymTblItem *ni = 0; Assert(theRec->find(name, ni)); return ni->sym() ? ((const NetAddrSym&)ni->sym()->cast(NetAddrSym::TheType)).val() : NetAddr(); } bool RecSym::getSize(const String &name, BigSize &sz) const { SynSymTblItem *ni = 0; Assert(theRec->find(name, ni)); if (!ni->sym()) return false; sz = ((const SizeSym&)ni->sym()->cast(SizeSym::TheType)).val(); return true; } bool RecSym::getRate(const String &name, double &rate) const { SynSymTblItem *ri = 0; Assert(theRec->find(name, ri)); if (ri->sym()) rate = ((const RateSym&)ri->sym()->cast(RateSym::TheType)).val(); return ri->sym() != 0; } bool RecSym::getBwidth(const String &name, Bwidth &bw) const { SynSymTblItem *bi = 0; Assert(theRec->find(name, bi)); if (!bi->sym()) return false; bw = ((const BwidthSym&)bi->sym()->cast(BwidthSym::TheType)).val(); return true; } bool RecSym::getNetAddrs(const String &name, Array &addrs) const { SynSymTblItem *si = 0; Assert(theRec->find(name, si)); if (!si->sym()) return false; ArraySym &ss = (ArraySym&)si->sym()->cast(ArraySym::TheType); for (int i = 0; i < ss.count(); ++i) { const NetAddr &addr = ((const NetAddrSym&)ss[i]->cast(NetAddrSym::TheType)).val(); addrs.append(new NetAddr(addr)); } return true; } ContainerSym *RecSym::getContainerSym(const String &name) const { SynSymTblItem *contsi = 0; Assert(theRec); Assert(theRec->find(name, contsi)); if (!contsi->sym()) return 0; ContainerSym &cont = (ContainerSym&)contsi->sym()->cast(ContainerSym::TheType); return cont.count() > 0 ? &cont : 0; } ArraySym *RecSym::getArraySym(const String &name) const { SynSymTblItem *arrsi = 0; Assert(theRec); Assert(theRec->find(name, arrsi)); if (!arrsi->sym()) return 0; ArraySym &arr = (ArraySym&)arrsi->sym()->cast(ArraySym::TheType); return arr.count() > 0 ? &arr : 0; } bool RecSym::getStrings(const String &name, Array &strs) const { if (ArraySym *as = getArraySym(name)) { const int count = as->count(); strs.stretch(strs.count() + count); for (int i = 0; i < count; ++i) { const String &str = ((const StringSym&)as->item(i)->cast(StringSym::TheType)).val(); strs.append(new String(str)); } return true; } return false; } bool RecSym::getStringArray(const String &name, StringArray &strs) const { if (ContainerSym *s = getContainerSym(name)) { s->toStringArray(strs); return true; } return false; } RndDistr *RecSym::namesToDistr(const String &fieldName, const StrIdentifier &names) const { Assert(names.count()); SynSymTblItem *fti = 0; Assert(theRec->find(fieldName, fti)); if (!fti->sym()) return 0; // undefined // build selector using label index ArraySym &nts = (ArraySym&)fti->sym()->cast(ArraySym::TheType); Array probs_in(names.count()); Array probs_out(names.count()); nts.copyProbs(probs_in); for (int p = 0; p < probs_in.count(); ++p) { const String &name = ((const StringSym&)nts[p]->cast(StringSym::TheType)).val(); const int id = names.lookup(name); if (id <= 0) { cerr << loc() << "unknown quoted name `" << name << "'; known names within " << fieldName << " context are:"; for (StrIdentifier::Iter i = names.iterator(); i; ++i) cerr << " \"" << i.str() << '"'; cerr << endl; exit(-2); } if (probs_in[p] > 0) probs_out.put(probs_in[p], id); } if (!probs_out.count()) return 0; return TblDistr::FromDistrTable(type() + "-" + fieldName, probs_out); } RecSym *RecSym::getRecSym(const String &name, bool emptyOk) const { SynSymTblItem *rsi = 0; Assert(theRec); Assert(theRec->find(name, rsi)); if (!rsi->sym()) return 0; RecSym &rs = (RecSym&)rsi->sym()->cast(TheType); return rs.empty() && !emptyOk ? 0 : &rs; }