include/o3tl/concepts.hxx | 7 +++ include/o3tl/hash_combine.hxx | 15 +++----- o3tl/CppunitTest_o3tl_tests.mk | 1 o3tl/qa/test-hash_combine.cxx | 73 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 8 deletions(-)
New commits: commit 794e86b99dae26358b9837645a5db95073dfccd4 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Thu Feb 27 10:49:44 2025 +0900 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Mon Mar 3 09:43:18 2025 +0100 o3tl: Add concepts for 32/64 bit types, use in hash_combine This simplifies determining what the byte size of the template type is, so we can write a specific implementation for 32 and 64 bit seeds for hash_combine. Change-Id: Icd68e4618151957ecc00585dd521adf11fe3931a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182266 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/include/o3tl/concepts.hxx b/include/o3tl/concepts.hxx index f47aef5f256d..07ddcdc459ea 100644 --- a/include/o3tl/concepts.hxx +++ b/include/o3tl/concepts.hxx @@ -45,4 +45,11 @@ template <typename T> concept floating_point = std::is_floating_point_v<T>; #endif +// Common concepts +namespace o3tl +{ +template <typename T> concept type_32_bit = sizeof(T) == 4; +template <typename T> concept type_64_bit = sizeof(T) == 8; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/include/o3tl/hash_combine.hxx b/include/o3tl/hash_combine.hxx index 48e14262228e..80b2a7fa0825 100644 --- a/include/o3tl/hash_combine.hxx +++ b/include/o3tl/hash_combine.hxx @@ -12,11 +12,12 @@ #include <cstddef> #include <functional> #include <type_traits> +#include <o3tl/concepts.hxx> namespace o3tl { -template <typename T, typename N> -inline std::enable_if_t<(sizeof(N) == 4)> hash_combine(N& nSeed, T const* pValue, size_t nCount) +template <typename T, type_32_bit N> +inline void hash_combine(N& nSeed, T const* pValue, size_t nCount) { static_assert(sizeof(nSeed) == 4); for (size_t i = 0; i < nCount; ++i) @@ -26,15 +27,14 @@ inline std::enable_if_t<(sizeof(N) == 4)> hash_combine(N& nSeed, T const* pValue } } -template <typename T, typename N> -inline std::enable_if_t<(sizeof(N) == 4)> hash_combine(N& nSeed, T const& nValue) +template <typename T, type_32_bit N> inline void hash_combine(N& nSeed, T const& nValue) { static_assert(sizeof(nSeed) == 4); nSeed ^= std::hash<T>{}(nValue) + 0x9E3779B9u + (nSeed << 6) + (nSeed >> 2); } -template <typename T, typename N> -inline std::enable_if_t<(sizeof(N) == 8)> hash_combine(N& nSeed, T const* pValue, size_t nCount) +template <typename T, type_64_bit N> +inline void hash_combine(N& nSeed, T const* pValue, size_t nCount) { static_assert(sizeof(nSeed) == 8); for (size_t i = 0; i < nCount; ++i) @@ -44,8 +44,7 @@ inline std::enable_if_t<(sizeof(N) == 8)> hash_combine(N& nSeed, T const* pValue } } -template <typename T, typename N> -inline std::enable_if_t<(sizeof(N) == 8)> hash_combine(N& nSeed, T const& nValue) +template <typename T, type_64_bit N> inline void hash_combine(N& nSeed, T const& nValue) { static_assert(sizeof(nSeed) == 8); nSeed ^= std::hash<T>{}(nValue) + 0x9E3779B97F4A7C15llu + (nSeed << 12) + (nSeed >> 4); diff --git a/o3tl/CppunitTest_o3tl_tests.mk b/o3tl/CppunitTest_o3tl_tests.mk index 1715659ffbee..01f6e410a1b2 100644 --- a/o3tl/CppunitTest_o3tl_tests.mk +++ b/o3tl/CppunitTest_o3tl_tests.mk @@ -39,6 +39,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,o3tl_tests,\ o3tl/qa/test-typed_flags \ o3tl/qa/test-unit_conversion \ o3tl/qa/test-vector_pool \ + o3tl/qa/test-hash_combine \ )) # vim: set noet sw=4: diff --git a/o3tl/qa/test-hash_combine.cxx b/o3tl/qa/test-hash_combine.cxx new file mode 100644 index 000000000000..0bf72036ed10 --- /dev/null +++ b/o3tl/qa/test-hash_combine.cxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <sal/types.h> +#include <rtl/ustring.hxx> +#include <o3tl/hash_combine.hxx> + +namespace +{ +struct TestStruct +{ +}; + +class HashCombineTest : public CppUnit::TestFixture +{ +public: + void testBaseUsage() + { + TestStruct objectA; + TestStruct objectB; + + { + sal_uInt64 seed(0); + o3tl::hash_combine(seed, OUString("Hmm-..")); + o3tl::hash_combine(seed, 24); + o3tl::hash_combine(seed, 42u); + o3tl::hash_combine(seed, 5.1); + o3tl::hash_combine(seed, &objectA); + o3tl::hash_combine(seed, &objectB); + CPPUNIT_ASSERT(seed != sal_uInt64(0)); + + static_assert(sizeof(seed) == 8); + } + + { + sal_uInt32 seed(0); + o3tl::hash_combine(seed, OUString("Hmm-..")); + o3tl::hash_combine(seed, 24); + o3tl::hash_combine(seed, 42u); + o3tl::hash_combine(seed, 5.1); + o3tl::hash_combine(seed, &objectA); + o3tl::hash_combine(seed, &objectB); + CPPUNIT_ASSERT(seed != sal_uInt32(0)); + + static_assert(sizeof(seed) == 4); + } + + // No assert of the actual value - we just check this compiles and runs. Hash algorithm is probably + // also implementation specific. + + // Using sal_uInt16 for seed doesn't compile as there is not compatible hash_combine override for seed that is 16 bit. + } + + CPPUNIT_TEST_SUITE(HashCombineTest); + CPPUNIT_TEST(testBaseUsage); + CPPUNIT_TEST_SUITE_END(); +}; +} + +CPPUNIT_TEST_SUITE_REGISTRATION(HashCombineTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */