diff --git a/hash/doc/changes.qbk b/hash/doc/changes.qbk
index eb6572f..c47bd56 100644
--- a/hash/doc/changes.qbk
+++ b/hash/doc/changes.qbk
@@ -123,4 +123,11 @@
* Avoid warning due with gcc's `-Wconversion` flag.
+[h2 Boost 1.50.0]
+
+* [@http://svn.boost.org/trac/boost/ticket/6771 Ticket 6771]:
+ Avoid gcc's `-Wfloat-equal` warning.
+* [@http://svn.boost.org/trac/boost/ticket/6806 Ticket 6806]:
+ Support `std::array` and `std::tuple` when available.
+
[endsect]
diff --git a/hash/doc/ref.xml b/hash/doc/ref.xml
index 318bf85..fa29fcd 100644
--- a/hash/doc/ref.xml
+++ b/hash/doc/ref.xml
@@ -744,6 +744,25 @@ for(; first != last; ++first)
std::type_index
+
+
+
+
+ std::size_t
+
+
+ std::size_t
+ std::array<T, N> const&
+
+
+
+
+
+
+ std::size_t
+ std::tuple<T...>
+
+
Generally shouldn't be called directly by users, instead they should use
boost::hash, boost::hash_range
@@ -809,7 +828,8 @@ for(; first != last; ++first)
std::set<K, C, A>
,
std::multiset<K, C, A>
,
std::map<K, T, C, A>
,
- std::multimap<K, T, C, A>
+ std::multimap<K, T, C, A>
,
+ std::array<T, N>
hash_range(val.begin(), val.end())
@@ -818,6 +838,14 @@ for(; first != last; ++first)
size_t seed = 0;
hash_combine(seed, val.first);
hash_combine(seed, val.second);
+return seed;
+
+
+ std::tuple<T...>
+ size_t seed = 0;
+hash_combine(seed, get<0>(val));
+hash_combine(seed, get<1>(val));
+// ....
return seed;
diff --git a/hash/test/Jamfile.v2 b/hash/test/Jamfile.v2
index 7b3ccd9..af24329 100644
--- a/hash/test/Jamfile.v2
+++ b/hash/test/Jamfile.v2
@@ -10,8 +10,8 @@ project hash-tests
all
intel:on
intel:-strict-ansi
- gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion"
- darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion"
+ gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal"
+ darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal"
msvc:on
#gcc:on
#darwin:on
@@ -40,6 +40,8 @@ test-suite functional/hash
[ run hash_map_test.cpp : : : BOOST_HASH_NO_IMPLICIT_CASTS ]
[ run hash_complex_test.cpp : : : BOOST_HASH_NO_IMPLICIT_CASTS ]
[ run hash_type_index_test.cpp : : : BOOST_HASH_NO_IMPLICIT_CASTS ]
+ [ run hash_std_array_test.cpp : : : BOOST_HASH_NO_IMPLICIT_CASTS ]
+ [ run hash_std_tuple_test.cpp : : : BOOST_HASH_NO_IMPLICIT_CASTS ]
[ run link_test.cpp link_test_2.cpp : : : BOOST_HASH_NO_IMPLICIT_CASTS ]
[ run link_ext_test.cpp link_no_ext_test.cpp : : : BOOST_HASH_NO_IMPLICIT_CASTS ]
[ run extensions_hpp_test.cpp : : : BOOST_HASH_NO_IMPLICIT_CASTS ]
diff --git a/hash/test/hash_complex_test.cpp b/hash/test/hash_complex_test.cpp
index 67e2aff..bb1592c 100644
--- a/hash/test/hash_complex_test.cpp
+++ b/hash/test/hash_complex_test.cpp
@@ -35,6 +35,10 @@ int main() {}
#endif
#endif
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+
#include
#include
#include
diff --git a/hash/test/hash_float_test.hpp b/hash/test/hash_float_test.hpp
index dd1358e..c608915 100644
--- a/hash/test/hash_float_test.hpp
+++ b/hash/test/hash_float_test.hpp
@@ -30,6 +30,10 @@
#endif
#endif
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+
char const* float_type(float*) { return "float"; }
char const* float_type(double*) { return "double"; }
char const* float_type(long double*) { return "long double"; }
diff --git a/hash/test/hash_map_test.cpp b/hash/test/hash_map_test.cpp
index 2f813c3..7e117c7 100644
--- a/hash/test/hash_map_test.cpp
+++ b/hash/test/hash_map_test.cpp
@@ -27,7 +27,7 @@ using std::multimap;
#define CONTAINER_TYPE multimap
#include "./hash_map_test.hpp"
-#endif // TEST_EXTENSTIONS
+#endif // TEST_EXTENSIONS
int main()
{
diff --git a/hash/test/hash_number_test.cpp b/hash/test/hash_number_test.cpp
index b989d22..b233c71 100644
--- a/hash/test/hash_number_test.cpp
+++ b/hash/test/hash_number_test.cpp
@@ -28,6 +28,10 @@
#pragma warning(disable:4310) // cast truncates constant value
#endif
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+
template
void numeric_test(T*)
{
diff --git a/hash/test/hash_std_array_test.cpp b/hash/test/hash_std_array_test.cpp
new file mode 100644
index 0000000..540b676
--- /dev/null
+++ b/hash/test/hash_std_array_test.cpp
@@ -0,0 +1,103 @@
+
+// Copyright 2012 Daniel James.
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include "./config.hpp"
+
+#ifdef TEST_EXTENSIONS
+# ifdef TEST_STD_INCLUDES
+# include
+# else
+# include
+# endif
+#endif
+
+#include
+#include
+
+#if defined(TEST_EXTENSIONS) && !defined(BOOST_NO_0X_HDR_ARRAY)
+#define TEST_ARRAY
+#include
+#include
+#endif
+
+#ifdef TEST_ARRAY
+
+template
+void array_tests(T const& v) {
+ boost::hash hf;
+ for(typename T::const_iterator i = v.begin(); i != v.end(); ++i) {
+ for(typename T::const_iterator j = v.begin(); j != v.end(); ++j) {
+ if (i != j)
+ BOOST_TEST(hf(*i) != hf(*j));
+ else
+ BOOST_TEST(hf(*i) == hf(*j));
+ }
+ }
+}
+
+void empty_array_test() {
+/*
+ boost::hash > empty_array_hash;
+ std::array empty_array;
+ BOOST_TEST(empty_array_hash(empty_array) == boost::hash_value(empty_array));
+*/
+}
+
+void int_1_array_test()
+{
+ std::vector > arrays;
+ std::array val;
+ val[0] = 0;
+ arrays.push_back(val);
+ val[0] = 1;
+ arrays.push_back(val);
+ val[0] = 2;
+ arrays.push_back(val);
+ array_tests(arrays);
+}
+
+void string_1_array_test()
+{
+ std::vector > arrays;
+ std::array val;
+ arrays.push_back(val);
+ val[0] = "one";
+ arrays.push_back(val);
+ val[0] = "two";
+ arrays.push_back(val);
+ array_tests(arrays);
+}
+
+void string_3_array_test()
+{
+ std::vector > arrays;
+ std::array val;
+ arrays.push_back(val);
+ val[0] = "one";
+ arrays.push_back(val);
+ val[0] = ""; val[1] = "one"; val[2] = "";
+ arrays.push_back(val);
+ val[0] = ""; val[1] = ""; val[2] = "one";
+ arrays.push_back(val);
+ val[0] = "one"; val[1] = "one"; val[2] = "one";
+ arrays.push_back(val);
+ val[0] = "one"; val[1] = "two"; val[2] = "three";
+ arrays.push_back(val);
+ array_tests(arrays);
+}
+
+#endif // TEST_ARRAY
+
+int main()
+{
+#ifdef TEST_ARRAY
+ empty_array_test();
+ int_1_array_test();
+ string_1_array_test();
+ string_3_array_test();
+#endif
+
+ return boost::report_errors();
+}
diff --git a/hash/test/hash_std_tuple_test.cpp b/hash/test/hash_std_tuple_test.cpp
new file mode 100644
index 0000000..15ef483
--- /dev/null
+++ b/hash/test/hash_std_tuple_test.cpp
@@ -0,0 +1,77 @@
+
+// Copyright 2012 Daniel James.
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include "./config.hpp"
+
+#ifdef TEST_EXTENSIONS
+# ifdef TEST_STD_INCLUDES
+# include
+# else
+# include
+# endif
+#endif
+
+#include
+#include
+
+#if defined(TEST_EXTENSIONS) && !defined(BOOST_NO_0X_HDR_TUPLE)
+#define TEST_TUPLE
+#include
+#include
+#endif
+
+#ifdef TEST_TUPLE
+
+template
+void tuple_tests(T const& v) {
+ boost::hash hf;
+ for(typename T::const_iterator i = v.begin(); i != v.end(); ++i) {
+ for(typename T::const_iterator j = v.begin(); j != v.end(); ++j) {
+ if (i != j)
+ BOOST_TEST(hf(*i) != hf(*j));
+ else
+ BOOST_TEST(hf(*i) == hf(*j));
+ }
+ }
+}
+
+void empty_tuple_test() {
+ boost::hash > empty_tuple_hash;
+ std::tuple<> empty_tuple;
+ BOOST_TEST(empty_tuple_hash(empty_tuple) == boost::hash_value(empty_tuple));
+}
+
+void int_tuple_test() {
+ std::vector > int_tuples;
+ int_tuples.push_back(std::make_tuple(0));
+ int_tuples.push_back(std::make_tuple(1));
+ int_tuples.push_back(std::make_tuple(2));
+ tuple_tests(int_tuples);
+}
+
+void int_string_tuple_test() {
+ std::vector > int_string_tuples;
+ int_string_tuples.push_back(std::make_tuple(0, std::string("zero")));
+ int_string_tuples.push_back(std::make_tuple(1, std::string("one")));
+ int_string_tuples.push_back(std::make_tuple(2, std::string("two")));
+ int_string_tuples.push_back(std::make_tuple(0, std::string("one")));
+ int_string_tuples.push_back(std::make_tuple(1, std::string("zero")));
+ int_string_tuples.push_back(std::make_tuple(0, std::string("")));
+ int_string_tuples.push_back(std::make_tuple(1, std::string("")));
+ tuple_tests(int_string_tuples);
+}
+
+#endif // TEST_TUPLE
+
+int main()
+{
+#ifdef TEST_TUPLE
+ empty_tuple_test();
+ int_tuple_test();
+ int_string_tuple_test();
+#endif
+
+ return boost::report_errors();
+}
diff --git a/include/boost/functional/hash/detail/container_fwd_0x.hpp b/include/boost/functional/hash/detail/container_fwd_0x.hpp
new file mode 100644
index 0000000..566f2af
--- /dev/null
+++ b/include/boost/functional/hash/detail/container_fwd_0x.hpp
@@ -0,0 +1,41 @@
+
+// Copyright 2012 Daniel James.
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#if !defined(BOOST_DETAIL_CONTAINER_FWD_0X_HPP)
+#define BOOST_DETAIL_CONTAINER_FWD_0X_HPP
+
+#include
+
+// std::array
+
+#if !defined(BOOST_NO_0X_HDR_ARRAY)
+ // Don't forward declare std::array for Dinkumware, as it seems to be
+ // just 'using std::tr1::array'.
+# if (defined(BOOST_DETAIL_NO_CONTAINER_FWD) && \
+ !defined(BOOST_DETAIL_TEST_FORCE_CONTAINER_FWD)) || \
+ (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
+# include
+# else
+namespace std {
+ template class array;
+}
+# endif
+#endif
+
+// std::tuple
+
+#if !defined(BOOST_NO_0X_HDR_TUPLE)
+# if (defined(BOOST_DETAIL_NO_CONTAINER_FWD) && \
+ !defined(BOOST_DETAIL_TEST_FORCE_CONTAINER_FWD)) || \
+ defined(BOOST_NO_VARIADIC_TEMPLATES)
+# include
+# else
+namespace std {
+ template class tuple;
+}
+# endif
+#endif
+
+#endif
diff --git a/include/boost/functional/hash/detail/hash_float.hpp b/include/boost/functional/hash/detail/hash_float.hpp
index ea1bc25..194be1c 100644
--- a/include/boost/functional/hash/detail/hash_float.hpp
+++ b/include/boost/functional/hash/detail/hash_float.hpp
@@ -86,10 +86,24 @@ namespace boost
{
namespace hash_detail
{
+ template
+ inline bool is_zero(T v)
+ {
+#if !defined(__GNUC__)
+ return v == 0;
+#else
+ // GCC's '-Wfloat-equal' will complain about comparing
+ // v to 0, but because it disables warnings for system
+ // headers it won't complain if you use std::equal_to to
+ // compare with 0. Resulting in this silliness:
+ return std::equal_to()(v, 0);
+#endif
+ }
+
template
inline std::size_t float_hash_value(T v)
{
- return v == 0 ? 0 : float_hash_impl(v);
+ return boost::hash_detail::is_zero(v) ? 0 : float_hash_impl(v);
}
}
}
diff --git a/include/boost/functional/hash/extensions.hpp b/include/boost/functional/hash/extensions.hpp
index 3c587a3..e61c2f3 100644
--- a/include/boost/functional/hash/extensions.hpp
+++ b/include/boost/functional/hash/extensions.hpp
@@ -14,7 +14,11 @@
#define BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP
#include
-#include
+#include
+#include
+#include
+#include
+#include
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
@@ -54,51 +58,51 @@ namespace boost
std::size_t hash_value(std::pair const& v)
{
std::size_t seed = 0;
- hash_combine(seed, v.first);
- hash_combine(seed, v.second);
+ boost::hash_combine(seed, v.first);
+ boost::hash_combine(seed, v.second);
return seed;
}
template
std::size_t hash_value(std::vector const& v)
{
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
}
template
std::size_t hash_value(std::list const& v)
{
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
}
template
std::size_t hash_value(std::deque const& v)
{
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
}
template
std::size_t hash_value(std::set const& v)
{
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
}
template
std::size_t hash_value(std::multiset const& v)
{
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
}
template
std::size_t hash_value(std::map const& v)
{
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
}
template
std::size_t hash_value(std::multimap const& v)
{
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
}
template
@@ -110,6 +114,71 @@ namespace boost
return seed;
}
+#if !defined(BOOST_NO_0X_HDR_ARRAY)
+ template
+ std::size_t hash_value(std::array const& v)
+ {
+ return boost::hash_range(v.begin(), v.end());
+ }
+#endif
+
+#if !defined(BOOST_NO_0X_HDR_TUPLE)
+ namespace hash_detail {
+ template
+ inline typename boost::enable_if_c<(I == std::tuple_size::value),
+ void>::type
+ hash_combine_tuple(std::size_t&, T const&)
+ {
+ }
+
+ template
+ inline typename boost::enable_if_c<(I < std::tuple_size::value),
+ void>::type
+ hash_combine_tuple(std::size_t& seed, T const& v)
+ {
+ boost::hash_combine(seed, std::get(v));
+ boost::hash_detail::hash_combine_tuple(seed, v);
+ }
+
+ template
+ inline std::size_t hash_tuple(T const& v)
+ {
+ std::size_t seed = 0;
+ boost::hash_detail::hash_combine_tuple<0>(seed, v);
+ return seed;
+ }
+ }
+
+#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
+ template
+ inline std::size_t hash_value(std::tuple const& v)
+ {
+ return boost::hash_detail::hash_tuple(v);
+ }
+#else
+
+ inline std::size_t hash_value(std::tuple<> const& v)
+ {
+ return boost::hash_detail::hash_tuple(v);
+ }
+
+# define BOOST_HASH_TUPLE_F(z, n, _) \
+ template< \
+ BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
+ > \
+ inline std::size_t hash_value(std::tuple< \
+ BOOST_PP_ENUM_PARAMS_Z(z, n, A) \
+ > const& v) \
+ { \
+ return boost::hash_detail::hash_tuple(v); \
+ }
+
+ BOOST_PP_REPEAT_FROM_TO(1, 11, BOOST_HASH_TUPLE_F, _)
+# undef BOOST_HASH_TUPLE_F
+#endif
+
+#endif
+
//
// call_hash_impl
//