Skip to content

Commit

Permalink
refactor(Any): SOO
Browse files Browse the repository at this point in the history
- encapsulate data holders
- add missing gets and ops
- eliminate g++ warnings with enable_if's
- default enable SOO
  • Loading branch information
aleks-f committed Apr 14, 2022
1 parent 7ae6b60 commit c032c16
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 76 deletions.
108 changes: 72 additions & 36 deletions Foundation/include/Poco/Any.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ template <class T> class VarHolderImpl;
}


template <class T, std::size_t S>
struct TypeSizeLE:
std::integral_constant<bool, (sizeof(T) <= S)>{};


template <class T, std::size_t S>
struct TypeSizeGT:
std::integral_constant<bool, (sizeof(T) > S)>{};


#ifndef POCO_NO_SOO


Expand All @@ -63,11 +73,25 @@ union Placeholder
erase();
}

void swap(Placeholder& other)
{
if (!isLocal() && !other.isLocal())
std::swap(pHolder, other.pHolder);
else
throw Poco::InvalidAccessException("Placeholder::swap()");
}

void erase()
{
std::memset(holder, 0, sizeof(Placeholder));
}

bool isEmpty() const
{
char buf[POCO_SMALL_OBJECT_SIZE] = {};
return 0 == std::memcmp(holder, buf, POCO_SMALL_OBJECT_SIZE);
}

bool isLocal() const
{
return holder[SizeV] != 0;
Expand All @@ -78,6 +102,22 @@ union Placeholder
holder[SizeV] = local ? 1 : 0;
}

template <typename T, typename V>
PlaceholderT* assignStack(const V& value)
{
new (reinterpret_cast<PlaceholderT*>(holder)) T(value);
setLocal(true);
return reinterpret_cast<PlaceholderT*>(holder);
}

template <typename T, typename V>
PlaceholderT* assignHeap(const V& value)
{
pHolder = new T(value);
setLocal(false);
return pHolder;
}

PlaceholderT* content() const
{
if (isLocal())
Expand All @@ -86,20 +126,12 @@ union Placeholder
return pHolder;
}

// MSVC71,80 won't extend friendship to nested class (Any::Holder)
#if !defined(POCO_MSVC_VERSION) || (defined(POCO_MSVC_VERSION) && (POCO_MSVC_VERSION > 80))
private:
#endif
typedef typename std::aligned_storage<SizeV + 1>::type AlignerType;

PlaceholderT* pHolder;
mutable char holder[SizeV + 1];
AlignerType aligner;
typedef typename std::aligned_storage<SizeV+1>::type AlignerType;

friend class Any;
friend class Dynamic::Var;
friend class Dynamic::VarHolder;
template <class> friend class Dynamic::VarHolderImpl;
PlaceholderT* pHolder;
mutable unsigned char holder[SizeV+1];
AlignerType aligner;
};


Expand Down Expand Up @@ -205,7 +237,7 @@ class Any

if (!_valueHolder.isLocal() && !other._valueHolder.isLocal())
{
std::swap(_valueHolder.pHolder, other._valueHolder.pHolder);
_valueHolder.swap(other._valueHolder);
}
else
{
Expand Down Expand Up @@ -252,8 +284,7 @@ class Any
bool empty() const
/// Returns true if the Any is empty.
{
char buf[POCO_SMALL_OBJECT_SIZE] = { 0 };
return 0 == std::memcmp(_valueHolder.holder, buf, POCO_SMALL_OBJECT_SIZE);
return _valueHolder.isEmpty();
}

const std::type_info & type() const
Expand Down Expand Up @@ -290,21 +321,27 @@ class Any

virtual void clone(Placeholder<ValueHolder>* pPlaceholder) const
{
if ((sizeof(Holder<ValueType>) <= POCO_SMALL_OBJECT_SIZE))
{
new ((ValueHolder*) pPlaceholder->holder) Holder(_held);
pPlaceholder->setLocal(true);
}
else
{
pPlaceholder->pHolder = new Holder(_held);
pPlaceholder->setLocal(false);
}
cloneSOO(pPlaceholder, _held);
}

ValueType _held;

private:

template<typename VT,
typename std::enable_if<TypeSizeLE<Holder<VT>, Placeholder<VT>::Size::value>::value>::type* = nullptr>
static void cloneSOO(Placeholder<ValueHolder>* pPlaceholder, VT& held)
{
pPlaceholder->assignStack<Holder<ValueType>, ValueType>(held);
}

template<typename VT,
typename std::enable_if<TypeSizeGT<Holder<VT>, Placeholder<VT>::Size::value>::value>::type* = nullptr>
static void cloneSOO(Placeholder<ValueHolder>* pPlaceholder, VT& held)
{
pPlaceholder->assignHeap<Holder<ValueType>, ValueType>(held);
}

Holder & operator = (const Holder &);
};

Expand All @@ -313,19 +350,18 @@ class Any
return _valueHolder.content();
}

template<typename ValueType>
template<typename ValueType,
typename std::enable_if<TypeSizeLE<Holder<ValueType>, Placeholder<ValueType>::Size::value>::value>::type* = nullptr>
void construct(const ValueType& value)
{
if (sizeof(Holder<ValueType>) <= Placeholder<ValueType>::Size::value)
{
new (reinterpret_cast<ValueHolder*>(_valueHolder.holder)) Holder<ValueType>(value);
_valueHolder.setLocal(true);
}
else
{
_valueHolder.pHolder = new Holder<ValueType>(value);
_valueHolder.setLocal(false);
}
_valueHolder.assignStack<Holder<ValueType>, ValueType>(value);
}

