/* Web Polygraph http://www.web-polygraph.org/ * (C) 2003-2006 The Measurement Factory * Licensed under the Apache License, Version 2.0 */ #ifndef POLYGRAPH__BASE_OLOG_H #define POLYGRAPH__BASE_OLOG_H #include "xstd/h/iosfwd.h" #include "xstd/Time.h" #include "xstd/Size.h" #include "xstd/NetDouble.h" #include "xstd/BigSize.h" #include "xstd/String.h" #include "xstd/NetAddr.h" #include "xstd/Array.h" // some environments do not know better than #define these #ifdef getc # undef getc #endif #ifdef putc # undef putc #endif // buffered binary output log class OLog { public: typedef void (Manip)(class OLog &); public: OLog(); virtual ~OLog(); Size capacity() const { return theCapacity; } Size size() const { return theSize; } void stream(const String &aName, ostream *aStream); void capacity(Size aCap); void putc(char c) { put(&c, 1); } void putb(bool b) { putc((char)(b ? 1 : 0)); } void puti(int x) { x = htonl(x); put(&x, SizeOf(x)); } void puti(const int *x, int count); void puts(const char *s, Size size) { puti(size); if (size) put(s, size); } void puta(const struct sockaddr_storage &a) { put(&a, SizeOf(a)); } virtual void begEntry(int tag); void endEntry(); void flush(Size maxSize); // flushes up-to max size void flush() { flush(theSize); } void close(); // flushes if needed protected: void resize(Size minCap); inline void put(const void *buf, Size size); void overflow(const void *buf, Size size); virtual void putHeader(); virtual void putTrailer(); protected: ostream *theStream; String theName; char *theBuf; Size theCapacity; // buffer space allocated Size theSize; // buffer space used Size thePos; // global offset char *theEntry; // start of the current entry int theEntryTag; // tag saved until endEntry() Array theDir; // directory (one entry per tag) }; /* manipulators to begin and end logging of a named entry */ struct bege { bege(int t, int cat): tag(t | (cat << 16)) {} int tag; }; inline void ende(OLog &log) { log.endEntry(); } /* logging of common types */ inline OLog &operator <<(OLog &ol, char c) { ol.putc(c); return ol; } inline OLog &operator <<(OLog &ol, bool b) { ol.putb(b); return ol; } inline OLog &operator <<(OLog &ol, int x) { ol.puti(x); return ol; } inline OLog &operator <<(OLog &ol, double x) { NetDouble nd(x); return ol << nd.mnt << nd.exp; } inline OLog &operator <<(OLog &ol, const char *s) { ol.puts(s, strlen(s)+1); return ol; } inline OLog &operator <<(OLog &ol, const String &s) { if (s) ol.puts(s.cstr(), s.len()+1); else ol.puts(0, 0); return ol; } inline OLog &operator <<(OLog &ol, const Time &t) { ol.puti(t.tv_sec); ol.puti(t.tv_usec); return ol; } inline OLog &operator <<(OLog &ol, const BigSize &bs) { return ol << bs.theAcc << bs.theCnt; } // XXX: should log either A or N inline OLog &operator <<(OLog &ol, const NetAddr &a) { ol.puta(a.addrN().sockAddr(a.port())); return ol; } inline OLog &operator <<(OLog &ol, const bege &b) { ol.begEntry(b.tag); return ol; } inline OLog &operator <<(OLog &ol, OLog::Manip m) { m(ol); return ol; } template inline OLog &operator <<(OLog &ol, const Array &a) { ol.puti(a.count()); for (int i = 0; i < a.count(); ++i) ol << a[i]; return ol; } // store array of not-null pointers to items #ifdef COMPILER_CAN_HANDLE_NONTRIVIAL_TEMPLATES template inline void OLogStorePtrs(OLog &ol, const Array &a) { ol.puti(a.count()); for (int i = 0; i < a.count(); ++i) { Assert(a[i]); ol << *a[i]; } } #else # define OLogStorePtrs(ol, a) { \ (ol).puti((a).count()); \ for (int i = 0; i < (a).count(); ++i) { \ Assert((a)[i]); \ (ol) << *(a)[i]; \ } \ } #endif /* inlined methods */ inline void OLog::put(const void *buf, Size size) { if (size > 0 && theStream) { // just append if fits if (theSize + size <= theCapacity) { memcpy(theBuf + theSize, buf, size); theSize += size; thePos += size; } else { overflow(buf, size); // always uses put() recursively } } } #endif