zeek/auxil/spicy/3rdparty/any/test_any.cpp
Patrick Kelley 8fd444092b initial
2025-05-07 15:35:15 -04:00

317 lines
8.4 KiB
C++

// Very simplist test, could be better.
#include "any.hpp"
#include "test_shared_lib.hpp"
#include <memory>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <vector>
#if defined(ANY_IMPL_NO_EXCEPTIONS) && defined(_MSC_VER)
# include <excpt.h>
#endif
#define CHECK(x) ((x)? (void)(0) : (void(fprintf(stdout, "Failed at %d:%s: %s\n", __LINE__, __FILE__, #x)), std::exit(EXIT_FAILURE)))
template<size_t N>
struct words
{
void* w[N];
};
struct big_type
{
char i_wanna_be_big[256];
std::string value;
big_type() :
value(std::string(300, 'b'))
{
i_wanna_be_big[0] = i_wanna_be_big[50] = 'k';
}
bool check()
{
CHECK(value.size() == 300);
CHECK(value.front() == 'b' && value.back() == 'b');
CHECK(i_wanna_be_big[0] == 'k' && i_wanna_be_big[50] == 'k');
return true;
}
};
// small type which has nothrow move ctor but throw copy ctor
struct regression1_type
{
const void* confuse_stack_storage = (void*)(0);
regression1_type() {}
regression1_type(const regression1_type&) {}
regression1_type(regression1_type&&) noexcept {}
regression1_type& operator=(const regression1_type&) { return *this; }
regression1_type& operator=(regression1_type&&) { return *this; }
};
int main()
{
using linb::any;
using linb::any_cast;
using linb::bad_any_cast;
using linb::make_any;
{
any x = 4;
any y = big_type();
any z = 6;
CHECK(any().empty());
CHECK(!any(1).empty());
CHECK(!any(big_type()).empty());
CHECK(!x.empty() && !y.empty() && !z.empty());
y.clear();
CHECK(!x.empty() && y.empty() && !z.empty());
x = y;
CHECK(x.empty() && y.empty() && !z.empty());
z = any();
CHECK(x.empty() && y.empty() && z.empty());
}
{
any o1 = make_any<std::vector<int>>({2, 2});
any o2 = make_any<std::vector<int>>(2, 2);
CHECK(any_cast<std::vector<int>>(o1) == any_cast<std::vector<int>>(o2));
}
#ifndef ANY_IMPL_NO_RTTI
{
CHECK(any().type() == typeid(void));
CHECK(any(4).type() == typeid(int));
CHECK(any(big_type()).type() == typeid(big_type));
CHECK(any(1.5f).type() == typeid(float));
}
#endif
{
bool except0 = false;
bool except1 = false, except2 = false;
bool except3 = false, except4 = false;
#ifndef ANY_IMPL_NO_EXCEPTIONS
try {
any_cast<int>(any());
}
catch(const bad_any_cast&) {
except0 = true;
}
try {
any_cast<int>(any(4.0f));
}
catch(const bad_any_cast&) {
except1 = true;
}
try {
any_cast<float>(any(4.0f));
}
catch(const bad_any_cast&) {
except2 = true;
}
try {
any_cast<float>(any(big_type()));
}
catch(const bad_any_cast&) {
except3 = true;
}
try {
any_cast<big_type>(any(big_type()));
}
catch(const bad_any_cast&) {
except4 = true;
}
#elif _MSC_VER
// we can test segmentation faults with msvc
# ifdef _CPPUNWIND
# error Must use msvc compiler with exceptions disabled (no /EHa, /EHsc, /EHs)
# endif
__try {
any_cast<int>(any());
} __except (EXCEPTION_EXECUTE_HANDLER) {
except0 = true;
}
__try {
any_cast<int>(any(4.0f));
} __except (EXCEPTION_EXECUTE_HANDLER) {
except1 = true;
}
__try {
any_cast<float>(any(4.0f));
} __except (EXCEPTION_EXECUTE_HANDLER) {
except2 = true;
}
__try {
any_cast<float>(any(big_type()));
} __except (EXCEPTION_EXECUTE_HANDLER) {
except3 = true;
}
__try {
any_cast<big_type>(any(big_type()));
} __except (EXCEPTION_EXECUTE_HANDLER) {
except4 = true;
}
#endif
CHECK(except0 == true);
CHECK(except1 == true && except2 == false);
CHECK(except3 == true && except4 == false);
}
{
any i4 = 4;
any i5 = 5;
any f6 = 6.0f;
any big1 = big_type();
any big2 = big_type();
any big3 = big_type();
CHECK(any_cast<int>(&i4) != nullptr);
CHECK(any_cast<float>(&i4) == nullptr);
CHECK(any_cast<int>(i5) == 5);
CHECK(any_cast<float>(f6) == 6.0f);
CHECK(any_cast<big_type>(big1).check()
&& any_cast<big_type>(big2).check()
&& any_cast<big_type>(big3).check());
}
{
std::shared_ptr<int> ptr_count(new int);
std::weak_ptr<int> weak = ptr_count;
any p0 = 0;
CHECK(weak.use_count() == 1);
any p1 = ptr_count;
CHECK(weak.use_count() == 2);
any p2 = p1;
CHECK(weak.use_count() == 3);
p0 = p1;
CHECK(weak.use_count() == 4);
p0 = 0;
CHECK(weak.use_count() == 3);
p0 = std::move(p1);
CHECK(weak.use_count() == 3);
p0.swap(p1);
CHECK(weak.use_count() == 3);
p0 = 0;
CHECK(weak.use_count() == 3);
p1.clear();
CHECK(weak.use_count() == 2);
p2 = any(big_type());
CHECK(weak.use_count() == 1);
p1 = ptr_count;
CHECK(weak.use_count() == 2);
ptr_count = nullptr;
CHECK(weak.use_count() == 1);
p1 = any();
CHECK(weak.use_count() == 0);
}
{
auto is_stack_allocated = [](const any& a, const void* obj1) {
uintptr_t a_ptr = (uintptr_t)(&a);
uintptr_t obj = (uintptr_t)(obj1);
return (obj >= a_ptr && obj < a_ptr + sizeof(any));
};
//static_assert(sizeof(std::unique_ptr<big_type>) <= sizeof(void*) * 1, "unique_ptr too big");
static_assert(sizeof(std::shared_ptr<big_type>) <= sizeof(void*) * 2, "shared_ptr too big");
any i = 400;
any f = 400.0f;
//any unique = std::unique_ptr<big_type>(); -- must be copy constructible
any shared = std::shared_ptr<big_type>();
any rawptr = (void*)(nullptr);
any big = big_type();
any w2 = words<2>();
any w3 = words<3>();
CHECK(is_stack_allocated(i, any_cast<int>(&i)));
CHECK(is_stack_allocated(f, any_cast<float>(&f)));
CHECK(is_stack_allocated(rawptr, any_cast<void*>(&rawptr)));
//CHECK(is_stack_allocated(unique, any_cast<std::unique_ptr<big_type>>(&unique)));
CHECK(is_stack_allocated(shared, any_cast<std::shared_ptr<big_type>>(&shared)));
CHECK(!is_stack_allocated(big, any_cast<big_type>(&big)));
CHECK(is_stack_allocated(w2, any_cast<words<2>>(&w2)));
CHECK(!is_stack_allocated(w3, any_cast<words<3>>(&w3)));
// Regression test for GitHub Issue #1
any r1 = regression1_type();
CHECK(is_stack_allocated(r1, any_cast<const regression1_type>(&r1)));
}
// correctly stored decayed and retrieved in decayed form
{
const int i = 42;
any a = i;
// retrieve
CHECK(any_cast<int>(&a) != nullptr);
CHECK(any_cast<const int>(&a) != nullptr);
#ifndef ANY_IMPL_NO_EXCEPTIONS
// must not throw
bool except1 = false, except2 = false, except3 = false;
// same with reference to any
try {
any_cast<int>(a);
}
catch(const bad_any_cast&) {
except1 = true;
}
try {
any_cast<const int>(a);
}
catch(const bad_any_cast&) {
except2 = true;
}
try {
any_cast<const int>(std::move(a));
}
catch(const bad_any_cast&) {
except3 = true;
}
CHECK(except1 == false);
CHECK(except2 == false);
CHECK(except3 == false);
#endif
}
{
bool except1 = false, except2 = false;
auto big_any = shared_test_lib::createBigData();
auto small_any = shared_test_lib::createSmallData();
try {
any_cast<shared_test_lib::big_data>(big_any);
} catch (const bad_any_cast &) {
except1 = true;
}
try {
any_cast<shared_test_lib::small_data>(small_any);
} catch (const bad_any_cast &) {
except2 = true;
}
#ifndef ANY_IMPL_NO_RTTI
CHECK(except1 == false);
CHECK(except2 == false);
#else
CHECK(except1 == true);
CHECK(except2 == true);
#endif
}
}