diff --git a/doomsday/libdeng2/include/de/core/log.h b/doomsday/libdeng2/include/de/core/log.h index b51d9b9351..4e48ef44f6 100644 --- a/doomsday/libdeng2/include/de/core/log.h +++ b/doomsday/libdeng2/include/de/core/log.h @@ -447,23 +447,28 @@ class DENG2_PUBLIC LogEntry : public Lockable, public ISerializable }; public: - Arg() : _type(IntegerArgument) { _data.intValue = 0; } - Arg(dint i) : _type(IntegerArgument) { _data.intValue = i; } - Arg(duint i) : _type(IntegerArgument) { _data.intValue = i; } - Arg(long int i) : _type(IntegerArgument) { _data.intValue = i; } - Arg(long unsigned int i) : _type(IntegerArgument) { _data.intValue = i; } - Arg(duint64 i) : _type(IntegerArgument) { _data.intValue = dint64(i); } - Arg(dint64 i) : _type(IntegerArgument) { _data.intValue = i; } - Arg(ddouble d) : _type(FloatingPointArgument) { _data.floatValue = d; } - Arg(void const *p) : _type(IntegerArgument) { _data.intValue = dint64(p); } - Arg(char const *s) : _type(StringArgument) { _data.stringValue = new String(s); } - Arg(String const &s) : _type(StringArgument) { _data.stringValue = new String(s.data(), s.size()); } - - Arg(Base const &arg); - Arg(Arg const &other); - + Arg(); ~Arg(); + void clear(); + + void setValue(dint i); + void setValue(duint i); + void setValue(long int i); + void setValue(long unsigned int i); + void setValue(duint64 i); + void setValue(dint64 i); + void setValue(ddouble d); + void setValue(void const *p); + void setValue(char const *s); + void setValue(String const &s); + void setValue(Base const &arg); + + template + Arg &set(ValueType const &s) { setValue(s); return *this; } + + Arg &operator = (Arg const &other); + inline Type type() const { return _type; } inline dint64 intValue() const { DENG2_ASSERT(_type == IntegerArgument); @@ -486,6 +491,15 @@ class DENG2_PUBLIC LogEntry : public Lockable, public ISerializable void operator >> (Writer &to) const; void operator << (Reader &from); + public: + static Arg *newFromPool(); + static void returnToPool(Arg *arg); + + template + static inline Arg *newFromPool(ValueType const &v) { + return &(newFromPool()->set(v)); + } + private: Type _type; union Data { @@ -702,16 +716,16 @@ class DENG2_PUBLIC LogEntryStager /// Appends a new argument to the entry. template inline LogEntryStager &operator << (ValueType const &v) { + // Args are created only if the level is enabled. if(!_disabled) { - // Args are created only if the level is enabled. - _args.append(new LogEntry::Arg(v)); + _args << LogEntry::Arg::newFromPool(v); } return *this; } ~LogEntryStager() { if(!_disabled) { - // Ownership of the entries is transferred to the LogEntry. + // Ownership of the args is transferred to the LogEntry. LOG().enter(_metadata, _format, _args); } } diff --git a/doomsday/libdeng2/src/core/log.cpp b/doomsday/libdeng2/src/core/log.cpp index a5e27a0a98..654bd71883 100644 --- a/doomsday/libdeng2/src/core/log.cpp +++ b/doomsday/libdeng2/src/core/log.cpp @@ -24,6 +24,7 @@ #include "de/Guard" #include "de/Reader" #include "de/Writer" +#include "de/FIFO" #include "logtextstyle.h" #include @@ -64,50 +65,133 @@ 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()) +/// Unused entry arguments are stored here in the pool. +static FIFO argPool; + +LogEntry::Arg::Arg() : _type(IntegerArgument) { - switch(_type) - { - case IntegerArgument: - _data.intValue = arg.asInt64(); - break; + _data.intValue = 0; +} - case FloatingPointArgument: - _data.floatValue = arg.asDouble(); - break; +LogEntry::Arg::~Arg() +{ + clear(); +} - case StringArgument: { - String s = arg.asText(); - _data.stringValue = new String(s.data(), s.size()); - break; } +void LogEntry::Arg::clear() +{ + if(_type == StringArgument) + { + delete _data.stringValue; + _data.stringValue = 0; + _type = IntegerArgument; } } -LogEntry::Arg::Arg(Arg const &other) - : String::IPatternArg(), ISerializable(), _type(other._type) +void LogEntry::Arg::setValue(dint i) +{ + clear(); + _type = IntegerArgument; + _data.intValue = i; +} + +void LogEntry::Arg::setValue(duint i) +{ + clear(); + _type = IntegerArgument; + _data.intValue = i; +} + +void LogEntry::Arg::setValue(long int i) +{ + clear(); + _type = IntegerArgument; + _data.intValue = i; +} + +void LogEntry::Arg::setValue(long unsigned int i) +{ + clear(); + _type = IntegerArgument; + _data.intValue = i; +} + +void LogEntry::Arg::setValue(duint64 i) +{ + clear(); + _type = IntegerArgument; + _data.intValue = dint64(i); +} + +void LogEntry::Arg::setValue(dint64 i) +{ + clear(); + _type = IntegerArgument; + _data.intValue = i; +} + +void LogEntry::Arg::setValue(ddouble d) +{ + clear(); + _type = FloatingPointArgument; + _data.floatValue = d; +} + +void LogEntry::Arg::setValue(void const *p) +{ + clear(); + _type = IntegerArgument; + _data.intValue = dint64(p); +} + +void LogEntry::Arg::setValue(char const *s) +{ + clear(); + _type = StringArgument; + _data.stringValue = new String(s); +} + +void LogEntry::Arg::setValue(String const &s) +{ + clear(); + _type = StringArgument; + // Ensure a deep copy of the string is taken. + _data.stringValue = new String(s.data(), s.size()); +} + +void LogEntry::Arg::setValue(LogEntry::Arg::Base const &arg) { - switch(other._type) + clear(); + _type = arg.logEntryArgType(); + switch(_type) { case IntegerArgument: - _data.intValue = other._data.intValue; + _data.intValue = arg.asInt64(); break; case FloatingPointArgument: - _data.floatValue = other._data.floatValue; + _data.floatValue = arg.asDouble(); break; case StringArgument: - _data.stringValue = new String(*other._data.stringValue); + setValue(arg.asText()); // deep copy break; } } -LogEntry::Arg::~Arg() +LogEntry::Arg &LogEntry::Arg::operator = (Arg const &other) { - if(_type == StringArgument) + clear(); + if(other._type == StringArgument) { - delete _data.stringValue; + setValue(*other._data.stringValue); // deep copy } + else + { + _type = other._type; + _data = other._data; + } + return *this; } ddouble LogEntry::Arg::asNumber() const @@ -183,6 +267,20 @@ void LogEntry::Arg::operator << (Reader &from) } } +LogEntry::Arg *LogEntry::Arg::newFromPool() +{ + Arg *arg = argPool.take(); + if(arg) return arg; + // Need a new one. + return new LogEntry::Arg; +} + +void LogEntry::Arg::returnToPool(Arg *arg) +{ + arg->clear(); + argPool.put(arg); +} + LogEntry::LogEntry() : _metadata(0), _sectionDepth(0), _disabled(true) {} @@ -213,7 +311,9 @@ LogEntry::LogEntry(LogEntry const &other, Flags extraFlags) { DENG2_FOR_EACH_CONST(Args, i, other._args) { - _args.append(new Arg(**i)); + Arg *a = Arg::newFromPool(); + *a = **i; + _args.append(a); } } @@ -221,10 +321,10 @@ LogEntry::~LogEntry() { DENG2_GUARD(this); - // The entry has ownership of its args. + // Put the arguments back to the shared pool. for(Args::iterator i = _args.begin(); i != _args.end(); ++i) { - delete *i; + Arg::returnToPool(*i); } } diff --git a/doomsday/tools/shell/shell-gui/src/linkwindow.cpp b/doomsday/tools/shell/shell-gui/src/linkwindow.cpp index fa349da3bc..0dc2779dde 100644 --- a/doomsday/tools/shell/shell-gui/src/linkwindow.cpp +++ b/doomsday/tools/shell/shell-gui/src/linkwindow.cpp @@ -480,7 +480,7 @@ void LinkWindow::sendCommandToServer(de::String command) { // Echo the command locally. LogEntry *e = new LogEntry(LogEntry::Generic | LogEntry::Note, "", 0, ">", - LogEntry::Args() << new LogEntry::Arg(command)); + LogEntry::Args() << LogEntry::Arg::newFromPool(command)); d->logBuffer.add(e); QScopedPointer packet(d->link->protocol().newCommand(command));