Skip to content

Commit

Permalink
fix(Any): As of C++11, std::swap is noexcept. #2386
Browse files Browse the repository at this point in the history
  • Loading branch information
aleks-f committed Jun 27, 2022
1 parent 113bc4a commit fcf7e78
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 6 deletions.
29 changes: 27 additions & 2 deletions Foundation/include/Poco/Any.h
Expand Up @@ -23,6 +23,9 @@
#include <cstring>


#define poco_any_assert(cond) do { if (!(cond)) std::abort(); } while (0)


namespace Poco {

class Any;
Expand Down Expand Up @@ -56,6 +59,9 @@ union Placeholder
/// (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).
///
/// Important: for SOO builds, only same-type (or trivial both-empty no-op)
/// swap operation is allowed.
{
public:
struct Size
Expand All @@ -82,8 +88,22 @@ union Placeholder

void swap(Placeholder& other) noexcept
{
poco_assert (isLocal() && other.isLocal());
std::swap(pHolder, other.pHolder);
bool empty = isEmpty();
bool otherEmpty = other.isEmpty();
bool local = isLocal();
bool otherLocal = other.isLocal();

if (empty && otherEmpty) return;
poco_any_assert (local == otherLocal);
if (!local) std::swap(pHolder, other.pHolder);
else
{
unsigned int sz = SizeV + 1;
unsigned char tmpHolder[sz] = {};
std::memcpy(tmpHolder, holder, sz);
std::memcpy(holder, other.holder, sz);
std::memcpy(other.holder, tmpHolder, sz);
}
}

void erase()
Expand Down Expand Up @@ -314,6 +334,11 @@ class Any
return empty() ? typeid(void) : content()->type();
}

bool local() const
{
return _valueHolder.isLocal();
}

private:
class ValueHolder
{
Expand Down
2 changes: 1 addition & 1 deletion Foundation/include/Poco/Config.h
Expand Up @@ -79,7 +79,7 @@
// while those smaller will be placement new-ed into an
// internal stack-auto-allocated buffer.
#if !defined(POCO_SMALL_OBJECT_SIZE)
#define POCO_SMALL_OBJECT_SIZE 32
#define POCO_SMALL_OBJECT_SIZE 64
#endif


Expand Down
53 changes: 50 additions & 3 deletions Foundation/testsuite/src/AnyTest.cpp
Expand Up @@ -186,6 +186,14 @@ void AnyTest::testAnySwap()
{
std::string text = "test message";
Any original = text, swapped;
#ifdef POCO_NO_SOO
assertFalse (original.local());
#else
assertTrue (original.local());
#endif
assertFalse (original.empty());
assertFalse (swapped.local());
assertTrue (swapped.empty());
std::string* originalPtr = AnyCast<std::string>(&original);
Any* swapResult = &original.swap(swapped);

Expand All @@ -194,10 +202,49 @@ void AnyTest::testAnySwap()
assertTrue (swapped.type() == typeid(std::string));
assertTrue (text == AnyCast<std::string>(swapped));
assertTrue (0 != originalPtr);
#ifdef POCO_NO_SOO // pointers only match when heap-allocated
assertTrue (originalPtr == AnyCast<std::string>(&swapped));
#endif
assertTrue (swapResult == &original);

struct BigObject
{
Poco::UInt64 one = 1;
Poco::UInt64 two = 2;
Poco::UInt64 three = 3;
Poco::UInt64 four = 4;
Poco::UInt64 five = 5;
Poco::UInt64 six = 6;
Poco::UInt64 seven = 7;
Poco::UInt64 eight = 8;
Poco::UInt64 nine = 9;

bool operator==(const BigObject& other)
{
return one == other.one &&
two == other.two &&
three == other.three &&
four == other.four &&
five == other.five &&
six == other.six &&
seven == other.seven &&
eight == other.eight &&
nine == other.nine;
}
};

BigObject bigObject;
Any bigOriginal = bigObject, swappedBig;
assertFalse (bigOriginal.local());
assertFalse (bigOriginal.empty());
assertFalse (swappedBig.local());
assertTrue (swappedBig.empty());
BigObject* bigPtr = AnyCast<BigObject>(&bigOriginal);
Any* swapBigResult = &bigOriginal.swap(swappedBig);

assertTrue (bigOriginal.empty());
assertTrue (!swappedBig.empty());
assertTrue (swappedBig.type() == typeid(BigObject));
assertTrue (bigObject == AnyCast<BigObject>(swappedBig));
assertTrue (0 != bigPtr);
assertTrue (swapBigResult == &bigOriginal);
}


Expand Down

0 comments on commit fcf7e78

Please sign in to comment.