diff options
author | Jan Huwald <jh@sotun.de> | 2012-05-07 19:53:27 (GMT) |
---|---|---|
committer | Jan Huwald <jh@sotun.de> | 2012-05-07 19:53:27 (GMT) |
commit | 00b209240138660db1ded3ef3870023964ce6e4e (patch) | |
tree | 8ffaec780b060bdc478929aa714b8af2ee760671 /code/core/interface.cpp |
Diffstat (limited to 'code/core/interface.cpp')
-rw-r--r-- | code/core/interface.cpp | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/code/core/interface.cpp b/code/core/interface.cpp new file mode 100644 index 0000000..c2d3a3b --- /dev/null +++ b/code/core/interface.cpp @@ -0,0 +1,262 @@ +#include <unistd.h> +#include <asm-generic/errno.h> +#include <boost/lexical_cast.hpp> + +#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 interface> +class Action { +public: + Action<interface>(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 interface> +class ActionCountRecordSize : public Action<interface> { +public: + ActionCountRecordSize<interface>(interface ifc) : Action<interface>(ifc), result(0) {} + + template<class T> + 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 interface> +class ActionWriteTitle : public Action<interface> { +public: + ActionWriteTitle<interface>(interface ifc) : Action<interface>(ifc) {} + + template<class T> + 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 interface> +class ActionWriteTypes : public Action<interface> { +public: + ActionWriteTypes<interface>(interface ifc) : Action<interface>(ifc) {} + + template<class T> + bool operator() (T &val, char * desc) { + if (this->isFiltered(desc)) return true; + this->ifc->buf.append(type2name<T>()); + 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 interface> +class ActionWriteValues : public Action<interface> { +public: + ActionWriteValues<interface>(interface ifc) : Action<interface>(ifc) {} + + template<class T> + bool operator() (T &val, char *desc) { + if (this->isFiltered(desc)) return true; + return this->ifc->bufWrite(val); + } +}; + +// read serialized values +template<class interface> +class ActionRead : public Action<interface> { +public: + ActionRead<interface>(interface ifc) : Action<interface>(ifc) {} + + template<class T> + bool operator() (T &val, char * desc) { + if (this->isFiltered(desc)) return true; + return this->ifc->bufRead(val); + } +}; + +/* implementation of InputInterface */ + +template<class T> +InputInterface<T>::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<class T> +bool InputInterface<T>::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<class T> +bool InputInterface<T>::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<class T> +double InputInterface<T>::peekNextTime() { + double res; + if (!bufRead(res, false)) { + if (eof) { + return INFINITY; + }else{ + DIE("peeking next time failed"); + } + } + return res; +} + + +template<class Tif> template<class Tval> +bool InputInterface<Tif>::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<Tval>(buf.substr(rpos, p-1)); + } catch(...) { + return false; + } + + if (proceedRPos) rpos = p + 1; + } + return true; +} + +template<class T> +bool InputInterface<T>::readEntireFile() { + return readFileUntil(INFINITY); +} + +template<typename T> +bool InputInterface<T>::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<InputInterface<T> > ia(this); + if (!(T::singleton(id)->interface(ia))) return false; + } + return true; +} + +template<class T> +OutputInterface<T>::OutputInterface(int fd, bool binary, IfObjectFilter *ifo, IfElementFilter *ife) + : fd(fd), binary(binary), ifo(ifo), ife(ife), buf() {} + +template<class T> +bool OutputInterface<T>::pushObject(T *o) { + ActionWriteValues<OutputInterface<T> > ia(this); + return o->interface(ia); +} + +template<class T> +bool OutputInterface<T>::pushClass() { + if (ifo->empty()) { + // for every object of the class + for (int i=0; i<T::numElements(); i++) + if (!pushObject(T::singleton(i))) return false; + }else{ + // for all objects specified by ifo + for (IfObjectFilter::iterator i = ifo->begin(); i != ifo->end(); i++) + if (!pushObject(T::singleton(*i))) return false; + } +} + +template<class T> +bool OutputInterface<T>::isContained(typename T::id_type id) { + return ifo->empty() || ifo->count(id); +} + +template<class Tif> template<class Tval> +bool OutputInterface<Tif>::bufWrite(Tval &val) { + try { + buf.append(boost::lexical_cast<std::string>(val)); + }catch (...) { + return false; + } + return true; +} |