Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r78144 - in trunk: boost/functional/hash boost/functional/hash/detail libs/functional/hash/doc libs/functional/hash/test
From: dnljms_at_[hidden]
Date: 2012-04-22 15:46:29


Author: danieljames
Date: 2012-04-22 15:46:28 EDT (Sun, 22 Apr 2012)
New Revision: 78144
URL: http://svn.boost.org/trac/boost/changeset/78144

Log:
Hash: Support std::array and std::tuple. Refs #6806.
Added:
   trunk/boost/functional/hash/detail/container_fwd_0x.hpp (contents, props changed)
   trunk/libs/functional/hash/test/hash_std_array_test.cpp (contents, props changed)
   trunk/libs/functional/hash/test/hash_std_tuple_test.cpp (contents, props changed)
Text files modified:
   trunk/boost/functional/hash/extensions.hpp | 89 +++++++++++++++++++++++++++++++++++----
   trunk/libs/functional/hash/doc/changes.qbk | 2
   trunk/libs/functional/hash/doc/ref.xml | 28 ++++++++++++
   trunk/libs/functional/hash/test/Jamfile.v2 | 2
   trunk/libs/functional/hash/test/hash_map_test.cpp | 2
   5 files changed, 112 insertions(+), 11 deletions(-)

Added: trunk/boost/functional/hash/detail/container_fwd_0x.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/functional/hash/detail/container_fwd_0x.hpp 2012-04-22 15:46:28 EDT (Sun, 22 Apr 2012)
@@ -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 <boost/detail/container_fwd.hpp>
+
+// 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 <array>
+# else
+namespace std {
+ template <class, std::size_t> 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 <tuple>
+# else
+namespace std {
+ template <typename...> class tuple;
+}
+# endif
+#endif
+
+#endif

Modified: trunk/boost/functional/hash/extensions.hpp
==============================================================================
--- trunk/boost/functional/hash/extensions.hpp (original)
+++ trunk/boost/functional/hash/extensions.hpp 2012-04-22 15:46:28 EDT (Sun, 22 Apr 2012)
@@ -14,7 +14,11 @@
 #define BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP
 
 #include <boost/functional/hash/hash.hpp>
-#include <boost/detail/container_fwd.hpp>
+#include <boost/functional/hash/detail/container_fwd_0x.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/preprocessor/repetition/repeat_from_to.hpp>
+#include <boost/preprocessor/repetition/enum_params.hpp>
 
 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
 # pragma once
@@ -54,51 +58,51 @@
     std::size_t hash_value(std::pair<A, B> 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 <class T, class A>
     std::size_t hash_value(std::vector<T, A> const& v)
     {
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
     }
 
     template <class T, class A>
     std::size_t hash_value(std::list<T, A> const& v)
     {
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
     }
 
     template <class T, class A>
     std::size_t hash_value(std::deque<T, A> const& v)
     {
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
     }
 
     template <class K, class C, class A>
     std::size_t hash_value(std::set<K, C, A> const& v)
     {
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
     }
 
     template <class K, class C, class A>
     std::size_t hash_value(std::multiset<K, C, A> const& v)
     {
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
     }
 
     template <class K, class T, class C, class A>
     std::size_t hash_value(std::map<K, T, C, A> const& v)
     {
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
     }
 
     template <class K, class T, class C, class A>
     std::size_t hash_value(std::multimap<K, T, C, A> const& v)
     {
- return hash_range(v.begin(), v.end());
+ return boost::hash_range(v.begin(), v.end());
     }
 
     template <class T>
@@ -110,6 +114,71 @@
         return seed;
     }
 
+#if !defined(BOOST_NO_0X_HDR_ARRAY)
+ template <class T, std::size_t N>
+ std::size_t hash_value(std::array<T, N> const& v)
+ {
+ return boost::hash_range(v.begin(), v.end());
+ }
+#endif
+
+#if !defined(BOOST_NO_0X_HDR_TUPLE)
+ namespace hash_detail {
+ template <std::size_t I, typename T>
+ inline typename boost::enable_if_c<(I == std::tuple_size<T>::value),
+ void>::type
+ hash_combine_tuple(std::size_t&, T const&)
+ {
+ }
+
+ template <std::size_t I, typename T>
+ inline typename boost::enable_if_c<(I < std::tuple_size<T>::value),
+ void>::type
+ hash_combine_tuple(std::size_t& seed, T const& v)
+ {
+ boost::hash_combine(seed, std::get<I>(v));
+ boost::hash_detail::hash_combine_tuple<I + 1>(seed, v);
+ }
+
+ template <typename T>
+ 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 <typename... T>
+ inline std::size_t hash_value(std::tuple<T...> 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
     //

Modified: trunk/libs/functional/hash/doc/changes.qbk
==============================================================================
--- trunk/libs/functional/hash/doc/changes.qbk (original)
+++ trunk/libs/functional/hash/doc/changes.qbk 2012-04-22 15:46:28 EDT (Sun, 22 Apr 2012)
@@ -126,5 +126,7 @@
 [h2 Boost 1.50.0]
 
 * 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]

Modified: trunk/libs/functional/hash/doc/ref.xml
==============================================================================
--- trunk/libs/functional/hash/doc/ref.xml (original)
+++ trunk/libs/functional/hash/doc/ref.xml 2012-04-22 15:46:28 EDT (Sun, 22 Apr 2012)
@@ -744,6 +744,25 @@
           <parameter name="val"><paramtype>std::type_index</paramtype></parameter>
         </signature>
 
+ <signature>
+ <template>
+ <template-type-parameter name="T"/>
+ <template-nontype-parameter name="N">
+ <type>std::size_t</type>
+ </template-nontype-parameter>
+ </template>
+ <type>std::size_t</type>
+ <parameter name="val"><paramtype>std::array&lt;T, N&gt; const&amp;</paramtype></parameter>
+ </signature>
+
+ <signature>
+ <template>
+ <template-type-parameter name="T" pack="1"/>
+ </template>
+ <type>std::size_t</type>
+ <parameter name="val"><paramtype>std::tuple&lt;T...&gt;</paramtype></parameter>
+ </signature>
+
         <description><para>
           Generally shouldn't be called directly by users, instead they should use
           <classname>boost::hash</classname>, <functionname>boost::hash_range</functionname>
@@ -810,6 +829,7 @@
                     <code>std::multiset&lt;K,&#160;C,&#160;A&gt;</code>,
                     <code>std::map&lt;K,&#160;T,&#160;C,&#160;A&gt;</code>,
                     <code>std::multimap&lt;K,&#160;T,&#160;C,&#160;A&gt;</code>
+ <code>std::array&lt;T,&#160;N&gt;</code>
                   </entry>
                   <entry><code>hash_range(val.begin(), val.end())</code></entry>
                 </row>
@@ -821,6 +841,14 @@
 return seed;</programlisting></entry>
                 </row>
                 <row>
+ <entry><code>std::tuple&lt;T...&gt;</code></entry>
+ <entry><programlisting>size_t seed = 0;
+<functionname>hash_combine</functionname>(seed, get&lt;0&gt;(val));
+<functionname>hash_combine</functionname>(seed, get&lt;1&gt;(val));
+// ....
+return seed;</programlisting></entry>
+ </row>
+ <row>
                   <entry>
                     <code>std::complex&lt;T&gt;</code>
                   </entry>

Modified: trunk/libs/functional/hash/test/Jamfile.v2
==============================================================================
--- trunk/libs/functional/hash/test/Jamfile.v2 (original)
+++ trunk/libs/functional/hash/test/Jamfile.v2 2012-04-22 15:46:28 EDT (Sun, 22 Apr 2012)
@@ -40,6 +40,8 @@
         [ run hash_map_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
         [ run hash_complex_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
         [ run hash_type_index_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
+ [ run hash_std_array_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
+ [ run hash_std_tuple_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
         [ run link_test.cpp link_test_2.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
         [ run link_ext_test.cpp link_no_ext_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
         [ run extensions_hpp_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]

Modified: trunk/libs/functional/hash/test/hash_map_test.cpp
==============================================================================
--- trunk/libs/functional/hash/test/hash_map_test.cpp (original)
+++ trunk/libs/functional/hash/test/hash_map_test.cpp 2012-04-22 15:46:28 EDT (Sun, 22 Apr 2012)
@@ -27,7 +27,7 @@
 #define CONTAINER_TYPE multimap
 #include "./hash_map_test.hpp"
 
-#endif // TEST_EXTENSTIONS
+#endif // TEST_EXTENSIONS
 
 int main()
 {

Added: trunk/libs/functional/hash/test/hash_std_array_test.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/functional/hash/test/hash_std_array_test.cpp 2012-04-22 15:46:28 EDT (Sun, 22 Apr 2012)
@@ -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 <functional>
+# else
+# include <boost/functional/hash.hpp>
+# endif
+#endif
+
+#include <boost/config.hpp>
+#include <boost/detail/lightweight_test.hpp>
+
+#if defined(TEST_EXTENSIONS) && !defined(BOOST_NO_0X_HDR_ARRAY)
+#define TEST_ARRAY
+#include <array>
+#include <vector>
+#endif
+
+#ifdef TEST_ARRAY
+
+template <typename T>
+void array_tests(T const& v) {
+ boost::hash<typename T::value_type> 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<std::array<int, 0> > empty_array_hash;
+ std::array<int, 0> empty_array;
+ BOOST_TEST(empty_array_hash(empty_array) == boost::hash_value(empty_array));
+*/
+}
+
+void int_1_array_test()
+{
+ std::vector<std::array<int, 1> > arrays;
+ std::array<int, 1> val;
+ val[0] = 0;
+ arrays.emplace_back(val);
+ val[0] = 1;
+ arrays.emplace_back(val);
+ val[0] = 2;
+ arrays.emplace_back(val);
+ array_tests(arrays);
+}
+
+void string_1_array_test()
+{
+ std::vector<std::array<std::string, 1> > arrays;
+ std::array<std::string, 1> val;
+ arrays.emplace_back(val);
+ val[0] = "one";
+ arrays.emplace_back(val);
+ val[0] = "two";
+ arrays.emplace_back(val);
+ array_tests(arrays);
+}
+
+void string_3_array_test()
+{
+ std::vector<std::array<std::string,3 > > arrays;
+ std::array<std::string, 3> val;
+ arrays.emplace_back(val);
+ val[0] = "one";
+ arrays.emplace_back(val);
+ val[0] = ""; val[1] = "one"; val[2] = "";
+ arrays.emplace_back(val);
+ val[0] = ""; val[1] = ""; val[2] = "one";
+ arrays.emplace_back(val);
+ val[0] = "one"; val[1] = "one"; val[2] = "one";
+ arrays.emplace_back(val);
+ val[0] = "one"; val[1] = "two"; val[2] = "three";
+ arrays.emplace_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();
+}

Added: trunk/libs/functional/hash/test/hash_std_tuple_test.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/functional/hash/test/hash_std_tuple_test.cpp 2012-04-22 15:46:28 EDT (Sun, 22 Apr 2012)
@@ -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 <functional>
+# else
+# include <boost/functional/hash.hpp>
+# endif
+#endif
+
+#include <boost/config.hpp>
+#include <boost/detail/lightweight_test.hpp>
+
+#if defined(TEST_EXTENSIONS) && !defined(BOOST_NO_0X_HDR_TUPLE)
+#define TEST_TUPLE
+#include <tuple>
+#include <vector>
+#endif
+
+#ifdef TEST_TUPLE
+
+template <typename T>
+void tuple_tests(T const& v) {
+ boost::hash<typename T::value_type> 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<std::tuple<> > 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<std::tuple<int> > 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<std::tuple<int, std::string> > int_string_tuples;
+ int_string_tuples.push_back(std::make_tuple(0, "zero"));
+ int_string_tuples.push_back(std::make_tuple(1, "one"));
+ int_string_tuples.push_back(std::make_tuple(2, "two"));
+ int_string_tuples.push_back(std::make_tuple(0, "one"));
+ int_string_tuples.push_back(std::make_tuple(1, "zero"));
+ int_string_tuples.push_back(std::make_tuple(0, ""));
+ int_string_tuples.push_back(std::make_tuple(1, ""));
+ 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();
+}


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk