diff --git a/SG14/inplace_function.h b/SG14/inplace_function.h index 83b6a072..eae9bf20 100644 --- a/SG14/inplace_function.h +++ b/SG14/inplace_function.h @@ -36,6 +36,35 @@ namespace inplace_function_detail { static constexpr size_t InplaceFunctionDefaultCapacity = 32; +#if defined(__GLIBCXX__) // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61458 +template +union aligned_storage_helper { + struct double1 { double a; }; + struct double4 { double a[4]; }; + template using maybe = std::conditional_t<(Cap >= sizeof(T)), T, char>; + char real_data[Cap]; + maybe a; + maybe b; + maybe c; + maybe d; + maybe e; + maybe f; + maybe g; + maybe h; +}; + +template>::value> +struct aligned_storage { + using type = std::aligned_storage_t; +}; + +template>::value> +using aligned_storage_t = typename aligned_storage::type; +#else +using std::aligned_storage; +using std::aligned_storage_t; +#endif + template struct wrapper { using type = T; @@ -116,7 +145,7 @@ struct is_valid_inplace_dst : std::true_type template< typename Signature, size_t Capacity = inplace_function_detail::InplaceFunctionDefaultCapacity, - size_t Alignment = std::alignment_of>::value + size_t Alignment = std::alignment_of>::value > class inplace_function; // unspecified @@ -132,7 +161,7 @@ class inplace_function using capacity = std::integral_constant; using alignment = std::integral_constant; - using storage_t = std::aligned_storage_t; + using storage_t = inplace_function_detail::aligned_storage_t; using vtable_t = inplace_function_detail::vtable; using vtable_ptr_t = const vtable_t*; diff --git a/SG14_test/inplace_function_test.cpp b/SG14_test/inplace_function_test.cpp index 50091d24..c683485d 100644 --- a/SG14_test/inplace_function_test.cpp +++ b/SG14_test/inplace_function_test.cpp @@ -1,5 +1,5 @@ #include "SG14_test.h" -#include "../SG14/inplace_function.h" +#include "inplace_function.h" #include #include #include @@ -260,6 +260,22 @@ void AssignmentDifferentFunctor() EXPECT_EQ(4, calls); } +template +constexpr size_t expected_alignment_for_capacity() +{ + constexpr size_t alignof_ptr = std::alignment_of::value; + constexpr size_t alignof_cap = std::alignment_of>::value; +#define MIN(a,b) (a < b ? a : b) +#define MAX(a,b) (a > b ? a : b) +#if defined(__GLIBCXX__) // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61458 + return MAX(MIN(Cap, alignof_cap), alignof_ptr); +#else // other STLs + return MAX(alignof_cap, alignof_ptr); +#endif +#undef MAX +#undef MIN +} + void sg14_test::inplace_function_test() { // first set of tests (from Optiver) @@ -287,12 +303,13 @@ void sg14_test::inplace_function_test() #endif static_assert(std::is_nothrow_destructible::value, ""); - constexpr int alignof_ptr = std::alignment_of::value; - static_assert(std::alignment_of< stdext::inplace_function >::value == std::max(1, alignof_ptr), ""); - static_assert(std::alignment_of< stdext::inplace_function >::value == std::max(2, alignof_ptr), ""); - static_assert(std::alignment_of< stdext::inplace_function >::value == std::max(4, alignof_ptr), ""); - static_assert(std::alignment_of< stdext::inplace_function >::value == std::max(8, alignof_ptr), ""); - static_assert(std::alignment_of< stdext::inplace_function >::value == std::max(16, alignof_ptr), ""); + static_assert(std::alignment_of< stdext::inplace_function >::value == expected_alignment_for_capacity<1>(), ""); + static_assert(std::alignment_of< stdext::inplace_function >::value == expected_alignment_for_capacity<2>(), ""); + static_assert(std::alignment_of< stdext::inplace_function >::value == expected_alignment_for_capacity<4>(), ""); + static_assert(std::alignment_of< stdext::inplace_function >::value == expected_alignment_for_capacity<8>(), ""); + static_assert(std::alignment_of< stdext::inplace_function >::value == expected_alignment_for_capacity<16>(), ""); + static_assert(std::alignment_of< stdext::inplace_function >::value == expected_alignment_for_capacity<32>(), ""); + static_assert(sizeof( stdext::inplace_function ) == 2 * sizeof(void*), ""); IPF func;