// Very simplist test, could be better. #include "any.hpp" #include "test_shared_lib.hpp" #include #include #include #include #include #if defined(ANY_IMPL_NO_EXCEPTIONS) && defined(_MSC_VER) # include #endif #define CHECK(x) ((x)? (void)(0) : (void(fprintf(stdout, "Failed at %d:%s: %s\n", __LINE__, __FILE__, #x)), std::exit(EXIT_FAILURE))) template 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>({2, 2}); any o2 = make_any>(2, 2); CHECK(any_cast>(o1) == any_cast>(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(any()); } catch(const bad_any_cast&) { except0 = true; } try { any_cast(any(4.0f)); } catch(const bad_any_cast&) { except1 = true; } try { any_cast(any(4.0f)); } catch(const bad_any_cast&) { except2 = true; } try { any_cast(any(big_type())); } catch(const bad_any_cast&) { except3 = true; } try { any_cast(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(any()); } __except (EXCEPTION_EXECUTE_HANDLER) { except0 = true; } __try { any_cast(any(4.0f)); } __except (EXCEPTION_EXECUTE_HANDLER) { except1 = true; } __try { any_cast(any(4.0f)); } __except (EXCEPTION_EXECUTE_HANDLER) { except2 = true; } __try { any_cast(any(big_type())); } __except (EXCEPTION_EXECUTE_HANDLER) { except3 = true; } __try { any_cast(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(&i4) != nullptr); CHECK(any_cast(&i4) == nullptr); CHECK(any_cast(i5) == 5); CHECK(any_cast(f6) == 6.0f); CHECK(any_cast(big1).check() && any_cast(big2).check() && any_cast(big3).check()); } { std::shared_ptr ptr_count(new int); std::weak_ptr 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) <= sizeof(void*) * 1, "unique_ptr too big"); static_assert(sizeof(std::shared_ptr) <= sizeof(void*) * 2, "shared_ptr too big"); any i = 400; any f = 400.0f; //any unique = std::unique_ptr(); -- must be copy constructible any shared = std::shared_ptr(); any rawptr = (void*)(nullptr); any big = big_type(); any w2 = words<2>(); any w3 = words<3>(); CHECK(is_stack_allocated(i, any_cast(&i))); CHECK(is_stack_allocated(f, any_cast(&f))); CHECK(is_stack_allocated(rawptr, any_cast(&rawptr))); //CHECK(is_stack_allocated(unique, any_cast>(&unique))); CHECK(is_stack_allocated(shared, any_cast>(&shared))); CHECK(!is_stack_allocated(big, any_cast(&big))); CHECK(is_stack_allocated(w2, any_cast>(&w2))); CHECK(!is_stack_allocated(w3, any_cast>(&w3))); // Regression test for GitHub Issue #1 any r1 = regression1_type(); CHECK(is_stack_allocated(r1, any_cast(&r1))); } // correctly stored decayed and retrieved in decayed form { const int i = 42; any a = i; // retrieve CHECK(any_cast(&a) != nullptr); CHECK(any_cast(&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(a); } catch(const bad_any_cast&) { except1 = true; } try { any_cast(a); } catch(const bad_any_cast&) { except2 = true; } try { any_cast(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(big_any); } catch (const bad_any_cast &) { except1 = true; } try { any_cast(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 } }