diff --git a/include/boost/uuid/detail/cstring.hpp b/include/boost/uuid/detail/cstring.hpp index b223857..0d93a9f 100644 --- a/include/boost/uuid/detail/cstring.hpp +++ b/include/boost/uuid/detail/cstring.hpp @@ -26,6 +26,24 @@ BOOST_CXX14_CONSTEXPR inline void memcpy( unsigned char* dest, unsigned char con } } +BOOST_CXX14_CONSTEXPR inline int memcmp( unsigned char const* s1, unsigned char const* s2, std::size_t n ) +{ + if( is_constant_evaluated() ) + { + for( std::size_t i = 0; i < n; ++i ) + { + if( s1[ i ] < s2[ i ] ) return -1; + if( s1[ i ] > s2[ i ] ) return +1; + } + + return 0; + } + else + { + return std::memcmp( s1, s2, n ); + } +} + }}} // namespace boost::uuids::detail diff --git a/include/boost/uuid/detail/uuid_generic.ipp b/include/boost/uuid/detail/uuid_generic.ipp index 8e78c4a..38fdee1 100644 --- a/include/boost/uuid/detail/uuid_generic.ipp +++ b/include/boost/uuid/detail/uuid_generic.ipp @@ -6,6 +6,9 @@ // https://www.boost.org/LICENSE_1_0.txt #include +#include +#include +#include #include #if defined(BOOST_UUID_REPORT_IMPLEMENTATION) @@ -18,65 +21,63 @@ BOOST_PRAGMA_MESSAGE( "Using uuid_generic.ipp" ) namespace boost { namespace uuids { -inline bool uuid::is_nil() const noexcept +BOOST_CXX14_CONSTEXPR inline bool operator==( uuid const& lhs, uuid const& rhs ) noexcept { - std::uint64_t v = detail::load_native_u64( this->data + 0 ); - std::uint64_t w = detail::load_native_u64( this->data + 8 ); + if( detail::is_constant_evaluated() ) + { + return detail::memcmp( lhs.data(), rhs.data(), 16 ) == 0; + } + else + { + std::uint64_t v1 = detail::load_native_u64( lhs.data() + 0 ); + std::uint64_t w1 = detail::load_native_u64( lhs.data() + 8 ); - return v == 0 && w == 0; + std::uint64_t v2 = detail::load_native_u64( rhs.data() + 0 ); + std::uint64_t w2 = detail::load_native_u64( rhs.data() + 8 ); + + return v1 == v2 && w1 == w2; + } } -inline void uuid::swap( uuid& rhs ) noexcept +BOOST_CXX14_CONSTEXPR inline bool operator<( uuid const& lhs, uuid const& rhs ) noexcept { - std::uint64_t v1 = detail::load_native_u64( this->data + 0 ); - std::uint64_t w1 = detail::load_native_u64( this->data + 8 ); + if( detail::is_constant_evaluated() ) + { + return detail::memcmp( lhs.data(), rhs.data(), 16 ) < 0; + } + else + { + std::uint64_t v1 = detail::load_big_u64( lhs.data() + 0 ); + std::uint64_t w1 = detail::load_big_u64( lhs.data() + 8 ); - std::uint64_t v2 = detail::load_native_u64( rhs.data + 0 ); - std::uint64_t w2 = detail::load_native_u64( rhs.data + 8 ); + std::uint64_t v2 = detail::load_big_u64( rhs.data() + 0 ); + std::uint64_t w2 = detail::load_big_u64( rhs.data() + 8 ); - detail::store_native_u64( this->data + 0, v2 ); - detail::store_native_u64( this->data + 8, w2 ); - - detail::store_native_u64( rhs.data + 0, v1 ); - detail::store_native_u64( rhs.data + 8, w1 ); -} - -inline bool operator==( uuid const& lhs, uuid const& rhs ) noexcept -{ - std::uint64_t v1 = detail::load_native_u64( lhs.data + 0 ); - std::uint64_t w1 = detail::load_native_u64( lhs.data + 8 ); - - std::uint64_t v2 = detail::load_native_u64( rhs.data + 0 ); - std::uint64_t w2 = detail::load_native_u64( rhs.data + 8 ); - - return v1 == v2 && w1 == w2; -} - -inline bool operator<( uuid const& lhs, uuid const& rhs ) noexcept -{ - std::uint64_t v1 = detail::load_big_u64( lhs.data + 0 ); - std::uint64_t w1 = detail::load_big_u64( lhs.data + 8 ); - - std::uint64_t v2 = detail::load_big_u64( rhs.data + 0 ); - std::uint64_t w2 = detail::load_big_u64( rhs.data + 8 ); - - return v1 < v2 || ( !( v2 < v1 ) && w1 < w2 ); + return v1 < v2 || ( !( v2 < v1 ) && w1 < w2 ); + } } #if defined(BOOST_UUID_HAS_THREE_WAY_COMPARISON) -inline std::strong_ordering operator<=> (uuid const& lhs, uuid const& rhs) noexcept +BOOST_CXX14_CONSTEXPR inline std::strong_ordering operator<=> (uuid const& lhs, uuid const& rhs) noexcept { - std::uint64_t v1 = detail::load_big_u64( lhs.data + 0 ); - std::uint64_t w1 = detail::load_big_u64( lhs.data + 8 ); + if( detail::is_constant_evaluated() ) + { + return detail::memcmp( lhs.data(), rhs.data(), 16 ) <=> 0; + } + else + { + std::uint64_t v1 = detail::load_big_u64( lhs.data() + 0 ); + std::uint64_t w1 = detail::load_big_u64( lhs.data() + 8 ); - std::uint64_t v2 = detail::load_big_u64( rhs.data + 0 ); - std::uint64_t w2 = detail::load_big_u64( rhs.data + 8 ); + std::uint64_t v2 = detail::load_big_u64( rhs.data() + 0 ); + std::uint64_t w2 = detail::load_big_u64( rhs.data() + 8 ); - if( v1 < v2 ) return std::strong_ordering::less; - if( v1 > v2 ) return std::strong_ordering::greater; + if( v1 < v2 ) return std::strong_ordering::less; + if( v1 > v2 ) return std::strong_ordering::greater; - return w1 <=> w2; + return w1 <=> w2; + } } #endif diff --git a/include/boost/uuid/detail/uuid_uint128.ipp b/include/boost/uuid/detail/uuid_uint128.ipp index 5e6f71c..1ad8635 100644 --- a/include/boost/uuid/detail/uuid_uint128.ipp +++ b/include/boost/uuid/detail/uuid_uint128.ipp @@ -6,6 +6,9 @@ // https://www.boost.org/LICENSE_1_0.txt #include +#include +#include +#include #if defined(BOOST_UUID_REPORT_IMPLEMENTATION) @@ -17,45 +20,51 @@ BOOST_PRAGMA_MESSAGE( "Using uuid_uint128.ipp" ) namespace boost { namespace uuids { -inline bool uuid::is_nil() const noexcept +BOOST_CXX14_CONSTEXPR inline bool operator==( uuid const& lhs, uuid const& rhs ) noexcept { - __uint128_t v = detail::load_native_u128( this->data ); - return v == 0; + if( detail::is_constant_evaluated() ) + { + return detail::memcmp( lhs.data(), rhs.data(), 16 ) == 0; + } + else + { + __uint128_t v1 = detail::load_native_u128( lhs.data() ); + __uint128_t v2 = detail::load_native_u128( rhs.data() ); + + return v1 == v2; + } } -inline void uuid::swap( uuid& rhs ) noexcept +BOOST_CXX14_CONSTEXPR inline bool operator<( uuid const& lhs, uuid const& rhs ) noexcept { - __uint128_t v1 = detail::load_native_u128( this->data ); - __uint128_t v2 = detail::load_native_u128( rhs.data ); + if( detail::is_constant_evaluated() ) + { + return detail::memcmp( lhs.data(), rhs.data(), 16 ) < 0; + } + else + { + __uint128_t v1 = detail::load_big_u128( lhs.data() ); + __uint128_t v2 = detail::load_big_u128( rhs.data() ); - detail::store_native_u128( this->data, v2 ); - detail::store_native_u128( rhs.data, v1 ); -} - -inline bool operator==( uuid const& lhs, uuid const& rhs ) noexcept -{ - __uint128_t v1 = detail::load_native_u128( lhs.data ); - __uint128_t v2 = detail::load_native_u128( rhs.data ); - - return v1 == v2; -} - -inline bool operator<( uuid const& lhs, uuid const& rhs ) noexcept -{ - __uint128_t v1 = detail::load_big_u128( lhs.data ); - __uint128_t v2 = detail::load_big_u128( rhs.data ); - - return v1 < v2; + return v1 < v2; + } } #if defined(BOOST_UUID_HAS_THREE_WAY_COMPARISON) -inline std::strong_ordering operator<=> (uuid const& lhs, uuid const& rhs) noexcept +BOOST_CXX14_CONSTEXPR inline std::strong_ordering operator<=> (uuid const& lhs, uuid const& rhs) noexcept { - __uint128_t v1 = detail::load_big_u128( lhs.data ); - __uint128_t v2 = detail::load_big_u128( rhs.data ); + if( detail::is_constant_evaluated() ) + { + return detail::memcmp( lhs.data(), rhs.data(), 16 ) <=> 0; + } + else + { + __uint128_t v1 = detail::load_big_u128( lhs.data() ); + __uint128_t v2 = detail::load_big_u128( rhs.data() ); - return v1 <=> v2; + return v1 <=> v2; + } } #endif diff --git a/include/boost/uuid/detail/uuid_x86.ipp b/include/boost/uuid/detail/uuid_x86.ipp index 43671d0..bf380a1 100644 --- a/include/boost/uuid/detail/uuid_x86.ipp +++ b/include/boost/uuid/detail/uuid_x86.ipp @@ -14,6 +14,9 @@ #define BOOST_UUID_DETAIL_UUID_X86_IPP_INCLUDED_ #include +#include +#include +#include #include #if defined(BOOST_UUID_REPORT_IMPLEMENTATION) @@ -102,53 +105,55 @@ BOOST_FORCEINLINE void compare(uuid const& lhs, uuid const& rhs, std::uint32_t& } // namespace detail -inline bool uuid::is_nil() const noexcept +BOOST_CXX14_CONSTEXPR inline bool operator== (uuid const& lhs, uuid const& rhs) noexcept { - __m128i mm = uuids::detail::load_unaligned_si128(data); -#if defined(BOOST_UUID_USE_SSE41) - return _mm_test_all_zeros(mm, mm) != 0; -#else - mm = _mm_cmpeq_epi32(mm, _mm_setzero_si128()); - return _mm_movemask_epi8(mm) == 0xFFFF; -#endif -} - -inline void uuid::swap(uuid& rhs) noexcept -{ - __m128i mm_this = uuids::detail::load_unaligned_si128(data); - __m128i mm_rhs = uuids::detail::load_unaligned_si128(rhs.data); - _mm_storeu_si128(reinterpret_cast< __m128i* >(rhs.data+0), mm_this); - _mm_storeu_si128(reinterpret_cast< __m128i* >(data+0), mm_rhs); -} - -inline bool operator== (uuid const& lhs, uuid const& rhs) noexcept -{ - __m128i mm_left = uuids::detail::load_unaligned_si128(lhs.data); - __m128i mm_right = uuids::detail::load_unaligned_si128(rhs.data); + if( detail::is_constant_evaluated() ) + { + return detail::memcmp( lhs.data(), rhs.data(), 16 ) == 0; + } + else + { + __m128i mm_left = uuids::detail::load_unaligned_si128(lhs.data); + __m128i mm_right = uuids::detail::load_unaligned_si128(rhs.data); #if defined(BOOST_UUID_USE_SSE41) - __m128i mm = _mm_xor_si128(mm_left, mm_right); - return _mm_test_all_zeros(mm, mm) != 0; + __m128i mm = _mm_xor_si128(mm_left, mm_right); + return _mm_test_all_zeros(mm, mm) != 0; #else - __m128i mm_cmp = _mm_cmpeq_epi32(mm_left, mm_right); - return _mm_movemask_epi8(mm_cmp) == 0xFFFF; + __m128i mm_cmp = _mm_cmpeq_epi32(mm_left, mm_right); + return _mm_movemask_epi8(mm_cmp) == 0xFFFF; #endif + } } -inline bool operator< (uuid const& lhs, uuid const& rhs) noexcept +BOOST_CXX14_CONSTEXPR inline bool operator< (uuid const& lhs, uuid const& rhs) noexcept { - std::uint32_t cmp, rcmp; - uuids::detail::compare(lhs, rhs, cmp, rcmp); - return cmp < rcmp; + if( detail::is_constant_evaluated() ) + { + return detail::memcmp( lhs.data(), rhs.data(), 16 ) < 0; + } + else + { + std::uint32_t cmp = 0, rcmp = 0; + uuids::detail::compare(lhs, rhs, cmp, rcmp); + return cmp < rcmp; + } } #if defined(BOOST_UUID_HAS_THREE_WAY_COMPARISON) -inline std::strong_ordering operator<=> (uuid const& lhs, uuid const& rhs) noexcept +BOOST_CXX14_CONSTEXPR inline std::strong_ordering operator<=> (uuid const& lhs, uuid const& rhs) noexcept { - std::uint32_t cmp, rcmp; - uuids::detail::compare(lhs, rhs, cmp, rcmp); - return cmp <=> rcmp; + if( detail::is_constant_evaluated() ) + { + return detail::memcmp( lhs.data(), rhs.data(), 16 ) <=> 0; + } + else + { + std::uint32_t cmp = 0, rcmp = 0; + uuids::detail::compare(lhs, rhs, cmp, rcmp); + return cmp <=> rcmp; + } } #endif diff --git a/include/boost/uuid/uuid.hpp b/include/boost/uuid/uuid.hpp index e647967..c16877a 100644 --- a/include/boost/uuid/uuid.hpp +++ b/include/boost/uuid/uuid.hpp @@ -136,7 +136,7 @@ public: // is_nil - bool is_nil() const noexcept; + BOOST_CXX14_CONSTEXPR bool is_nil() const noexcept; // variant @@ -272,42 +272,55 @@ public: // swap - void swap( uuid& rhs ) noexcept; + BOOST_CXX14_CONSTEXPR void swap( uuid& rhs ) noexcept + { + uuid tmp( *this ); + *this = rhs; + rhs = tmp; + } }; // operators -inline bool operator==( uuid const& lhs, uuid const& rhs ) noexcept; -inline bool operator< ( uuid const& lhs, uuid const& rhs ) noexcept; +BOOST_CXX14_CONSTEXPR inline bool operator==( uuid const& lhs, uuid const& rhs ) noexcept; +BOOST_CXX14_CONSTEXPR inline bool operator< ( uuid const& lhs, uuid const& rhs ) noexcept; -inline bool operator!=( uuid const& lhs, uuid const& rhs ) noexcept +BOOST_CXX14_CONSTEXPR inline bool operator!=( uuid const& lhs, uuid const& rhs ) noexcept { return !(lhs == rhs); } -inline bool operator>( uuid const& lhs, uuid const& rhs ) noexcept +BOOST_CXX14_CONSTEXPR inline bool operator>( uuid const& lhs, uuid const& rhs ) noexcept { return rhs < lhs; } -inline bool operator<=( uuid const& lhs, uuid const& rhs ) noexcept + +BOOST_CXX14_CONSTEXPR inline bool operator<=( uuid const& lhs, uuid const& rhs ) noexcept { return !(rhs < lhs); } -inline bool operator>=( uuid const& lhs, uuid const& rhs ) noexcept +BOOST_CXX14_CONSTEXPR inline bool operator>=( uuid const& lhs, uuid const& rhs ) noexcept { return !(lhs < rhs); } #if defined(BOOST_UUID_HAS_THREE_WAY_COMPARISON) -inline std::strong_ordering operator<=>( uuid const& lhs, uuid const& rhs ) noexcept; +BOOST_CXX14_CONSTEXPR inline std::strong_ordering operator<=>( uuid const& lhs, uuid const& rhs ) noexcept; #endif +// is_nil + +BOOST_CXX14_CONSTEXPR inline bool uuid::is_nil() const noexcept +{ + return *this == uuid{}; +} + // swap -inline void swap( uuid& lhs, uuid& rhs ) noexcept +BOOST_CXX14_CONSTEXPR inline void swap( uuid& lhs, uuid& rhs ) noexcept { lhs.swap( rhs ); } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 05c31f2..5ecd2d4 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -57,9 +57,9 @@ rule test_headers alias test_headers : [ test_headers ] ; -# test including all .hpp files in 2 translations units +# test including all .hpp files in 2 translation units # to look for issues when using multiple translation units -# e.g. missing inline on a global functionstate is not missing +# e.g. missing inline on a global function run test_include1.cpp test_include2.cpp ; @@ -217,6 +217,9 @@ run test_constants.cpp ; compile test_uuid_cx.cpp ; run test_uuid_cx2.cpp ; +run test_uuid_cx3.cpp + : : : BOOST_UUID_REPORT_IMPLEMENTATION ; +run test_uuid_cx3.cpp : : : BOOST_UUID_NO_SIMD BOOST_UUID_REPORT_IMPLEMENTATION : test_uuid_cx3_no_simd ; run test_string_generator_cx.cpp ; run test_string_generator_cx2.cpp ; diff --git a/test/test_uuid_cx2.cpp b/test/test_uuid_cx2.cpp index fa1560e..f3f867c 100644 --- a/test/test_uuid_cx2.cpp +++ b/test/test_uuid_cx2.cpp @@ -1,4 +1,4 @@ -// Copyright 2024 Peter Dimov +// Copyright 2024, 2025 Peter Dimov // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt diff --git a/test/test_uuid_cx3.cpp b/test/test_uuid_cx3.cpp new file mode 100644 index 0000000..70fdc48 --- /dev/null +++ b/test/test_uuid_cx3.cpp @@ -0,0 +1,65 @@ +// Copyright 2025 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +#if defined(BOOST_NO_CXX14_CONSTEXPR) +# define TEST_EQ(x, y) BOOST_TEST_EQ(x, y) +# define TEST_NE(x, y) BOOST_TEST_NE(x, y) +# define TEST_LT(x, y) BOOST_TEST_LT(x, y) +# define TEST(x) BOOST_TEST(x) +#else +# define TEST_EQ(x, y) STATIC_ASSERT((x)==(y)); BOOST_TEST_EQ(x, y) +# define TEST_NE(x, y) STATIC_ASSERT((x)!=(y)); BOOST_TEST_NE(x, y) +# define TEST_LT(x, y) STATIC_ASSERT((x)<(y)); BOOST_TEST_LT(x, y) +# define TEST(x) STATIC_ASSERT(x); BOOST_TEST(x) +#endif + +using namespace boost::uuids; + +int main() +{ + BOOST_CXX14_CONSTEXPR uuid u1; + BOOST_CXX14_CONSTEXPR uuid u2 = {{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}; + BOOST_CXX14_CONSTEXPR uuid u3 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }}; + + TEST_EQ( u1.is_nil(), true ); + TEST_EQ( u2.is_nil(), false ); + TEST_EQ( u3.is_nil(), false ); + + TEST_EQ( u1, u1 ); + TEST_EQ( u2, u2 ); + TEST_EQ( u3, u3 ); + + TEST_NE( u1, u2 ); + TEST_NE( u1, u3 ); + TEST_NE( u2, u3 ); + + TEST_LT( u1, u2 ); + TEST_LT( u1, u3 ); + TEST_LT( u3, u2 ); + +#if defined(BOOST_UUID_HAS_THREE_WAY_COMPARISON) + + constexpr auto eq = std::strong_ordering::equal; + constexpr auto lt = std::strong_ordering::less; + constexpr auto gt = std::strong_ordering::greater; + + TEST( ( u1 <=> u1 ) == eq ); + TEST( ( u2 <=> u2 ) == eq ); + TEST( ( u3 <=> u3 ) == eq ); + + TEST( ( u1 <=> u2 ) == lt ); + TEST( ( u1 <=> u3 ) == lt ); + TEST( ( u2 <=> u3 ) == gt ); + +#endif + + return boost::report_errors(); +}