diff --git a/doomsday/libdeng2/include/de/core/log.h b/doomsday/libdeng2/include/de/core/log.h index 0e3467a6be..e8b217cbc8 100644 --- a/doomsday/libdeng2/include/de/core/log.h +++ b/doomsday/libdeng2/include/de/core/log.h @@ -24,6 +24,7 @@ #include "../String" #include "../Lockable" #include "../Guard" +#include "../ISerializable" #include #include @@ -96,7 +97,7 @@ class LogBuffer; * * @ingroup core */ -class DENG2_PUBLIC LogEntry : public Lockable +class DENG2_PUBLIC LogEntry : public Lockable, public ISerializable { public: /// Level of the log entry. @@ -195,7 +196,7 @@ class DENG2_PUBLIC LogEntry : public Lockable * * @ingroup core */ - class DENG2_PUBLIC Arg : public String::IPatternArg + class DENG2_PUBLIC Arg : public String::IPatternArg, public ISerializable { public: /// The wrong type is used in accessing the value. @ingroup errors @@ -234,6 +235,7 @@ class DENG2_PUBLIC LogEntry : public Lockable }; public: + Arg() : _type(INTEGER) { _data.intValue = 0; } Arg(dint i) : _type(INTEGER) { _data.intValue = i; } Arg(duint i) : _type(INTEGER) { _data.intValue = i; } Arg(long int i) : _type(INTEGER) { _data.intValue = i; } @@ -248,38 +250,9 @@ class DENG2_PUBLIC LogEntry : public Lockable Arg(String const &s) : _type(STRING) { _data.stringValue = new String(s.data(), s.size()); } - Arg(Base const &arg) : _type(arg.logEntryArgType()) { - switch(_type) { - case INTEGER: - _data.intValue = arg.asInt64(); - break; - case FLOATING_POINT: - _data.floatValue = arg.asDouble(); - break; - case STRING: { - String s = arg.asText(); - _data.stringValue = new String(s.data(), s.size()); - break; } - } - } - Arg(Arg const &other) : _type(other._type) { - switch(other._type) { - case INTEGER: - _data.intValue = other._data.intValue; - break; - case FLOATING_POINT: - _data.floatValue = other._data.floatValue; - break; - case STRING: { - _data.stringValue = new String(*other._data.stringValue); - break; } - } - } - ~Arg() { - if(_type == STRING) { - delete _data.stringValue; - } - } + Arg(Base const &arg); + Arg(Arg const &other); + ~Arg(); Type type() const { return _type; } dint64 intValue() const { @@ -296,27 +269,12 @@ class DENG2_PUBLIC LogEntry : public Lockable } // Implements String::IPatternArg. - ddouble asNumber() const { - if(_type == INTEGER) { - return ddouble(_data.intValue); - } - else if(_type == FLOATING_POINT) { - return _data.floatValue; - } - throw TypeError("Log::Arg::asNumber", "String argument cannot be used as a number"); - } - String asText() const { - if(_type == STRING) { - return *_data.stringValue; - } - else if(_type == INTEGER) { - return String::number(_data.intValue); - } - else if(_type == FLOATING_POINT) { - return String::number(_data.floatValue); - } - throw TypeError("Log::Arg::asText", "Number argument cannot be used a string"); - } + ddouble asNumber() const; + String asText() const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); private: Type _type; @@ -395,6 +353,10 @@ class DENG2_PUBLIC LogEntry : public Lockable */ String asText(Flags const &flags = 0, int shortenSection = 0) const; + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + private: void advanceFormat(String::const_iterator &i) const; diff --git a/doomsday/libdeng2/src/core/log.cpp b/doomsday/libdeng2/src/core/log.cpp index 5016b361b8..1e0d3aba90 100644 --- a/doomsday/libdeng2/src/core/log.cpp +++ b/doomsday/libdeng2/src/core/log.cpp @@ -22,6 +22,8 @@ #include "de/Date" #include "de/LogBuffer" #include "de/Guard" +#include "de/Reader" +#include "de/Writer" #include "logtextstyle.h" #include @@ -62,6 +64,124 @@ class Logs : public QMap, public Lockable /// The logs table contains the log of each thread that uses logging. static std::auto_ptr logsPtr; +LogEntry::Arg::Arg(const LogEntry::Arg::Base &arg) : _type(arg.logEntryArgType()) +{ + switch(_type) + { + case INTEGER: + _data.intValue = arg.asInt64(); + break; + + case FLOATING_POINT: + _data.floatValue = arg.asDouble(); + break; + + case STRING: { + String s = arg.asText(); + _data.stringValue = new String(s.data(), s.size()); + break; } + } +} + +LogEntry::Arg::Arg(Arg const &other) : _type(other._type) +{ + switch(other._type) + { + case INTEGER: + _data.intValue = other._data.intValue; + break; + + case FLOATING_POINT: + _data.floatValue = other._data.floatValue; + break; + + case STRING: + _data.stringValue = new String(*other._data.stringValue); + break; + } +} + +LogEntry::Arg::~Arg() +{ + if(_type == STRING) + { + delete _data.stringValue; + } +} + +ddouble LogEntry::Arg::asNumber() const +{ + if(_type == INTEGER) + { + return ddouble(_data.intValue); + } + else if(_type == FLOATING_POINT) + { + return _data.floatValue; + } + throw TypeError("Log::Arg::asNumber", "String argument cannot be used as a number"); +} + +String LogEntry::Arg::asText() const +{ + if(_type == STRING) + { + return *_data.stringValue; + } + else if(_type == INTEGER) + { + return String::number(_data.intValue); + } + else if(_type == FLOATING_POINT) + { + return String::number(_data.floatValue); + } + throw TypeError("Log::Arg::asText", "Number argument cannot be used a string"); +} + +void LogEntry::Arg::operator >> (Writer &to) const +{ + to << dbyte(_type); + + switch(_type) + { + case INTEGER: + to << _data.intValue; + break; + + case FLOATING_POINT: + to << _data.floatValue; + break; + + case STRING: + to << *_data.stringValue; + break; + } +} + +void LogEntry::Arg::operator << (Reader &from) +{ + if(_type == STRING) delete _data.stringValue; + + from.readAs(_type); + + switch(_type) + { + case INTEGER: + from >> _data.intValue; + break; + + case FLOATING_POINT: + from >> _data.floatValue; + break; + + case STRING: + _data.stringValue = new String; + from >> *_data.stringValue; + break; + } +} + LogEntry::LogEntry() : _level(TRACE), _sectionDepth(0), _disabled(true) {} @@ -281,6 +401,32 @@ String LogEntry::asText(Flags const &formattingFlags, int shortenSection) const return result; } +void LogEntry::operator >> (Writer &to) const +{ + to << _when + << _section + << _format + << dbyte(_level) + << dbyte(_sectionDepth) + << duint32(_defaultFlags); + + to.writeObjects(_args); +} + +void LogEntry::operator << (Reader &from) +{ + foreach(Arg *a, _args) delete a; + _args.clear(); + + from >> _when + >> _section + >> _format; + from.readAs(_level) + .readAs(_sectionDepth) + .readAs(_defaultFlags) + .readObjects(_args); +} + QTextStream &operator << (QTextStream &stream, LogEntry::Arg const &arg) { switch(arg.type())