template<typename ValueType,
typename std::enable_if<TypeSizeGT<Holder<ValueType>, Placeholder<ValueType>::Size::value>::value>::type* = nullptr>
void construct(const ValueType& value)
{
_valueHolder.assignHeap<Holder<ValueType>, ValueType>(value);
}

void construct(const Any& other)
Expand Down
8 changes: 2 additions & 6 deletions Foundation/include/Poco/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,15 @@
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!! NOTE: Any/Dynamic::Var SOO will NOT work reliably !!!
// !!! without C++11 (std::aligned_storage in particular). !!!
// !!! Only comment this out if your compiler has support !!!
// !!! for std::aligned_storage. !!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
#ifndef POCO_ENABLE_SOO
#define POCO_NO_SOO
#endif
//#define POCO_NO_SOO


// Small object size in bytes. When assigned to Any or Var,
// objects larger than this value will be alocated on the heap,
// while those smaller will be placement new-ed into an
// internal buffer.
// internal stack-auto-allocated buffer.
#if !defined(POCO_SMALL_OBJECT_SIZE) && !defined(POCO_NO_SOO)
#define POCO_SMALL_OBJECT_SIZE 32
#endif
Expand Down
38 changes: 17 additions & 21 deletions Foundation/include/Poco/Dynamic/Var.h
Original file line number Diff line number Diff line change
Expand Up @@ -633,34 +633,30 @@ class Foundation_API Var
return _placeholder.content();
}

template<typename ValueType,
typename std::enable_if<TypeSizeLE<VarHolderImpl<ValueType>, Placeholder<ValueType>::Size::value>::value>::type* = nullptr>
void constructSOO(const ValueType& value)
{
_placeholder.assignStack<VarHolderImpl<ValueType>, ValueType>(value);
}

template<typename ValueType,
typename std::enable_if<TypeSizeGT<VarHolderImpl<ValueType>, Placeholder<ValueType>::Size::value>::value>::type* = nullptr>
void constructSOO(const ValueType& value)
{
_placeholder.assignHeap<VarHolderImpl<ValueType>, ValueType>(value);
}

template<typename ValueType>
void construct(const ValueType& value)
{
if (sizeof(VarHolderImpl<ValueType>) <= Placeholder<ValueType>::Size::value)
{
new (reinterpret_cast<VarHolder*>(_placeholder.holder)) VarHolderImpl<ValueType>(value);
_placeholder.setLocal(true);
}
else
{
_placeholder.pHolder = new VarHolderImpl<ValueType>(value);
_placeholder.setLocal(false);
}
constructSOO(value);
}

void construct(const char* value)
{
std::string val(value);
if (sizeof(VarHolderImpl<std::string>) <= Placeholder<std::string>::Size::value)
{
new (reinterpret_cast<VarHolder*>(_placeholder.holder)) VarHolderImpl<std::string>(val);
_placeholder.setLocal(true);
}
else
{
_placeholder.pHolder = new VarHolderImpl<std::string>(val);
_placeholder.setLocal(false);
}
constructSOO(val);
}

void construct(const Var& other)
Expand Down Expand Up @@ -709,7 +705,7 @@ inline void Var::swap(Var& other)

if (!_placeholder.isLocal() && !other._placeholder.isLocal())
{
std::swap(_placeholder.pHolder, other._placeholder.pHolder);
_placeholder.swap(other._placeholder);
}
else
{
Expand Down
34 changes: 21 additions & 13 deletions Foundation/include/Poco/Dynamic/VarHolder.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,19 +307,8 @@ class Foundation_API VarHolder
(void)pVarHolder;
return new VarHolderImpl<T>(val);
#else
poco_check_ptr (pVarHolder);
if ((sizeof(VarHolderImpl<T>) <= Placeholder<T>::Size::value))
{
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;
}
poco_check_ptr (pVarHolder);
return makeSOOHolder(pVarHolder, val);
#endif
}

Expand Down Expand Up @@ -420,6 +409,25 @@ class Foundation_API VarHolder
}

private:

#ifndef POCO_NO_SOO
template<typename T,
typename std::enable_if<TypeSizeLE<VarHolderImpl<T>, Placeholder<T>::Size::value>::value>::type* = nullptr>
VarHolder* makeSOOHolder(Placeholder<VarHolder>* pVarHolder, const T& val) const
{
poco_check_ptr (pVarHolder);
return pVarHolder->assignStack<VarHolderImpl<T>, T>(val);
}

template<typename T,
typename std::enable_if<TypeSizeGT<VarHolderImpl<T>, Placeholder<T>::Size::value>::value>::type* = nullptr>
VarHolder* makeSOOHolder(Placeholder<VarHolder>* pVarHolder, const T& val) const
{
poco_check_ptr (pVarHolder);
return pVarHolder->assignHeap<VarHolderImpl<T>, T>(val);
}
#endif

template <typename F, typename T>
void checkUpperLimit(const F& from) const
{
Expand Down

0 comments on commit c032c16

Please sign in to comment.