1 // Copyright 2016-2021 Francesco Biscani (bluescarni@gmail.com) 2 // 3 // This file is part of the mp++ library. 4 // 5 // This Source Code Form is subject to the terms of the Mozilla 6 // Public License v. 2.0. If a copy of the MPL was not distributed 7 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 9 #include <cstddef> 10 #include <functional> 11 #include <random> 12 #include <tuple> 13 #include <type_traits> 14 15 #include <gmp.h> 16 17 #include <mp++/integer.hpp> 18 19 #include "catch.hpp" 20 #include "test_utils.hpp" 21 22 static const int ntries = 1000; 23 24 // NOLINTNEXTLINE(google-build-using-namespace) 25 using namespace mppp; 26 // NOLINTNEXTLINE(google-build-using-namespace) 27 using namespace mppp_test; 28 29 using sizes = std::tuple<std::integral_constant<std::size_t, 1>, std::integral_constant<std::size_t, 2>, 30 std::integral_constant<std::size_t, 3>, std::integral_constant<std::size_t, 6>, 31 std::integral_constant<std::size_t, 10>>; 32 33 // NOLINTNEXTLINE(cert-err58-cpp, cert-msc32-c, cert-msc51-cpp, cppcoreguidelines-avoid-non-const-global-variables) 34 static std::mt19937 rng; 35 36 struct hash_tester { 37 template <typename S> operator ()hash_tester38 inline void operator()(const S &) const 39 { 40 using integer = integer<S::value>; 41 const std::hash<integer> hasher{}; 42 integer n1, n2; 43 REQUIRE((hash(n1) == 0u)); 44 REQUIRE((hasher(n1) == 0u)); 45 n1.promote(); 46 REQUIRE((hash(n1) == 0u)); 47 REQUIRE((hasher(n1) == 0u)); 48 n1 = integer{12}; 49 n2 = n1; 50 REQUIRE(n2.is_static()); 51 n1.promote(); 52 REQUIRE(n1.is_dynamic()); 53 REQUIRE((hash(n1) == hash(n2))); 54 REQUIRE((hasher(n1) == hash(n2))); 55 n1 = integer{-12}; 56 n2 = n1; 57 REQUIRE(n2.is_static()); 58 n1.promote(); 59 REQUIRE(n1.is_dynamic()); 60 REQUIRE((hash(n1) == hash(n2))); 61 REQUIRE((hash(n1) == hasher(n2))); 62 detail::mpz_raii tmp; 63 std::uniform_int_distribution<int> sdist(0, 1); 64 // Run a variety of tests with operands with x number of limbs. 65 auto random_xy = [&](unsigned x) { 66 for (int i = 0; i < ntries; ++i) { 67 random_integer(tmp, x, rng); 68 n1 = integer(detail::mpz_to_str(&tmp.m_mpz)); 69 if (sdist(rng)) { 70 n1.neg(); 71 } 72 n2 = n1; 73 if (n2.is_static()) { 74 n1.promote(); 75 } 76 REQUIRE((hash(n1) == hash(n2))); 77 REQUIRE((hasher(n1) == hash(n2))); 78 } 79 }; 80 81 random_xy(0); 82 random_xy(1); 83 random_xy(2); 84 random_xy(3); 85 random_xy(4); 86 } 87 }; 88 89 TEST_CASE("hash") 90 { 91 tuple_for_each(sizes{}, hash_tester{}); 92 } 93