Dynamic::Var SOO

Dynamic::Var  small object optimization and some refactoring
This commit is contained in:
aleks-f 2013-02-05 22:12:21 -06:00
parent 54a92c59e5
commit 21da0129b6
16 changed files with 401 additions and 208 deletions

3
.gitignore vendored
View File

@ -100,3 +100,6 @@ lib/
lib64/ lib64/
pocomsg.h pocomsg.h
# Temporary files #
###################
*.bak

View File

@ -225,9 +225,9 @@ public:
val = DateTimeFormatter::format(dt, "%Y/%m/%d"); val = DateTimeFormatter::format(dt, "%Y/%m/%d");
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const Poco::Data::Date& value() const const Poco::Data::Date& value() const

View File

@ -272,9 +272,9 @@ public:
val.assign(_val.begin(), _val.end()); val.assign(_val.begin(), _val.end());
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const Poco::Data::BLOB& value() const const Poco::Data::BLOB& value() const
@ -310,9 +310,9 @@ public:
val.assign(_val.begin(), _val.end()); val.assign(_val.begin(), _val.end());
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const Poco::Data::CLOB& value() const const Poco::Data::CLOB& value() const

View File

@ -229,9 +229,9 @@ public:
val = DateTimeFormatter::format(dt, "%H:%M:%S"); val = DateTimeFormatter::format(dt, "%H:%M:%S");
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const Poco::Data::Time& value() const const Poco::Data::Time& value() const

View File

@ -48,6 +48,68 @@
namespace Poco { namespace Poco {
namespace Dynamic {
class Var;
class VarHolder;
template <class> class VarHolderImpl;
}
template <typename PlaceholderT, unsigned int SizeV = POCO_SMALL_OBJECT_SIZE>
union Placeholder
/// ValueHolder union (used by Poco::Any and Poco::Dynamic::Var for small
/// object optimization).
///
/// If Holder<Type> fits into POCO_SMALL_OBJECT_SIZE bytes of storage,
/// it will be placement-new-allocated into the local buffer
/// (i.e. there will be no heap-allocation). The local buffer size is one byte
/// larger - [POCO_SMALL_OBJECT_SIZE + 1], additional byte value indicating
/// where the object was allocated (0 => heap, 1 => local).
{
public:
static const unsigned int SIZE = SizeV;
Placeholder ()
{
erase();
}
void erase()
{
std::memset(holder, 0, sizeof(Placeholder));
}
bool isLocal() const
{
return holder[SIZE] != 0;
}
void setLocal(bool local) const
{
holder[SIZE] = local ? 1 : 0;
}
PlaceholderT* content() const
{
if(isLocal())
return reinterpret_cast<PlaceholderT*>(holder);
else
return pHolder;
}
private:
PlaceholderT* pHolder;
mutable unsigned char holder[SIZE + 1];
friend class Any;
friend class Dynamic::Var;
friend class Dynamic::VarHolder;
template <class> friend class VarHolderImpl;
};
class Any class Any
/// An Any class represents a general type and is capable of storing any type, supporting type-safe extraction /// An Any class represents a general type and is capable of storing any type, supporting type-safe extraction
/// of the internally stored data. /// of the internally stored data.
@ -58,13 +120,10 @@ class Any
/// Modified for small object optimization support (optionally supported through conditional compilation) /// Modified for small object optimization support (optionally supported through conditional compilation)
/// by Alex Fabijanic. /// by Alex Fabijanic.
{ {
public:
#ifndef POCO_NO_SOO #ifndef POCO_NO_SOO
union PH;
public:
Any() Any()
/// Creates an empty any type. /// Creates an empty any type.
{ {
@ -75,8 +134,8 @@ public:
/// Creates an any which stores the init parameter inside. /// Creates an any which stores the init parameter inside.
/// ///
/// Example: /// Example:
/// Any a(13); /// Any a(13);
/// Any a(string("12345")); /// Any a(string("12345"));
{ {
construct(value); construct(value);
} }
@ -89,13 +148,13 @@ public:
} }
~Any() ~Any()
/// Destructor. If Any is locally held, calls Placeholder destructor; /// Destructor. If Any is locally held, calls ValueHolder destructor;
/// otherwise, deletes the placeholder from the heap. /// otherwise, deletes the placeholder from the heap.
{ {
if(!empty()) if(!empty())
{ {
if(_placeholder.isLocal()) if(_valueHolder.isLocal())
content()->~Placeholder(); content()->~ValueHolder();
else else
delete content(); delete content();
} }
@ -110,14 +169,14 @@ public:
{ {
if (this == &other) return *this; if (this == &other) return *this;
if (!_placeholder.isLocal() && !other._placeholder.isLocal()) if (!_valueHolder.isLocal() && !other._valueHolder.isLocal())
{ {
std::swap(_placeholder.pHolder, other._placeholder.pHolder); std::swap(_valueHolder.pHolder, other._valueHolder.pHolder);
} }
else else
{ {
Any tmp(*this); Any tmp(*this);
if (_placeholder.isLocal()) this->~Any(); if (_valueHolder.isLocal()) this->~Any();
construct(other); construct(other);
other = tmp; other = tmp;
} }
@ -143,7 +202,7 @@ public:
if ((this != &rhs) && !rhs.empty()) if ((this != &rhs) && !rhs.empty())
construct(rhs); construct(rhs);
else if ((this != &rhs) && rhs.empty()) else if ((this != &rhs) && rhs.empty())
_placeholder.erase(); _valueHolder.erase();
return *this; return *this;
} }
@ -152,7 +211,7 @@ public:
/// Returns true if the Any is empty. /// Returns true if the Any is empty.
{ {
char buf[POCO_SMALL_OBJECT_SIZE] = { 0 }; char buf[POCO_SMALL_OBJECT_SIZE] = { 0 };
return 0 == std::memcmp(_placeholder.holder, buf, POCO_SMALL_OBJECT_SIZE); return 0 == std::memcmp(_valueHolder.holder, buf, _valueHolder.SIZE);
} }
const std::type_info & type() const const std::type_info & type() const
@ -166,20 +225,20 @@ public:
private: private:
class Placeholder class ValueHolder
{ {
public: public:
virtual ~Placeholder() virtual ~ValueHolder()
{ {
} }
virtual const std::type_info & type() const = 0; virtual const std::type_info & type() const = 0;
virtual void clone(Any::PH*) const = 0; virtual void clone(Placeholder<ValueHolder>*) const = 0;
}; };
template<typename ValueType> template<typename ValueType>
class Holder : public Placeholder class Holder : public ValueHolder
{ {
public: public:
Holder(const ValueType & value) : _held(value) Holder(const ValueType & value) : _held(value)
@ -191,11 +250,11 @@ private:
return typeid(ValueType); return typeid(ValueType);
} }
virtual void clone(Any::PH* pPlaceholder) const virtual void clone(Placeholder<ValueHolder>* pPlaceholder) const
{ {
if ((sizeof(Holder<ValueType>) <= POCO_SMALL_OBJECT_SIZE)) if ((sizeof(Holder<ValueType>) <= pPlaceholder->SIZE))
{ {
new ((Placeholder*) pPlaceholder->holder) Holder(_held); new ((ValueHolder*) pPlaceholder->holder) Holder(_held);
pPlaceholder->setLocal(true); pPlaceholder->setLocal(true);
} }
else else
@ -211,78 +270,40 @@ private:
Holder & operator = (const Holder &); Holder & operator = (const Holder &);
}; };
Placeholder* content() const ValueHolder* content() const
{ {
return _placeholder.content(); return _valueHolder.content();
} }
template<typename ValueType> template<typename ValueType>
void construct(const ValueType& value) void construct(const ValueType& value)
{ {
if (sizeof(Holder<ValueType>) <= POCO_SMALL_OBJECT_SIZE) if (sizeof(Holder<ValueType>) <= _valueHolder.SIZE)
{ {
new (reinterpret_cast<Placeholder*>(_placeholder.holder)) Holder<ValueType>(value); new (reinterpret_cast<ValueHolder*>(_valueHolder.holder)) Holder<ValueType>(value);
_placeholder.setLocal(true); _valueHolder.setLocal(true);
} }
else else
{ {
_placeholder.pHolder = new Holder<ValueType>(value); _valueHolder.pHolder = new Holder<ValueType>(value);
_placeholder.setLocal(false); _valueHolder.setLocal(false);
} }
} }
void construct(const Any& other) void construct(const Any& other)
{ {
if(!other.empty()) if(!other.empty())
other.content()->clone(&_placeholder); other.content()->clone(&_valueHolder);
else else
_placeholder.erase(); _valueHolder.erase();
} }
union PH Placeholder<ValueHolder> _valueHolder;
/// Placeholder union. If Holder<Type> fits into POCO_SMALL_OBJECT_SIZE
/// bytes of storage, it will be placement-new-allocated into the local buffer
/// (i.e. there will be no heap-allocation. The local buffer size is one byte
/// larger - [POCO_SMALL_OBJECT_SIZE + 1], additional byte value indicating
/// where the object was allocated (0 => heap, 1 => local).
{
PH ()
{
erase();
}
void erase()
{
std::memset(holder, 0, sizeof(PH));
}
bool isLocal() const
{
return holder[POCO_SMALL_OBJECT_SIZE] != 0;
}
void setLocal(bool local) const
{
holder[POCO_SMALL_OBJECT_SIZE] = local ? 1 : 0;
}
Placeholder* content() const
{
if(isLocal())
return reinterpret_cast<Placeholder*>(holder);
else
return pHolder;
}
Placeholder* pHolder;
mutable unsigned char holder[POCO_SMALL_OBJECT_SIZE + 1];
} _placeholder;
#else // if POCO_NO_SOO #else // if POCO_NO_SOO
public:
Any(): _pHolder(0) Any(): _pHolder(0)
/// Creates an empty any type. /// Creates an empty any type.
{ {
@ -352,19 +373,19 @@ public:
} }
private: private:
class Placeholder class ValueHolder
{ {
public: public:
virtual ~Placeholder() virtual ~ValueHolder()
{ {
} }
virtual const std::type_info& type() const = 0; virtual const std::type_info& type() const = 0;
virtual Placeholder* clone() const = 0; virtual ValueHolder* clone() const = 0;
}; };
template <typename ValueType> template <typename ValueType>
class Holder: public Placeholder class Holder: public ValueHolder
{ {
public: public:
Holder(const ValueType& value): Holder(const ValueType& value):
@ -377,7 +398,7 @@ private:
return typeid(ValueType); return typeid(ValueType);
} }
virtual Placeholder* clone() const virtual ValueHolder* clone() const
{ {
return new Holder(_held); return new Holder(_held);
} }
@ -388,13 +409,13 @@ private:
Holder & operator=(const Holder &); Holder & operator=(const Holder &);
}; };
Placeholder* content() const ValueHolder* content() const
{ {
return _pHolder; return _pHolder;
} }
private: private:
Placeholder* _pHolder; ValueHolder* _pHolder;
#endif // POCO_NO_SOO #endif // POCO_NO_SOO

View File

@ -93,6 +93,16 @@
// (see Poco/Types.h for default values). // (see Poco/Types.h for default values).
// #define POCO_NO_SOO // #define POCO_NO_SOO
// Small object size in bytes. Where applicable (e.g.
// SmallObjectAllocator<char*> specialization, Any, Var, etc)
// objects longer than this value will be alocated on the heap.
// See Poco/SmallObjectAllocator.h for usage of this value.
#if !defined(POCO_SMALL_OBJECT_SIZE)
#define POCO_SMALL_OBJECT_SIZE 32
#endif
// Following are options to remove certain features // Following are options to remove certain features
// to reduce library/executable size for smaller // to reduce library/executable size for smaller
// embedded platforms. By enabling these options, // embedded platforms. By enabling these options,

View File

@ -229,9 +229,9 @@ public:
throw BadCastException("Pair -> Poco::Timestamp"); throw BadCastException("Pair -> Poco::Timestamp");
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const Pair<std::string>& value() const const Pair<std::string>& value() const
@ -378,9 +378,9 @@ public:
throw BadCastException("Pair -> Poco::Timestamp"); throw BadCastException("Pair -> Poco::Timestamp");
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const Pair<int>& value() const const Pair<int>& value() const

View File

@ -325,9 +325,9 @@ public:
throw BadCastException("Struct -> Poco::Timestamp"); throw BadCastException("Struct -> Poco::Timestamp");
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const Struct<std::string>& value() const const Struct<std::string>& value() const
@ -496,9 +496,9 @@ public:
throw BadCastException("Struct -> Poco::Timestamp"); throw BadCastException("Struct -> Poco::Timestamp");
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const Struct<int>& value() const const Struct<int>& value() const

View File

@ -53,6 +53,7 @@ namespace Dynamic {
template <typename T> template <typename T>
class Struct; class Struct;
class Foundation_API Var class Foundation_API Var
/// Var allows to store data of different types and to convert between these types transparently. /// Var allows to store data of different types and to convert between these types transparently.
/// Var puts forth the best effort to provide intuitive and reasonable conversion semantics and prevent /// Var puts forth the best effort to provide intuitive and reasonable conversion semantics and prevent
@ -88,7 +89,7 @@ class Foundation_API Var
/// '+', '+=', '-', '-=', '*', '*=' , '/' and '/=' /// '+', '+=', '-', '-=', '*', '*=' , '/' and '/='
/// ///
/// - for integral values, following operations are supported: /// - for integral values, following operations are supported:
/// prefix and postfix increment (++) and decement (--) /// prefix and postfix increment (++) and decrement (--)
/// ///
/// - for all other types, InvalidArgumentException is thrown upon attempt of an arithmetic operation /// - for all other types, InvalidArgumentException is thrown upon attempt of an arithmetic operation
/// ///
@ -100,11 +101,15 @@ public:
/// Creates an empty Var. /// Creates an empty Var.
template <typename T> template <typename T>
Var(const T& val): Var(const T& val)
_pHolder(new VarHolderImpl<T>(val))
/// Creates the Var from the given value. /// Creates the Var from the given value.
#ifdef POCO_NO_SOO
:_pHolder(new VarHolderImpl<T>(val)) { }
#else
{ {
construct(val);
} }
#endif
Var(const char* pVal); Var(const char* pVal);
// Convenience constructor for const char* which gets mapped to a std::string internally, i.e. pVal is deep-copied. // Convenience constructor for const char* which gets mapped to a std::string internally, i.e. pVal is deep-copied.
@ -133,10 +138,12 @@ public:
/// not available for the given type. /// not available for the given type.
/// Throws InvalidAccessException if Var is empty. /// Throws InvalidAccessException if Var is empty.
{ {
if (!_pHolder) VarHolder* pHolder = content();
if (!pHolder)
throw InvalidAccessException("Can not convert empty value."); throw InvalidAccessException("Can not convert empty value.");
_pHolder->convert(val); pHolder->convert(val);
} }
template <typename T> template <typename T>
@ -153,13 +160,15 @@ public:
/// not available for the given type. /// not available for the given type.
/// Throws InvalidAccessException if Var is empty. /// Throws InvalidAccessException if Var is empty.
{ {
if (!_pHolder) VarHolder* pHolder = content();
if (!pHolder)
throw InvalidAccessException("Can not convert empty value."); throw InvalidAccessException("Can not convert empty value.");
if (typeid(T) == _pHolder->type()) return extract<T>(); if (typeid(T) == pHolder->type()) return extract<T>();
T result; T result;
_pHolder->convert(result); pHolder->convert(result);
return result; return result;
} }
@ -177,15 +186,17 @@ public:
/// not available for the given type. /// not available for the given type.
/// Throws InvalidAccessException if Var is empty. /// Throws InvalidAccessException if Var is empty.
{ {
if (!_pHolder) VarHolder* pHolder = content();
if (!pHolder)
throw InvalidAccessException("Can not convert empty value."); throw InvalidAccessException("Can not convert empty value.");
if (typeid(T) == _pHolder->type()) if (typeid(T) == pHolder->type())
return extract<T>(); return extract<T>();
else else
{ {
T result; T result;
_pHolder->convert(result); pHolder->convert(result);
return result; return result;
} }
} }
@ -199,16 +210,18 @@ public:
/// is thrown. /// is thrown.
/// Throws InvalidAccessException if Var is empty. /// Throws InvalidAccessException if Var is empty.
{ {
if (_pHolder && _pHolder->type() == typeid(T)) VarHolder* pHolder = content();
if (pHolder && pHolder->type() == typeid(T))
{ {
VarHolderImpl<T>* pHolderImpl = static_cast<VarHolderImpl<T>*>(_pHolder); VarHolderImpl<T>* pHolderImpl = static_cast<VarHolderImpl<T>*>(pHolder);
return pHolderImpl->value(); return pHolderImpl->value();
} }
else if (!_pHolder) else if (!pHolder)
throw InvalidAccessException("Can not extract empty value."); throw InvalidAccessException("Can not extract empty value.");
else else
throw BadCastException(format("Can not convert %s to %s.", throw BadCastException(format("Can not convert %s to %s.",
_pHolder->type().name(), pHolder->type().name(),
typeid(T).name())); typeid(T).name()));
} }
@ -216,8 +229,12 @@ public:
Var& operator = (const T& other) Var& operator = (const T& other)
/// Assignment operator for assigning POD to Var /// Assignment operator for assigning POD to Var
{ {
#ifdef POCO_NO_SOO
Var tmp(other); Var tmp(other);
swap(tmp); swap(tmp);
#else
construct(other);
#endif
return *this; return *this;
} }
@ -536,9 +553,11 @@ private:
template <typename T, typename E> template <typename T, typename E>
VarHolderImpl<T>* holderImpl(const std::string errorMessage = "") const VarHolderImpl<T>* holderImpl(const std::string errorMessage = "") const
{ {
if (_pHolder && _pHolder->type() == typeid(T)) VarHolder* pHolder = content();
return static_cast<VarHolderImpl<T>*>(_pHolder);
else if (!_pHolder) if (pHolder && pHolder->type() == typeid(T))
return static_cast<VarHolderImpl<T>*>(pHolder);
else if (!pHolder)
throw InvalidAccessException("Can not access empty value."); throw InvalidAccessException("Can not access empty value.");
else else
throw E(errorMessage); throw E(errorMessage);
@ -546,7 +565,64 @@ private:
Var& structIndexOperator(VarHolderImpl<Struct<int> >* pStr, int n) const; Var& structIndexOperator(VarHolderImpl<Struct<int> >* pStr, int n) const;
#ifdef POCO_NO_SOO
VarHolder* content() const
{
return _pHolder;
}
VarHolder* _pHolder; VarHolder* _pHolder;
#else
VarHolder* content() const
{
return _placeholder.content();
}
template<typename ValueType>
void construct(const ValueType& value)
{
if (sizeof(VarHolderImpl<ValueType>) <= _placeholder.SIZE)
{
new (reinterpret_cast<VarHolder*>(_placeholder.holder)) VarHolderImpl<ValueType>(value);
_placeholder.setLocal(true);
}
else
{
_placeholder.pHolder = new VarHolderImpl<ValueType>(value);
_placeholder.setLocal(false);
}
}
void construct(const char* value)
{
std::string val(value);
if (sizeof(VarHolderImpl<std::string>) <= _placeholder.SIZE)
{
new (reinterpret_cast<VarHolder*>(_placeholder.holder)) VarHolderImpl<std::string>(val);
_placeholder.setLocal(true);
}
else
{
_placeholder.pHolder = new VarHolderImpl<std::string>(val);
_placeholder.setLocal(false);
}
}
void construct(const Var& other)
{
if(!other.isEmpty())
other.content()->clone(&_placeholder);
else
_placeholder.erase();
}
Placeholder<VarHolder> _placeholder;
#endif // POCO_NO_SOO
}; };
@ -559,15 +635,36 @@ private:
/// Var members /// Var members
/// ///
inline void Var::swap(Var& ptr) inline void Var::swap(Var& other)
{ {
std::swap(_pHolder, ptr._pHolder); #ifdef POCO_NO_SOO
std::swap(_pHolder, other._pHolder);
#else
if (this == &other) return;
if (!_placeholder.isLocal() && !other._placeholder.isLocal())
{
std::swap(_placeholder.pHolder, other._placeholder.pHolder);
}
else
{
Var tmp(*this);
if (_placeholder.isLocal()) this->~Var();
construct(other);
other = tmp;
}
#endif
} }
inline const std::type_info& Var::type() const inline const std::type_info& Var::type() const
{ {
return _pHolder ? _pHolder->type() : typeid(void); VarHolder* pHolder = content();
return pHolder ? pHolder->type() : typeid(void);
} }
@ -603,49 +700,56 @@ inline bool Var::operator ! () const
inline bool Var::isEmpty() const inline bool Var::isEmpty() const
{ {
return 0 == _pHolder; return 0 == content();
} }
inline bool Var::isArray() const inline bool Var::isArray() const
{ {
return _pHolder ? _pHolder->isArray() : false; VarHolder* pHolder = content();
return pHolder ? pHolder->isArray() : false;
} }
inline bool Var::isStruct() const inline bool Var::isStruct() const
{ {
return _pHolder ? _pHolder->isStruct() : false; VarHolder* pHolder = content();
return pHolder ? pHolder->isStruct() : false;
} }
inline bool Var::isInteger() const inline bool Var::isInteger() const
{ {
return _pHolder ? _pHolder->isInteger() : false; VarHolder* pHolder = content();
return pHolder ? pHolder->isInteger() : false;
} }
inline bool Var::isSigned() const inline bool Var::isSigned() const
{ {
return _pHolder ? _pHolder->isSigned() : false; VarHolder* pHolder = content();
return pHolder ? pHolder->isSigned() : false;
} }
inline bool Var::isNumeric() const inline bool Var::isNumeric() const
{ {
return _pHolder ? _pHolder->isNumeric() : false; VarHolder* pHolder = content();
return pHolder ? pHolder->isNumeric() : false;
} }
inline bool Var::isString() const inline bool Var::isString() const
{ {
return _pHolder ? _pHolder->isString() : false; VarHolder* pHolder = content();
return pHolder ? pHolder->isString() : false;
} }
/// ///
/// Var non-member functions /// Var non-member functions
/// ///
inline const Var operator + (const char* other, const Var& da) inline const Var operator + (const char* other, const Var& da)
/// Addition operator for adding Var to const char* /// Addition operator for adding Var to const char*
{ {

View File

@ -50,6 +50,7 @@
#include "Poco/DateTimeFormatter.h" #include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeParser.h" #include "Poco/DateTimeParser.h"
#include "Poco/String.h" #include "Poco/String.h"
#include "Poco/Any.h"
#include "Poco/Exception.h" #include "Poco/Exception.h"
#include <vector> #include <vector>
#include <typeinfo> #include <typeinfo>
@ -68,6 +69,7 @@ class Var;
bool Foundation_API isJSONString(const Var& any); bool Foundation_API isJSONString(const Var& any);
/// Returns true for values that should be JSON-formatted as string. /// Returns true for values that should be JSON-formatted as string.
void Foundation_API appendJSONString(std::string& val, const Var& any); void Foundation_API appendJSONString(std::string& val, const Var& any);
/// Converts the any to a JSON value and adds it to val /// Converts the any to a JSON value and adds it to val
@ -92,13 +94,17 @@ public:
virtual ~VarHolder(); virtual ~VarHolder();
/// Destroys the VarHolder. /// Destroys the VarHolder.
virtual VarHolder* clone() const; virtual VarHolder* clone(Placeholder<VarHolder>* pHolder = 0) const = 0;
/// Throws NotImplementedException. Implementation should /// Implementation must implement this function to
/// deep-copy the VarHolder. /// deep-copy the VarHolder.
/// If small object optimization is enabled (i.e. if
virtual const std::type_info& type() const; /// POCO_NO_SOO is not defined), VarHolder will be
/// Throws NotImplementedException. Implementation should /// instantiated in-place if it's size is smaller
/// return the type information for the stored content. /// than POCO_SMALL_OBJECT_SIZE.
virtual const std::type_info& type() const = 0;
/// Implementation must return the type information
/// (typeid) for the stored content.
virtual void convert(Int8& val) const; virtual void convert(Int8& val) const;
/// Throws BadCastException. Must be overriden in a type /// Throws BadCastException. Must be overriden in a type
@ -145,12 +151,15 @@ public:
/// specialization in order to suport the conversion. /// specialization in order to suport the conversion.
#ifndef POCO_LONG_IS_64_BIT #ifndef POCO_LONG_IS_64_BIT
void convert(long& val) const; void convert(long& val) const;
/// Calls convert(Int32). /// Calls convert(Int32).
void convert(unsigned long& val) const; void convert(unsigned long& val) const;
/// Calls convert(UInt32). /// Calls convert(UInt32).
#endif #endif
virtual void convert(bool& val) const; virtual void convert(bool& val) const;
/// Throws BadCastException. Must be overriden in a type /// Throws BadCastException. Must be overriden in a type
/// specialization in order to suport the conversion. /// specialization in order to suport the conversion.
@ -199,6 +208,35 @@ protected:
VarHolder(); VarHolder();
/// Creates the VarHolder. /// Creates the VarHolder.
template <typename T>
VarHolder* cloneHolder(Placeholder<VarHolder>* pVarHolder, const T& val) const
/// Instantiates value holder wrapper. If size of the wrapper is
/// larger than POCO_SMALL_OBJECT_SIZE, holder is instantiated on
/// the heap, otherwise it is instantiated in-place (in the
/// pre-allocated buffer inside the holder).
///
/// Called from clone() member function of the implementation when
/// smal object optimization is enabled.
{
#ifdef POCO_NO_SOO
return new VarHolderImpl<T>(val);
#else
poco_check_ptr (pVarHolder);
if ((sizeof(VarHolderImpl<T>) <= pVarHolder->SIZE))
{
new ((VarHolder*) pVarHolder->holder) VarHolderImpl<T>(val);
pVarHolder->setLocal(true);
return (VarHolder*) pVarHolder->holder;
}
else
{
pVarHolder->pHolder = new VarHolderImpl<T>(val);
pVarHolder->setLocal(false);
return pVarHolder->pHolder;
}
#endif
}
template <typename F, typename T> template <typename F, typename T>
void convertToSmaller(const F& from, T& to) const void convertToSmaller(const F& from, T& to) const
/// This function is meant to convert signed numeric values from /// This function is meant to convert signed numeric values from
@ -338,16 +376,6 @@ private:
// inlines // inlines
// //
inline VarHolder* VarHolder::clone() const
{
throw NotImplementedException("Not implemented: VarHolder::clone()");
}
inline const std::type_info& VarHolder::type() const
{
throw NotImplementedException("Not implemented: VarHolder::type()");
}
inline void VarHolder::convert(Int8& /*val*/) const inline void VarHolder::convert(Int8& /*val*/) const
{ {
@ -414,8 +442,8 @@ inline void VarHolder::convert(Timestamp& /*val*/) const
throw BadCastException("Can not convert to Timestamp"); throw BadCastException("Can not convert to Timestamp");
} }
#ifndef POCO_LONG_IS_64_BIT #ifndef POCO_LONG_IS_64_BIT
inline void VarHolder::convert(long& val) const inline void VarHolder::convert(long& val) const
{ {
Int32 tmp; Int32 tmp;
@ -430,8 +458,8 @@ inline void VarHolder::convert(unsigned long& val) const
convert(tmp); convert(tmp);
val = tmp; val = tmp;
} }
#endif
#endif
inline void VarHolder::convert(bool& /*val*/) const inline void VarHolder::convert(bool& /*val*/) const
{ {
@ -533,9 +561,9 @@ public:
return typeid(T); return typeid(T);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const T& value() const const T& value() const
@ -634,9 +662,9 @@ public:
val = NumberFormatter::format(_val); val = NumberFormatter::format(_val);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const Int8& value() const const Int8& value() const
@ -767,9 +795,9 @@ public:
val = NumberFormatter::format(_val); val = NumberFormatter::format(_val);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const Int16& value() const const Int16& value() const
@ -900,9 +928,9 @@ public:
val = NumberFormatter::format(_val); val = NumberFormatter::format(_val);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const Int32& value() const const Int32& value() const
@ -1048,9 +1076,9 @@ public:
val = Timestamp(_val); val = Timestamp(_val);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const Int64& value() const const Int64& value() const
@ -1181,9 +1209,9 @@ public:
val = NumberFormatter::format(_val); val = NumberFormatter::format(_val);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const UInt8& value() const const UInt8& value() const
@ -1314,9 +1342,9 @@ public:
val = NumberFormatter::format(_val); val = NumberFormatter::format(_val);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const UInt16& value() const const UInt16& value() const
@ -1447,9 +1475,9 @@ public:
val = NumberFormatter::format(_val); val = NumberFormatter::format(_val);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const UInt32& value() const const UInt32& value() const
@ -1601,9 +1629,9 @@ public:
val = Timestamp(tmp); val = Timestamp(tmp);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const UInt64& value() const const UInt64& value() const
@ -1732,9 +1760,9 @@ public:
val = (_val ? "true" : "false"); val = (_val ? "true" : "false");
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const bool& value() const const bool& value() const
@ -1866,9 +1894,9 @@ public:
val = NumberFormatter::format(_val); val = NumberFormatter::format(_val);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const float& value() const const float& value() const
@ -2006,9 +2034,9 @@ public:
val = NumberFormatter::format(_val); val = NumberFormatter::format(_val);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const double& value() const const double& value() const
@ -2137,9 +2165,9 @@ public:
val = std::string(1, _val); val = std::string(1, _val);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const char& value() const const char& value() const
@ -2316,9 +2344,9 @@ public:
ts = tmp.timestamp(); ts = tmp.timestamp();
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const std::string& value() const const std::string& value() const
@ -2452,9 +2480,9 @@ public:
val = NumberFormatter::format(_val); val = NumberFormatter::format(_val);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const long& value() const const long& value() const
@ -2585,9 +2613,9 @@ public:
val = NumberFormatter::format(_val); val = NumberFormatter::format(_val);
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const unsigned long& value() const const unsigned long& value() const
@ -2678,9 +2706,9 @@ public:
val.append(" ]"); val.append(" ]");
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const std::vector<T>& value() const const std::vector<T>& value() const
@ -2799,9 +2827,9 @@ public:
ts = _val.timestamp(); ts = _val.timestamp();
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const DateTime& value() const const DateTime& value() const
@ -2895,9 +2923,9 @@ public:
ts = _val.timestamp(); ts = _val.timestamp();
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const LocalDateTime& value() const const LocalDateTime& value() const
@ -2991,9 +3019,9 @@ public:
ts = _val; ts = _val;
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const Timestamp& value() const const Timestamp& value() const

View File

@ -150,7 +150,7 @@ class SmallObjectAllocator <char*>
/// ///
/// The treshold between auto and heap allocation /// The treshold between auto and heap allocation
/// is controlled through POCO_SMALL_OBJECT_SIZE compile /// is controlled through POCO_SMALL_OBJECT_SIZE compile
/// time constant, which on 32 or 64 systems defaults /// time constant, which on 32 or 64-bit systems defaults
/// to 31 or 63 bytes respectively. This specialization /// to 31 or 63 bytes respectively. This specialization
/// adds an extra byte to indicate the allocation strategy. /// adds an extra byte to indicate the allocation strategy.
/// ///

View File

@ -220,17 +220,6 @@ namespace Poco {
#endif #endif
// Small object size in bytes. Where applicable (e.g.
// SmallObjectAllocator<char*> specialization of , Any, etc)
// objects longer than this value will be alocated on the heap.
// See Poco/SmallObjectAllocator.h for details.
#if (POCO_PTR_IS_64_BIT == 1)
#define POCO_SMALL_OBJECT_SIZE 63
#else
#define POCO_SMALL_OBJECT_SIZE 31
#endif
} // namespace Poco } // namespace Poco

View File

@ -44,35 +44,64 @@ namespace Poco {
namespace Dynamic { namespace Dynamic {
Var::Var(): _pHolder(0) Var::Var()
#ifdef POCO_NO_SOO
: _pHolder(0)
#endif
{ {
} }
Var::Var(const char* pVal): Var::Var(const char* pVal)
_pHolder(new VarHolderImpl<std::string>(pVal)) #ifdef POCO_NO_SOO
: _pHolder(new VarHolderImpl<std::string>(pVal)) { }
#else
{ {
construct(std::string(pVal));
} }
#endif
Var::Var(const Var& other): Var::Var(const Var& other)
_pHolder(0) #ifdef POCO_NO_SOO
: _pHolder(0)
{ {
if (other._pHolder) if (other._pHolder)
_pHolder = other._pHolder->clone(); _pHolder = other._pHolder->clone();
} }
#else
{
if ((this != &other) && !other.isEmpty())
construct(other);
}
#endif
Var::~Var() Var::~Var()
{ {
delete _pHolder; if(!isEmpty())
{
#ifndef POCO_NO_SOO
if(_placeholder.isLocal())
content()->~VarHolder();
else
#endif
delete content();
}
} }
Var& Var::operator = (const Var& other) Var& Var::operator = (const Var& rhs)
{ {
Var tmp(other); #ifdef POCO_NO_SOO
Var tmp(rhs);
swap(tmp); swap(tmp);
#else
if ((this != &rhs) && !rhs.isEmpty())
construct(rhs);
else if ((this != &rhs) && rhs.isEmpty())
_placeholder.erase();
#endif
return *this; return *this;
} }
@ -320,8 +349,14 @@ bool Var::operator && (const Var& other) const
void Var::empty() void Var::empty()
{ {
#ifdef POCO_NO_SOO
delete _pHolder; delete _pHolder;
_pHolder = 0; _pHolder = 0;
#else
if (_placeholder.isLocal()) this->~Var();
else delete content();
_placeholder.erase();
#endif
} }

View File

@ -279,22 +279,22 @@ public:
void convert(DateTime& /*val*/) const void convert(DateTime& /*val*/) const
{ {
throw BadCastException(); throw BadCastException("Cannot convert Array to DateTime");
} }
void convert(LocalDateTime& /*ldt*/) const void convert(LocalDateTime& /*ldt*/) const
{ {
throw BadCastException(); throw BadCastException("Cannot convert Array to LocalDateTime");
} }
void convert(Timestamp& /*ts*/) const void convert(Timestamp& /*ts*/) const
{ {
throw BadCastException(); throw BadCastException("Cannot convert Array to Timestamp");
} }
VarHolder* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const JSON::Array::Ptr& value() const const JSON::Array::Ptr& value() const

View File

@ -291,21 +291,24 @@ public:
void convert(DateTime& /*val*/) const void convert(DateTime& /*val*/) const
{ {
//TODO: val = _val; //TODO: val = _val;
throw NotImplementedException("Conversion not implemented: JSON:Object => DateTime");
} }
void convert(LocalDateTime& /*ldt*/) const void convert(LocalDateTime& /*ldt*/) const
{ {
//TODO: ldt = _val.timestamp(); //TODO: ldt = _val.timestamp();
throw NotImplementedException("Conversion not implemented: JSON:Object => LocalDateTime");
} }
void convert(Timestamp& /*ts*/) const void convert(Timestamp& /*ts*/) const
{ {
//TODO: ts = _val.timestamp(); //TODO: ts = _val.timestamp();
throw NotImplementedException("Conversion not implemented: JSON:Object => Timestamp");
} }
VarHolderImpl* clone() const VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{ {
return new VarHolderImpl(_val); return cloneHolder(pVarHolder, _val);
} }
const JSON::Object::Ptr& value() const const JSON::Object::Ptr& value() const

View File

@ -393,8 +393,8 @@ private:
char _memory[sizeof(Poco::Net::Impl::IPv6AddressImpl)]; char _memory[sizeof(Poco::Net::Impl::IPv6AddressImpl)];
friend class IPv4AddressImpl; friend class Poco::Net::Impl::IPv4AddressImpl;
friend class IPv6AddressImpl; friend class Poco::Net::Impl::IPv6AddressImpl;
}; };