#include #include #include #include "type2name.h" #include "log.h" #include "min.h" #include "interface.h" /* action definitions (the stuff implementing the different reflection primtives) */ // (abstract) action (to implement filtering stuff) template class Action { public: Action(interface *ifc) : ifc(ifc) {} bool isFiltered(char *desc) { // true -> don't use this element return ! (ifc->ife.empty() || ifc->ifo.count(desc)); } interface *ifc; }; // count the length of a record assuming binary encoding template class ActionCountRecordSize : public Action { public: ActionCountRecordSize(interface ifc) : Action(ifc), result(0) {} template bool operator() (T &val, char *desc) { if (this->isFiltered(desc)) return true; result += sizeof(val); return true; } int result; }; // put the chosen titles in a string template class ActionWriteTitle : public Action { public: ActionWriteTitle(interface ifc) : Action(ifc) {} template bool operator() (T &val, char * desc) { if (this->isFiltered(desc)) return true; this->ifc->bufWrite(desc); this->ifc->bufWrite(" "); return true; } }; // put the choosen types in a string template class ActionWriteTypes : public Action { public: ActionWriteTypes(interface ifc) : Action(ifc) {} template bool operator() (T &val, char * desc) { if (this->isFiltered(desc)) return true; this->ifc->buf.append(type2name()); this->ifc->buf.append(" "); return true; } }; // put the serialized values to the string (space-delimited) // put the binary values to the string (no delimiter) template class ActionWriteValues : public Action { public: ActionWriteValues(interface ifc) : Action(ifc) {} template bool operator() (T &val, char *desc) { if (this->isFiltered(desc)) return true; return this->ifc->bufWrite(val); } }; // read serialized values template class ActionRead : public Action { public: ActionRead(interface ifc) : Action(ifc) {} template bool operator() (T &val, char * desc) { if (this->isFiltered(desc)) return true; return this->ifc->bufRead(val); } }; /* implementation of InputInterface */ template InputInterface::InputInterface(int fd, bool binary, IfObjectFilter *ifo, IfElementFilter *ife) : binary(binary), fd(fd), ifo(ifo), ifo(ife), buf(), rpos(0), npos(0), wpos(0), eof(false) { buf.reserve(buf_size); } template bool InputInterface::garantueeBuf(size_t size) { // no chance? if (eof) return (wpos - rpos >= size); if (size >= buf_size/2) return false; // relocate buffer? if (rpos > buf_size/2) { buf = buf.substr(rpos); buf.reserve(buf_size); npos -= rpos; wpos -= rpos; rpos = 0; } // read more? do { if (wpos < buf_size) { ssize_t res = read(fd, buf.data(), buf_size - wpos); switch (res) { case 0: // EOF eof = true; break; case EAGAIN: // TO DECIDE: wait? // read again (if neccessary) break; case EIO: case EBADF: case EINVAL: case EINTR: case EFAULT: return false; default: // read res bytes wpos += res; } } } while ((wpos - rpos < size) || eof); // loop in case of EAGAIN return wpos - rpos >= size; } // make sure that a "\n"-terminated, non-empty string is in the buffer (starting at rpos) template bool InputInterface::garantueeLine() { if (npos <= rpos) npos = rpos + 1; while (true) { if ((npos > wpos) && !garantueeBuf(npos - rpos)) return false; // increase amount of data in buffer if (buf[npos] == '\n') return true; npos++; } } template double InputInterface::peekNextTime() { double res; if (!bufRead(res, false)) { if (eof) { return INFINITY; }else{ DIE("peeking next time failed"); } } return res; } template template bool InputInterface::bufRead(Tval &val, bool proceedRPos=true) { if (binary) { if (!garantueeBuf(sizeof(Tval))) return false; val = *((Tval*) &(buf[npos])); if (proceedRPos) rpos += sizeof(Tval); }else{ if (!garantueeLine()) return false; // find next delimiter size_t p = buf.find_first_of(" \n", rpos); if (!p || (p == buf.npos)) return false; // parse substring try { val = boost::lexical_cast(buf.substr(rpos, p-1)); } catch(...) { return false; } if (proceedRPos) rpos = p + 1; } return true; } template bool InputInterface::readEntireFile() { return readFileUntil(INFINITY); } template bool InputInterface::readFileUntil(double time) { // iterate over events while (peekNextTime() <= min(time, INFINITY)) { // read (and forget) time to proceed rpos double _foo; bufRead(_foo); // get element id typename T::id_type id; if (!bufRead(id)) return false; // TODO: check if the id refers to a valid object // ignore it? if (!ifo->empty() && !ifo->count(id)) return false; // construct interface action and apply it ActionRead > ia(this); if (!(T::singleton(id)->interface(ia))) return false; } return true; } template OutputInterface::OutputInterface(int fd, bool binary, IfObjectFilter *ifo, IfElementFilter *ife) : fd(fd), binary(binary), ifo(ifo), ife(ife), buf() {} template bool OutputInterface::pushObject(T *o) { ActionWriteValues > ia(this); return o->interface(ia); } template bool OutputInterface::pushClass() { if (ifo->empty()) { // for every object of the class for (int i=0; ibegin(); i != ifo->end(); i++) if (!pushObject(T::singleton(*i))) return false; } } template bool OutputInterface::isContained(typename T::id_type id) { return ifo->empty() || ifo->count(id); } template template bool OutputInterface::bufWrite(Tval &val) { try { buf.append(boost::lexical_cast(val)); }catch (...) { return false; } return true; }