Squashed 'third_party/boostorg/container_hash/' content from commit 9fbda1a

Change-Id: I3db45eeb90d6b7e18fb95c2df04c0afc15541790
git-subtree-dir: third_party/boostorg/container_hash
git-subtree-split: 9fbda1a98a32498c52a1c8ebf62311bb36a44ad4
diff --git a/.appveyor.yml b/.appveyor.yml
new file mode 100644
index 0000000..2247248
--- /dev/null
+++ b/.appveyor.yml
@@ -0,0 +1,36 @@
+# Copyright 2017 Daniel James
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
+
+version: 1.0.{build}-{branch}
+
+shallow_clone: true
+
+environment:
+  matrix:
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
+      TOOLSET: msvc-10.0,msvc-11.0,msvc-12.0
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+      TOOLSET: msvc-14.0
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+      TOOLSET: msvc-14.1
+      CXXSTD: 14,17
+
+install:
+  - cd c:\projects
+  - curl -sSL -o boost.7z https://dl.bintray.com/boostorg/release/1.67.0/source/boost_1_67_0.7z
+  - 7z x boost.7z
+  - set BOOST_ROOT=c:\projects\boost_1_67_0
+  - rd /s /q %BOOST_ROOT%\boost\functional\hash
+  - cd %BOOST_ROOT%\tools\build
+  - cmd /c bootstrap
+  - cd %APPVEYOR_BUILD_FOLDER%
+  - echo. 2>Jamroot.jam
+
+build: off
+
+test_script:
+  - if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
+  - cd %APPVEYOR_BUILD_FOLDER%\test
+  - cmd /c %BOOST_ROOT%\tools\build\b2 -j 3 toolset=%TOOLSET% %CXXSTD% include=%APPVEYOR_BUILD_FOLDER%\include include=%BOOST_ROOT% --verbose-test hash_info
+  - cmd /c %BOOST_ROOT%\tools\build\b2 -j 3 toolset=%TOOLSET% %CXXSTD% include=%APPVEYOR_BUILD_FOLDER%\include include=%BOOST_ROOT%
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..3e84d7c
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,96 @@
+* text=auto !eol svneol=native#text/plain
+*.gitattributes text svneol=native#text/plain
+
+# Scriptish formats
+*.bat        text svneol=native#text/plain
+*.bsh        text svneol=native#text/x-beanshell
+*.cgi        text svneol=native#text/plain
+*.cmd        text svneol=native#text/plain
+*.js         text svneol=native#text/javascript
+*.php        text svneol=native#text/x-php
+*.pl         text svneol=native#text/x-perl
+*.pm         text svneol=native#text/x-perl
+*.py         text svneol=native#text/x-python
+*.sh         eol=lf svneol=LF#text/x-sh
+configure    eol=lf svneol=LF#text/x-sh
+
+# Image formats
+*.bmp        binary svneol=unset#image/bmp
+*.gif        binary svneol=unset#image/gif
+*.ico        binary svneol=unset#image/ico
+*.jpeg       binary svneol=unset#image/jpeg
+*.jpg        binary svneol=unset#image/jpeg
+*.png        binary svneol=unset#image/png
+*.tif        binary svneol=unset#image/tiff
+*.tiff       binary svneol=unset#image/tiff
+*.svg        text svneol=native#image/svg%2Bxml
+
+# Data formats
+*.pdf        binary svneol=unset#application/pdf
+*.avi        binary svneol=unset#video/avi
+*.doc        binary svneol=unset#application/msword
+*.dsp        text svneol=crlf#text/plain
+*.dsw        text svneol=crlf#text/plain
+*.eps        binary svneol=unset#application/postscript
+*.gz         binary svneol=unset#application/gzip
+*.mov        binary svneol=unset#video/quicktime
+*.mp3        binary svneol=unset#audio/mpeg
+*.ppt        binary svneol=unset#application/vnd.ms-powerpoint
+*.ps         binary svneol=unset#application/postscript
+*.psd        binary svneol=unset#application/photoshop
+*.rdf        binary svneol=unset#text/rdf
+*.rss        text svneol=unset#text/xml
+*.rtf        binary svneol=unset#text/rtf
+*.sln        text svneol=native#text/plain
+*.swf        binary svneol=unset#application/x-shockwave-flash
+*.tgz        binary svneol=unset#application/gzip
+*.vcproj     text svneol=native#text/xml
+*.vcxproj    text svneol=native#text/xml
+*.vsprops    text svneol=native#text/xml
+*.wav        binary svneol=unset#audio/wav
+*.xls        binary svneol=unset#application/vnd.ms-excel
+*.zip        binary svneol=unset#application/zip
+
+# Text formats
+.htaccess    text svneol=native#text/plain
+*.bbk        text svneol=native#text/xml
+*.cmake      text svneol=native#text/plain
+*.css        text svneol=native#text/css
+*.dtd        text svneol=native#text/xml
+*.htm        text svneol=native#text/html
+*.html       text svneol=native#text/html
+*.ini        text svneol=native#text/plain
+*.log        text svneol=native#text/plain
+*.mak        text svneol=native#text/plain
+*.qbk        text svneol=native#text/plain
+*.rst        text svneol=native#text/plain
+*.sql        text svneol=native#text/x-sql
+*.txt        text svneol=native#text/plain
+*.xhtml      text svneol=native#text/xhtml%2Bxml
+*.xml        text svneol=native#text/xml
+*.xsd        text svneol=native#text/xml
+*.xsl        text svneol=native#text/xml
+*.xslt       text svneol=native#text/xml
+*.xul        text svneol=native#text/xul
+*.yml        text svneol=native#text/plain
+boost-no-inspect text svneol=native#text/plain
+CHANGES      text svneol=native#text/plain
+COPYING      text svneol=native#text/plain
+INSTALL      text svneol=native#text/plain
+Jamfile      text svneol=native#text/plain
+Jamroot      text svneol=native#text/plain
+Jamfile.v2   text svneol=native#text/plain
+Jamrules     text svneol=native#text/plain
+Makefile*    text svneol=native#text/plain
+README       text svneol=native#text/plain
+TODO         text svneol=native#text/plain
+
+# Code formats
+*.c          text svneol=native#text/plain
+*.cpp        text svneol=native#text/plain
+*.h          text svneol=native#text/plain
+*.hpp        text svneol=native#text/plain
+*.ipp        text svneol=native#text/plain
+*.tpp        text svneol=native#text/plain
+*.jam        text svneol=native#text/plain
+*.java       text svneol=native#text/plain
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..0f98508
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,78 @@
+# Copyright (C) 2016 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)
+
+# Use Trusty to get a reasonably recent version of Boost.
+sudo: required
+dist: trusty
+
+language: c++
+
+matrix:
+    include:
+      - compiler: gcc
+        env: |
+            USER_CONFIG="using gcc : : g++-4.8 ;"
+            CXXSTD=03,11
+      - compiler: g++-7
+        env: |
+            USER_CONFIG="using gcc : : g++-7 ;"
+            CXXSTD=11,14,17
+        addons:
+          apt:
+            packages:
+              - g++-7
+            sources:
+              - ubuntu-toolchain-r-test
+      - compiler: clang
+        env: |
+            USER_CONFIG="using clang : : clang++ ;"
+            CXXSTD=03,11
+      - compiler: clang
+        env: |
+            USER_CONFIG="using clang : : clang++ -D_HAS_AUTO_PTR_ETC=0 ;"
+            CXXSTD=11
+
+before_script:
+    - export BOOST_VERSION=1.67.0
+    - export BOOST_FILENAME=boost_1_67_0
+    - export BOOST_ROOT=${HOME}/boost
+    - cd ${TRAVIS_BUILD_DIR}
+    - touch Jamroot.jam
+    - cd $HOME
+    - echo $USER_CONFIG > ~/user-config.jam
+    - cat ~/user-config.jam
+    - |
+        mkdir $HOME/download
+        mkdir $HOME/extract
+        cd $HOME/download
+        if [ "$TRAVIS_EVENT_TYPE" == "cron" ]
+        then
+            if [ "$TRAVIS_BRANCH" == "master" ]
+            then
+                snapshot_branch=master
+            else
+                snapshot_branch=develop
+            fi
+            download_url=$(curl https://api.bintray.com/packages/boostorg/$snapshot_branch/snapshot/files |
+                    python -c "import os.path, sys, json; x = json.load(sys.stdin); print '\n'.join(a['path'] for a in x if os.path.splitext(a['path'])[1] == '.bz2')" |
+                    head -n 1 |
+                    sed "s/^/http:\/\/dl.bintray.com\/boostorg\/$snapshot_branch\//")
+        else
+            download_url=https://sourceforge.net/projects/boost/files/boost/${BOOST_VERSION}/${BOOST_FILENAME}.tar.bz2/download
+        fi
+        echo "Downloading ${download_url}"
+        wget -O boost.tar.bz2 $download_url
+        cd $HOME/extract
+        tar -xjf $HOME/download/boost.tar.bz2
+        mv * ${BOOST_ROOT}
+    - rm -r ${BOOST_ROOT}/boost/functional
+    - cd ${BOOST_ROOT}/tools/build
+    - mkdir ${HOME}/opt
+    - ./bootstrap.sh
+    - ./b2 install --prefix=$HOME/opt
+
+script:
+    - cd ${TRAVIS_BUILD_DIR}/test
+    - ${HOME}/opt/bin/b2 --verbose-test -j 3 cxxstd=$CXXSTD -q ${BJAM_TOOLSET} include=${BOOST_ROOT} include=${TRAVIS_BUILD_DIR}/include hash_info
+    - ${HOME}/opt/bin/b2 -j 3 cxxstd=$CXXSTD -q ${BJAM_TOOLSET} include=${BOOST_ROOT} include=${TRAVIS_BUILD_DIR}/include
diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2
new file mode 100644
index 0000000..86f889a
--- /dev/null
+++ b/doc/Jamfile.v2
@@ -0,0 +1,25 @@
+
+# Copyright 2005-2008 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)
+
+using boostbook ;
+using quickbook ;
+
+xml hash : hash.qbk ;
+boostbook standalone : hash :
+    <xsl:param>boost.root=../../../..
+
+    <xsl:param>chunk.first.sections=1
+    <xsl:param>chunk.section.depth=2
+    <xsl:param>generate.section.toc.level=2
+    <xsl:param>toc.section.depth=1
+    <xsl:param>toc.max.depth=1
+    <format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/libs/container_hash/doc/html
+    ;
+
+###############################################################################
+    alias boostdoc : hash ;
+    explicit boostdoc ;
+    alias boostrelease ;
+    explicit boostrelease ;
diff --git a/doc/changes.qbk b/doc/changes.qbk
new file mode 100644
index 0000000..459a15d
--- /dev/null
+++ b/doc/changes.qbk
@@ -0,0 +1,222 @@
+
+[/ Copyright 2005-2008 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) ]
+
+[template ticket[number]'''<ulink url="https://svn.boost.org/trac/boost/ticket/'''[number]'''">'''#[number]'''</ulink>''']
+
+[section:changes Change Log]
+
+[h2 Boost 1.33.0]
+
+* Initial Release
+
+[h2 Boost 1.33.1]
+
+* Fixed the points example, as pointed out by 沈慧峰.
+
+[h2 Boost 1.34.0]
+
+* Use declarations for standard classes, so that the library
+  doesn't need to include all of their headers
+* Deprecated the `<boost/functional/hash/*.hpp>` headers. Now a single header,
+  <[headerref boost/functional/hash.hpp]> is used.
+* Add support for the `BOOST_HASH_NO_EXTENSIONS` macro, which
+  disables the extensions to TR1.
+
+* Minor improvements to the hash functions for floating point numbers.
+* Update the portable example to hopefully be more generally portable.
+
+[h2 Boost 1.34.1]
+
+* [@http://svn.boost.org/trac/boost/ticket/952 Ticket 952]:
+  Suppress incorrect 64-bit warning on Visual C++.
+
+[h2 Boost 1.35.0]
+
+* Support for `long long`, `std::complex`.
+* Improved algorithm for hashing floating point numbers:
+  * Improved portablity, as described by Daniel Krügler in
+    [@http://lists.boost.org/boost-users/2005/08/13418.php
+    a post to the boost users list].
+  * Fits more information into each combine loop, which can reduce the
+    the number of times combine is called and hopefully give a better
+    quality hash function.
+  * Improved the algorithm for hashing floating point numbers.
+  * On Cygwin use a binary hash function for floating point numbers, as
+    Cygwin doesn't have decent floating point functions for `long double`.
+  * Never uses `fpclass` which doesn't support `long double`.
+  * [@http://svn.boost.org/trac/boost/ticket/1064 Ticket 1064]:
+    Removed unnecessary use of `errno`.
+* Explicitly overload for more built in types.
+* Minor improvements to the documentation.
+* A few bug and warning fixes:
+  * [@http://svn.boost.org/trac/boost/ticket/1509 Ticket 1509]:
+    Suppress another Visual C++ warning.
+  * Some workarounds for the Sun compilers.
+
+[h2 Boost 1.36.0]
+
+* Stop using OpenBSD's dodgy `std::numeric_limits`.
+* Using the boost typedefs for `long long` and `unsigned long long`.
+* Move the extensions into their own header.
+
+[h2 Boost 1.37.0]
+
+* [@http://svn.boost.org/trac/boost/ticket/2264 Ticket 2264]:
+  In Visual C++, always use C99 float functions for `long double` and `float` as
+  the C++ overloads aren't always availables.
+
+[h2 Boost 1.38.0]
+
+* Changed the warnings in the deprecated headers from 1.34.0 to errors. These
+  will be removed in a future version of Boost.
+* Moved detail headers out of `boost/container_hash/detail`, since they are part of
+  functional/hash, not container_hash. `boost/container_hash/detail/container_fwd.hpp`
+  has been moved to `boost/detail/container_fwd.hpp` as it's used outside of
+  this library, the others have been moved to `boost/functional/hash/detail`.
+
+[h2 Boost 1.39.0]
+
+* Move the hash_fwd.hpp implementation into the hash subdirectory, leaving a
+  forwarding header in the old location. You should still use the old location,
+  the new location is mainly for implementation and possible modularization.
+* [@https://svn.boost.org/trac/boost/ticket/2412 Ticket 2412]: Removed deprecated
+  headers.
+* [@https://svn.boost.org/trac/boost/ticket/2957 Ticket 2957]: Fix configuration
+  for vxworks.
+
+[h2 Boost 1.40.0]
+
+* Automatically configure the float functions using template metaprogramming
+  instead of trying to configure every possibility manually.
+* Workaround for when STLport doesn't support long double.
+
+[h2 Boost 1.42.0]
+
+* Reduce the number of warnings for Visual C++ warning level 4.
+* Some code formatting changes to fit lines into 80 characters.
+* Rename an internal namespace.
+
+[h2 Boost 1.43.0]
+
+* [@https://svn.boost.org/trac/boost/ticket/3866 Ticket 3866]:
+  Don't foward declare containers when using gcc's parallel library,
+  allow user to stop forward declaration by defining the
+  `BOOST_DETAIL_NO_CONTAINER_FWD` macro.
+* [@https://svn.boost.org/trac/boost/ticket/4038 Ticket 4038]:
+  Avoid hashing 0.5 and 0 to the same number.
+* Stop using deprecated `BOOST_HAS_*` macros.
+
+[h2 Boost 1.44.0]
+
+* Add option to prevent implicit conversions when calling `hash_value` by
+  defining `BOOST_HASH_NO_IMPLICIT_CASTS`. When using `boost::hash`
+  for a type that does not have `hash_value` declared but does have
+  an implicit conversion to a type that does, it would use that
+  implicit conversion to hash it. Which can sometimes go very wrong,
+  e.g. using a conversion to bool and only hashing to 2 possible
+  values. Since fixing this is a breaking change and was only
+  approached quite late in the release cycle with little discussion
+  it's opt-in for now. This, or something like it, will become the
+  default in a future version.
+
+[h2 Boost 1.46.0]
+
+* 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.
+* Add deprecation warning to the long deprecated
+  `boost/container_hash/detail/container_fwd.hpp`.
+
+[h2 Boost 1.51.0]
+
+* Support the standard smart pointers.
+* `hash_value` now implemented using SFINAE to avoid implicit casts to built
+  in types when calling it.
+* Updated to use the new config macros.
+
+[h2 Boost 1.52.0]
+
+* Restore `enum` support, which was accidentally removed in the last version.
+* New floating point hasher - will hash the binary representation on more
+  platforms, which should be faster.
+
+[h2 Boost 1.53.0]
+
+* Add support for `boost::int128_type` and `boost::uint128_type` where
+  available - currently only `__int128` and `unsigned __int128` on some
+  versions of gcc.
+* On platforms that are known to have the standard floating point functions,
+  don't use automatic detection - which can break if there are ambiguous
+  overloads.
+* Fix undefined behaviour when using the binary float hash (Thomas Heller).
+
+[h2 Boost 1.54.0]
+
+* [@https://svn.boost.org/trac/boost/ticket/7957 Ticket 7957]:
+  Fixed a typo.
+
+[h2 Boost 1.55.0]
+
+* Simplify a SFINAE check so that it will hopefully work on Sun 5.9
+  ([ticket 8822]).
+* Suppress Visual C++ infinite loop warning ([ticket 8568]).
+
+[h2 Boost 1.56.0]
+
+* Removed some Visual C++ 6 workarounds.
+* Ongoing work on improving `hash_combine`. This changes the combine function
+  which was previously defined in the reference documentation.
+
+[h2 Boost 1.58.0]
+
+* Fixed strict aliasing violation
+  ([@https://github.com/boostorg/container_hash/pull/3 GitHub #3]).
+
+[h2 Boost 1.63.0]
+
+* Fixed some warnings.
+* Only define hash for `std::wstring` when we know we have a `wchar_t`.
+  Otherwise there's a compile error as there's no overload for hashing
+  the characters in wide strings ([ticket 8552]).
+
+[h2 Boost 1.64.0]
+
+* Fix for recent versions of Visual C++ which have removed `std::unary_function`
+  and `std::binary_function` ([ticket 12353]).
+
+[h2 Boost 1.65.0]
+
+* Support for `char16_t`, `char32_t`, `u16string`, `u32string`
+
+[h2 Boost 1.66.0]
+
+* Avoid float comparison warning when using Clang - this workaround was
+  already in place for GCC, and was used when Clang pretends to be GCC,
+  but the warning was appearing when running Clang in other contexts.
+
+[h2 Boost 1.67.0]
+
+* Moved library into its own module, `container_hash`.
+* Moved headers for new module name, now at:
+  `<boost/container_hash/hash.hpp>`,
+  `<boost/container_hash/hash_fwd.hpp>`,
+  `<boost/container_hash/extensions.hpp>`.
+* Added forwarding headers to support the old headers locations.
+* Support `std::string_view`, `std::error_code`, `std::error_condition`
+  `std::optional`, `std::variant`, `std::monostate` where available.
+* Update include paths from other Boost libraries.
+* Manually write out tuple overloads, rather than using the
+  preprocessor to generate them. Should improve usability, due
+  to better error messages, and easier debugging.
+* Fix tutorial example ([ticket 11017]).
+* Quick fix for hashing `vector<bool>` when using libc++. Will try to introduce
+  a more general fix in the next release.
+
+[endsect]
diff --git a/doc/disable.qbk b/doc/disable.qbk
new file mode 100644
index 0000000..5373b42
--- /dev/null
+++ b/doc/disable.qbk
@@ -0,0 +1,29 @@
+
+[/ Copyright 2005-2008 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) ]
+
+[section:disable Disabling The Extensions]
+
+While [classref boost::hash]'s extensions are generally useful, you might want
+to turn them of in order to check that your code will work with other
+implementations of TR1. To do this define the macro `BOOST_HASH_NO_EXTENSIONS`.
+When this macro is defined, only the specialisations detailed
+in TR1 will be declared. But, if you later undefine the macro and include
+<[headerref boost/container_hash/hash.hpp]> then the non-specialised form will be defined
+- activating the extensions.
+
+It is strongly recommended that you never undefine the macro - and only define
+it so that it applies to the complete translation unit, either by defining it
+at the beginning of the main source file or, preferably, by using a compiler
+switch or preference. And you really should never define it in header files.
+
+If you are writing a library which has code in the header which requires the
+extensions, then the best action is to tell users not to define the macro.
+Their code won't ['require] the macro.
+
+Translation units that are compiled with the macro defined will link with units
+that were compiled without it. This feature has been designed to avoid ODR
+violations.
+
+[endsect]
diff --git a/doc/hash.qbk b/doc/hash.qbk
new file mode 100644
index 0000000..3bcc80e
--- /dev/null
+++ b/doc/hash.qbk
@@ -0,0 +1,29 @@
+[library Boost.ContainerHash
+    [quickbook 1.5]
+    [authors [James, Daniel]]
+    [copyright 2005 2006 2007 2008 Daniel James]
+    [purpose A TR1 hash function object that can be extended to hash user
+        defined types]
+    [category higher-order]
+    [id hash]
+    [dirname container_hash]
+    [license
+        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])
+    ]
+]
+
+[def __issues__
+    [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf
+    Library Extension Technical Report Issues List]]
+
+[include:hash intro.qbk]
+[include:hash tutorial.qbk]
+[include:hash portability.qbk]
+[include:hash disable.qbk]
+[include:hash changes.qbk]
+[include:hash rationale.qbk]
+[xinclude ref.xml]
+[include:hash links.qbk]
+[include:hash thanks.qbk]
diff --git a/doc/intro.qbk b/doc/intro.qbk
new file mode 100644
index 0000000..076e997
--- /dev/null
+++ b/doc/intro.qbk
@@ -0,0 +1,52 @@
+
+[/ Copyright 2005-2008 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) ]
+
+[section:intro Introduction]
+
+[def __tr1-full__
+    [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
+    Draft Technical Report on C++ Library Extensions]]
+[def __tr1__
+    [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
+    TR1]]
+[def __unordered__ [link unordered Boost.Unordered]]
+[def __intrusive__ [link intrusive.unordered_set_unordered_multiset Boost.Intrusive]]
+[def __multi-index__ [@boost:/libs/multi_index/doc/index.html
+    Boost Multi-Index Containers Library]]
+[def __multi-index-short__ [@boost:/libs/multi_index/doc/index.html
+    Boost.MultiIndex]]
+[def __bimap__ [@boost:/libs/bimap/index.html Boost.Bimap]]
+[def __hash-function__ [@http://en.wikipedia.org/wiki/Hash_function hash function]]
+[def __hash-table__ [@http://en.wikipedia.org/wiki/Hash_table hash table]]
+
+[classref boost::hash] is an implementation of the __hash-function__ object
+specified by the __tr1-full__ (TR1). It is the default hash function for
+__unordered__, __intrusive__'s unordered associative containers, and
+__multi-index-short__'s hash indicies and __bimap__'s `unordered_set_of`.
+
+As it is compliant with __tr1__, it will work with:
+
+* integers
+* floats
+* pointers
+* strings
+
+It also implements the extension proposed by Peter Dimov in issue 6.18 of the
+__issues__ (page 63), this adds support for:
+
+* arrays
+* `std::pair`
+* the standard containers.
+* extending [classref boost::hash] for custom types.
+
+[note
+This hash function is designed to be used in containers based on
+the STL and is not suitable as a general purpose hash function.
+For more details see the [link hash.rationale rationale].
+]
+
+
+[endsect]
+
diff --git a/doc/links.qbk b/doc/links.qbk
new file mode 100644
index 0000000..405536e
--- /dev/null
+++ b/doc/links.qbk
@@ -0,0 +1,27 @@
+
+[/ Copyright 2005-2008 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) ]
+
+[section:links Links]
+
+[*A Proposal to Add Hash Tables to the Standard Library]
+[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1456.html]
+The hash table proposal explains much of the design. The hash function object
+is discussed in Section D.
+
+[*The C++ Standard Library Technical Report.]
+[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf]
+Contains the hash function specification in section 6.3.2.
+
+[*Library Extension Technical Report Issues List.]
+[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf]
+The library implements the extension described in Issue 6.18, pages 63-67.
+
+[*Methods for Identifying Versioned and Plagiarised Documents]
+Timothy C. Hoad, Justin Zobel
+[@http://www.cs.rmit.edu.au/~jz/fulltext/jasist-tch.pdf]
+Contains the hash function that [funcref boost::hash_combine] is based on.
+
+[endsect]
+
diff --git a/doc/portability.qbk b/doc/portability.qbk
new file mode 100644
index 0000000..d667b89
--- /dev/null
+++ b/doc/portability.qbk
@@ -0,0 +1,93 @@
+
+[/ Copyright 2005-2008 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) ]
+
+[section:portability Portability]
+
+[def __boost_hash__ [classref boost::hash]]
+
+__boost_hash__ is written to be as portable as possible, but unfortunately, several
+older compilers don't support argument dependent lookup (ADL) - the mechanism
+used for customisation.  On those compilers custom overloads for `hash_value`
+needs to be declared in the boost namespace.
+
+On a strictly standards compliant compiler, an overload defined in the
+boost namespace won't be found when __boost_hash__ is instantiated,
+so for these compilers the overload should only be declared in the same
+namespace as the class.
+
+Let's say we have a simple custom type:
+
+    namespace foo
+    {
+        template <class T>
+        class custom_type
+        {
+            T value;
+        public:
+            custom_type(T x) : value(x) {}
+
+            friend std::size_t hash_value(custom_type x)
+            {
+                __boost_hash__<int> hasher;
+                return hasher(x.value);
+            }
+        };
+    }
+
+On a compliant compiler, when `hash_value` is called for this type,
+it will look at the namespace inside the type and find `hash_value`
+but on a compiler which doesn't support ADL `hash_value` won't be found.
+To make things worse, some compilers which do support ADL won't find
+a friend class defined inside the class.
+
+So first move the member function out of the class:
+
+    namespace foo
+    {
+        template <class T>
+        class custom_type
+        {
+            T value;
+        public:
+            custom_type(T x) : value(x) {}
+
+            std::size_t hash(custom_type x)
+            {
+                __boost_hash__<T> hasher;
+                return hasher(value);
+            }
+        };
+
+        template <class T>
+        inline std::size_t hash_value(custom_type<T> x)
+        {
+            return x.hash();
+        }
+    }
+
+Unfortunately, I couldn't declare hash_value as a friend, as some compilers
+don't support template friends, so instead I declared a member function to
+calculate the hash, and called it from hash_value.
+
+For compilers which don't support ADL, hash_value needs to be defined in the
+boost namespace:
+
+    #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
+    namespace boost
+    #else
+    namespace foo
+    #endif
+    {
+        template <class T>
+        std::size_t hash_value(foo::custom_type<T> x)
+        {
+            return x.hash();
+        }
+    }
+
+Full code for this example is at
+[@boost:/libs/container_hash/examples/portable.cpp /libs/container_hash/examples/portable.cpp].
+
+[endsect]
diff --git a/doc/rationale.qbk b/doc/rationale.qbk
new file mode 100644
index 0000000..76ff6d1
--- /dev/null
+++ b/doc/rationale.qbk
@@ -0,0 +1,50 @@
+
+[/ Copyright 2011 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) ]
+
+[section:rationale Rationale]
+
+The rationale can be found in the original design
+[footnote issue 6.18 of the __issues__ (page 63)].
+
+[heading Quality of the hash function]
+
+Many hash functions strive to have little correlation between the input
+and output values. They attempt to uniformally distribute the output
+values for very similar inputs. This hash function makes no such
+attempt. In fact, for integers, the result of the hash function is often
+just the input value. So similar but different input values will often
+result in similar but different output values.
+This means that it is not appropriate as a general hash function. For
+example, a hash table may discard bits from the hash function resulting
+in likely collisions, or might have poor collision resolution when hash
+values are clustered together. In such cases this hash function will
+preform poorly.
+
+But the standard has no such requirement for the hash function,
+it just requires that the hashes of two different values are unlikely
+to collide. Containers or algorithms
+designed to work with the standard hash function will have to be
+implemented to work well when the hash function's output is correlated
+to its input. Since they are paying that cost a higher quality hash function
+would be wasteful.
+
+For other use cases, if you do need a higher quality hash function,
+then neither the standard hash function or `boost::hash` are appropriate.
+There are several options
+available. One is to use a second hash on the output of this hash
+function, such as [@http://web.archive.org/web/20121102023700/http://www.concentric.net/~Ttwang/tech/inthash.htm
+Thomas Wang's hash function]. This this may not work as
+well as a hash algorithm tailored for the input.
+
+For strings there are several fast, high quality hash functions
+available (for example [@http://code.google.com/p/smhasher/ MurmurHash3]
+and [@http://code.google.com/p/cityhash/ Google's CityHash]),
+although they tend to be more machine specific.
+These may also be appropriate for hashing a binary representation of
+your data - providing that all equal values have an equal
+representation, which is not always the case (e.g. for floating point
+values).
+
+[endsect]
diff --git a/doc/ref.xml b/doc/ref.xml
new file mode 100644
index 0000000..1c8bca9
--- /dev/null
+++ b/doc/ref.xml
@@ -0,0 +1,994 @@
+
+<!--
+Copyright Daniel James 2005-2009
+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)
+-->
+
+<library-reference>
+  <section id="hash.reference.specification">
+    <para>For the full specification, see section 6.3 of the
+        <ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf">C++ Standard Library Technical Report</ulink>
+        and issue 6.18 of the
+        <ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf">Library Extension Technical Report Issues List</ulink> (page 63).
+    </para>
+  </section>
+  <header name="boost/container_hash/hash.hpp">
+    <para>
+      Defines <code><classname>boost::hash</classname></code>,
+      and helper functions.
+    </para>
+
+    <namespace name="boost">
+
+      <!--
+        boost::hash
+        -->
+
+      <struct name="hash">
+        <template>
+          <template-type-parameter name="T"/>
+        </template>
+
+        <inherit access="public">
+          <classname>std::unary_function&lt;T, std::size_t&gt;</classname>
+        </inherit>
+
+        <purpose><simpara>A <ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf">TR1</ulink> compliant hash function object.</simpara></purpose>
+
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>T const&amp;</paramtype>
+          </parameter>
+          <returns><para>
+            <programlisting><functionname>hash_value</functionname>(val)</programlisting>
+          </para></returns>
+          <notes>
+            <para>
+              The call to <code><functionname>hash_value</functionname></code>
+              is unqualified, so that custom overloads can be
+              found via argument dependent lookup.
+            </para>
+            <para>
+              This is not defined when the macro <code>BOOST_HASH_NO_EXTENSIONS</code>
+              is defined. The specializations are still defined, so only the specializations
+              required by TR1 are defined.
+            </para>
+            <para>
+              Forward declared in
+              <code>&lt;boost/container_hash/hash_fwd.hpp&gt;</code>
+            </para>
+            <para>
+              This hash function is not intended for general use, and isn't
+              guaranteed to be equal during separate runs of a program - so
+              please don't use it for any persistent storage or communication.
+            </para>
+          </notes>
+          <throws><para>
+            Only throws if
+            <code><functionname>hash_value</functionname>(T)</code> throws.
+          </para></throws>
+        </method>
+      </struct>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>bool</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>bool</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>char</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>char</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>signed char</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>signed char</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>unsigned char</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>unsigned char</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>wchar_t</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>wchar_t</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>char16_t</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>char16_t</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>char32_t</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>char32_t</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>short</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>short</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>unsigned short</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>unsigned short</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>int</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>int</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>unsigned int</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>unsigned int</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>long</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>long</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>unsigned long</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>unsigned long</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>long long</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>long long</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>unsigned long long</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>unsigned long long</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>float</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>float</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>double</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>double</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>long double</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>long double</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>std::string</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>std::string const&amp;</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>std::wstring</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>std::wstring const&amp;</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>std::u16string</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>std::u16string const&amp;</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>std::u32string</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>std::u32string const&amp;</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+            <para><functionname>hash_value</functionname>(val) in Boost.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template>
+          <template-type-parameter name="T"/>
+        </template>
+        <specialization>
+          <template-arg>T*</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>T*</paramtype>
+          </parameter>
+          <returns>
+            <para>Unspecified in TR1, except that equal arguments yield the same result.</para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+      </struct-specialization>
+
+      <struct-specialization name="hash">
+        <template></template>
+        <specialization>
+          <template-arg>std::type_index</template-arg>
+        </specialization>
+        <method name="operator()" cv="const">
+          <type>std::size_t</type>
+          <parameter name="val">
+            <paramtype>std::type_index</paramtype>
+          </parameter>
+          <returns>
+            <para><code>val.hash_code()</code></para>
+          </returns>
+          <throws><para>Doesn't throw</para></throws>
+        </method>
+        <notes>
+          <para>
+            Only available if it's in your standard library and Boost.Config
+            is aware of it.
+          </para>
+        </notes>
+      </struct-specialization>
+
+      <free-function-group name="Support functions (Boost extension)."> 
+
+      <!--
+        boost::hash_combine
+        -->
+
+      <function name="hash_combine">
+        <template>
+          <template-type-parameter name="T"/>
+        </template>
+        <type>void</type>
+        <parameter name="seed"><paramtype>size_t &amp;</paramtype></parameter>
+        <parameter name="v"><paramtype>T const&amp;</paramtype></parameter>
+        <purpose><simpara>
+            Called repeatedly to incrementally create a hash value from
+            several variables.
+        </simpara></purpose>
+        <effects>
+            Updates <code>seed</code> with a new hash value generated by
+            combining it with the result of
+            <code><functionname>hash_value</functionname>(v)</code>. Will
+            always produce the same result for the same combination of
+            <code>seed</code> and
+            <code><functionname>hash_value</functionname>(v)</code> during
+            the single run of a program.
+        </effects>
+        <notes>
+          <para><functionname>hash_value</functionname> is called without
+          qualification, so that overloads can be found via ADL.</para>
+          <para>This is an extension to TR1</para>
+          <para>
+            Forward declared in
+            <code>&lt;boost/container_hash/hash_fwd.hpp&gt;</code>
+          </para>
+          <para>
+            This hash function is not intended for general use, and isn't
+            guaranteed to be equal during separate runs of a program - so
+            please don't use it for any persistent storage or communication.
+          </para>
+        </notes>
+        <throws>
+          Only throws if <functionname>hash_value</functionname>(T) throws.
+          Strong exception safety, as long as <functionname>hash_value</functionname>(T)
+          also has strong exception safety.
+        </throws>
+      </function>
+
+      <!--
+        boost::hash_range
+        -->
+
+      <overloaded-function name="hash_range">
+        <signature>
+          <template>
+            <template-type-parameter name="It"/>
+          </template>
+          <type>std::size_t</type>
+          <parameter name="first"><paramtype>It</paramtype></parameter>
+          <parameter name="last"><paramtype>It</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <template>
+            <template-type-parameter name="It"/>
+          </template>
+          <type>void</type>
+          <parameter name="seed"><paramtype>std::size_t&amp;</paramtype></parameter>
+          <parameter name="first"><paramtype>It</paramtype></parameter>
+          <parameter name="last"><paramtype>It</paramtype></parameter>
+        </signature>
+
+        <purpose><simpara>
+            Calculate the combined hash value of the elements of an iterator
+            range.
+        </simpara></purpose>
+        <effects>
+          <para>For the two argument overload:
+<programlisting>
+size_t seed = 0;
+
+for(; first != last; ++first)
+{
+    <functionname>hash_combine</functionname>(seed, *first);
+}
+
+return seed;
+</programlisting>
+          </para>
+          <para>For the three arguments overload:</para>
+<programlisting>
+for(; first != last; ++first)
+{
+    <functionname>hash_combine</functionname>(seed, *first);
+}
+</programlisting>
+        </effects>
+        <notes>
+          <para>
+            <code>hash_range</code> is sensitive to the order of the elements
+            so it wouldn't be appropriate to use this with an unordered
+            container.
+          </para>
+          <para>This is an extension to TR1</para>
+          <para>
+            Forward declared in
+            <code>&lt;boost/container_hash/hash_fwd.hpp&gt;</code>
+          </para>
+          <para>
+            This hash function is not intended for general use, and isn't
+            guaranteed to be equal during separate runs of a program - so
+            please don't use it for any persistent storage or communication.
+          </para>
+        </notes>
+        <throws><para>
+          Only throws if <code><functionname>hash_value</functionname>(std::iterator_traits&lt;It&gt;::value_type)</code>
+          throws. <code>hash_range(std::size_t&amp;, It, It)</code> has basic exception safety as long as
+          <code><functionname>hash_value</functionname>(std::iterator_traits&lt;It&gt;::value_type)</code>
+          has basic exception safety.
+        </para></throws>
+      </overloaded-function>
+
+      </free-function-group>
+
+      <free-function-group name="Overloadable hash implementation (Boost extension).">
+
+      <!--
+        boost::hash_value - integers
+        -->
+
+      <overloaded-function name="hash_value">
+        <purpose><simpara>
+            Implementation of the hash function.
+        </simpara></purpose>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>bool</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>char</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>signed char</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>unsigned char</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>wchar_t</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>char16_t</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>char32_t</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>short</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>unsigned short</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>int</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>unsigned int</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>long</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>unsigned long</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>long long</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>unsigned long long</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>float</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>double</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>long double</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <template><template-type-parameter name="T"/></template>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>T* const&amp;</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <template>
+            <template-type-parameter name="T"/>
+            <template-nontype-parameter name="N"><type>unsigned</type></template-nontype-parameter>
+          </template>
+          <type>std::size_t</type>
+          <parameter><paramtype>T (&amp;val)[N]</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <template>
+            <template-type-parameter name="T"/>
+            <template-nontype-parameter name="N"><type>unsigned</type></template-nontype-parameter>
+          </template>
+          <type>std::size_t</type>
+          <parameter><paramtype>const T (&amp;val)[N]</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <template>
+            <template-type-parameter name="Ch"/>
+            <template-type-parameter name="A"/>
+          </template>
+          <type>std::size_t</type>
+          <parameter name="val">
+              <paramtype>std::basic_string&lt;Ch, std::char_traits&lt;Ch&gt;, A&gt; const&amp;</paramtype>
+          </parameter>
+        </signature>
+              
+       <signature>
+          <template>
+            <template-type-parameter name="A"/>
+            <template-type-parameter name="B"/>
+          </template>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>std::pair&lt;A, B&gt; const&amp;</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <template>
+            <template-type-parameter name="T"/>
+            <template-type-parameter name="A"/>
+          </template>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>std::vector&lt;T, A&gt; const&amp;</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <template>
+            <template-type-parameter name="T"/>
+            <template-type-parameter name="A"/>
+          </template>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>std::list&lt;T, A&gt; const&amp;</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <template>
+            <template-type-parameter name="T"/>
+            <template-type-parameter name="A"/>
+          </template>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>std::deque&lt;T, A&gt; const&amp;</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <template>
+            <template-type-parameter name="K"/>
+            <template-type-parameter name="C"/>
+            <template-type-parameter name="A"/>
+          </template>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>std::set&lt;K, C, A&gt; const&amp;</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <template>
+            <template-type-parameter name="K"/>
+            <template-type-parameter name="C"/>
+            <template-type-parameter name="A"/>
+          </template>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>std::multiset&lt;K, C, A&gt; const&amp;</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <template>
+            <template-type-parameter name="K"/>
+            <template-type-parameter name="T"/>
+            <template-type-parameter name="C"/>
+            <template-type-parameter name="A"/>
+          </template>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>std::map&lt;K, T, C, A&gt; const&amp;</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <template>
+            <template-type-parameter name="K"/>
+            <template-type-parameter name="T"/>
+            <template-type-parameter name="C"/>
+            <template-type-parameter name="A"/>
+          </template>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>std::multimap&lt;K, T, C, A&gt; const&amp;</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <template>
+            <template-type-parameter name="T"/>
+          </template>
+          <type>std::size_t</type>
+          <parameter name="val"><paramtype>std::complex&lt;T&gt; const&amp;</paramtype></parameter>
+        </signature>
+
+        <signature>
+          <type>std::size_t</type>
+          <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>
+          or <functionname>boost::hash_combine</functionname> which
+          call <code>hash_value</code> without namespace qualification so that overloads
+          for custom types are found via ADL.
+        </para></description>
+
+        <notes>
+          <para>This is an extension to TR1</para>
+          <para>
+            This hash function is not intended for general use, and isn't
+            guaranteed to be equal during separate runs of a program - so
+            please don't use it for any persistent storage or communication.
+          </para>
+        </notes>
+
+        <throws>
+            Only throws if a user supplied version of
+            <code><functionname>hash_value</functionname></code>
+            throws for an element of a container, or
+            one of the types stored in a pair.
+        </throws>
+
+        <returns>
+          <informaltable>
+            <tgroup cols="2">
+              <thead>
+                <row>
+                  <entry>Types</entry>
+                  <entry>Returns</entry>
+                </row>
+              </thead>
+              <tbody>
+                <row>
+                  <entry><code>bool</code>,
+                    <code>char</code>, <code>signed char</code>, <code>unsigned char</code>,
+                    <code>wchar_t</code>, <code>char16_t</code>, <code>char32_t</code>,
+                    <code>short</code>, <code>unsigned short</code>,
+                    <code>int</code>, <code>unsigned int</code>, <code>long</code>, <code>unsigned long</code>
+                  </entry>
+                  <entry><code>val</code></entry>
+                </row>
+                <row>
+                  <entry><code>long long</code>, <code>unsigned long long</code></entry>
+                  <entry><code>val</code> when <code>abs(val) &lt;= std::numeric_limits&lt;std::size_t&gt;::max()</code>.</entry>
+                </row>
+                <row>
+                  <entry><code>float</code>, <code>double</code>, <code>long double</code></entry>
+                  <entry>An unspecified value, except that equal arguments shall yield the same result.</entry>
+                </row>
+                <row>
+                  <entry><code>T*</code></entry>
+                  <entry>An unspecified value, except that equal arguments shall yield the same result.</entry>
+                </row>
+                <row>
+                  <entry>
+                    <code>T&#160;val[N]</code>,
+                    <code>const&#160;T&#160;val[N]</code>
+                  </entry>
+                  <entry><code>hash_range(val, val+N)</code></entry>
+                </row>
+                <row>
+                  <entry>
+                    <code>std:basic_string&lt;Ch,&#160;std::char_traits&lt;Ch&gt;,&#160;A&gt;</code>,
+                    <code>std::vector&lt;T,&#160;A&gt;</code>,
+                    <code>std::list&lt;T,&#160;A&gt;</code>,
+                    <code>std::deque&lt;T,&#160;A&gt;</code>,
+                    <code>std::set&lt;K,&#160;C,&#160;A&gt;</code>,
+                    <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>
+                <row>
+                  <entry><code>std::pair&lt;A, B&gt;</code></entry>
+                  <entry><programlisting>size_t seed = 0;
+<functionname>hash_combine</functionname>(seed, val.first);
+<functionname>hash_combine</functionname>(seed, val.second);
+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>
+                  <entry>When <code>T</code> is a built in type and <code>val.imag() == 0</code>, the result is equal to <code>hash_value(val.real())</code>. Otherwise an unspecified value, except that equal arguments shall yield the same result.</entry>
+                </row>
+                <row>
+                  <entry>
+                    <code>std::type_index</code>
+                  </entry>
+                  <entry><code>val.hash_code()</code></entry>
+                </row>
+              </tbody>
+            </tgroup>
+          </informaltable>
+        </returns>
+      </overloaded-function>
+      </free-function-group>
+    </namespace>
+  </header>
+</library-reference>
+
diff --git a/doc/samples/tutorial.cpp b/doc/samples/tutorial.cpp
new file mode 100644
index 0000000..b11609b
--- /dev/null
+++ b/doc/samples/tutorial.cpp
@@ -0,0 +1,27 @@
+#include <boost/container_hash/hash.hpp>
+#include <vector>
+#include <algorithm>
+#include <iterator>
+#include <cassert>
+
+//[ get_hashes
+template <class Container>
+std::vector<std::size_t> get_hashes(Container const& x)
+{
+    std::vector<std::size_t> hashes;
+    std::transform(x.begin(), x.end(), std::back_inserter(hashes),
+        boost::hash<typename Container::value_type>());
+
+    return hashes;
+}
+//]
+
+int main() {
+    std::vector<int> values;
+    values.push_back(10);
+    values.push_back(20);
+
+    std::vector<std::size_t> hashes = get_hashes(values);
+    assert(hashes[0] = boost::hash<int>()(values[0]));
+    assert(hashes[1] = boost::hash<int>()(values[1]));
+}
diff --git a/doc/thanks.qbk b/doc/thanks.qbk
new file mode 100644
index 0000000..fcc5108
--- /dev/null
+++ b/doc/thanks.qbk
@@ -0,0 +1,28 @@
+
+[/ Copyright 2005-2008 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) ]
+
+[section:acknowledgements Acknowledgements]
+
+This library is based on the design by Peter Dimov. During the initial
+development
+Joaquín M López Muñoz made many useful suggestions and contributed fixes.
+
+The formal review was managed by Thorsten Ottosen, and the library reviewed by:
+David Abrahams, Alberto Barbati, Topher Cooper, Caleb Epstein, Dave Harris,
+Chris Jefferson, Bronek Kozicki, John Maddock, Tobias Swinger, Jaap Suter,
+Rob Stewart and Pavel Vozenilek. Since then, further constructive criticism has
+been made by Daniel Krügler, Alexander Nasonov and 沈慧峰.
+
+The implementation of the hash function for pointers is based on suggestions
+made by Alberto Barbati and Dave Harris. Dave Harris also suggested an
+important improvement to [funcref boost::hash_combine] that was taken up.
+
+Some useful improvements to the floating point hash algorithm were suggested
+by Daniel Krügler.
+
+The original implementation came from Jeremy B. Maitin-Shepard's hash table
+library, although this is a complete rewrite.
+
+[endsect]
diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk
new file mode 100644
index 0000000..234b759
--- /dev/null
+++ b/doc/tutorial.qbk
@@ -0,0 +1,207 @@
+
+[/ Copyright 2005-2008 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) ]
+
+[quickbook 1.7]
+[import samples/tutorial.cpp]
+
+[def __multi-index-short__ [@boost:/libs/multi_index/doc/index.html
+    Boost.MultiIndex]]
+
+[section:tutorial Tutorial]
+
+When using a hash index with __multi-index-short__, you don't need to do
+anything to use [classref boost::hash] as it uses it by default.
+To find out how to use a user-defined type, read the
+[link hash.custom section on extending boost::hash for a custom data type].
+
+If your standard library supplies its own implementation of the unordered
+associative containers and you wish to use
+[classref boost::hash], just use an extra template parameter:
+
+    std::unordered_multiset<int, ``[classref boost::hash]``<int> >
+            set_of_ints;
+
+    std::unordered_set<std::pair<int, int>, ``[classref boost::hash]``<std::pair<int, int> >
+            set_of_pairs;
+
+    std::unordered_map<int, std::string, ``[classref boost::hash]``<int> > map_int_to_string;
+
+To use [classref boost::hash] directly, create an instance and call it as a function:
+
+    #include <``[headerref boost/container_hash/hash.hpp]``>
+
+    int main()
+    {
+        ``[classref boost::hash]``<std::string> string_hash;
+
+        std::size_t h = string_hash("Hash me");
+    }
+
+For an example of generic use, here is a function to generate a vector
+containing the hashes of the elements of a container:
+
+[get_hashes]
+
+[endsect]
+
+[section:custom Extending boost::hash for a custom data type]
+
+[classref boost::hash] is implemented by calling the function
+[funcref boost::hash_value hash_value].
+The namespace isn't specified so that it can detect overloads via argument
+dependant lookup. So if there is a free function `hash_value` in the same
+namespace as a custom type, it will get called.
+
+If you have a structure `library::book`, where each `book` is uniquely
+defined by it's member `id`:
+
+    namespace library
+    {
+        struct book
+        {
+            int id;
+            std::string author;
+            std::string title;
+
+            // ....
+        };
+
+        bool operator==(book const& a, book const& b)
+        {
+            return a.id == b.id;
+        }
+    }
+
+Then all you would need to do is write the function `library::hash_value`:
+
+    namespace library
+    {
+        std::size_t hash_value(book const& b)
+        {
+            ``[classref boost::hash]``<int> hasher;
+            return hasher(b.id);
+        }
+    }
+
+And you can now use [classref boost::hash] with book:
+
+    library::book knife(3458, "Zane Grey", "The Hash Knife Outfit");
+    library::book dandelion(1354, "Paul J. Shanley",
+        "Hash & Dandelion Greens");
+
+    ``[classref boost::hash]``<library::book> book_hasher;
+    std::size_t knife_hash_value = book_hasher(knife);
+
+    // If std::unordered_set is available:
+    std::unordered_set<library::book, ``[classref boost::hash]``<library::book> > books;
+    books.insert(knife);
+    books.insert(library::book(2443, "Lindgren, Torgny", "Hash"));
+    books.insert(library::book(1953, "Snyder, Bernadette M.",
+        "Heavenly Hash: A Tasty Mix of a Mother's Meditations"));
+
+    assert(books.find(knife) != books.end());
+    assert(books.find(dandelion) == books.end());
+
+The full example can be found in:
+[@boost:/libs/container_hash/examples/books.hpp /libs/container_hash/examples/books.hpp]
+and
+[@boost:/libs/container_hash/examples/books.cpp /libs/container_hash/examples/books.cpp].
+
+[tip
+When writing a hash function, first look at how the equality function works.
+Objects that are equal must generate the same hash value.
+When objects are not equal they should generate different hash values.
+In this object equality was based just on the id so the hash function
+only hashes the id. If it was based on the object's name and author
+then the hash function should take them into account
+(how to do this is discussed in the next section).
+]
+
+[endsect]
+
+[section:combine Combining hash values]
+
+Say you have a point class, representing a two dimensional location:
+
+    class point
+    {
+        int x;
+        int y;
+    public:
+        point() : x(0), y(0) {}
+        point(int x, int y) : x(x), y(y) {}
+
+        bool operator==(point const& other) const
+        {
+            return x == other.x && y == other.y;
+        }
+    };
+
+and you wish to use it as the key for an `unordered_map`. You need to
+customise the hash for this structure. To do this we need to combine
+the hash values for `x` and `y`. The function
+[funcref boost::hash_combine] is supplied for this purpose:
+
+    class point
+    {
+        ...
+
+        friend std::size_t hash_value(point const& p)
+        {
+            std::size_t seed = 0;
+            ``[funcref boost::hash_combine]``(seed, p.x);
+            ``[funcref boost::hash_combine]``(seed, p.y);
+
+            return seed;
+        }
+
+        ...
+    };
+
+Calls to hash_combine incrementally build the hash from the different members
+of point, it can be repeatedly called for any number of elements. It calls
+[funcref boost::hash_value hash_value] on the supplied element, and combines it with the seed.
+
+Full code for this example is at
+[@boost:/libs/container_hash/examples/point.cpp /libs/container_hash/examples/point.cpp].
+
+[note
+When using [funcref boost::hash_combine] the order of the
+calls matters.
+'''
+<programlisting>
+    std::size_t seed = 0;
+    boost::hash_combine(seed, 1);
+    boost::hash_combine(seed, 2);
+</programlisting>
+results in a different seed to:
+<programlisting>
+    std::size_t seed = 0;
+    boost::hash_combine(seed, 2);
+    boost::hash_combine(seed, 1);
+</programlisting>
+'''
+If you are calculating a hash value for data where the order of the data
+doesn't matter in comparisons (e.g. a set) you will have to ensure that the
+data is always supplied in the same order.
+]
+
+To calculate the hash of an iterator range you can use [funcref boost::hash_range]:
+
+    std::vector<std::string> some_strings;
+    std::size_t hash = ``[funcref boost::hash_range]``(some_strings.begin(), some_strings.end());
+
+Note that when writing template classes, you might not want to include the main
+hash header as it's quite an expensive include that brings in a lot of other
+headers, so instead you can include the `<boost/container_hash/hash_fwd.hpp>`
+header which forward declares [classref boost::hash],
+[funcref boost::hash_range] and [funcref boost::hash_combine]. You'll need to
+include the main header before instantiating [classref boost::hash]. When using
+a container that uses [classref boost::hash] it should do that for you, so your
+type will work fine with the boost hash containers. There's an example of this
+in [@boost:/libs/container_hash/examples/template.hpp template.hpp] and
+[@boost:/libs/container_hash/examples/template.cpp template.cpp].
+
+[endsect]
diff --git a/examples/Jamfile.v2 b/examples/Jamfile.v2
new file mode 100644
index 0000000..6291621
--- /dev/null
+++ b/examples/Jamfile.v2
@@ -0,0 +1,9 @@
+
+# Copyright Daniel James 2005. Use, modification, and distribution are
+# subject to 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)
+
+run books.cpp ;
+run point.cpp ;
+run portable.cpp ;
+run template.cpp ;
diff --git a/examples/books.cpp b/examples/books.cpp
new file mode 100644
index 0000000..3dfa547
--- /dev/null
+++ b/examples/books.cpp
@@ -0,0 +1,51 @@
+
+// Copyright 2005-2009 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 "./books.hpp"
+#include <boost/container_hash/hash.hpp>
+#include <cassert>
+
+// If std::unordered_set was available:
+//#include <unordered_set>
+
+// This example illustrates how to use boost::hash with a custom hash function.
+// For full details, see the tutorial.
+
+int main()
+{
+    library::book knife(3458, "Zane Grey", "The Hash Knife Outfit");
+    library::book dandelion(1354, "Paul J. Shanley", "Hash & Dandelion Greens");
+
+    boost::hash<library::book> book_hasher;
+    std::size_t knife_hash_value = book_hasher(knife);
+    (void)knife_hash_value; // suppress unused variable warning
+
+    // If std::unordered_set was available:
+    //
+    //std::unordered_set<library::book, boost::hash<library::book> > books;
+    //books.insert(knife);
+    //books.insert(library::book(2443, "Lindgren, Torgny", "Hash"));
+    //books.insert(library::book(1953, "Snyder, Bernadette M.",
+    //    "Heavenly Hash: A Tasty Mix of a Mother's Meditations"));
+
+    //assert(books.find(knife) != books.end());
+    //assert(books.find(dandelion) == books.end());
+
+    return 0;
+}
+
+namespace library
+{
+    bool operator==(book const& a, book const& b)
+    {
+        return a.id == b.id;
+    }
+
+    std::size_t hash_value(book const& b)
+    {
+        boost::hash<int> hasher;
+        return hasher(b.id);
+    }
+}
diff --git a/examples/books.hpp b/examples/books.hpp
new file mode 100644
index 0000000..ac87a9d
--- /dev/null
+++ b/examples/books.hpp
@@ -0,0 +1,26 @@
+
+// Copyright 2005-2009 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)
+
+// This example illustrates how to use boost::hash with a custom hash function.
+// The implementation is contained in books.cpp
+
+#include <cstddef>
+#include <string>
+
+namespace library
+{
+    struct book
+    {
+        int id;
+        std::string author;
+        std::string title;
+
+        book(int i, std::string const& a, std::string const& t)
+            : id(i), author(a), title(t) {}
+    };
+
+    bool operator==(book const&, book const&);
+    std::size_t hash_value(book const&);
+}
diff --git a/examples/point.cpp b/examples/point.cpp
new file mode 100644
index 0000000..3f5e8be
--- /dev/null
+++ b/examples/point.cpp
@@ -0,0 +1,59 @@
+
+// Copyright 2005 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)
+
+// Force use of assert.
+#if defined(NDEBUG)
+#undef NDEBUG
+#endif
+
+#include <boost/container_hash/hash.hpp>
+#include <cassert>
+
+// This example illustrates how to use boost::hash_combine to generate a hash
+// value from the different members of a class. For full details see the hash
+// tutorial.
+
+class point
+{
+    int x;
+    int y;
+public:
+    point() : x(0), y(0) {}
+    point(int x, int y) : x(x), y(y) {}
+
+    bool operator==(point const& other) const
+    {
+        return x == other.x && y == other.y;
+    }
+
+    friend std::size_t hash_value(point const& p)
+    {
+        std::size_t seed = 0;
+        boost::hash_combine(seed, p.x);
+        boost::hash_combine(seed, p.y);
+
+        return seed;
+    }
+};
+
+int main()
+{
+    boost::hash<point> point_hasher;
+
+    point p1(0, 0);
+    point p2(1, 2);
+    point p3(4, 1);
+    point p4 = p1;
+
+    assert(point_hasher(p1) == point_hasher(p4));
+
+    // These tests could legally fail, but if they did it'd be a pretty bad
+    // hash function.
+    assert(point_hasher(p1) != point_hasher(p2));
+    assert(point_hasher(p1) != point_hasher(p3));
+
+    return 0;
+}
+
diff --git a/examples/portable.cpp b/examples/portable.cpp
new file mode 100644
index 0000000..e0ea96a
--- /dev/null
+++ b/examples/portable.cpp
@@ -0,0 +1,59 @@
+
+// Copyright 2005-2009 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)
+
+// Force use of assert.
+#if defined(NDEBUG)
+#undef NDEBUG
+#endif
+
+#include <boost/container_hash/hash.hpp>
+#include <cassert>
+
+// This example illustrates how to customise boost::hash portably, so that
+// it'll work on both compilers that don't implement argument dependent lookup
+// and compilers that implement strict two-phase template instantiation.
+
+namespace foo
+{
+    template <class T>
+    class custom_type
+    {
+        T value;
+    public:
+        custom_type(T x) : value(x) {}
+
+        std::size_t hash() const
+        {
+            boost::hash<T> hasher;
+            return hasher(value);
+        }
+    };
+}
+
+#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
+namespace boost
+#else
+namespace foo
+#endif
+{
+    template <class T>
+    std::size_t hash_value(foo::custom_type<T> x)
+    {
+        return x.hash();
+    }
+}
+
+int main()
+{
+    foo::custom_type<int> x(1), y(2), z(1);
+
+    boost::hash<foo::custom_type<int> > hasher;
+
+    assert(hasher(x) == hasher(x));
+    assert(hasher(x) != hasher(y));
+    assert(hasher(x) == hasher(z));
+
+    return 0;
+}
diff --git a/examples/template.cpp b/examples/template.cpp
new file mode 100644
index 0000000..d74f0a9
--- /dev/null
+++ b/examples/template.cpp
@@ -0,0 +1,18 @@
+
+// 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 "template.hpp"
+#include <cassert>
+#include <boost/unordered_set.hpp>
+
+int main()
+{
+    typedef my_pair<int, float> pair;
+    boost::unordered_set<pair> pair_set;
+    pair_set.emplace(10, 0.5f);
+
+    assert(pair_set.find(pair(10, 0.5f)) != pair_set.end());
+    assert(pair_set.find(pair(10, 0.6f)) == pair_set.end());
+}
diff --git a/examples/template.hpp b/examples/template.hpp
new file mode 100644
index 0000000..0a2fe13
--- /dev/null
+++ b/examples/template.hpp
@@ -0,0 +1,36 @@
+
+// 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)
+
+// This is an example of how to write a hash function for a template
+// class.
+
+#include <boost/container_hash/hash_fwd.hpp>
+
+template <typename A, typename B>
+class my_pair
+{
+    A value1;
+    B value2;
+public:
+    my_pair(A const& v1, B const& v2)
+        : value1(v1), value2(v2)
+    {}
+
+    bool operator==(my_pair const& other) const
+    {
+        return value1 == other.value1 &&
+            value2 == other.value2;
+    }
+
+    friend std::size_t hash_value(my_pair const& p)
+    {
+        std::size_t seed = 0;
+        boost::hash_combine(seed, p.value1);
+        boost::hash_combine(seed, p.value2);
+
+        return seed;
+    }
+};
+
diff --git a/include/boost/container_hash/detail/float_functions.hpp b/include/boost/container_hash/detail/float_functions.hpp
new file mode 100644
index 0000000..f3db52f
--- /dev/null
+++ b/include/boost/container_hash/detail/float_functions.hpp
@@ -0,0 +1,336 @@
+
+// Copyright 2005-2009 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_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP)
+#define BOOST_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP
+
+#include <boost/config.hpp>
+#if defined(BOOST_HAS_PRAGMA_ONCE)
+#pragma once
+#endif
+
+#include <boost/config/no_tr1/cmath.hpp>
+
+// Set BOOST_HASH_CONFORMANT_FLOATS to 1 for libraries known to have
+// sufficiently good floating point support to not require any
+// workarounds.
+//
+// When set to 0, the library tries to automatically
+// use the best available implementation. This normally works well, but
+// breaks when ambiguities are created by odd namespacing of the functions.
+//
+// Note that if this is set to 0, the library should still take full
+// advantage of the platform's floating point support.
+
+#if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
+#   define BOOST_HASH_CONFORMANT_FLOATS 0
+#elif defined(__LIBCOMO__)
+#   define BOOST_HASH_CONFORMANT_FLOATS 0
+#elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
+// Rogue Wave library:
+#   define BOOST_HASH_CONFORMANT_FLOATS 0
+#elif defined(_LIBCPP_VERSION)
+// libc++
+#   define BOOST_HASH_CONFORMANT_FLOATS 1
+#elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
+// GNU libstdc++ 3
+#   if defined(__GNUC__) && __GNUC__ >= 4
+#       define BOOST_HASH_CONFORMANT_FLOATS 1
+#   else
+#       define BOOST_HASH_CONFORMANT_FLOATS 0
+#   endif
+#elif defined(__STL_CONFIG_H)
+// generic SGI STL
+#   define BOOST_HASH_CONFORMANT_FLOATS 0
+#elif defined(__MSL_CPP__)
+// MSL standard lib:
+#   define BOOST_HASH_CONFORMANT_FLOATS 0
+#elif defined(__IBMCPP__)
+// VACPP std lib (probably conformant for much earlier version).
+#   if __IBMCPP__ >= 1210
+#       define BOOST_HASH_CONFORMANT_FLOATS 1
+#   else
+#       define BOOST_HASH_CONFORMANT_FLOATS 0
+#   endif
+#elif defined(MSIPL_COMPILE_H)
+// Modena C++ standard library
+#   define BOOST_HASH_CONFORMANT_FLOATS 0
+#elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
+// Dinkumware Library (this has to appear after any possible replacement libraries):
+#   if _CPPLIB_VER >= 405
+#       define BOOST_HASH_CONFORMANT_FLOATS 1
+#   else
+#       define BOOST_HASH_CONFORMANT_FLOATS 0
+#   endif
+#else
+#   define BOOST_HASH_CONFORMANT_FLOATS 0
+#endif
+
+#if BOOST_HASH_CONFORMANT_FLOATS
+
+// The standard library is known to be compliant, so don't use the
+// configuration mechanism.
+
+namespace boost {
+    namespace hash_detail {
+        template <typename Float>
+        struct call_ldexp {
+            typedef Float float_type;
+            inline Float operator()(Float x, int y) const {
+                return std::ldexp(x, y);
+            }
+        };
+
+        template <typename Float>
+        struct call_frexp {
+            typedef Float float_type;
+            inline Float operator()(Float x, int* y) const {
+                return std::frexp(x, y);
+            }
+        };
+
+        template <typename Float>
+        struct select_hash_type
+        {
+            typedef Float type;
+        };
+    }
+}
+
+#else // BOOST_HASH_CONFORMANT_FLOATS == 0
+
+// The C++ standard requires that the C float functions are overloarded
+// for float, double and long double in the std namespace, but some of the older
+// library implementations don't support this. On some that don't, the C99
+// float functions (frexpf, frexpl, etc.) are available.
+//
+// The following tries to automatically detect which are available.
+
+namespace boost {
+    namespace hash_detail {
+
+        // Returned by dummy versions of the float functions.
+    
+        struct not_found {
+            // Implicitly convertible to float and long double in order to avoid
+            // a compile error when the dummy float functions are used.
+
+            inline operator float() const { return 0; }
+            inline operator long double() const { return 0; }
+        };
+          
+        // A type for detecting the return type of functions.
+
+        template <typename T> struct is;
+        template <> struct is<float> { char x[10]; };
+        template <> struct is<double> { char x[20]; };
+        template <> struct is<long double> { char x[30]; };
+        template <> struct is<boost::hash_detail::not_found> { char x[40]; };
+            
+        // Used to convert the return type of a function to a type for sizeof.
+
+        template <typename T> is<T> float_type(T);
+
+        // call_ldexp
+        //
+        // This will get specialized for float and long double
+        
+        template <typename Float> struct call_ldexp
+        {
+            typedef double float_type;
+            
+            inline double operator()(double a, int b) const
+            {
+                using namespace std;
+                return ldexp(a, b);
+            }
+        };
+
+        // call_frexp
+        //
+        // This will get specialized for float and long double
+
+        template <typename Float> struct call_frexp
+        {
+            typedef double float_type;
+            
+            inline double operator()(double a, int* b) const
+            {
+                using namespace std;
+                return frexp(a, b);
+            }
+        };
+    }
+}
+            
+// A namespace for dummy functions to detect when the actual function we want
+// isn't available. ldexpl, ldexpf etc. might be added tby the macros below.
+//
+// AFAICT these have to be outside of the boost namespace, as if they're in
+// the boost namespace they'll always be preferable to any other function
+// (since the arguments are built in types, ADL can't be used).
+
+namespace boost_hash_detect_float_functions {
+    template <class Float> boost::hash_detail::not_found ldexp(Float, int);
+    template <class Float> boost::hash_detail::not_found frexp(Float, int*);    
+}
+
+// Macros for generating specializations of call_ldexp and call_frexp.
+//
+// check_cpp and check_c99 check if the C++ or C99 functions are available.
+//
+// Then the call_* functions select an appropriate implementation.
+//
+// I used c99_func in a few places just to get a unique name.
+//
+// Important: when using 'using namespace' at namespace level, include as
+// little as possible in that namespace, as Visual C++ has an odd bug which
+// can cause the namespace to be imported at the global level. This seems to
+// happen mainly when there's a template in the same namesapce.
+
+#define BOOST_HASH_CALL_FLOAT_FUNC(cpp_func, c99_func, type1, type2)    \
+namespace boost_hash_detect_float_functions {                           \
+    template <class Float>                                              \
+    boost::hash_detail::not_found c99_func(Float, type2);               \
+}                                                                       \
+                                                                        \
+namespace boost {                                                       \
+    namespace hash_detail {                                             \
+        namespace c99_func##_detect {                                   \
+            using namespace std;                                        \
+            using namespace boost_hash_detect_float_functions;          \
+                                                                        \
+            struct check {                                              \
+                static type1 x;                                         \
+                static type2 y;                                         \
+                BOOST_STATIC_CONSTANT(bool, cpp =                       \
+                    sizeof(float_type(cpp_func(x,y)))                   \
+                        == sizeof(is<type1>));                          \
+                BOOST_STATIC_CONSTANT(bool, c99 =                       \
+                    sizeof(float_type(c99_func(x,y)))                   \
+                        == sizeof(is<type1>));                          \
+            };                                                          \
+        }                                                               \
+                                                                        \
+        template <bool x>                                               \
+        struct call_c99_##c99_func :                                    \
+            boost::hash_detail::call_##cpp_func<double> {};             \
+                                                                        \
+        template <>                                                     \
+        struct call_c99_##c99_func<true> {                              \
+            typedef type1 float_type;                                   \
+                                                                        \
+            template <typename T>                                       \
+            inline type1 operator()(type1 a, T b)  const                \
+            {                                                           \
+                using namespace std;                                    \
+                return c99_func(a, b);                                  \
+            }                                                           \
+        };                                                              \
+                                                                        \
+        template <bool x>                                               \
+        struct call_cpp_##c99_func :                                    \
+            call_c99_##c99_func<                                        \
+                ::boost::hash_detail::c99_func##_detect::check::c99     \
+            > {};                                                       \
+                                                                        \
+        template <>                                                     \
+        struct call_cpp_##c99_func<true> {                              \
+            typedef type1 float_type;                                   \
+                                                                        \
+            template <typename T>                                       \
+            inline type1 operator()(type1 a, T b)  const                \
+            {                                                           \
+                using namespace std;                                    \
+                return cpp_func(a, b);                                  \
+            }                                                           \
+        };                                                              \
+                                                                        \
+        template <>                                                     \
+        struct call_##cpp_func<type1> :                                 \
+            call_cpp_##c99_func<                                        \
+                ::boost::hash_detail::c99_func##_detect::check::cpp     \
+            > {};                                                       \
+    }                                                                   \
+}
+
+#define BOOST_HASH_CALL_FLOAT_MACRO(cpp_func, c99_func, type1, type2)   \
+namespace boost {                                                       \
+    namespace hash_detail {                                             \
+                                                                        \
+        template <>                                                     \
+        struct call_##cpp_func<type1> {                                 \
+            typedef type1 float_type;                                   \
+            inline type1 operator()(type1 x, type2 y) const {           \
+                return c99_func(x, y);                                  \
+            }                                                           \
+        };                                                              \
+    }                                                                   \
+}
+
+#if defined(ldexpf)
+BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpf, float, int)
+#else
+BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpf, float, int)
+#endif
+
+#if defined(ldexpl)
+BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpl, long double, int)
+#else
+BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpl, long double, int)
+#endif
+
+#if defined(frexpf)
+BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpf, float, int*)
+#else
+BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpf, float, int*)
+#endif
+
+#if defined(frexpl)
+BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpl, long double, int*)
+#else
+BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpl, long double, int*)
+#endif
+
+#undef BOOST_HASH_CALL_FLOAT_MACRO
+#undef BOOST_HASH_CALL_FLOAT_FUNC
+
+
+namespace boost
+{
+    namespace hash_detail
+    {
+        template <typename Float1, typename Float2>
+        struct select_hash_type_impl {
+            typedef double type;
+        };
+
+        template <>
+        struct select_hash_type_impl<float, float> {
+            typedef float type;
+        };
+
+        template <>
+        struct select_hash_type_impl<long double, long double> {
+            typedef long double type;
+        };
+
+
+        // select_hash_type
+        //
+        // If there is support for a particular floating point type, use that
+        // otherwise use double (there's always support for double).
+             
+        template <typename Float>
+        struct select_hash_type : select_hash_type_impl<
+                BOOST_DEDUCED_TYPENAME call_ldexp<Float>::float_type,
+                BOOST_DEDUCED_TYPENAME call_frexp<Float>::float_type
+            > {};            
+    }
+}
+
+#endif // BOOST_HASH_CONFORMANT_FLOATS
+
+#endif
diff --git a/include/boost/container_hash/detail/hash_float.hpp b/include/boost/container_hash/detail/hash_float.hpp
new file mode 100644
index 0000000..f763428
--- /dev/null
+++ b/include/boost/container_hash/detail/hash_float.hpp
@@ -0,0 +1,271 @@
+
+// Copyright 2005-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_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_HEADER)
+#define BOOST_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_HEADER
+
+#include <boost/config.hpp>
+#if defined(BOOST_HAS_PRAGMA_ONCE)
+#pragma once
+#endif
+
+#include <boost/container_hash/detail/float_functions.hpp>
+#include <boost/container_hash/detail/limits.hpp>
+#include <boost/core/enable_if.hpp>
+#include <boost/integer/static_log2.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/assert.hpp>
+#include <boost/limits.hpp>
+#include <cstring>
+
+#if defined(BOOST_MSVC)
+#pragma warning(push)
+#if BOOST_MSVC >= 1400
+#pragma warning(disable:6294) // Ill-defined for-loop: initial condition does
+                              // not satisfy test. Loop body not executed
+#endif
+#endif
+
+// Can we use fpclassify?
+
+// STLport
+#if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
+#define BOOST_HASH_USE_FPCLASSIFY 0
+
+// GNU libstdc++ 3
+#elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
+#  if (defined(__USE_ISOC99) || defined(_GLIBCXX_USE_C99_MATH)) && \
+      !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
+#    define BOOST_HASH_USE_FPCLASSIFY 1
+#  else
+#    define BOOST_HASH_USE_FPCLASSIFY 0
+#  endif
+
+// Everything else
+#else
+#  define BOOST_HASH_USE_FPCLASSIFY 0
+#endif
+
+namespace boost
+{
+    namespace hash_detail
+    {
+        inline void hash_float_combine(std::size_t& seed, std::size_t value)
+        {
+            seed ^= value + (seed<<6) + (seed>>2);
+        }
+
+        ////////////////////////////////////////////////////////////////////////
+        // Binary hash function
+        //
+        // Only used for floats with known iec559 floats, and certain values in
+        // numeric_limits
+
+        inline std::size_t hash_binary(char* ptr, std::size_t length)
+        {
+            std::size_t seed = 0;
+
+            if (length >= sizeof(std::size_t)) {
+                std::memcpy(&seed, ptr, sizeof(std::size_t));
+                length -= sizeof(std::size_t);
+                ptr += sizeof(std::size_t);
+
+                while(length >= sizeof(std::size_t)) {
+                    std::size_t buffer = 0;
+                    std::memcpy(&buffer, ptr, sizeof(std::size_t));
+                    hash_float_combine(seed, buffer);
+                    length -= sizeof(std::size_t);
+                    ptr += sizeof(std::size_t);
+                }
+            }
+
+            if (length > 0) {
+                std::size_t buffer = 0;
+                std::memcpy(&buffer, ptr, length);
+                hash_float_combine(seed, buffer);
+            }
+
+            return seed;
+        }
+
+        template <typename Float, unsigned digits, unsigned max_exponent>
+        struct enable_binary_hash
+        {
+            BOOST_STATIC_CONSTANT(bool, value =
+                std::numeric_limits<Float>::is_iec559 &&
+                std::numeric_limits<Float>::digits == digits &&
+                std::numeric_limits<Float>::radix == 2 &&
+                std::numeric_limits<Float>::max_exponent == max_exponent);
+        };
+
+        template <typename Float>
+        inline std::size_t float_hash_impl(Float v,
+            BOOST_DEDUCED_TYPENAME boost::enable_if_c<
+                enable_binary_hash<Float, 24, 128>::value,
+                std::size_t>::type)
+        {
+            return hash_binary((char*) &v, 4);
+        }
+
+
+        template <typename Float>
+        inline std::size_t float_hash_impl(Float v,
+            BOOST_DEDUCED_TYPENAME boost::enable_if_c<
+                enable_binary_hash<Float, 53, 1024>::value,
+                std::size_t>::type)
+        {
+            return hash_binary((char*) &v, 8);
+        }
+
+        template <typename Float>
+        inline std::size_t float_hash_impl(Float v,
+            BOOST_DEDUCED_TYPENAME boost::enable_if_c<
+                enable_binary_hash<Float, 64, 16384>::value,
+                std::size_t>::type)
+        {
+            return hash_binary((char*) &v, 10);
+        }
+
+        template <typename Float>
+        inline std::size_t float_hash_impl(Float v,
+            BOOST_DEDUCED_TYPENAME boost::enable_if_c<
+                enable_binary_hash<Float, 113, 16384>::value,
+                std::size_t>::type)
+        {
+            return hash_binary((char*) &v, 16);
+        }
+
+        ////////////////////////////////////////////////////////////////////////
+        // Portable hash function
+        //
+        // Used as a fallback when the binary hash function isn't supported.
+
+        template <class T>
+        inline std::size_t float_hash_impl2(T v)
+        {
+            boost::hash_detail::call_frexp<T> frexp;
+            boost::hash_detail::call_ldexp<T> ldexp;
+
+            int exp = 0;
+
+            v = frexp(v, &exp);
+
+            // A postive value is easier to hash, so combine the
+            // sign with the exponent and use the absolute value.
+            if(v < 0) {
+                v = -v;
+                exp += limits<T>::max_exponent -
+                    limits<T>::min_exponent;
+            }
+
+            v = ldexp(v, limits<std::size_t>::digits);
+            std::size_t seed = static_cast<std::size_t>(v);
+            v -= static_cast<T>(seed);
+
+            // ceiling(digits(T) * log2(radix(T))/ digits(size_t)) - 1;
+            std::size_t const length
+                = (limits<T>::digits *
+                        boost::static_log2<limits<T>::radix>::value
+                        + limits<std::size_t>::digits - 1)
+                / limits<std::size_t>::digits;
+
+            for(std::size_t i = 0; i != length; ++i)
+            {
+                v = ldexp(v, limits<std::size_t>::digits);
+                std::size_t part = static_cast<std::size_t>(v);
+                v -= static_cast<T>(part);
+                hash_float_combine(seed, part);
+            }
+
+            hash_float_combine(seed, static_cast<std::size_t>(exp));
+
+            return seed;
+        }
+
+#if !defined(BOOST_HASH_DETAIL_TEST_WITHOUT_GENERIC)
+        template <class T>
+        inline std::size_t float_hash_impl(T v, ...)
+        {
+            typedef BOOST_DEDUCED_TYPENAME select_hash_type<T>::type type;
+            return float_hash_impl2(static_cast<type>(v));
+        }
+#endif
+    }
+}
+
+#if BOOST_HASH_USE_FPCLASSIFY
+
+#include <boost/config/no_tr1/cmath.hpp>
+
+namespace boost
+{
+    namespace hash_detail
+    {
+        template <class T>
+        inline std::size_t float_hash_value(T v)
+        {
+#if defined(fpclassify)
+            switch (fpclassify(v))
+#elif BOOST_HASH_CONFORMANT_FLOATS
+            switch (std::fpclassify(v))
+#else
+            using namespace std;
+            switch (fpclassify(v))
+#endif
+            {
+            case FP_ZERO:
+                return 0;
+            case FP_INFINITE:
+                return (std::size_t)(v > 0 ? -1 : -2);
+            case FP_NAN:
+                return (std::size_t)(-3);
+            case FP_NORMAL:
+            case FP_SUBNORMAL:
+                return float_hash_impl(v, 0);
+            default:
+                BOOST_ASSERT(0);
+                return 0;
+            }
+        }
+    }
+}
+
+#else // !BOOST_HASH_USE_FPCLASSIFY
+
+namespace boost
+{
+    namespace hash_detail
+    {
+        template <class T>
+        inline bool is_zero(T v)
+        {
+#if !defined(__GNUC__) && !defined(__clang__)
+            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<T>()(v, 0);
+#endif
+        }
+
+        template <class T>
+        inline std::size_t float_hash_value(T v)
+        {
+            return boost::hash_detail::is_zero(v) ? 0 : float_hash_impl(v, 0);
+        }
+    }
+}
+
+#endif // BOOST_HASH_USE_FPCLASSIFY
+
+#undef BOOST_HASH_USE_FPCLASSIFY
+
+#if defined(BOOST_MSVC)
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/include/boost/container_hash/detail/limits.hpp b/include/boost/container_hash/detail/limits.hpp
new file mode 100644
index 0000000..4a971a6
--- /dev/null
+++ b/include/boost/container_hash/detail/limits.hpp
@@ -0,0 +1,62 @@
+
+// Copyright 2005-2009 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)
+//
+// On some platforms std::limits gives incorrect values for long double.
+// This tries to work around them.
+
+#if !defined(BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER)
+#define BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER
+
+#include <boost/config.hpp>
+#if defined(BOOST_HAS_PRAGMA_ONCE)
+#pragma once
+#endif
+
+#include <boost/limits.hpp>
+
+// On OpenBSD, numeric_limits is not reliable for long doubles, but
+// the macros defined in <float.h> are and support long double when STLport
+// doesn't.
+
+#if defined(__OpenBSD__) || defined(_STLP_NO_LONG_DOUBLE)
+#include <float.h>
+#endif
+
+namespace boost
+{
+    namespace hash_detail
+    {
+        template <class T>
+        struct limits : std::numeric_limits<T> {};
+
+#if defined(__OpenBSD__) || defined(_STLP_NO_LONG_DOUBLE)
+        template <>
+        struct limits<long double>
+             : std::numeric_limits<long double>
+        {
+            static long double epsilon() {
+                return LDBL_EPSILON;
+            }
+
+            static long double (max)() {
+                return LDBL_MAX;
+            }
+
+            static long double (min)() {
+                return LDBL_MIN;
+            }
+
+            BOOST_STATIC_CONSTANT(int, digits = LDBL_MANT_DIG);
+            BOOST_STATIC_CONSTANT(int, max_exponent = LDBL_MAX_EXP);
+            BOOST_STATIC_CONSTANT(int, min_exponent = LDBL_MIN_EXP);
+#if defined(_STLP_NO_LONG_DOUBLE)
+            BOOST_STATIC_CONSTANT(int, radix = FLT_RADIX);
+#endif
+        };
+#endif // __OpenBSD__
+    }
+}
+
+#endif
diff --git a/include/boost/container_hash/extensions.hpp b/include/boost/container_hash/extensions.hpp
new file mode 100644
index 0000000..4eebb4b
--- /dev/null
+++ b/include/boost/container_hash/extensions.hpp
@@ -0,0 +1,414 @@
+
+// Copyright 2005-2009 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)
+
+//  Based on Peter Dimov's proposal
+//  http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
+//  issue 6.18.
+
+// This implements the extensions to the standard.
+// It's undocumented, so you shouldn't use it....
+
+#if !defined(BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP)
+#define BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP
+
+#include <boost/config.hpp>
+#if defined(BOOST_HAS_PRAGMA_ONCE)
+#pragma once
+#endif
+
+#include <boost/container_hash/hash.hpp>
+#include <boost/detail/container_fwd.hpp>
+#include <boost/core/enable_if.hpp>
+#include <boost/static_assert.hpp>
+#include <vector>
+
+#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
+#   include <array>
+#endif
+
+#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
+#   include <tuple>
+#endif
+
+#if !defined(BOOST_NO_CXX11_HDR_MEMORY)
+#   include <memory>
+#endif
+
+#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
+#include <boost/type_traits/is_array.hpp>
+#endif
+
+namespace boost
+{
+    template <class A, class B>
+    std::size_t hash_value(std::pair<A, B> const&);
+    template <class T, class A>
+    std::size_t hash_value(std::vector<T, A> const&);
+    template <class T, class A>
+    std::size_t hash_value(std::list<T, A> const& v);
+    template <class T, class A>
+    std::size_t hash_value(std::deque<T, A> const& v);
+    template <class K, class C, class A>
+    std::size_t hash_value(std::set<K, C, A> const& v);
+    template <class K, class C, class A>
+    std::size_t hash_value(std::multiset<K, C, A> const& v);
+    template <class K, class T, class C, class A>
+    std::size_t hash_value(std::map<K, T, C, A> const& v);
+    template <class K, class T, class C, class A>
+    std::size_t hash_value(std::multimap<K, T, C, A> const& v);
+
+    template <class T>
+    std::size_t hash_value(std::complex<T> const&);
+
+    template <class A, class B>
+    std::size_t hash_value(std::pair<A, B> const& v)
+    {
+        std::size_t seed = 0;
+        boost::hash_combine(seed, v.first);
+        boost::hash_combine(seed, v.second);
+        return seed;
+    }
+
+    inline std::size_t hash_range(
+        std::vector<bool>::iterator first,
+        std::vector<bool>::iterator last)
+    {
+        std::size_t seed = 0;
+
+        for(; first != last; ++first)
+        {
+            hash_combine<bool>(seed, *first);
+        }
+
+        return seed;
+    }
+
+    inline std::size_t hash_range(
+        std::vector<bool>::const_iterator first,
+        std::vector<bool>::const_iterator last)
+    {
+        std::size_t seed = 0;
+
+        for(; first != last; ++first)
+        {
+            hash_combine<bool>(seed, *first);
+        }
+
+        return seed;
+    }
+
+    inline void hash_range(
+        std::size_t& seed,
+        std::vector<bool>::iterator first,
+        std::vector<bool>::iterator last)
+    {
+        for(; first != last; ++first)
+        {
+            hash_combine<bool>(seed, *first);
+        }
+    }
+
+    inline void hash_range(
+        std::size_t& seed,
+        std::vector<bool>::const_iterator first,
+        std::vector<bool>::const_iterator last)
+    {
+        for(; first != last; ++first)
+        {
+            hash_combine<bool>(seed, *first);
+        }
+    }
+
+    template <class T, class A>
+    std::size_t hash_value(std::vector<T, A> const& v)
+    {
+        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 boost::hash_range(v.begin(), v.end());
+    }
+
+    template <class T, class A>
+    std::size_t hash_value(std::deque<T, A> const& v)
+    {
+        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 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 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 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 boost::hash_range(v.begin(), v.end());
+    }
+
+    template <class T>
+    std::size_t hash_value(std::complex<T> const& v)
+    {
+        boost::hash<T> hasher;
+        std::size_t seed = hasher(v.imag());
+        seed ^= hasher(v.real()) + (seed<<6) + (seed>>2);
+        return seed;
+    }
+
+#if !defined(BOOST_NO_CXX11_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_CXX11_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_CXX11_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);
+    }
+
+    template<typename A0>
+    inline std::size_t hash_value(std::tuple<A0> const& v)
+    {
+        return boost::hash_detail::hash_tuple(v);
+    }
+
+    template<typename A0, typename A1>
+    inline std::size_t hash_value(std::tuple<A0, A1> const& v)
+    {
+        return boost::hash_detail::hash_tuple(v);
+    }
+
+    template<typename A0, typename A1, typename A2>
+    inline std::size_t hash_value(std::tuple<A0, A1, A2> const& v)
+    {
+        return boost::hash_detail::hash_tuple(v);
+    }
+
+    template<typename A0, typename A1, typename A2, typename A3>
+    inline std::size_t hash_value(std::tuple<A0, A1, A2, A3> const& v)
+    {
+        return boost::hash_detail::hash_tuple(v);
+    }
+
+    template<typename A0, typename A1, typename A2, typename A3, typename A4>
+    inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4> const& v)
+    {
+        return boost::hash_detail::hash_tuple(v);
+    }
+
+    template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
+    inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5> const& v)
+    {
+        return boost::hash_detail::hash_tuple(v);
+    }
+
+    template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
+    inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6> const& v)
+    {
+        return boost::hash_detail::hash_tuple(v);
+    }
+
+    template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
+    inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6, A7> const& v)
+    {
+        return boost::hash_detail::hash_tuple(v);
+    }
+
+    template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
+    inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6, A7, A8> const& v)
+    {
+        return boost::hash_detail::hash_tuple(v);
+    }
+
+    template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
+    inline std::size_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6, A7, A8, A9> const& v)
+    {
+        return boost::hash_detail::hash_tuple(v);
+    }
+
+#endif
+
+#endif
+
+#if !defined(BOOST_NO_CXX11_SMART_PTR)
+    template <typename T>
+    inline std::size_t hash_value(std::shared_ptr<T> const& x) {
+        return boost::hash_value(x.get());
+    }
+
+    template <typename T, typename Deleter>
+    inline std::size_t hash_value(std::unique_ptr<T, Deleter> const& x) {
+        return boost::hash_value(x.get());
+    }
+#endif
+
+    //
+    // call_hash_impl
+    //
+
+    // On compilers without function template ordering, this deals with arrays.
+
+#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
+    namespace hash_detail
+    {
+        template <bool IsArray>
+        struct call_hash_impl
+        {
+            template <class T>
+            struct inner
+            {
+                static std::size_t call(T const& v)
+                {
+                    using namespace boost;
+                    return hash_value(v);
+                }
+            };
+        };
+
+        template <>
+        struct call_hash_impl<true>
+        {
+            template <class Array>
+            struct inner
+            {
+                static std::size_t call(Array const& v)
+                {
+                    const int size = sizeof(v) / sizeof(*v);
+                    return boost::hash_range(v, v + size);
+                }
+            };
+        };
+
+        template <class T>
+        struct call_hash
+            : public call_hash_impl<boost::is_array<T>::value>
+                ::BOOST_NESTED_TEMPLATE inner<T>
+        {
+        };
+    }
+#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING
+
+    //
+    // boost::hash
+    //
+
+
+#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
+
+    template <class T> struct hash
+        : boost::hash_detail::hash_base<T>
+    {
+#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
+        std::size_t operator()(T const& val) const
+        {
+            return hash_value(val);
+        }
+#else
+        std::size_t operator()(T const& val) const
+        {
+            return hash_detail::call_hash<T>::call(val);
+        }
+#endif
+    };
+
+#if BOOST_WORKAROUND(__DMC__, <= 0x848)
+    template <class T, unsigned int n> struct hash<T[n]>
+        : boost::hash_detail::hash_base<T[n]>
+    {
+        std::size_t operator()(const T* val) const
+        {
+            return boost::hash_range(val, val+n);
+        }
+    };
+#endif
+
+#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+
+    // On compilers without partial specialization, boost::hash<T>
+    // has already been declared to deal with pointers, so just
+    // need to supply the non-pointer version of hash_impl.
+
+    namespace hash_detail
+    {
+        template <bool IsPointer>
+        struct hash_impl;
+
+        template <>
+        struct hash_impl<false>
+        {
+            template <class T>
+            struct inner
+                : boost::hash_detail::hash_base<T>
+            {
+#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
+                std::size_t operator()(T const& val) const
+                {
+                    return hash_value(val);
+                }
+#else
+                std::size_t operator()(T const& val) const
+                {
+                    return hash_detail::call_hash<T>::call(val);
+                }
+#endif
+            };
+        };
+    }
+#endif  // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+}
+
+#endif
diff --git a/include/boost/container_hash/hash.hpp b/include/boost/container_hash/hash.hpp
new file mode 100644
index 0000000..76de793
--- /dev/null
+++ b/include/boost/container_hash/hash.hpp
@@ -0,0 +1,761 @@
+
+// Copyright 2005-2014 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)
+
+//  Based on Peter Dimov's proposal
+//  http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
+//  issue 6.18.
+//
+//  This also contains public domain code from MurmurHash. From the
+//  MurmurHash header:
+
+// MurmurHash3 was written by Austin Appleby, and is placed in the public
+// domain. The author hereby disclaims copyright to this source code.
+
+#if !defined(BOOST_FUNCTIONAL_HASH_HASH_HPP)
+#define BOOST_FUNCTIONAL_HASH_HASH_HPP
+
+#include <boost/container_hash/hash_fwd.hpp>
+#include <functional>
+#include <boost/container_hash/detail/hash_float.hpp>
+#include <string>
+#include <boost/limits.hpp>
+#include <boost/type_traits/is_enum.hpp>
+#include <boost/type_traits/is_integral.hpp>
+#include <boost/core/enable_if.hpp>
+#include <boost/cstdint.hpp>
+
+#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
+#include <boost/type_traits/is_pointer.hpp>
+#endif
+
+#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
+#include <typeindex>
+#endif
+
+#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
+#include <system_error>
+#endif
+
+#if defined(BOOST_MSVC)
+#pragma warning(push)
+
+#if BOOST_MSVC >= 1400
+#pragma warning(disable:6295) // Ill-defined for-loop : 'unsigned int' values
+                              // are always of range '0' to '4294967295'.
+                              // Loop executes infinitely.
+#endif
+
+#endif
+
+#if BOOST_WORKAROUND(__GNUC__, < 3) \
+    && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)
+#define BOOST_HASH_CHAR_TRAITS string_char_traits
+#else
+#define BOOST_HASH_CHAR_TRAITS char_traits
+#endif
+
+#if defined(_MSC_VER)
+#   define BOOST_FUNCTIONAL_HASH_ROTL32(x, r) _rotl(x,r)
+#else
+#   define BOOST_FUNCTIONAL_HASH_ROTL32(x, r) (x << r) | (x >> (32 - r))
+#endif
+
+// Detect whether standard library has C++17 headers
+
+#if !defined(BOOST_HASH_CXX17)
+#   if defined(BOOST_MSVC)
+#       if defined(_HAS_CXX17) && _HAS_CXX17
+#           define BOOST_HASH_CXX17 1
+#       endif
+#   elif defined(__cplusplus) && __cplusplus >= 201703
+#       define BOOST_HASH_CXX17 1
+#   endif
+#endif
+
+#if !defined(BOOST_HASH_CXX17)
+#   define BOOST_HASH_CXX17 0
+#endif
+
+#if BOOST_HASH_CXX17 && defined(__has_include)
+#   if !defined(BOOST_HASH_HAS_STRING_VIEW) && __has_include(<string_view>)
+#       define BOOST_HASH_HAS_STRING_VIEW 1
+#   endif
+#   if !defined(BOOST_HASH_HAS_OPTIONAL) && __has_include(<optional>)
+#       define BOOST_HASH_HAS_OPTIONAL 1
+#   endif
+#   if !defined(BOOST_HASH_HAS_VARIANT) && __has_include(<variant>)
+#       define BOOST_HASH_HAS_VARIANT 1
+#   endif
+#endif
+
+#if !defined(BOOST_HASH_HAS_STRING_VIEW)
+#   define BOOST_HASH_HAS_STRING_VIEW 0
+#endif
+
+#if !defined(BOOST_HASH_HAS_OPTIONAL)
+#   define BOOST_HASH_HAS_OPTIONAL 0
+#endif
+
+#if !defined(BOOST_HASH_HAS_VARIANT)
+#   define BOOST_HASH_HAS_VARIANT 0
+#endif
+
+#if BOOST_HASH_HAS_STRING_VIEW
+#   include <string_view>
+#endif
+
+#if BOOST_HASH_HAS_OPTIONAL
+#   include <optional>
+#endif
+
+#if BOOST_HASH_HAS_VARIANT
+#   include <variant>
+#endif
+
+namespace boost
+{
+    namespace hash_detail
+    {
+#if defined(_HAS_AUTO_PTR_ETC) && !_HAS_AUTO_PTR_ETC
+        template <typename T>
+        struct hash_base
+        {
+            typedef T argument_type;
+            typedef std::size_t result_type;
+        };
+#else
+        template <typename T>
+        struct hash_base : std::unary_function<T, std::size_t> {};
+#endif
+
+        struct enable_hash_value { typedef std::size_t type; };
+
+        template <typename T> struct basic_numbers {};
+        template <typename T> struct long_numbers;
+        template <typename T> struct ulong_numbers;
+        template <typename T> struct float_numbers {};
+
+        template <> struct basic_numbers<bool> :
+            boost::hash_detail::enable_hash_value {};
+        template <> struct basic_numbers<char> :
+            boost::hash_detail::enable_hash_value {};
+        template <> struct basic_numbers<unsigned char> :
+            boost::hash_detail::enable_hash_value {};
+        template <> struct basic_numbers<signed char> :
+            boost::hash_detail::enable_hash_value {};
+        template <> struct basic_numbers<short> :
+            boost::hash_detail::enable_hash_value {};
+        template <> struct basic_numbers<unsigned short> :
+            boost::hash_detail::enable_hash_value {};
+        template <> struct basic_numbers<int> :
+            boost::hash_detail::enable_hash_value {};
+        template <> struct basic_numbers<unsigned int> :
+            boost::hash_detail::enable_hash_value {};
+        template <> struct basic_numbers<long> :
+            boost::hash_detail::enable_hash_value {};
+        template <> struct basic_numbers<unsigned long> :
+            boost::hash_detail::enable_hash_value {};
+
+#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
+        template <> struct basic_numbers<wchar_t> :
+            boost::hash_detail::enable_hash_value {};
+#endif
+
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+        template <> struct basic_numbers<char16_t> :
+            boost::hash_detail::enable_hash_value {};
+#endif
+
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+        template <> struct basic_numbers<char32_t> :
+            boost::hash_detail::enable_hash_value {};
+#endif
+
+        // long_numbers is defined like this to allow for separate
+        // specialization for long_long and int128_type, in case
+        // they conflict.
+        template <typename T> struct long_numbers2 {};
+        template <typename T> struct ulong_numbers2 {};
+        template <typename T> struct long_numbers : long_numbers2<T> {};
+        template <typename T> struct ulong_numbers : ulong_numbers2<T> {};
+
+#if !defined(BOOST_NO_LONG_LONG)
+        template <> struct long_numbers<boost::long_long_type> :
+            boost::hash_detail::enable_hash_value {};
+        template <> struct ulong_numbers<boost::ulong_long_type> :
+            boost::hash_detail::enable_hash_value {};
+#endif
+
+#if defined(BOOST_HAS_INT128)
+        template <> struct long_numbers2<boost::int128_type> :
+            boost::hash_detail::enable_hash_value {};
+        template <> struct ulong_numbers2<boost::uint128_type> :
+            boost::hash_detail::enable_hash_value {};
+#endif
+
+        template <> struct float_numbers<float> :
+            boost::hash_detail::enable_hash_value {};
+        template <> struct float_numbers<double> :
+            boost::hash_detail::enable_hash_value {};
+        template <> struct float_numbers<long double> :
+            boost::hash_detail::enable_hash_value {};
+    }
+
+    template <typename T>
+    typename boost::hash_detail::basic_numbers<T>::type hash_value(T);
+    template <typename T>
+    typename boost::hash_detail::long_numbers<T>::type hash_value(T);
+    template <typename T>
+    typename boost::hash_detail::ulong_numbers<T>::type hash_value(T);
+
+    template <typename T>
+    typename boost::enable_if<boost::is_enum<T>, std::size_t>::type
+        hash_value(T);
+
+#if !BOOST_WORKAROUND(__DMC__, <= 0x848)
+    template <class T> std::size_t hash_value(T* const&);
+#else
+    template <class T> std::size_t hash_value(T*);
+#endif
+
+#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
+    template< class T, unsigned N >
+    std::size_t hash_value(const T (&x)[N]);
+
+    template< class T, unsigned N >
+    std::size_t hash_value(T (&x)[N]);
+#endif
+
+    template <class Ch, class A>
+    std::size_t hash_value(
+        std::basic_string<Ch, std::BOOST_HASH_CHAR_TRAITS<Ch>, A> const&);
+
+#if BOOST_HASH_HAS_STRING_VIEW
+    template <class Ch>
+    std::size_t hash_value(
+        std::basic_string_view<Ch, std::BOOST_HASH_CHAR_TRAITS<Ch> > const&);
+#endif
+
+    template <typename T>
+    typename boost::hash_detail::float_numbers<T>::type hash_value(T);
+
+#if BOOST_HASH_HAS_OPTIONAL
+    template <typename T>
+    std::size_t hash_value(std::optional<T> const&);
+#endif
+
+#if BOOST_HASH_HAS_VARIANT
+    std::size_t hash_value(std::monostate);
+    template <typename... Types>
+    std::size_t hash_value(std::variant<Types...> const&);
+#endif
+
+#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
+    std::size_t hash_value(std::type_index);
+#endif
+
+#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
+    std::size_t hash_value(std::error_code const&);
+    std::size_t hash_value(std::error_condition const&);
+#endif
+
+    // Implementation
+
+    namespace hash_detail
+    {
+        template <class T>
+        inline std::size_t hash_value_signed(T val)
+        {
+             const unsigned int size_t_bits = std::numeric_limits<std::size_t>::digits;
+             // ceiling(std::numeric_limits<T>::digits / size_t_bits) - 1
+             const int length = (std::numeric_limits<T>::digits - 1)
+                 / static_cast<int>(size_t_bits);
+
+             std::size_t seed = 0;
+             T positive = val < 0 ? -1 - val : val;
+
+             // Hopefully, this loop can be unrolled.
+             for(unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits)
+             {
+                 seed ^= (std::size_t) (positive >> i) + (seed<<6) + (seed>>2);
+             }
+             seed ^= (std::size_t) val + (seed<<6) + (seed>>2);
+
+             return seed;
+        }
+
+        template <class T>
+        inline std::size_t hash_value_unsigned(T val)
+        {
+             const unsigned int size_t_bits = std::numeric_limits<std::size_t>::digits;
+             // ceiling(std::numeric_limits<T>::digits / size_t_bits) - 1
+             const int length = (std::numeric_limits<T>::digits - 1)
+                 / static_cast<int>(size_t_bits);
+
+             std::size_t seed = 0;
+
+             // Hopefully, this loop can be unrolled.
+             for(unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits)
+             {
+                 seed ^= (std::size_t) (val >> i) + (seed<<6) + (seed>>2);
+             }
+             seed ^= (std::size_t) val + (seed<<6) + (seed>>2);
+
+             return seed;
+        }
+
+        template <typename SizeT>
+        inline void hash_combine_impl(SizeT& seed, SizeT value)
+        {
+            seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
+        }
+
+        inline void hash_combine_impl(boost::uint32_t& h1,
+                boost::uint32_t k1)
+        {
+            const uint32_t c1 = 0xcc9e2d51;
+            const uint32_t c2 = 0x1b873593;
+
+            k1 *= c1;
+            k1 = BOOST_FUNCTIONAL_HASH_ROTL32(k1,15);
+            k1 *= c2;
+
+            h1 ^= k1;
+            h1 = BOOST_FUNCTIONAL_HASH_ROTL32(h1,13);
+            h1 = h1*5+0xe6546b64;
+        }
+
+
+// Don't define 64-bit hash combine on platforms without 64 bit integers,
+// and also not for 32-bit gcc as it warns about the 64-bit constant.
+#if !defined(BOOST_NO_INT64_T) && \
+        !(defined(__GNUC__) && ULONG_MAX == 0xffffffff)
+
+        inline void hash_combine_impl(boost::uint64_t& h,
+                boost::uint64_t k)
+        {
+            const boost::uint64_t m = UINT64_C(0xc6a4a7935bd1e995);
+            const int r = 47;
+
+            k *= m;
+            k ^= k >> r;
+            k *= m;
+
+            h ^= k;
+            h *= m;
+
+            // Completely arbitrary number, to prevent 0's
+            // from hashing to 0.
+            h += 0xe6546b64;
+        }
+
+#endif // BOOST_NO_INT64_T
+    }
+
+    template <typename T>
+    typename boost::hash_detail::basic_numbers<T>::type hash_value(T v)
+    {
+        return static_cast<std::size_t>(v);
+    }
+
+    template <typename T>
+    typename boost::hash_detail::long_numbers<T>::type hash_value(T v)
+    {
+        return hash_detail::hash_value_signed(v);
+    }
+
+    template <typename T>
+    typename boost::hash_detail::ulong_numbers<T>::type hash_value(T v)
+    {
+        return hash_detail::hash_value_unsigned(v);
+    }
+
+    template <typename T>
+    typename boost::enable_if<boost::is_enum<T>, std::size_t>::type
+        hash_value(T v)
+    {
+        return static_cast<std::size_t>(v);
+    }
+
+    // Implementation by Alberto Barbati and Dave Harris.
+#if !BOOST_WORKAROUND(__DMC__, <= 0x848)
+    template <class T> std::size_t hash_value(T* const& v)
+#else
+    template <class T> std::size_t hash_value(T* v)
+#endif
+    {
+#if defined(__VMS) && __INITIAL_POINTER_SIZE == 64
+    // for some reason ptrdiff_t on OpenVMS compiler with
+    // 64 bit is not 64 bit !!!
+        std::size_t x = static_cast<std::size_t>(
+           reinterpret_cast<long long int>(v));
+#else
+        std::size_t x = static_cast<std::size_t>(
+           reinterpret_cast<std::ptrdiff_t>(v));
+#endif
+        return x + (x >> 3);
+    }
+
+#if defined(BOOST_MSVC)
+#pragma warning(push)
+#if BOOST_MSVC <= 1400
+#pragma warning(disable:4267) // 'argument' : conversion from 'size_t' to
+                              // 'unsigned int', possible loss of data
+                              // A misguided attempt to detect 64-bit
+                              // incompatability.
+#endif
+#endif
+
+    template <class T>
+    inline void hash_combine(std::size_t& seed, T const& v)
+    {
+        boost::hash<T> hasher;
+        return boost::hash_detail::hash_combine_impl(seed, hasher(v));
+    }
+
+#if defined(BOOST_MSVC)
+#pragma warning(pop)
+#endif
+
+    template <class It>
+    inline std::size_t hash_range(It first, It last)
+    {
+        std::size_t seed = 0;
+
+        for(; first != last; ++first)
+        {
+            hash_combine(seed, *first);
+        }
+
+        return seed;
+    }
+
+    template <class It>
+    inline void hash_range(std::size_t& seed, It first, It last)
+    {
+        for(; first != last; ++first)
+        {
+            hash_combine(seed, *first);
+        }
+    }
+
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551))
+    template <class T>
+    inline std::size_t hash_range(T* first, T* last)
+    {
+        std::size_t seed = 0;
+
+        for(; first != last; ++first)
+        {
+            boost::hash<T> hasher;
+            seed ^= hasher(*first) + 0x9e3779b9 + (seed<<6) + (seed>>2);
+        }
+
+        return seed;
+    }
+
+    template <class T>
+    inline void hash_range(std::size_t& seed, T* first, T* last)
+    {
+        for(; first != last; ++first)
+        {
+            boost::hash<T> hasher;
+            seed ^= hasher(*first) + 0x9e3779b9 + (seed<<6) + (seed>>2);
+        }
+    }
+#endif
+
+#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
+    template< class T, unsigned N >
+    inline std::size_t hash_value(const T (&x)[N])
+    {
+        return hash_range(x, x + N);
+    }
+
+    template< class T, unsigned N >
+    inline std::size_t hash_value(T (&x)[N])
+    {
+        return hash_range(x, x + N);
+    }
+#endif
+
+    template <class Ch, class A>
+    inline std::size_t hash_value(
+        std::basic_string<Ch, std::BOOST_HASH_CHAR_TRAITS<Ch>, A> const& v)
+    {
+        return hash_range(v.begin(), v.end());
+    }
+
+#if BOOST_HASH_HAS_STRING_VIEW
+    template <class Ch>
+    inline std::size_t hash_value(
+        std::basic_string_view<Ch, std::BOOST_HASH_CHAR_TRAITS<Ch> > const& v)
+    {
+        return hash_range(v.begin(), v.end());
+    }
+#endif
+
+    template <typename T>
+    typename boost::hash_detail::float_numbers<T>::type hash_value(T v)
+    {
+        return boost::hash_detail::float_hash_value(v);
+    }
+
+#if BOOST_HASH_HAS_OPTIONAL
+    template <typename T>
+    inline std::size_t hash_value(std::optional<T> const& v) {
+        if (!v) {
+            // Arbitray value for empty optional.
+            return 0x12345678;
+        } else {
+            boost::hash<T> hf;
+            return hf(*v);
+        }
+    }
+#endif
+
+#if BOOST_HASH_HAS_VARIANT
+    inline std::size_t hash_value(std::monostate) {
+        return 0x87654321;
+    }
+
+    template <typename... Types>
+    inline std::size_t hash_value(std::variant<Types...> const& v) {
+        std::size_t seed = 0;
+        hash_combine(seed, v.index());
+        std::visit([&seed](auto&& x) { hash_combine(seed, x); }, v);
+        return seed;
+    }
+#endif
+
+
+#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
+    inline std::size_t hash_value(std::type_index v)
+    {
+        return v.hash_code();
+    }
+#endif
+
+#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
+    inline std::size_t hash_value(std::error_code const& v) {
+        std::size_t seed = 0;
+        hash_combine(seed, v.value());
+        hash_combine(seed, &v.category());
+        return seed;
+    }
+
+    inline std::size_t hash_value(std::error_condition const& v) {
+        std::size_t seed = 0;
+        hash_combine(seed, v.value());
+        hash_combine(seed, &v.category());
+        return seed;
+    }
+#endif
+
+    //
+    // boost::hash
+    //
+
+    // Define the specializations required by the standard. The general purpose
+    // boost::hash is defined later in extensions.hpp if
+    // BOOST_HASH_NO_EXTENSIONS is not defined.
+
+    // BOOST_HASH_SPECIALIZE - define a specialization for a type which is
+    // passed by copy.
+    //
+    // BOOST_HASH_SPECIALIZE_REF - define a specialization for a type which is
+    // passed by const reference.
+    //
+    // These are undefined later.
+
+#define BOOST_HASH_SPECIALIZE(type) \
+    template <> struct hash<type> \
+         : public boost::hash_detail::hash_base<type> \
+    { \
+        std::size_t operator()(type v) const \
+        { \
+            return boost::hash_value(v); \
+        } \
+    };
+
+#define BOOST_HASH_SPECIALIZE_REF(type) \
+    template <> struct hash<type> \
+         : public boost::hash_detail::hash_base<type> \
+    { \
+        std::size_t operator()(type const& v) const \
+        { \
+            return boost::hash_value(v); \
+        } \
+    };
+
+#define BOOST_HASH_SPECIALIZE_TEMPLATE_REF(type) \
+    struct hash<type> \
+         : public boost::hash_detail::hash_base<type> \
+    { \
+        std::size_t operator()(type const& v) const \
+        { \
+            return boost::hash_value(v); \
+        } \
+    };
+
+    BOOST_HASH_SPECIALIZE(bool)
+    BOOST_HASH_SPECIALIZE(char)
+    BOOST_HASH_SPECIALIZE(signed char)
+    BOOST_HASH_SPECIALIZE(unsigned char)
+#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
+    BOOST_HASH_SPECIALIZE(wchar_t)
+#endif
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+    BOOST_HASH_SPECIALIZE(char16_t)
+#endif
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+    BOOST_HASH_SPECIALIZE(char32_t)
+#endif
+    BOOST_HASH_SPECIALIZE(short)
+    BOOST_HASH_SPECIALIZE(unsigned short)
+    BOOST_HASH_SPECIALIZE(int)
+    BOOST_HASH_SPECIALIZE(unsigned int)
+    BOOST_HASH_SPECIALIZE(long)
+    BOOST_HASH_SPECIALIZE(unsigned long)
+
+    BOOST_HASH_SPECIALIZE(float)
+    BOOST_HASH_SPECIALIZE(double)
+    BOOST_HASH_SPECIALIZE(long double)
+
+    BOOST_HASH_SPECIALIZE_REF(std::string)
+#if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
+    BOOST_HASH_SPECIALIZE_REF(std::wstring)
+#endif
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+    BOOST_HASH_SPECIALIZE_REF(std::basic_string<char16_t>)
+#endif
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+    BOOST_HASH_SPECIALIZE_REF(std::basic_string<char32_t>)
+#endif
+
+#if BOOST_HASH_HAS_STRING_VIEW
+    BOOST_HASH_SPECIALIZE_REF(std::string_view)
+#   if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
+    BOOST_HASH_SPECIALIZE_REF(std::wstring_view)
+#   endif
+#   if !defined(BOOST_NO_CXX11_CHAR16_T)
+    BOOST_HASH_SPECIALIZE_REF(std::basic_string_view<char16_t>)
+#   endif
+#   if !defined(BOOST_NO_CXX11_CHAR32_T)
+    BOOST_HASH_SPECIALIZE_REF(std::basic_string_view<char32_t>)
+#   endif
+#endif
+
+#if !defined(BOOST_NO_LONG_LONG)
+    BOOST_HASH_SPECIALIZE(boost::long_long_type)
+    BOOST_HASH_SPECIALIZE(boost::ulong_long_type)
+#endif
+
+#if defined(BOOST_HAS_INT128)
+    BOOST_HASH_SPECIALIZE(boost::int128_type)
+    BOOST_HASH_SPECIALIZE(boost::uint128_type)
+#endif
+
+#if BOOST_HASH_HAS_OPTIONAL
+    template <typename T>
+    BOOST_HASH_SPECIALIZE_TEMPLATE_REF(std::optional<T>)
+#endif
+
+#if !defined(BOOST_HASH_HAS_VARIANT)
+    template <typename... T>
+    BOOST_HASH_SPECIALIZE_TEMPLATE_REF(std::variant<T...>)
+    BOOST_HASH_SPECIALIZE(std::monostate)
+#endif
+
+#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
+    BOOST_HASH_SPECIALIZE(std::type_index)
+#endif
+
+#undef BOOST_HASH_SPECIALIZE
+#undef BOOST_HASH_SPECIALIZE_REF
+#undef BOOST_HASH_SPECIALIZE_TEMPLATE_REF
+
+// Specializing boost::hash for pointers.
+
+#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
+
+    template <class T>
+    struct hash<T*>
+        : public boost::hash_detail::hash_base<T*>
+    {
+        std::size_t operator()(T* v) const
+        {
+#if !BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590)
+            return boost::hash_value(v);
+#else
+            std::size_t x = static_cast<std::size_t>(
+                reinterpret_cast<std::ptrdiff_t>(v));
+
+            return x + (x >> 3);
+#endif
+        }
+    };
+
+#else
+
+    // For compilers without partial specialization, we define a
+    // boost::hash for all remaining types. But hash_impl is only defined
+    // for pointers in 'extensions.hpp' - so when BOOST_HASH_NO_EXTENSIONS
+    // is defined there will still be a compile error for types not supported
+    // in the standard.
+
+    namespace hash_detail
+    {
+        template <bool IsPointer>
+        struct hash_impl;
+
+        template <>
+        struct hash_impl<true>
+        {
+            template <class T>
+            struct inner
+                : public boost::hash_detail::hash_base<T>
+            {
+                std::size_t operator()(T val) const
+                {
+#if !BOOST_WORKAROUND(__SUNPRO_CC, <= 590)
+                    return boost::hash_value(val);
+#else
+                    std::size_t x = static_cast<std::size_t>(
+                        reinterpret_cast<std::ptrdiff_t>(val));
+
+                    return x + (x >> 3);
+#endif
+                }
+            };
+        };
+    }
+
+    template <class T> struct hash
+        : public boost::hash_detail::hash_impl<boost::is_pointer<T>::value>
+            ::BOOST_NESTED_TEMPLATE inner<T>
+    {
+    };
+
+#endif
+}
+
+#undef BOOST_HASH_CHAR_TRAITS
+#undef BOOST_FUNCTIONAL_HASH_ROTL32
+
+#if defined(BOOST_MSVC)
+#pragma warning(pop)
+#endif
+
+#endif // BOOST_FUNCTIONAL_HASH_HASH_HPP
+
+// Include this outside of the include guards in case the file is included
+// twice - once with BOOST_HASH_NO_EXTENSIONS defined, and then with it
+// undefined.
+
+#if !defined(BOOST_HASH_NO_EXTENSIONS) \
+    && !defined(BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP)
+#include <boost/container_hash/extensions.hpp>
+#endif
diff --git a/include/boost/container_hash/hash_fwd.hpp b/include/boost/container_hash/hash_fwd.hpp
new file mode 100644
index 0000000..a87c182
--- /dev/null
+++ b/include/boost/container_hash/hash_fwd.hpp
@@ -0,0 +1,36 @@
+
+// Copyright 2005-2009 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)
+
+//  Based on Peter Dimov's proposal
+//  http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
+//  issue 6.18. 
+
+#if !defined(BOOST_FUNCTIONAL_HASH_FWD_HPP)
+#define BOOST_FUNCTIONAL_HASH_FWD_HPP
+
+#include <boost/config/workaround.hpp>
+#include <cstddef>
+
+#if defined(BOOST_HAS_PRAGMA_ONCE)
+#pragma once
+#endif
+
+
+namespace boost
+{
+    template <class T> struct hash;
+
+    template <class T> void hash_combine(std::size_t& seed, T const& v);
+
+    template <class It> std::size_t hash_range(It, It);
+    template <class It> void hash_range(std::size_t&, It, It);
+
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551))
+    template <class T> inline std::size_t hash_range(T*, T*);
+    template <class T> inline void hash_range(std::size_t&, T*, T*);
+#endif
+}
+
+#endif
diff --git a/include/boost/functional/hash.hpp b/include/boost/functional/hash.hpp
new file mode 100644
index 0000000..327a3ec
--- /dev/null
+++ b/include/boost/functional/hash.hpp
@@ -0,0 +1,6 @@
+
+// Copyright 2005-2009 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 <boost/container_hash/hash.hpp>
diff --git a/include/boost/functional/hash/extensions.hpp b/include/boost/functional/hash/extensions.hpp
new file mode 100644
index 0000000..ab14211
--- /dev/null
+++ b/include/boost/functional/hash/extensions.hpp
@@ -0,0 +1,6 @@
+
+// Copyright 2017 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 <boost/container_hash/extensions.hpp>
diff --git a/include/boost/functional/hash/hash.hpp b/include/boost/functional/hash/hash.hpp
new file mode 100644
index 0000000..327a3ec
--- /dev/null
+++ b/include/boost/functional/hash/hash.hpp
@@ -0,0 +1,6 @@
+
+// Copyright 2005-2009 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 <boost/container_hash/hash.hpp>
diff --git a/include/boost/functional/hash/hash_fwd.hpp b/include/boost/functional/hash/hash_fwd.hpp
new file mode 100644
index 0000000..62bc23c
--- /dev/null
+++ b/include/boost/functional/hash/hash_fwd.hpp
@@ -0,0 +1,6 @@
+
+// Copyright 2005-2009 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 <boost/container_hash/hash_fwd.hpp>
diff --git a/include/boost/functional/hash_fwd.hpp b/include/boost/functional/hash_fwd.hpp
new file mode 100644
index 0000000..62bc23c
--- /dev/null
+++ b/include/boost/functional/hash_fwd.hpp
@@ -0,0 +1,6 @@
+
+// Copyright 2005-2009 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 <boost/container_hash/hash_fwd.hpp>
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..4b26a41
--- /dev/null
+++ b/index.html
@@ -0,0 +1,16 @@
+
+<!--
+Copyright 2005-2007 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)
+-->
+
+<html>
+<head>
+    <meta http-equiv="refresh" content="0; URL=../../doc/html/hash.html">
+</head>
+<body>
+Automatic redirection failed, please go to
+<a href="../../doc/html/hash.html">../../doc/html/hash.html</a>
+</body>
+</html>
diff --git a/meta/explicit-failures-markup.xml b/meta/explicit-failures-markup.xml
new file mode 100644
index 0000000..bb205cc
--- /dev/null
+++ b/meta/explicit-failures-markup.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2018 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)
+-->
+<explicit-failures-markup>
+    <!-- container_hash -->
+    <library name="container_hash">
+        <mark-expected-failures>
+            <test name="hash_value_array_test"/>
+            <toolset name="msvc-6.5*"/>
+            <toolset name="msvc-7.0*"/>
+            <note author="Daniel James">
+              hash_value is not overloaded for arrays for older versions
+              of Visual C++. There is a work around so that
+              boost::hash&lt;T[N]&gt;, boost::hash_combine and boost::hash_range
+              work.
+            </note>
+        </mark-expected-failures>
+
+        <mark-expected-failures>
+            <test name="hash_function_pointer_test"/>
+            <toolset name="msvc-6.5*"/>
+            <toolset name="msvc-7.0*"/>
+            <note refid="2" author="Daniel James"/>
+        </mark-expected-failures>
+
+        <mark-expected-failures>
+            <test name="hash_function_pointer_test"/>
+            <toolset name="sun-5.7"/>
+            <toolset name="sun-5.8"/>
+            <toolset name="sun-5.9"/>
+            <note author="Daniel James">
+                On these compilers the wrong overload of hash_value is called
+                when the argument is a hash function pointer. So calling
+                hash_value doesn't work but boost::hash does work (and it's
+                recommended that user never call hash_value directly so this
+                shouldn't be a problem).
+            </note>
+        </mark-expected-failures>
+
+        <mark-expected-failures>
+            <test name="hash_long_double_test"/>
+            <toolset name="gcc-3.4.3_sunos"/>
+            <toolset name="*pa_risc"/>
+            <note author="Daniel James">
+                This platform has poor support for <code>long double</code> so
+                the hash function perform poorly for values out of the range
+                of <code>double</code> or if they differ at a greater precision
+                that <code>double</code> is capable of representing.
+            </note>
+        </mark-expected-failures>
+
+        <mark-expected-failures>
+            <test name="point" />
+            <test name="books" />
+            <toolset name="msvc-6.5*"/>
+            <toolset name="msvc-7.0*"/>
+            <note author="Daniel James">
+                These examples only work on compilers with support for ADL.
+                It is possible to work around this, but I wanted to keep the
+                example code as clean as possible.
+            </note>
+        </mark-expected-failures>
+
+        <mark-expected-failures>
+            <test name="point" />
+            <toolset name="borland-*"/>
+            <note author="Daniel James">
+                It appears that Borland doesn't find friend functions defined
+                in a class by ADL. This is easily fixed but this example is
+                meant to show the typical way of customising boost::hash, not
+                the portable way.
+            </note>
+        </mark-expected-failures>
+
+        <mark-expected-failures>
+            <test name="hash_global_namespace_test" />
+            <toolset name="borland-*"/>
+            <note author="Daniel James">
+                The test demonstrates a Borland bug - functions that aren't
+                in a namespace don't appear to be found by ADL.
+            </note>
+        </mark-expected-failures>
+
+        <mark-expected-failures>
+            <test name="container_fwd_gcc_debug"/>
+            <toolset name="darwin-4.2"/>
+            <note author="Daniel James">
+              Debug containers aren't supported on Apple's version of gcc 4.2.
+            </note>
+        </mark-expected-failures>
+    </library>
+</explicit-failures-markup>
diff --git a/meta/libraries.json b/meta/libraries.json
new file mode 100644
index 0000000..b1b075b
--- /dev/null
+++ b/meta/libraries.json
@@ -0,0 +1,20 @@
+[
+    {
+        "key": "functional/hash",
+        "boost-version": "1.33.0",
+        "name": "Container Hash",
+        "authors": [
+            "Daniel James"
+        ],
+        "maintainers": [
+            "Daniel James <dnljms -at- gmail.com>"
+        ],
+        "description": "An STL-compatible hash function object that can be extended to hash user defined types.",
+        "std": [
+            "tr1"
+        ],
+        "category": [
+            "Function-objects"
+        ]
+    }
+]
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
new file mode 100644
index 0000000..a9dddfb
--- /dev/null
+++ b/test/Jamfile.v2
@@ -0,0 +1,87 @@
+
+# Copyright 2005-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)
+
+import testing ;
+
+project hash-tests
+    : requirements
+        <warnings>all
+        <toolset>intel:<warnings>on
+        #<toolset>intel:<cxxflags>-strict-ansi
+        <toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
+        <toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
+        <toolset>clang:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow"
+        #<toolset>msvc:<warnings-as-errors>on
+        #<toolset>gcc:<warnings-as-errors>on
+        #<toolset>darwin:<warnings-as-errors>on
+    ;
+
+test-suite container_hash/hash
+    :
+        [ run hash_info.cpp : : : <test-info>always_show_run_output ]
+        [ compile check_float_funcs.cpp ]
+        [ run hash_fwd_test_1.cpp ]
+        [ run hash_fwd_test_2.cpp ]
+        [ run hash_number_test.cpp ]
+        [ run hash_enum_test.cpp ]
+        [ run hash_pointer_test.cpp ]
+        [ run hash_function_pointer_test.cpp ]
+        [ run hash_float_test.cpp ]
+        [ run hash_long_double_test.cpp ]
+        [ run hash_string_test.cpp ]
+        [ run hash_range_test.cpp ]
+        [ run hash_custom_test.cpp ]
+        [ run hash_global_namespace_test.cpp ]
+        [ run hash_friend_test.cpp ]
+        [ run hash_built_in_array_test.cpp ]
+        [ run hash_value_array_test.cpp ]
+        [ run hash_vector_test.cpp ]
+        [ run hash_list_test.cpp ]
+        [ run hash_deque_test.cpp ]
+        [ run hash_set_test.cpp ]
+        [ run hash_map_test.cpp ]
+        [ run hash_complex_test.cpp ]
+        [ run hash_optional_test.cpp ]
+        [ run hash_variant_test.cpp ]
+        [ run hash_type_index_test.cpp ]
+        [ run hash_system_error_test.cpp ]
+        [ run hash_std_array_test.cpp ]
+        [ run hash_std_tuple_test.cpp ]
+        [ run hash_std_smart_ptr_test.cpp ]
+        [ run link_test.cpp link_test_2.cpp ]
+        [ run link_ext_test.cpp link_no_ext_test.cpp ]
+        [ run extensions_hpp_test.cpp ]
+        [ compile-fail hash_no_ext_fail_test.cpp ]
+        [ compile-fail namespace_fail_test.cpp ]
+        [ run implicit_test.cpp ]
+        [ run hash_no_ext_macro_1.cpp ]
+        [ run hash_no_ext_macro_2.cpp ]
+    ;
+
+test-suite container_hash/hash_no_ext
+    :
+        [ run hash_number_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_number_test ]
+        [ run hash_pointer_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_pointer_test ]
+        [ run hash_function_pointer_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_function_pointer_test ]
+        [ run hash_float_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_float_test ]
+        [ run hash_long_double_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_long_double_test ]
+        [ run hash_string_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_string_test ]
+        [ run link_test.cpp link_test_2.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_link_test ]
+    ;
+
+# Tests to see if the floating point hash is using the binary hash.
+# Not run normally because on some platforms these should fail.
+test-suite container_hash/hash_no_generic_float
+    :
+        [ run hash_float_test.cpp
+            : : : <define>BOOST_HASH_DETAIL_TEST_WITHOUT_GENERIC
+            : hash_float_test_no_generic ]
+        [ run hash_long_double_test.cpp
+            : : : <define>BOOST_HASH_DETAIL_TEST_WITHOUT_GENERIC
+            : hash_long_double_test_no_generic ]
+    ;
+explicit container_hash/hash_no_generic_float ;
+
+build-project ../examples ;
diff --git a/test/check_float_funcs.cpp b/test/check_float_funcs.cpp
new file mode 100644
index 0000000..01d5168
--- /dev/null
+++ b/test/check_float_funcs.cpp
@@ -0,0 +1,58 @@
+
+// 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 <boost/static_assert.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <cmath>
+
+namespace test
+{
+    template <class T1>
+    struct check_return_type
+    {
+        template <class T2>
+        static void equals(T2)
+        {
+            BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
+        }
+
+        template <class T2>
+        static void equals_ref(T2&)
+        {
+            BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
+        }
+
+        template <class T2>
+        static void convertible(T2)
+        {
+            BOOST_STATIC_ASSERT((boost::is_convertible<T2, T1>::value));
+        }
+    };
+}
+
+int main() {
+    float f = 0;
+    double d = 0;
+    long double l = 0;
+
+    test::check_return_type<float>::equals(std::ldexp(f, 0));
+    test::check_return_type<double>::equals(std::ldexp(d, 0));
+    test::check_return_type<long double>::equals(std::ldexp(l, 0));
+
+    int dummy = 0;
+
+    test::check_return_type<float>::equals(std::frexp(f, &dummy));
+    test::check_return_type<double>::equals(std::frexp(d, &dummy));
+    test::check_return_type<long double>::equals(std::frexp(l, &dummy));
+
+#if BOOST_HASH_USE_FPCLASSIFY
+
+    int (*fpc1)(float) = std::fpclassify;
+    int (*fpc2)(double) = std::fpclassify;
+    int (*fpc3)(long double) = std::fpclassify;
+
+#endif
+}
diff --git a/test/compile_time.hpp b/test/compile_time.hpp
new file mode 100644
index 0000000..d7631b8
--- /dev/null
+++ b/test/compile_time.hpp
@@ -0,0 +1,20 @@
+
+// Copyright 2005-2009 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 <boost/config.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+template <class T>
+void compile_time_tests(T*)
+{
+    BOOST_STATIC_ASSERT((boost::is_same<T,
+        typename BOOST_HASH_TEST_NAMESPACE::hash<T>::argument_type
+    >::value));
+    BOOST_STATIC_ASSERT((boost::is_same<std::size_t,
+        typename BOOST_HASH_TEST_NAMESPACE::hash<T>::result_type
+    >::value));
+}
+
diff --git a/test/config.hpp b/test/config.hpp
new file mode 100644
index 0000000..28b28d4
--- /dev/null
+++ b/test/config.hpp
@@ -0,0 +1,25 @@
+
+// Copyright 2005-2009 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_HASH_TEST_STD)
+#  define BOOST_HASH_TEST_STD_INCLUDES
+#  define BOOST_HASH_TEST_NAMESPACE std
+#else
+#  define BOOST_HASH_TEST_NAMESPACE boost
+#  if !defined(BOOST_HASH_NO_EXTENSIONS)
+#    define BOOST_HASH_TEST_EXTENSIONS
+#  endif
+#endif
+
+#if defined(_WIN32_WCE)
+// The standard windows mobile headers trigger this warning so I disable it
+// before doing anything else.
+#pragma warning(disable:4201)   // nonstandard extension used :
+                                // nameless struct/union
+
+#endif
+
+#define HASH_TEST_CAT(x, y) HASH_TEST_CAT2(x, y)
+#define HASH_TEST_CAT2(x, y) x##y
diff --git a/test/extensions_hpp_test.cpp b/test/extensions_hpp_test.cpp
new file mode 100644
index 0000000..a388c23
--- /dev/null
+++ b/test/extensions_hpp_test.cpp
@@ -0,0 +1,19 @@
+
+// Copyright 2009 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)
+
+// Check that boost/container_hash/extensions.hpp works okay.
+//
+// It probably should be in boost/container_hash/detail, but since it isn't it
+// should work.
+
+#include "./config.hpp"
+
+#include <boost/container_hash/extensions.hpp>
+
+int main() {
+    int x[2] = { 2, 3 };
+    boost::hash<int[2]> hf;
+    hf(x);
+}
diff --git a/test/hash_built_in_array_test.cpp b/test/hash_built_in_array_test.cpp
new file mode 100644
index 0000000..ac782c3
--- /dev/null
+++ b/test/hash_built_in_array_test.cpp
@@ -0,0 +1,75 @@
+
+// Copyright 2005-2009 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 BOOST_HASH_TEST_EXTENSIONS
+#  ifdef BOOST_HASH_TEST_STD_INCLUDES
+#    include <functional>
+#  else
+#    include <boost/container_hash/hash.hpp>
+#  endif
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+
+void array_int_test()
+{
+    const int length1 = 25;
+    int array1[25] = {
+        26, -43, 32, 65, 45,
+        12, 67, 32, 12, 23,
+        0, 0, 0, 0, 0,
+        8, -12, 23, 65, 45,
+        -1, 93, -54, 987, 3
+    };
+    BOOST_HASH_TEST_NAMESPACE::hash<int[25]> hasher1;
+
+    const int length2 = 1;
+    int array2[1] = {3};
+    BOOST_HASH_TEST_NAMESPACE::hash<int[1]> hasher2;
+
+    const int length3 = 2;
+    int array3[2] = {2, 3};
+    BOOST_HASH_TEST_NAMESPACE::hash<int[2]> hasher3;
+
+    BOOST_TEST(hasher1(array1)
+            == BOOST_HASH_TEST_NAMESPACE::hash_range(array1, array1 + length1));
+    BOOST_TEST(hasher2(array2)
+            == BOOST_HASH_TEST_NAMESPACE::hash_range(array2, array2 + length2));
+    BOOST_TEST(hasher3(array3)
+            == BOOST_HASH_TEST_NAMESPACE::hash_range(array3, array3 + length3));
+}
+
+void two_dimensional_array_test()
+{
+    int array[3][2] = {{-5, 6}, {7, -3}, {26, 1}};
+    BOOST_HASH_TEST_NAMESPACE::hash<int[3][2]> hasher;
+
+    std::size_t seed1 = 0;
+    for(int i = 0; i < 3; ++i)
+    {
+        std::size_t seed2 = 0;
+        for(int j = 0; j < 2; ++j)
+            BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, array[i][j]);
+        BOOST_HASH_TEST_NAMESPACE::hash_combine(seed1, seed2);
+    }
+
+    BOOST_TEST(hasher(array) == seed1);
+    BOOST_TEST(hasher(array) == BOOST_HASH_TEST_NAMESPACE::hash_range(array, array + 3));
+}
+
+#endif // BOOST_HASH_TEST_EXTENSIONS
+
+int main()
+{
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+    array_int_test();
+    two_dimensional_array_test();
+#endif
+    return boost::report_errors();
+}
diff --git a/test/hash_complex_test.cpp b/test/hash_complex_test.cpp
new file mode 100644
index 0000000..5ecacbf
--- /dev/null
+++ b/test/hash_complex_test.cpp
@@ -0,0 +1,110 @@
+
+// Copyright 2005-2009 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"
+
+#if !defined(BOOST_HASH_TEST_EXTENSIONS)
+
+int main() {}
+
+#else
+
+#ifdef BOOST_HASH_TEST_STD_INCLUDES
+#  include <functional>
+#else
+#  include <boost/container_hash/hash.hpp>
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+
+#if defined(BOOST_MSVC)
+#pragma warning(disable:4244)   // conversion from 'unsigned long' to
+                                // 'unsigned short', possible loss of data
+#pragma warning(disable:4245)   // conversion from 'int' to
+                                // 'const unsigned short',
+                                // signed/unsigned mismatch
+#pragma warning(disable:4305)   // truncation from 'double' to
+                                // 'const std::complex<float>::_Ty'
+#pragma warning(disable:4309)   // truncation of constant value
+#pragma warning(disable:4512)   // assignment operator could not be generated
+#if BOOST_MSVC < 1400
+#pragma warning(disable:4267)   // conversion from 'size_t' to 'unsigned int',
+                                // possible loss of data
+#endif
+#endif
+
+#if defined(__GNUC__) && !defined(BOOST_INTEL_CXX_VERSION)
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+
+#include <complex>
+#include <sstream>
+#include <boost/limits.hpp>
+
+template <class T>
+void generic_complex_tests(std::complex<T> v)
+{
+    BOOST_HASH_TEST_NAMESPACE::hash<std::complex<T> > complex_hasher;
+
+    BOOST_TEST(complex_hasher(v) == complex_hasher(v));
+
+    BOOST_HASH_TEST_NAMESPACE::hash<T> real_hasher;
+    T real = v.real();
+    T imag = v.imag();
+
+    BOOST_TEST(real_hasher(real) == complex_hasher(std::complex<T>(real)));
+
+    if(imag != 0 && real_hasher(real) == complex_hasher(v)) {
+        std::ostringstream os;
+        os<<"real_hasher("<<real<<") == complex_hasher("
+            <<v.real()<<" + "<<v.imag()<<"i) == "
+            <<real_hasher(real)<<" (This might not be a bug).";
+        BOOST_ERROR(os.str().c_str());
+    }
+}
+
+template <class Float>
+void complex_float_tests(Float*)
+{
+    typedef std::complex<Float> complex;
+    generic_complex_tests(complex(0,0));
+    generic_complex_tests(complex(0.5,0));
+    generic_complex_tests(complex(25,0));
+    generic_complex_tests(complex(25,0));
+    generic_complex_tests(complex(static_cast<Float>(-67.5324535),static_cast<Float>(56.23578678)));
+}
+
+template <class Integer>
+void complex_integral_tests(Integer*)
+{
+    typedef std::complex<Integer> complex;
+    generic_complex_tests(complex(0,0));
+    generic_complex_tests(complex(15342,124));
+    generic_complex_tests(complex(25,54356));
+    generic_complex_tests(complex(5325,2346));
+    generic_complex_tests(complex(Integer(-243897),Integer(-49923874)));
+    generic_complex_tests(complex(Integer(-543),Integer(763)));
+}
+
+int main()
+{
+    // I've comments out the short and unsigned short tests
+    // as they cause warnings and don't really test
+    // anything that the other tests already deal with.
+
+    complex_float_tests((float*) 0);
+    complex_float_tests((double*) 0);
+    complex_float_tests((long double*) 0);
+    //complex_integral_tests((short*) 0);
+    complex_integral_tests((int*) 0);
+    complex_integral_tests((long*) 0);
+    //complex_integral_tests((unsigned short*) 0);
+    complex_integral_tests((unsigned int*) 0);
+    complex_integral_tests((unsigned long*) 0);
+
+    return boost::report_errors();
+}
+
+#endif // BOOST_HASH_TEST_EXTENSIONS
diff --git a/test/hash_custom_test.cpp b/test/hash_custom_test.cpp
new file mode 100644
index 0000000..a642f0e
--- /dev/null
+++ b/test/hash_custom_test.cpp
@@ -0,0 +1,100 @@
+
+// Copyright 2005-2009 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"
+#include <boost/config.hpp>
+#include <cstddef>
+
+namespace test
+{
+    struct custom
+    {
+        int value_;
+
+        std::size_t hash() const
+        {
+            return static_cast<std::size_t>(value_ * 10);
+        }
+
+#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
+        friend std::size_t hash_value(custom const& x )
+        {
+            return x.hash();
+        }
+#endif
+
+        custom(int x) : value_(x) {}
+    };
+}
+
+#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
+namespace boost
+{
+    std::size_t hash_value(test::custom x)
+    {
+        return x.hash();
+    }
+}
+#endif
+
+#include "./config.hpp"
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+#  ifdef BOOST_HASH_TEST_STD_INCLUDES
+#    include <functional>
+#  else
+#    include <boost/container_hash/hash.hpp>
+#  endif
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+
+#include <vector>
+#include <string>
+#include <cctype>
+
+void custom_tests()
+{
+    BOOST_HASH_TEST_NAMESPACE::hash<test::custom> custom_hasher;
+    BOOST_TEST(custom_hasher(10) == 100u);
+    test::custom x(55);
+    BOOST_TEST(custom_hasher(x) == 550u);
+
+    {
+        using namespace BOOST_HASH_TEST_NAMESPACE;
+        BOOST_TEST(custom_hasher(x) == hash_value(x));
+    }
+
+    std::vector<test::custom> custom_vector;
+    custom_vector.push_back(5);
+    custom_vector.push_back(25);
+    custom_vector.push_back(35);
+
+    std::size_t seed = 0;
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom(5));
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom(25));
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom(35));
+
+    std::size_t seed2 = 0;
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 50u);
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 250u);
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 350u);
+
+    BOOST_TEST(seed == BOOST_HASH_TEST_NAMESPACE::hash_range(
+        custom_vector.begin(), custom_vector.end()));
+    BOOST_TEST(seed == seed2);
+}
+
+#endif // BOOST_HASH_TEST_EXTENSIONS
+
+int main()
+{
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+    custom_tests();
+#endif
+    return boost::report_errors();
+}
diff --git a/test/hash_deque_test.cpp b/test/hash_deque_test.cpp
new file mode 100644
index 0000000..3b900b8
--- /dev/null
+++ b/test/hash_deque_test.cpp
@@ -0,0 +1,35 @@
+
+// Copyright 2005-2009 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 BOOST_HASH_TEST_EXTENSIONS
+#  ifdef BOOST_HASH_TEST_STD_INCLUDES
+#    include <functional>
+#  else
+#    include <boost/container_hash/hash.hpp>
+#  endif
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+
+#include <deque>
+
+using std::deque;
+#define CONTAINER_TYPE deque
+#include "./hash_sequence_test.hpp"
+
+#endif // BOOST_HASH_TEST_EXTENSIONS
+
+int main()
+{
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+    deque_tests::deque_hash_integer_tests();
+#endif
+
+    return boost::report_errors();
+}
diff --git a/test/hash_enum_test.cpp b/test/hash_enum_test.cpp
new file mode 100644
index 0000000..3d725b7
--- /dev/null
+++ b/test/hash_enum_test.cpp
@@ -0,0 +1,63 @@
+
+// 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 BOOST_HASH_TEST_STD_INCLUDES
+#  include <functional>
+#else
+#  include <boost/container_hash/hash.hpp>
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+#include "./compile_time.hpp"
+
+namespace test {
+    enum enum_override { enum_override1, enum_override2 };
+    std::size_t hash_value(enum_override) { return 896532; }
+
+    enum enum1 { enum1a };
+    enum enum2 { enum2a, enum2b };
+    enum enum3 { enum3a = 574, enum3b };
+    enum enum4 { enum4a = -12574, enum4b };
+}
+
+int main() {
+    compile_time_tests((test::enum1*) 0);
+    compile_time_tests((test::enum2*) 0);
+    compile_time_tests((test::enum3*) 0);
+    compile_time_tests((test::enum4*) 0);
+    compile_time_tests((test::enum_override*) 0);
+
+    BOOST_HASH_TEST_NAMESPACE::hash<test::enum1> hash1;
+    BOOST_HASH_TEST_NAMESPACE::hash<test::enum2> hash2;
+    BOOST_HASH_TEST_NAMESPACE::hash<test::enum3> hash3;
+    BOOST_HASH_TEST_NAMESPACE::hash<test::enum4> hash4;
+
+    BOOST_TEST(hash1(test::enum1a) == hash1(test::enum1a));
+
+    BOOST_TEST(hash2(test::enum2a) == hash2(test::enum2a));
+    BOOST_TEST(hash2(test::enum2a) != hash2(test::enum2b));
+    BOOST_TEST(hash2(test::enum2b) == hash2(test::enum2b));
+
+    BOOST_TEST(hash3(test::enum3a) == hash3(test::enum3a));
+    BOOST_TEST(hash3(test::enum3a) != hash3(test::enum3b));
+    BOOST_TEST(hash3(test::enum3b) == hash3(test::enum3b));
+
+    BOOST_TEST(hash4(test::enum4a) == hash4(test::enum4a));
+    BOOST_TEST(hash4(test::enum4a) != hash4(test::enum4b));
+    BOOST_TEST(hash4(test::enum4b) == hash4(test::enum4b));
+
+    BOOST_HASH_TEST_NAMESPACE::hash<test::enum_override> hash_override;
+
+    BOOST_TEST(hash_override(test::enum_override1) ==
+        hash_override(test::enum_override1));
+    BOOST_TEST(hash_override(test::enum_override1) ==
+        hash_override(test::enum_override2));
+    BOOST_TEST(hash_override(test::enum_override1) ==
+        hash_override(test::enum_override1));
+
+    return boost::report_errors();
+}
diff --git a/test/hash_float_test.cpp b/test/hash_float_test.cpp
new file mode 100644
index 0000000..2490f8d
--- /dev/null
+++ b/test/hash_float_test.cpp
@@ -0,0 +1,18 @@
+
+// Copyright 2005-2009 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 "hash_float_test.hpp"
+
+int main()
+{
+    std::cerr<<"Compiler: "<<BOOST_COMPILER<<"\n";
+    std::cerr<<"Platform: "<<BOOST_PLATFORM<<"\n";
+    std::cerr<<"Library: "<<BOOST_STDLIB<<"\n\n";
+
+    float_tests("float", (float*) 0);
+    float_tests("double", (double*) 0);
+
+    return boost::report_errors();
+}
diff --git a/test/hash_float_test.hpp b/test/hash_float_test.hpp
new file mode 100644
index 0000000..ab79a12
--- /dev/null
+++ b/test/hash_float_test.hpp
@@ -0,0 +1,309 @@
+
+// Copyright 2005-2009 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 BOOST_HASH_TEST_STD_INCLUDES
+#  include <functional>
+#else
+#  include <boost/container_hash/hash.hpp>
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+
+#include <cmath>
+#include <boost/container_hash/detail/limits.hpp>
+#include <boost/container_hash/detail/float_functions.hpp>
+#include <boost/config/workaround.hpp>
+
+#include <iostream>
+
+#if defined(BOOST_MSVC)
+#pragma warning(push)
+#pragma warning(disable:4127)   // conditional expression is constant
+#pragma warning(disable:4723)   // conditional expression is constant
+#if BOOST_MSVC < 1400
+#pragma warning(disable:4267)   // conversion from 'size_t' to 'unsigned int',
+                                // possible loss of data
+#endif
+#endif
+
+#if defined(__GNUC__) && !defined(BOOST_INTEL_CXX_VERSION)
+#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"; }
+
+template <class T>
+void float_tests(char const* name, T* = 0)
+{
+    std::cerr
+        <<  "\n"
+        <<  "Testing " BOOST_STRINGIZE(BOOST_HASH_TEST_NAMESPACE) "::hash<"
+        <<  name
+        <<  ">\n"
+        <<  "\n"
+        <<  "boost::hash_detail::limits<T>::digits = "
+        <<  boost::hash_detail::limits<T>::digits<< "\n"
+        <<  "boost::hash_detail::limits<int>::digits = "
+        <<  boost::hash_detail::limits<int>::digits<< "\n"
+        <<  "boost::hash_detail::limits<std::size_t>::digits = "
+        <<  boost::hash_detail::limits<std::size_t>::digits
+        <<  "\n"
+        <<  "\n"
+        <<  "boost::hash_detail::call_ldexp<T>::float_type = "
+        <<  float_type(static_cast<BOOST_DEDUCED_TYPENAME
+                boost::hash_detail::call_ldexp<T>::float_type*>(0))
+        <<  "\n"
+        <<  "boost::hash_detail::call_frexp<T>::float_type = "
+        <<  float_type(static_cast<BOOST_DEDUCED_TYPENAME
+                boost::hash_detail::call_frexp<T>::float_type*>(0))
+        <<  "\n"
+        <<  "boost::hash_detail::select_hash_type<T>::type = "
+        <<  float_type(static_cast<BOOST_DEDUCED_TYPENAME
+                boost::hash_detail::select_hash_type<T>::type*>(0))
+        <<  "\n"
+        <<  "\n"
+        ;
+
+    BOOST_HASH_TEST_NAMESPACE::hash<T> x1;
+
+    T zero = 0;
+    T minus_zero = (T) -1 * zero;
+
+    BOOST_TEST(zero == minus_zero);
+    BOOST_TEST(x1(zero) == x1(minus_zero));
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    BOOST_TEST(x1(zero) == BOOST_HASH_TEST_NAMESPACE::hash_value(zero));
+    BOOST_TEST(x1(minus_zero) == BOOST_HASH_TEST_NAMESPACE::hash_value(minus_zero));
+#endif
+
+    BOOST_TEST(x1(zero) != x1(0.5));
+    BOOST_TEST(x1(minus_zero) != x1(0.5));
+    BOOST_TEST(x1(0.5) != x1(-0.5));
+    BOOST_TEST(x1(1) != x1(-1));
+
+    using namespace std;
+
+// Doing anything with infinity causes borland to crash.
+#if defined(__BORLANDC__)
+    std::cerr
+        <<  "Not running infinity checks on Borland, as it causes it to crash."
+            "\n";
+#else
+    if(boost::hash_detail::limits<T>::has_infinity) {
+        T infinity = -log(zero);
+        T infinity2 = (T) 1. / zero;
+        T infinity3 = (T) -1. / minus_zero;
+        T infinity4 = boost::hash_detail::limits<T>::infinity();
+
+        T minus_infinity = log(zero);
+        T minus_infinity2 = (T) -1. / zero;
+        T minus_infinity3 = (T) 1. / minus_zero;
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+        BOOST_TEST(x1(infinity) == BOOST_HASH_TEST_NAMESPACE::hash_value(infinity));
+        BOOST_TEST(x1(minus_infinity)
+                == BOOST_HASH_TEST_NAMESPACE::hash_value(minus_infinity));
+#endif
+
+        if(infinity == infinity2)
+            BOOST_TEST(x1(infinity) == x1(infinity2));
+        if(infinity == infinity3)
+            BOOST_TEST(x1(infinity) == x1(infinity3));
+        if(infinity == infinity4)
+            BOOST_TEST(x1(infinity) == x1(infinity4));
+
+        if(minus_infinity == minus_infinity2)
+            BOOST_TEST(x1(minus_infinity) == x1(minus_infinity2));
+        if(minus_infinity == minus_infinity3)
+            BOOST_TEST(x1(minus_infinity) == x1(minus_infinity3));
+
+        BOOST_TEST(infinity != minus_infinity);
+
+        if(x1(infinity) == x1(minus_infinity)) {
+            std::cerr<<"x1(infinity) == x1(-infinity) == "<<x1(infinity)<<"\n";
+        }
+
+        // This should really be 'has_denorm == denorm_present' but some
+        // compilers don't have 'denorm_present'. See also a later use.
+        if(boost::hash_detail::limits<T>::has_denorm) {
+            if(x1(boost::hash_detail::limits<T>::denorm_min()) == x1(infinity))
+            {
+                std::cerr
+                    <<  "x1(denorm_min) == x1(infinity) == "
+                    <<  x1(infinity)
+                    <<  "\n";
+            }
+
+            if(x1(boost::hash_detail::limits<T>::denorm_min()) ==
+                x1(minus_infinity))
+            {
+                std::cerr
+                    <<  "x1(denorm_min) == x1(-infinity) == "
+                    <<  x1(minus_infinity)
+                    <<  "\n";
+            }
+        }
+
+        if(boost::hash_detail::limits<T>::has_quiet_NaN) {
+            if(x1(boost::hash_detail::limits<T>::quiet_NaN()) == x1(infinity))
+            {
+                std::cerr
+                    <<  "x1(quiet_NaN) == x1(infinity) == "
+                    <<  x1(infinity)
+                    <<  "\n";
+            }
+
+            if(x1(boost::hash_detail::limits<T>::quiet_NaN()) ==
+                x1(minus_infinity))
+            {
+                std::cerr
+                    <<  "x1(quiet_NaN) == x1(-infinity) == "
+                    <<  x1(minus_infinity)
+                    <<  "\n";
+            }
+        }
+    }
+#endif
+
+    T max = (boost::hash_detail::limits<T>::max)();
+    T half_max = max / 2;
+    T quarter_max = max / 4;
+    T three_quarter_max = max - quarter_max;
+    
+    // Check the limits::max is in range.
+    BOOST_TEST(max != half_max);
+    BOOST_TEST(max != quarter_max);
+    BOOST_TEST(max != three_quarter_max);
+    BOOST_TEST(half_max != quarter_max);
+    BOOST_TEST(half_max != three_quarter_max);
+    BOOST_TEST(quarter_max != three_quarter_max);
+
+    BOOST_TEST(max != -max);
+    BOOST_TEST(half_max != -half_max);
+    BOOST_TEST(quarter_max != -quarter_max);
+    BOOST_TEST(three_quarter_max != -three_quarter_max);
+
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    BOOST_TEST(x1(max) == BOOST_HASH_TEST_NAMESPACE::hash_value(max));
+    BOOST_TEST(x1(half_max) == BOOST_HASH_TEST_NAMESPACE::hash_value(half_max));
+    BOOST_TEST(x1(quarter_max) == BOOST_HASH_TEST_NAMESPACE::hash_value(quarter_max));
+    BOOST_TEST(x1(three_quarter_max) ==
+        BOOST_HASH_TEST_NAMESPACE::hash_value(three_quarter_max));
+#endif
+
+    // The '!=' tests could legitimately fail, but with my hash it indicates a
+    // bug.
+    BOOST_TEST(x1(max) == x1(max));
+    BOOST_TEST(x1(max) != x1(quarter_max));
+    BOOST_TEST(x1(max) != x1(half_max));
+    BOOST_TEST(x1(max) != x1(three_quarter_max));
+    BOOST_TEST(x1(quarter_max) == x1(quarter_max));
+    BOOST_TEST(x1(quarter_max) != x1(half_max));
+    BOOST_TEST(x1(quarter_max) != x1(three_quarter_max));
+    BOOST_TEST(x1(half_max) == x1(half_max));
+    BOOST_TEST(x1(half_max) != x1(three_quarter_max));
+    BOOST_TEST(x1(three_quarter_max) == x1(three_quarter_max));
+
+    BOOST_TEST(x1(max) != x1(-max));
+    BOOST_TEST(x1(half_max) != x1(-half_max));
+    BOOST_TEST(x1(quarter_max) != x1(-quarter_max));
+    BOOST_TEST(x1(three_quarter_max) != x1(-three_quarter_max));
+
+
+// Intel with gcc stdlib sometimes segfaults on calls to asin and acos.
+#if !((defined(__INTEL_COMPILER) || defined(__ICL) || \
+        defined(__ICC) || defined(__ECC)) && \
+    (defined(__GLIBCPP__) || defined(__GLIBCXX__)))
+    T v1 = asin((T) 1);
+    T v2 = acos((T) 0);
+    if(v1 == v2)
+        BOOST_TEST(x1(v1) == x1(v2));
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    BOOST_TEST(x1(v1) == BOOST_HASH_TEST_NAMESPACE::hash_value(v1));
+    BOOST_TEST(x1(v2) == BOOST_HASH_TEST_NAMESPACE::hash_value(v2));
+#endif
+    
+#endif
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    BOOST_TEST(x1(boost::hash_detail::limits<T>::epsilon()) ==
+            BOOST_HASH_TEST_NAMESPACE::hash_value(
+                boost::hash_detail::limits<T>::epsilon()));
+#endif
+
+    BOOST_TEST(boost::hash_detail::limits<T>::epsilon() != (T) 0);
+    if(x1(boost::hash_detail::limits<T>::epsilon()) == x1((T) 0))
+        std::cerr<<"x1(epsilon) == x1(0) == "<<x1((T) 0)<<"\n";
+
+    BOOST_TEST(-boost::hash_detail::limits<T>::epsilon() != (T) 0);
+    if(x1(-boost::hash_detail::limits<T>::epsilon()) == x1((T) 0))
+        std::cerr<<"x1(-epsilon) == x1(0) == "<<x1((T) 0)<<"\n";
+
+    BOOST_TEST((T) 1 + boost::hash_detail::limits<T>::epsilon() != (T) 1);
+    if(x1((T) 1 + boost::hash_detail::limits<T>::epsilon()) == x1((T) 1))
+        std::cerr<<"x1(1 + epsilon) == x1(1) == "<<x1((T) 1)<<"\n";
+
+    BOOST_TEST((T) 1 - boost::hash_detail::limits<T>::epsilon() != (T) 1);
+    if(x1((T) 1 - boost::hash_detail::limits<T>::epsilon()) == x1((T) 1))
+        std::cerr<<"x1(1 - epsilon) == x1(1) == "<<x1((T) 1)<<"\n";
+
+    BOOST_TEST((T) -1 + boost::hash_detail::limits<T>::epsilon() != (T) -1);
+    if(x1((T) -1 + boost::hash_detail::limits<T>::epsilon()) == x1((T) -1))
+        std::cerr<<"x1(-1 + epsilon) == x1(-1) == "<<x1((T) -1)<<"\n";
+
+    BOOST_TEST((T) -1 - boost::hash_detail::limits<T>::epsilon() != (T) -1);
+    if(x1((T) -1 - boost::hash_detail::limits<T>::epsilon()) == x1((T) -1))
+        std::cerr<<"x1(-1 - epsilon) == x1(-1) == "<<x1((T) -1)<<"\n";
+
+    // As before.
+    if(boost::hash_detail::limits<T>::has_denorm) {
+        if(x1(boost::hash_detail::limits<T>::denorm_min()) == x1(zero)) {
+            std::cerr<<"x1(denorm_min) == x1(zero) == "<<x1(zero)<<"\n";
+        }
+#if !BOOST_WORKAROUND(__DECCXX_VER,<70190006) && defined(BOOST_HASH_TEST_EXTENSIONS)
+        // The Tru64/CXX standard library prior to 7.1 contains a bug in the
+        // specialization of boost::hash_detail::limits::denorm_min() for long
+        // doubles which causes this test to fail.
+        if(x1(boost::hash_detail::limits<T>::denorm_min()) !=
+            BOOST_HASH_TEST_NAMESPACE::hash_value(
+                boost::hash_detail::limits<T>::denorm_min()))
+        {
+            std::cerr
+                <<  "x1(boost::hash_detail::limits<T>::denorm_min()) = "
+                <<  x1(boost::hash_detail::limits<T>::denorm_min())
+                <<  "\nhash_value(boost::hash_detail::limits<T>::denorm_min())"
+                    " = "
+                <<  BOOST_HASH_TEST_NAMESPACE::hash_value(
+                        boost::hash_detail::limits<T>::denorm_min())
+                <<  "\nx1(0) = "
+                <<  x1(0)
+                <<  "\n";
+        }
+#endif
+    }
+
+// NaN also causes borland to crash.
+#if !defined(__BORLANDC__) && defined(BOOST_HASH_TEST_EXTENSIONS)
+    if(boost::hash_detail::limits<T>::has_quiet_NaN) {
+        if(x1(boost::hash_detail::limits<T>::quiet_NaN()) == x1(1.0)) {
+            std::cerr<<"x1(quiet_NaN) == x1(1.0) == "<<x1(1.0)<<"\n";
+        }
+        BOOST_TEST(x1(boost::hash_detail::limits<T>::quiet_NaN()) ==
+            BOOST_HASH_TEST_NAMESPACE::hash_value(
+                boost::hash_detail::limits<T>::quiet_NaN()));
+    }
+#endif
+}
+
+#if defined(BOOST_MSVC)
+#pragma warning(pop)
+#endif
diff --git a/test/hash_friend_test.cpp b/test/hash_friend_test.cpp
new file mode 100644
index 0000000..60d172e
--- /dev/null
+++ b/test/hash_friend_test.cpp
@@ -0,0 +1,103 @@
+
+// Copyright 2006-2009 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"
+
+#include <boost/config.hpp>
+#include <cstddef>
+
+namespace test
+{
+    template <class T>
+    struct custom
+    {
+        int value_;
+
+        std::size_t hash() const
+        {
+            return static_cast<std::size_t>(value_ * 10);
+        }
+
+#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
+        friend std::size_t hash_value(custom const& x)
+        {
+            return x.hash();
+        }
+#endif
+
+        custom(int x) : value_(x) {}
+    };
+}
+
+#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
+namespace boost
+{
+    template <class T>
+    std::size_t hash_value(test::custom<T> x)
+    {
+        return x.hash();
+    }
+}
+#endif
+
+#include "./config.hpp"
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+#  ifdef BOOST_HASH_TEST_STD_INCLUDES
+#    include <functional>
+#  else
+#    include <boost/container_hash/hash.hpp>
+#  endif
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+
+#include <vector>
+#include <string>
+#include <cctype>
+
+void custom_tests()
+{
+    BOOST_HASH_TEST_NAMESPACE::hash<test::custom<int> > custom_hasher;
+    BOOST_TEST(custom_hasher(10) == 100u);
+    test::custom<int> x(55);
+    BOOST_TEST(custom_hasher(x) == 550u);
+
+    {
+        using namespace BOOST_HASH_TEST_NAMESPACE;
+        BOOST_TEST(custom_hasher(x) == hash_value(x));
+    }
+
+    std::vector<test::custom<int> > custom_vector;
+    custom_vector.push_back(5);
+    custom_vector.push_back(25);
+    custom_vector.push_back(35);
+
+    std::size_t seed = 0;
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom<int>(5));
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom<int>(25));
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom<int>(35));
+
+    std::size_t seed2 = 0;
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 50u);
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 250u);
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 350u);
+
+    BOOST_TEST(seed == BOOST_HASH_TEST_NAMESPACE::hash_range(
+        custom_vector.begin(), custom_vector.end()));
+    BOOST_TEST(seed == seed2);
+}
+
+#endif // BOOST_HASH_TEST_EXTENSIONS
+
+int main()
+{
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+    custom_tests();
+#endif
+    return boost::report_errors();
+}
diff --git a/test/hash_function_pointer_test.cpp b/test/hash_function_pointer_test.cpp
new file mode 100644
index 0000000..abc8c4a
--- /dev/null
+++ b/test/hash_function_pointer_test.cpp
@@ -0,0 +1,57 @@
+
+// Copyright 2005-2009 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 BOOST_HASH_TEST_STD_INCLUDES
+#  include <functional>
+#else
+#  include <boost/container_hash/hash.hpp>
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+#include "./compile_time.hpp"
+
+void void_func1() { static int x = 1; ++x; }
+void void_func2() { static int x = 2; --x; }
+int int_func1(int) { return 0; }
+int int_func2(int) { return 1; }
+
+void function_pointer_tests()
+{
+    compile_time_tests((void(**)()) 0);
+    compile_time_tests((int(**)(int)) 0);
+
+    BOOST_HASH_TEST_NAMESPACE::hash<void(*)()> hasher_void;
+    BOOST_HASH_TEST_NAMESPACE::hash<int(*)(int)> hasher_int;
+
+    BOOST_TEST(&void_func1 != &void_func2);
+    BOOST_TEST(&int_func1 != &int_func2);
+
+    BOOST_TEST(hasher_void(0) == hasher_void(0));
+    BOOST_TEST(hasher_void(&void_func1) == hasher_void(&void_func1));
+    BOOST_TEST(hasher_void(&void_func1) != hasher_void(&void_func2));
+    BOOST_TEST(hasher_void(&void_func1) != hasher_void(0));
+    BOOST_TEST(hasher_int(0) == hasher_int(0));
+    BOOST_TEST(hasher_int(&int_func1) == hasher_int(&int_func1));
+    BOOST_TEST(hasher_int(&int_func1) != hasher_int(&int_func2));
+    BOOST_TEST(hasher_int(&int_func1) != hasher_int(0));
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    BOOST_TEST(hasher_void(&void_func1)
+            == BOOST_HASH_TEST_NAMESPACE::hash_value(&void_func1));
+    BOOST_TEST(hasher_int(&int_func1)
+            == BOOST_HASH_TEST_NAMESPACE::hash_value(&int_func1));
+
+    // This isn't specified in Peter's proposal:
+    BOOST_TEST(hasher_void(0) == 0);
+#endif
+}
+
+int main()
+{
+    function_pointer_tests();
+
+    return boost::report_errors();
+}
diff --git a/test/hash_fwd_test.hpp b/test/hash_fwd_test.hpp
new file mode 100644
index 0000000..76fce57
--- /dev/null
+++ b/test/hash_fwd_test.hpp
@@ -0,0 +1,104 @@
+
+// Copyright 2006-2009 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"
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_HASH_TEST_STD_INCLUDES)
+#include <boost/container_hash/hash_fwd.hpp>
+
+#include <boost/config.hpp>
+#include <cstddef>
+#include <vector>
+
+namespace test {
+
+    template <class T>
+    struct test_type1
+    {
+        T value;
+        test_type1(T const& x) : value(x) {}
+    };
+
+#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
+    template <class T>
+    std::size_t hash_value(test_type1<T> const& x)
+    {
+        BOOST_HASH_TEST_NAMESPACE::hash<T> hasher;
+        return hasher(x.value);
+    }
+#endif
+
+    template <class T>
+    struct test_type2
+    {
+        T value1, value2;
+        test_type2(T const& x, T const& y) : value1(x), value2(y) {}
+    };
+
+#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
+    template <class T>
+    std::size_t hash_value(test_type2<T> const& x)
+    {
+        std::size_t seed = 0;
+        BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, x.value1);
+        BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, x.value2);
+        return seed;
+    }
+#endif
+
+    template <class T>
+    struct test_type3
+    {
+        std::vector<T> values;
+        test_type3(typename std::vector<T>::iterator x,
+                typename std::vector<T>::iterator y) : values(x, y) {}
+    };
+
+#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
+    template <class T>
+    std::size_t hash_value(test_type3<T> const& x)
+    {
+        std::size_t seed =
+            BOOST_HASH_TEST_NAMESPACE::hash_range(x.values.begin(), x.values.end());
+        BOOST_HASH_TEST_NAMESPACE::hash_range(seed, x.values.begin(), x.values.end());
+        return seed;
+    }
+#endif
+
+}
+
+#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
+
+namespace boost
+{
+    template <class T>
+    std::size_t hash_value(test::test_type1<T> const& x)
+    {
+        BOOST_HASH_TEST_NAMESPACE::hash<T> hasher;
+        return hasher(x.value);
+    }
+
+    template <class T>
+    std::size_t hash_value(test::test_type2<T> const& x)
+    {
+        std::size_t seed = 0;
+        BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, x.value1);
+        BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, x.value2);
+        return seed;
+    }
+
+    template <class T>
+    std::size_t hash_value(test::test_type3<T> const& x)
+    {
+        std::size_t seed =
+            BOOST_HASH_TEST_NAMESPACE::hash_range(x.values.begin(), x.values.end());
+        BOOST_HASH_TEST_NAMESPACE::hash_range(seed, x.values.begin(), x.values.end());
+        return seed;
+    }
+}
+
+#endif
+
+#endif
diff --git a/test/hash_fwd_test_1.cpp b/test/hash_fwd_test_1.cpp
new file mode 100644
index 0000000..70ab3c7
--- /dev/null
+++ b/test/hash_fwd_test_1.cpp
@@ -0,0 +1,96 @@
+
+// Copyright 2006-2009 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)
+
+// This checks that template code implemented using hash_fwd will work.
+
+#include "./config.hpp"
+
+#include "./hash_fwd_test.hpp"
+
+#include <boost/core/lightweight_test.hpp>
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_HASH_TEST_STD_INCLUDES)
+
+#include <boost/container_hash/hash.hpp>
+#include <string>
+
+void fwd_test1()
+{
+    test::test_type1<int> x(5);
+    test::test_type1<std::string> y("Test");
+
+    BOOST_HASH_TEST_NAMESPACE::hash<int> hasher_int;
+    BOOST_HASH_TEST_NAMESPACE::hash<std::string> hasher_string;
+    BOOST_HASH_TEST_NAMESPACE::hash<test::test_type1<int> > hasher_test_int;
+    BOOST_HASH_TEST_NAMESPACE::hash<test::test_type1<std::string> > hasher_test_string;
+
+    BOOST_TEST(hasher_int(5) == hasher_test_int(x));
+    BOOST_TEST(hasher_string("Test") == hasher_test_string(y));
+}
+
+void fwd_test2()
+{
+    test::test_type2<int> x(5, 10);
+    test::test_type2<std::string> y("Test1", "Test2");
+
+    std::size_t seed1 = 0;
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed1, 5);
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed1, 10);
+
+    std::size_t seed2 = 0;
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, std::string("Test1"));
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, std::string("Test2"));
+
+    BOOST_HASH_TEST_NAMESPACE::hash<test::test_type2<int> > hasher_test_int;
+    BOOST_HASH_TEST_NAMESPACE::hash<test::test_type2<std::string> > hasher_test_string;
+
+    BOOST_TEST(seed1 == hasher_test_int(x));
+    BOOST_TEST(seed2 == hasher_test_string(y));
+}
+
+void fwd_test3()
+{
+    std::vector<int> values1;
+    values1.push_back(10);
+    values1.push_back(15);
+    values1.push_back(20);
+    values1.push_back(3);
+
+    std::vector<std::string> values2;
+    values2.push_back("Chico");
+    values2.push_back("Groucho");
+    values2.push_back("Harpo");
+    values2.push_back("Gummo");
+    values2.push_back("Zeppo");
+
+    test::test_type3<int> x(values1.begin(), values1.end());
+    test::test_type3<std::string> y(values2.begin(), values2.end());
+
+    std::size_t seed1 =
+        BOOST_HASH_TEST_NAMESPACE::hash_range(values1.begin(), values1.end());
+    BOOST_HASH_TEST_NAMESPACE::hash_range(seed1, values1.begin(), values1.end());
+
+    std::size_t seed2 =
+        BOOST_HASH_TEST_NAMESPACE::hash_range(values2.begin(), values2.end());
+    BOOST_HASH_TEST_NAMESPACE::hash_range(seed2, values2.begin(), values2.end());
+
+    BOOST_HASH_TEST_NAMESPACE::hash<test::test_type3<int> > hasher_test_int;
+    BOOST_HASH_TEST_NAMESPACE::hash<test::test_type3<std::string> > hasher_test_string;
+
+    BOOST_TEST(seed1 == hasher_test_int(x));
+    BOOST_TEST(seed2 == hasher_test_string(y));
+}
+
+#endif
+
+int main()
+{
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+    fwd_test1();
+    fwd_test2();
+    fwd_test3();
+#endif
+    return boost::report_errors();
+}
diff --git a/test/hash_fwd_test_2.cpp b/test/hash_fwd_test_2.cpp
new file mode 100644
index 0000000..44f07c4
--- /dev/null
+++ b/test/hash_fwd_test_2.cpp
@@ -0,0 +1,47 @@
+
+// Copyright 2006-2009 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)
+
+// This test just makes sure a header which uses hash_fwd can compile without
+// the main hash headers.
+
+#include "./config.hpp"
+
+#if !defined(BOOST_HASH_TEST_EXTENSIONS) || defined(BOOST_HASH_TEST_STD_INCLUDES)
+
+int main() {}
+
+#else
+
+#include "./hash_fwd_test.hpp"
+#include <boost/core/lightweight_test.hpp>
+
+template <class T> void unused(T const&) {}
+
+void fwd_test()
+{
+    test::test_type1<int> x1(3);
+    test::test_type1<std::string> y1("Black");
+    test::test_type2<int> x2(25, 16);
+    test::test_type2<std::string> y2("White", "Green");
+
+    std::vector<int> empty;
+    std::vector<std::string> empty2;
+
+    test::test_type3<int> x3(empty.begin(), empty.end());
+    test::test_type3<std::string> y3(empty2.begin(), empty2.end());
+
+    // Prevent gcc warnings:
+    unused(x1); unused(x2); unused(x3);
+    unused(y1); unused(y2); unused(y3);
+}
+
+int main()
+{
+    fwd_test();
+
+    return boost::report_errors();
+}
+
+#endif // defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_HASH_TEST_STD_INCLUDES)
diff --git a/test/hash_global_namespace_test.cpp b/test/hash_global_namespace_test.cpp
new file mode 100644
index 0000000..6062ba9
--- /dev/null
+++ b/test/hash_global_namespace_test.cpp
@@ -0,0 +1,103 @@
+
+// Copyright 2006-2009 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)
+
+// This test demonstrates an ADL bug in Borland 5.5 where ADL isn't performed
+// in the global namespace.
+
+#include "./config.hpp"
+
+#include <boost/config.hpp>
+#include <cstddef>
+
+struct custom
+{
+    int value_;
+
+    std::size_t hash() const
+    {
+        return static_cast<std::size_t>(value_ * 10);
+    }
+
+#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
+    friend std::size_t hash_value(custom const& x )
+    {
+        return x.hash();
+    }
+#endif
+
+    custom(int x) : value_(x) {}
+};
+
+#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
+namespace boost
+{
+    std::size_t hash_value(custom x)
+    {
+        return x.hash();
+    }
+}
+#endif
+
+#include "./config.hpp"
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+#  ifdef BOOST_HASH_TEST_STD_INCLUDES
+#    include <functional>
+#  else
+#    include <boost/container_hash/hash.hpp>
+#  endif
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+
+#include <vector>
+#include <string>
+#include <cctype>
+
+void custom_tests()
+{
+    BOOST_HASH_TEST_NAMESPACE::hash<custom> custom_hasher;
+    BOOST_TEST(custom_hasher(10) == 100u);
+    custom x(55);
+    BOOST_TEST(custom_hasher(x) == 550u);
+
+    {
+        using namespace BOOST_HASH_TEST_NAMESPACE;
+        BOOST_TEST(custom_hasher(x) == hash_value(x));
+    }
+
+    std::vector<custom> custom_vector;
+    custom_vector.push_back(5);
+    custom_vector.push_back(25);
+    custom_vector.push_back(35);
+
+    std::size_t seed = 0;
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, custom(5));
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, custom(25));
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, custom(35));
+
+    std::size_t seed2 = 0;
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 50u);
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 250u);
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 350u);
+
+    BOOST_TEST(seed == BOOST_HASH_TEST_NAMESPACE::hash_range(
+        custom_vector.begin(), custom_vector.end()));
+    BOOST_TEST(seed == seed2);
+}
+
+#endif // BOOST_HASH_TEST_EXTENSIONS
+
+
+int main()
+{
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+    custom_tests();
+#endif
+    return boost::report_errors();
+}
+
diff --git a/test/hash_info.cpp b/test/hash_info.cpp
new file mode 100644
index 0000000..b683746
--- /dev/null
+++ b/test/hash_info.cpp
@@ -0,0 +1,102 @@
+
+// Copyright 2017 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)
+
+// Not a test, just a small program to write out configuration info
+
+#include <boost/container_hash/hash.hpp>
+#include <iostream>
+#include <algorithm>
+
+#if defined(BOOST_MSVC)
+
+struct msvc_version {
+    unsigned version;
+    char const* description;
+
+    friend bool operator<(msvc_version const& v1, msvc_version const& v2) {
+        return v1.version < v2.version;
+    }
+};
+
+void write_compiler_info() {
+    // From:
+    // https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B
+    // https://blogs.msdn.microsoft.com/vcblog/2017/11/15/side-by-side-minor-version-msvc-toolsets-in-visual-studio-2017/
+    msvc_version versions[] = {
+        {0, "Old Visual C++"},
+        {1000, "Visual C++ 4.x, VS4.0?"},
+        {1100, "Visual C++ 5.0, VS97"},
+        {1200, "Visual C++ 6.0, VS6.0"},
+        {1300, "Visual C++ 7.0, VS.NET 2002"},
+        {1310, "Visual C++ 7.1, VS.NET 2003"},
+        {1400, "Visual C++ 8.0, VS2005"},
+        {1500, "Visual C++ 9.0, VS2008"},
+        {1600, "Visual C++ 10.0, VS2010"},
+        {1700, "Visual C++ 11.0, VS2012"},
+        {1800, "Visual C++ 12.0, VS2013"},
+        {1900, "Visual C++ 14.00, VS2015"},
+        {1910, "Visual C++ 14.10, VS2017 15.1/2"},
+        {1911, "Visual C++ 14.11, VS2017 15.3/4"},
+        {1912, "Visual C++ 14.12, VS2017 15.5"},
+        {1913, "Visual C++ 14.13, VS2017 15.6"}
+    };
+
+    msvc_version msvc = { BOOST_MSVC, "" };
+    msvc_version* v = std::upper_bound(versions,
+        versions + sizeof(versions) / sizeof(*versions),
+        msvc) - 1;
+    unsigned difference = msvc.version - v->version;
+
+    std::cout << v->description << std::endl;
+    if (difference) {
+        std::cout << "+" << difference << std::endl;
+    }
+}
+
+#else
+
+void write_compiler_info() {
+}
+
+#endif
+
+int main() {
+    write_compiler_info();
+
+#if defined(__cplusplus)
+    std::cout << "__cplusplus: "
+        << __cplusplus
+        << std::endl;
+#endif
+
+    std::cout << "BOOST_HASH_CXX17: "
+        << BOOST_HASH_CXX17
+        << std::endl;
+
+    std::cout << "BOOST_HASH_HAS_STRING_VIEW: "
+        << BOOST_HASH_HAS_STRING_VIEW
+        << std::endl;
+
+    std::cout << "BOOST_HASH_HAS_OPTIONAL: "
+        << BOOST_HASH_HAS_OPTIONAL
+        << std::endl;
+
+    std::cout << "BOOST_HASH_HAS_VARIANT: "
+        << BOOST_HASH_HAS_VARIANT
+        << std::endl;
+
+#if defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
+    std::cout << "No <typeindex>" << std::endl;
+#else
+    std::cout << "<typeindex>" << std::endl;
+#endif
+
+#if defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
+    std::cout << "No <system_error>" << std::endl;
+#else
+    std::cout << "<system_error>" << std::endl;
+#endif
+
+}
diff --git a/test/hash_list_test.cpp b/test/hash_list_test.cpp
new file mode 100644
index 0000000..9b2c25f
--- /dev/null
+++ b/test/hash_list_test.cpp
@@ -0,0 +1,35 @@
+
+// Copyright 2005-2009 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 BOOST_HASH_TEST_EXTENSIONS
+#  ifdef BOOST_HASH_TEST_STD_INCLUDES
+#    include <functional>
+#  else
+#    include <boost/container_hash/hash.hpp>
+#  endif
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+
+#include <list>
+
+using std::list;
+#define CONTAINER_TYPE list
+#include "./hash_sequence_test.hpp"
+
+#endif // BOOST_HASH_TEST_EXTENSIONS
+
+int main()
+{
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+    list_tests::list_hash_integer_tests();
+#endif
+
+    return boost::report_errors();
+}
diff --git a/test/hash_long_double_test.cpp b/test/hash_long_double_test.cpp
new file mode 100644
index 0000000..860a679
--- /dev/null
+++ b/test/hash_long_double_test.cpp
@@ -0,0 +1,17 @@
+
+// Copyright 2005-2009 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 "hash_float_test.hpp"
+
+int main()
+{
+    std::cerr<<"Compiler: "<<BOOST_COMPILER<<"\n";
+    std::cerr<<"Platform: "<<BOOST_PLATFORM<<"\n";
+    std::cerr<<"Library: "<<BOOST_STDLIB<<"\n\n";
+
+    float_tests("long double", (long double*) 0);
+
+    return boost::report_errors();
+}
diff --git a/test/hash_map_test.cpp b/test/hash_map_test.cpp
new file mode 100644
index 0000000..b70a9be
--- /dev/null
+++ b/test/hash_map_test.cpp
@@ -0,0 +1,40 @@
+
+// Copyright 2005-2009 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 BOOST_HASH_TEST_EXTENSIONS
+#  ifdef BOOST_HASH_TEST_STD_INCLUDES
+#    include <functional>
+#  else
+#    include <boost/container_hash/hash.hpp>
+#  endif
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+
+#include <map>
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+
+using std::map;
+#define CONTAINER_TYPE map
+#include "./hash_map_test.hpp"
+
+using std::multimap;
+#define CONTAINER_TYPE multimap
+#include "./hash_map_test.hpp"
+
+#endif // BOOST_HASH_TEST_EXTENSIONS
+
+int main()
+{
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+    map_tests::map_hash_integer_tests();
+    multimap_tests::multimap_hash_integer_tests();
+#endif
+
+    return boost::report_errors();
+}
diff --git a/test/hash_map_test.hpp b/test/hash_map_test.hpp
new file mode 100644
index 0000000..95ca62c
--- /dev/null
+++ b/test/hash_map_test.hpp
@@ -0,0 +1,74 @@
+
+// Copyright 2005-2009 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(CONTAINER_TYPE)
+#error "CONTAINER_TYPE not defined"
+#else
+
+#if defined(BOOST_MSVC)
+#pragma warning(push)
+#pragma warning(disable:4244) // conversion from 'int' to 'float'
+#pragma warning(disable:4245) // signed/unsigned mismatch
+#endif
+
+namespace HASH_TEST_CAT(CONTAINER_TYPE, _tests)
+{
+    template <class T>
+    void integer_tests(T* = 0)
+    {
+        const int number_of_containers = 10;
+        T containers[number_of_containers];
+        typedef BOOST_DEDUCED_TYPENAME T::value_type pair;
+        typedef BOOST_DEDUCED_TYPENAME T::key_type key;
+        typedef BOOST_DEDUCED_TYPENAME T::mapped_type value;
+
+        for(int i = 0; i < 5; ++i) {
+            for(int j = 0; j < i; ++j)
+                containers[i].insert(pair(key(0), value(0)));
+        }
+
+        containers[6].insert(pair(key(1),value(0)));
+        containers[7].insert(pair(key(1),value(0)));
+        containers[7].insert(pair(key(1),value(0)));
+        containers[8].insert(pair(key(-1),value(1)));
+        containers[9].insert(pair(key(-1),value(3)));
+        containers[9].insert(pair(key(-1),value(3)));
+
+        BOOST_HASH_TEST_NAMESPACE::hash<T> hasher;
+
+        for(int i2 = 0; i2 < number_of_containers; ++i2) {
+            BOOST_TEST(hasher(containers[i2]) == hasher(containers[i2]));
+
+            BOOST_TEST(hasher(containers[i2]) ==
+                    BOOST_HASH_TEST_NAMESPACE::hash_value(containers[i2]));
+
+            BOOST_TEST(hasher(containers[i2])
+                    == BOOST_HASH_TEST_NAMESPACE::hash_range(
+                        containers[i2].begin(), containers[i2].end()));
+
+            for(int j2 = i2 + 1; j2 < number_of_containers; ++j2) {
+                BOOST_TEST(
+                        (containers[i2] == containers[j2]) ==
+                        (hasher(containers[i2]) == hasher(containers[j2]))
+                        );
+            }
+        }
+    }
+
+    void HASH_TEST_CAT(CONTAINER_TYPE, _hash_integer_tests())
+    {
+        integer_tests((CONTAINER_TYPE<char, unsigned char>*) 0);
+        integer_tests((CONTAINER_TYPE<int, float>*) 0);
+        integer_tests((CONTAINER_TYPE<unsigned long, unsigned long>*) 0);
+        integer_tests((CONTAINER_TYPE<double, short>*) 0);
+    }
+}
+
+#if defined(BOOST_MSVC)
+#pragma warning(pop)
+#endif
+
+#undef CONTAINER_TYPE
+#endif
diff --git a/test/hash_no_ext_fail_test.cpp b/test/hash_no_ext_fail_test.cpp
new file mode 100644
index 0000000..ee35950
--- /dev/null
+++ b/test/hash_no_ext_fail_test.cpp
@@ -0,0 +1,28 @@
+
+// Copyright 2006-2009 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"
+
+// Simple test to make sure BOOST_HASH_NO_EXTENSIONS does disable extensions
+// (or at least one of them).
+#if !defined(BOOST_HASH_NO_EXTENSIONS)
+#  define BOOST_HASH_NO_EXTENSIONS
+#endif
+
+#ifdef BOOST_HASH_TEST_STD_INCLUDES
+#  include <functional>
+#else
+#  include <boost/container_hash/hash.hpp>
+#endif
+
+template <class T> void ignore(T const&) {}
+
+int main()
+{
+    BOOST_HASH_TEST_NAMESPACE::hash< int[10] > hasher;
+    ignore(hasher);
+
+    return 0;
+}
diff --git a/test/hash_no_ext_macro_1.cpp b/test/hash_no_ext_macro_1.cpp
new file mode 100644
index 0000000..1bfcb95
--- /dev/null
+++ b/test/hash_no_ext_macro_1.cpp
@@ -0,0 +1,37 @@
+
+// Copyright 2006-2009 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"
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+
+// Include header without BOOST_HASH_NO_EXTENSIONS defined
+#  if defined(BOOST_HASH_NO_EXTENSIONS)
+#    undef BOOST_HASH_NO_EXTENSIONS
+#  endif
+#  include <boost/container_hash/hash.hpp>
+
+// Include header with BOOST_HASH_NO_EXTENSIONS defined
+#  define BOOST_HASH_NO_EXTENSIONS
+#  include <boost/container_hash/hash.hpp>
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+#include <deque>
+
+int main()
+{
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    std::deque<int> x;
+
+    x.push_back(1);
+    x.push_back(2);
+
+    BOOST_HASH_TEST_NAMESPACE::hash<std::deque<int> > hasher;
+    BOOST_TEST(hasher(x) == BOOST_HASH_TEST_NAMESPACE::hash_value(x));
+#endif
+
+    return boost::report_errors();
+}
diff --git a/test/hash_no_ext_macro_2.cpp b/test/hash_no_ext_macro_2.cpp
new file mode 100644
index 0000000..6f46018
--- /dev/null
+++ b/test/hash_no_ext_macro_2.cpp
@@ -0,0 +1,37 @@
+
+// Copyright 2006-2009 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"
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+
+// Include header with BOOST_HASH_NO_EXTENSIONS defined
+#  if !defined(BOOST_HASH_NO_EXTENSIONS)
+#    define BOOST_HASH_NO_EXTENSIONS
+#  endif
+#  include <boost/container_hash/hash.hpp>
+
+// Include header without BOOST_HASH_NO_EXTENSIONS defined
+#  undef BOOST_HASH_NO_EXTENSIONS
+#  include <boost/container_hash/hash.hpp>
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+#include <map>
+
+int main()
+{
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    std::map<int, int> x;
+
+    x.insert(std::map<int, int>::value_type(53, -42));
+    x.insert(std::map<int, int>::value_type(14, -75));
+
+    BOOST_HASH_TEST_NAMESPACE::hash<std::map<int, int> > hasher;
+    BOOST_TEST(hasher(x) == BOOST_HASH_TEST_NAMESPACE::hash_value(x));
+#endif
+    
+    return boost::report_errors();
+}
diff --git a/test/hash_number_test.cpp b/test/hash_number_test.cpp
new file mode 100644
index 0000000..72ab626
--- /dev/null
+++ b/test/hash_number_test.cpp
@@ -0,0 +1,203 @@
+
+// Copyright 2005-2009 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 BOOST_HASH_TEST_STD_INCLUDES
+#  include <functional>
+#else
+#  include <boost/container_hash/hash.hpp>
+#endif
+
+#include <iostream>
+#include <boost/core/lightweight_test.hpp>
+
+#include <boost/container_hash/detail/limits.hpp>
+#include <boost/core/enable_if.hpp>
+
+#include "./compile_time.hpp"
+
+#if defined(BOOST_MSVC)
+#pragma warning(push)
+#pragma warning(disable:4127) // conditional expression is constant
+#pragma warning(disable:4309) // truncation of constant value
+#pragma warning(disable:4310) // cast truncates constant value
+#endif
+
+#if defined(__GNUC__) && !defined(BOOST_INTEL_CXX_VERSION)
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+
+template <class T>
+void numeric_extra_tests(typename
+    boost::enable_if_c<boost::hash_detail::limits<T>::is_integer,
+        void*>::type = 0)
+{
+    typedef boost::hash_detail::limits<T> limits;
+
+    if(limits::is_signed ||
+        limits::digits <= boost::hash_detail::limits<std::size_t>::digits)
+    {
+        BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(T(-5)) == (std::size_t)T(-5));
+    }
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(T(0)) == (std::size_t)T(0u));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(T(10)) == (std::size_t)T(10u));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(T(25)) == (std::size_t)T(25u));
+}
+
+template <class T>
+void numeric_extra_tests(typename
+    boost::disable_if_c<boost::hash_detail::limits<T>::is_integer,
+        void*>::type = 0)
+{
+}
+
+template <class T>
+void numeric_test(T*)
+{
+    compile_time_tests((T*) 0);
+
+    BOOST_HASH_TEST_NAMESPACE::hash<T> x1;
+    BOOST_HASH_TEST_NAMESPACE::hash<T> x2;
+
+    T v1 = (T) -5;
+    BOOST_TEST(x1(v1) == x2(v1));
+    BOOST_TEST(x1(T(-5)) == x2(T(-5)));
+    BOOST_TEST(x1(T(0)) == x2(T(0)));
+    BOOST_TEST(x1(T(10)) == x2(T(10)));
+    BOOST_TEST(x1(T(25)) == x2(T(25)));
+    BOOST_TEST(x1(T(5) - T(5)) == x2(T(0)));
+    BOOST_TEST(x1(T(6) + T(4)) == x2(T(10)));
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    BOOST_TEST(x1(T(-5)) == BOOST_HASH_TEST_NAMESPACE::hash_value(T(-5)));
+    BOOST_TEST(x1(T(0)) == BOOST_HASH_TEST_NAMESPACE::hash_value(T(0)));
+    BOOST_TEST(x1(T(10)) == BOOST_HASH_TEST_NAMESPACE::hash_value(T(10)));
+    BOOST_TEST(x1(T(25)) == BOOST_HASH_TEST_NAMESPACE::hash_value(T(25)));
+
+    numeric_extra_tests<T>();
+#endif
+}
+
+template <class T>
+void limits_test(T*)
+{
+    typedef boost::hash_detail::limits<T> limits;
+
+    if(limits::is_specialized)
+    {
+        BOOST_HASH_TEST_NAMESPACE::hash<T> x1;
+        BOOST_HASH_TEST_NAMESPACE::hash<T> x2;
+
+        T min_value = (limits::min)();
+        T max_value = (limits::max)();
+
+        BOOST_TEST(x1(min_value) == x2((limits::min)()));
+        BOOST_TEST(x1(max_value) == x2((limits::max)()));
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+        BOOST_TEST(x1(min_value) == BOOST_HASH_TEST_NAMESPACE::hash_value(min_value));
+        BOOST_TEST(x1(max_value) == BOOST_HASH_TEST_NAMESPACE::hash_value(max_value));
+
+        if (limits::is_integer)
+        {
+            BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(min_value)
+                    == std::size_t(min_value));
+            BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(max_value)
+                    == std::size_t(max_value));
+        }
+#endif
+    }
+}
+
+template <class T>
+void poor_quality_tests(T*)
+{
+    typedef boost::hash_detail::limits<T> limits;
+
+    BOOST_HASH_TEST_NAMESPACE::hash<T> x1;
+    BOOST_HASH_TEST_NAMESPACE::hash<T> x2;
+
+    // A hash function can legally fail these tests, but it'll not be a good
+    // sign.
+    if(T(1) != T(-1))
+        BOOST_TEST(x1(T(1)) !=  x2(T(-1)));
+    if(T(1) != T(2))
+        BOOST_TEST(x1(T(1)) !=  x2(T(2)));
+
+    // TODO: This test is useless for floating point numbers.
+    T max_number = static_cast<T>((limits::max)());
+    T max_minus_one = static_cast<T>(max_number - 1);
+    if (max_number != max_minus_one) {
+        BOOST_TEST(x1(max_number) != x1(max_minus_one));
+    }
+}
+
+void bool_test()
+{
+    BOOST_HASH_TEST_NAMESPACE::hash<bool> x1;
+    BOOST_HASH_TEST_NAMESPACE::hash<bool> x2;
+
+    BOOST_TEST(x1(true) == x2(true));
+    BOOST_TEST(x1(false) == x2(false));
+    BOOST_TEST(x1(true) != x2(false));
+    BOOST_TEST(x1(false) != x2(true));
+}
+
+#define NUMERIC_TEST(type, name) \
+    std::cerr<<"Testing: " BOOST_STRINGIZE(name) "\n"; \
+    numeric_test((type*) 0); \
+    limits_test((type*) 0); \
+    poor_quality_tests((type*) 0);
+#define NUMERIC_TEST_NO_LIMITS(type, name) \
+    std::cerr<<"Testing: " BOOST_STRINGIZE(name) "\n"; \
+    numeric_test((type*) 0); \
+    poor_quality_tests((type*) 0);
+
+int main()
+{
+    NUMERIC_TEST(char, char)
+    NUMERIC_TEST(signed char, schar)
+    NUMERIC_TEST(unsigned char, uchar)
+#ifndef BOOST_NO_INTRINSIC_WCHAR_T
+    NUMERIC_TEST(wchar_t, wchar)
+#endif
+#ifndef BOOST_NO_CXX11_CHAR16_T
+    NUMERIC_TEST(char16_t, char16)
+#endif
+#ifndef BOOST_NO_CXX11_CHAR32_T
+    NUMERIC_TEST(char32_t, char32)
+#endif
+    NUMERIC_TEST(short, short)
+    NUMERIC_TEST(unsigned short, ushort)
+    NUMERIC_TEST(int, int)
+    NUMERIC_TEST(unsigned int, uint)
+    NUMERIC_TEST(long, hash_long)
+    NUMERIC_TEST(unsigned long, ulong)
+
+#if !defined(BOOST_NO_LONG_LONG)
+    NUMERIC_TEST_NO_LIMITS(boost::long_long_type, long_long)
+    NUMERIC_TEST_NO_LIMITS(boost::ulong_long_type, ulong_long)
+#endif
+
+#if defined(BOOST_HAS_INT128)
+    NUMERIC_TEST_NO_LIMITS(boost::int128_type, int128)
+    NUMERIC_TEST_NO_LIMITS(boost::uint128_type, uint128)
+#endif
+
+    NUMERIC_TEST(float, float)
+    NUMERIC_TEST(double, double)
+
+    NUMERIC_TEST(std::size_t, size_t)
+    NUMERIC_TEST(std::ptrdiff_t, ptrdiff_t)
+
+    bool_test();
+
+    return boost::report_errors();
+}
+
+#if defined(BOOST_MSVC)
+#pragma warning(pop)
+#endif
diff --git a/test/hash_optional_test.cpp b/test/hash_optional_test.cpp
new file mode 100644
index 0000000..4469395
--- /dev/null
+++ b/test/hash_optional_test.cpp
@@ -0,0 +1,70 @@
+
+// Copyright 2018 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"
+
+#ifndef BOOST_HASH_TEST_STD_INCLUDES
+#  include <boost/container_hash/hash.hpp>
+#endif
+#include <boost/config.hpp>
+#include <boost/core/lightweight_test.hpp>
+
+#if BOOST_HASH_HAS_OPTIONAL
+
+#include <optional>
+#include <string>
+
+void test_optional_int()
+{
+    std::optional<int> x1a;
+    std::optional<int> x1b;
+    std::optional<int> x2a(10);
+    std::optional<int> x2b(x2a);
+    std::optional<int> x3(20);
+
+    boost::hash<std::optional<int> > hasher;
+
+    BOOST_TEST(hasher(x1a) == hasher(x1a));
+    BOOST_TEST(hasher(x1a) == hasher(x1b));
+    BOOST_TEST(hasher(x1a) != hasher(x2a));
+    BOOST_TEST(hasher(x1a) != hasher(x3));
+    BOOST_TEST(hasher(x2a) == hasher(x2a));
+    BOOST_TEST(hasher(x2b) == hasher(x2b));
+    BOOST_TEST(hasher(x2a) != hasher(x3));
+    BOOST_TEST(hasher(x3) == hasher(x3));
+}
+
+void test_optional_string()
+{
+    std::optional<std::string> x1a;
+    std::optional<std::string> x1b;
+    std::optional<std::string> x2a("10");
+    std::optional<std::string> x2b(x2a);
+    std::optional<std::string> x3("20");
+
+    boost::hash<std::optional<std::string> > hasher;
+
+    BOOST_TEST(hasher(x1a) == hasher(x1a));
+    BOOST_TEST(hasher(x1a) == hasher(x1b));
+    BOOST_TEST(hasher(x1a) != hasher(x2a));
+    BOOST_TEST(hasher(x1a) != hasher(x3));
+    BOOST_TEST(hasher(x2a) == hasher(x2a));
+    BOOST_TEST(hasher(x2b) == hasher(x2b));
+    BOOST_TEST(hasher(x2a) != hasher(x3));
+    BOOST_TEST(hasher(x3) == hasher(x3));
+}
+
+#endif
+
+int main()
+{
+#if BOOST_HASH_HAS_OPTIONAL
+    test_optional_int();
+    test_optional_string();
+#else
+    BOOST_LIGHTWEIGHT_TEST_OSTREAM << "<optional> not available." << std::endl;
+#endif
+    return boost::report_errors();
+}
diff --git a/test/hash_pointer_test.cpp b/test/hash_pointer_test.cpp
new file mode 100644
index 0000000..7086a61
--- /dev/null
+++ b/test/hash_pointer_test.cpp
@@ -0,0 +1,45 @@
+
+// Copyright 2005-2009 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 BOOST_HASH_TEST_STD_INCLUDES
+#  include <functional>
+#else
+#  include <boost/container_hash/hash.hpp>
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+#include <boost/limits.hpp>
+#include "./compile_time.hpp"
+
+void pointer_tests()
+{
+    compile_time_tests((int**) 0);
+    compile_time_tests((void**) 0);
+
+    BOOST_HASH_TEST_NAMESPACE::hash<int*> x1;
+    BOOST_HASH_TEST_NAMESPACE::hash<int*> x2;
+
+    int int1;
+    int int2;
+
+    BOOST_TEST(x1(0) == x2(0));
+    BOOST_TEST(x1(&int1) == x2(&int1));
+    BOOST_TEST(x1(&int2) == x2(&int2));
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    BOOST_TEST(x1(&int1) == BOOST_HASH_TEST_NAMESPACE::hash_value(&int1));
+    BOOST_TEST(x1(&int2) == BOOST_HASH_TEST_NAMESPACE::hash_value(&int2));
+
+    // This isn't specified in Peter's proposal:
+    BOOST_TEST(x1(0) == 0);
+#endif
+}
+
+int main()
+{
+    pointer_tests();
+    return boost::report_errors();
+}
diff --git a/test/hash_range_test.cpp b/test/hash_range_test.cpp
new file mode 100644
index 0000000..4a309e3
--- /dev/null
+++ b/test/hash_range_test.cpp
@@ -0,0 +1,85 @@
+
+// Copyright 2005-2009 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"
+
+#if !defined(BOOST_HASH_TEST_EXTENSIONS)
+
+int main() {}
+
+#else
+
+#ifdef BOOST_HASH_TEST_STD_INCLUDES
+#  include <functional>
+#else
+#  include <boost/container_hash/hash.hpp>
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+#include <boost/limits.hpp>
+#include <vector>
+
+void hash_range_tests()
+{
+    std::vector<int> empty, values1, values2, values3, values4, values5;
+    values1.push_back(0);
+    values2.push_back(10);
+    values3.push_back(10);
+    values3.push_back(20);
+    values4.push_back(15);
+    values4.push_back(75);
+    values5.push_back(10);
+    values5.push_back(20);
+    values5.push_back(15);
+    values5.push_back(75);
+    values5.push_back(10);
+    values5.push_back(20);
+
+    std::vector<int> x;
+
+    std::size_t x_seed = 0;
+    BOOST_TEST(x_seed == BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
+
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(empty.begin(), empty.end())
+        == BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(empty.begin(), empty.end())
+        != BOOST_HASH_TEST_NAMESPACE::hash_range(values1.begin(), values1.end()));
+
+    x.push_back(10);
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(x_seed, 10);
+    BOOST_TEST(x_seed == BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
+
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(empty.begin(), empty.end())
+        != BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(values2.begin(), values2.end())
+        == BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
+
+    x.push_back(20);
+    BOOST_HASH_TEST_NAMESPACE::hash_combine(x_seed, 20);
+    BOOST_TEST(x_seed == BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
+
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(empty.begin(), empty.end())
+        != BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(values2.begin(), values2.end())
+        != BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_range(values3.begin(), values3.end())
+        == BOOST_HASH_TEST_NAMESPACE::hash_range(x.begin(), x.end()));
+
+    std::size_t seed =
+        BOOST_HASH_TEST_NAMESPACE::hash_range(values3.begin(), values3.end());
+    BOOST_HASH_TEST_NAMESPACE::hash_range(seed, values4.begin(), values4.end());
+    BOOST_HASH_TEST_NAMESPACE::hash_range(seed, x.begin(), x.end());
+    BOOST_TEST(seed ==
+        BOOST_HASH_TEST_NAMESPACE::hash_range(values5.begin(), values5.end()));
+}
+
+int main()
+{
+    hash_range_tests();
+
+    return boost::report_errors();
+}
+
+#endif // TEST_EXTESNIONS
diff --git a/test/hash_sequence_test.hpp b/test/hash_sequence_test.hpp
new file mode 100644
index 0000000..3e915f8
--- /dev/null
+++ b/test/hash_sequence_test.hpp
@@ -0,0 +1,76 @@
+
+// Copyright 2005-2009 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(CONTAINER_TYPE)
+#error "CONTAINER_TYPE not defined"
+#else
+
+#if defined(BOOST_MSVC)
+#pragma warning(push)
+#pragma warning(disable:4245) // signed/unsigned mismatch
+#endif
+
+namespace HASH_TEST_CAT(CONTAINER_TYPE, _tests)
+{
+    template <class T>
+    void integer_tests(T* = 0)
+    {
+        typedef typename T::value_type value_type;
+
+        const int number_of_containers = 11;
+        T containers[number_of_containers];
+
+        for(int i = 0; i < 5; ++i) {
+            for(int j = 0; j < i; ++j)
+                containers[i].push_back(0);
+        }
+
+        containers[5].push_back(value_type(1));
+        containers[6].push_back(value_type(1));
+        containers[6].push_back(value_type(1));
+        containers[7].push_back(value_type(-1));
+        containers[8].push_back(value_type(-1));
+        containers[8].push_back(value_type(-1));
+        containers[9].push_back(value_type(1));
+        containers[9].push_back(value_type(-1));
+        containers[10].push_back(value_type(-1));
+        containers[10].push_back(value_type(1));
+
+        BOOST_HASH_TEST_NAMESPACE::hash<T> hasher;
+
+        for(int i2 = 0; i2 < number_of_containers; ++i2) {
+            BOOST_TEST(hasher(containers[i2]) == hasher(containers[i2]));
+
+            BOOST_TEST(hasher(containers[i2]) ==
+                    BOOST_HASH_TEST_NAMESPACE::hash_value(containers[i2]));
+
+            BOOST_TEST(hasher(containers[i2])
+                    == BOOST_HASH_TEST_NAMESPACE::hash_range(
+                        containers[i2].begin(), containers[i2].end()));
+
+            for(int j2 = i2 + 1; j2 < number_of_containers; ++j2) {
+                BOOST_TEST(
+                        (containers[i2] == containers[j2]) ==
+                        (hasher(containers[i2]) == hasher(containers[j2]))
+                        );
+            }
+        }
+    }
+
+    void HASH_TEST_CAT(CONTAINER_TYPE, _hash_integer_tests())
+    {
+        integer_tests((CONTAINER_TYPE<char>*) 0);
+        integer_tests((CONTAINER_TYPE<int>*) 0);
+        integer_tests((CONTAINER_TYPE<unsigned long>*) 0);
+        integer_tests((CONTAINER_TYPE<double>*) 0);
+    }
+}
+
+#if defined(BOOST_MSVC)
+#pragma warning(pop)
+#endif
+
+#undef CONTAINER_TYPE
+#endif
diff --git a/test/hash_set_test.cpp b/test/hash_set_test.cpp
new file mode 100644
index 0000000..48dcc2b
--- /dev/null
+++ b/test/hash_set_test.cpp
@@ -0,0 +1,40 @@
+
+// Copyright 2005-2009 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 BOOST_HASH_TEST_EXTENSIONS
+#  ifdef BOOST_HASH_TEST_STD_INCLUDES
+#    include <functional>
+#  else
+#    include <boost/container_hash/hash.hpp>
+#  endif
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+
+#include <set>
+
+using std::set;
+#define CONTAINER_TYPE set
+#include "./hash_set_test.hpp"
+
+using std::multiset;
+#define CONTAINER_TYPE multiset
+#include "./hash_set_test.hpp"
+
+#endif
+
+int main()
+{
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+    set_tests::set_hash_integer_tests();
+    multiset_tests::multiset_hash_integer_tests();
+#endif
+
+    return boost::report_errors();
+}
diff --git a/test/hash_set_test.hpp b/test/hash_set_test.hpp
new file mode 100644
index 0000000..9a77756
--- /dev/null
+++ b/test/hash_set_test.hpp
@@ -0,0 +1,79 @@
+
+// Copyright 2005-2009 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(CONTAINER_TYPE)
+#error "CONTAINER_TYPE not defined"
+#else
+
+#if defined(BOOST_MSVC)
+#pragma warning(push)
+#pragma warning(disable:4245) // signed/unsigned mismatch
+#endif
+
+namespace HASH_TEST_CAT(CONTAINER_TYPE, _tests)
+{
+    template <class T>
+    void integer_tests(T* = 0)
+    {
+        typedef typename T::value_type value_type;
+
+        const int number_of_containers = 12;
+        T containers[number_of_containers];
+
+        for(int i = 0; i < 5; ++i) {
+            for(int j = 0; j < i; ++j)
+                containers[i].insert(0);
+        }
+
+        containers[6].insert(value_type(1));
+        containers[7].insert(value_type(1));
+        containers[7].insert(value_type(1));
+        containers[8].insert(value_type(-1));
+        containers[9].insert(value_type(-1));
+        containers[9].insert(value_type(-1));
+        containers[10].insert(value_type(-1));
+        containers[10].insert(value_type(1));
+        containers[11].insert(value_type(1));
+        containers[11].insert(value_type(2));
+        containers[11].insert(value_type(3));
+        containers[11].insert(value_type(4));
+        containers[11].insert(value_type(5));
+
+        BOOST_HASH_TEST_NAMESPACE::hash<T> hasher;
+
+        for(int i2 = 0; i2 < number_of_containers; ++i2) {
+            BOOST_TEST(hasher(containers[i2]) == hasher(containers[i2]));
+
+            BOOST_TEST(hasher(containers[i2]) ==
+                    BOOST_HASH_TEST_NAMESPACE::hash_value(containers[i2]));
+
+            BOOST_TEST(hasher(containers[i2])
+                    == BOOST_HASH_TEST_NAMESPACE::hash_range(
+                        containers[i2].begin(), containers[i2].end()));
+
+            for(int j2 = i2 + 1; j2 < number_of_containers; ++j2) {
+                BOOST_TEST(
+                        (containers[i2] == containers[j2]) ==
+                        (hasher(containers[i2]) == hasher(containers[j2]))
+                        );
+            }
+        }
+    }
+
+    void HASH_TEST_CAT(CONTAINER_TYPE, _hash_integer_tests())
+    {
+        integer_tests((CONTAINER_TYPE<char>*) 0);
+        integer_tests((CONTAINER_TYPE<int>*) 0);
+        integer_tests((CONTAINER_TYPE<unsigned long>*) 0);
+        integer_tests((CONTAINER_TYPE<double>*) 0);
+    }
+}
+
+#if defined(BOOST_MSVC)
+#pragma warning(pop)
+#endif
+
+#undef CONTAINER_TYPE
+#endif
diff --git a/test/hash_std_array_test.cpp b/test/hash_std_array_test.cpp
new file mode 100644
index 0000000..d8faee4
--- /dev/null
+++ b/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 BOOST_HASH_TEST_EXTENSIONS
+#  ifdef BOOST_HASH_TEST_STD_INCLUDES
+#    include <functional>
+#  else
+#    include <boost/container_hash/hash.hpp>
+#  endif
+#endif
+
+#include <boost/config.hpp>
+#include <boost/core/lightweight_test.hpp>
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_NO_CXX11_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.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<std::array<std::string, 1> > arrays;
+    std::array<std::string, 1> 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<std::array<std::string,3 > > arrays;
+    std::array<std::string, 3> 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/test/hash_std_smart_ptr_test.cpp b/test/hash_std_smart_ptr_test.cpp
new file mode 100644
index 0000000..b8625fe
--- /dev/null
+++ b/test/hash_std_smart_ptr_test.cpp
@@ -0,0 +1,80 @@
+
+// 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 BOOST_HASH_TEST_STD_INCLUDES
+#  include <functional>
+#else
+#  include <boost/container_hash/hash.hpp>
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+#include "./compile_time.hpp"
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_NO_CXX11_SMART_PTR)
+#define TEST_SMART_PTRS
+#include <memory>
+#endif
+
+#ifdef TEST_SMART_PTRS
+
+void shared_ptr_tests()
+{
+    std::shared_ptr<int> x;
+    compile_time_tests(&x);
+
+    BOOST_HASH_TEST_NAMESPACE::hash<std::shared_ptr<int> > x1;
+    BOOST_HASH_TEST_NAMESPACE::hash<std::shared_ptr<int> > x2;
+
+    std::shared_ptr<int> ptr1(new int(10));
+    std::shared_ptr<int> ptr2;
+
+    BOOST_TEST(x1(x) == x2(ptr2));
+    BOOST_TEST(x1(x) != x2(ptr1));
+    ptr2.reset(new int(10));
+    BOOST_TEST(x1(ptr1) == x2(ptr1));
+    BOOST_TEST(x1(ptr1) != x2(ptr2));
+    ptr2 = ptr1;
+    BOOST_TEST(x1(ptr1) == x2(ptr2));
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    BOOST_TEST(x1(x) == BOOST_HASH_TEST_NAMESPACE::hash_value(x));
+    BOOST_TEST(x1(ptr1) == BOOST_HASH_TEST_NAMESPACE::hash_value(ptr2));
+#endif
+}
+
+void unique_ptr_tests()
+{
+    std::unique_ptr<int> x;
+    compile_time_tests(&x);
+
+    BOOST_HASH_TEST_NAMESPACE::hash<std::unique_ptr<int> > x1;
+    BOOST_HASH_TEST_NAMESPACE::hash<std::unique_ptr<int> > x2;
+
+    std::unique_ptr<int> ptr1(new int(10));
+    std::unique_ptr<int> ptr2;
+
+    BOOST_TEST(x1(x) == x2(ptr2));
+    BOOST_TEST(x1(x) != x2(ptr1));
+    ptr2.reset(new int(10));
+    BOOST_TEST(x1(ptr1) == x2(ptr1));
+    BOOST_TEST(x1(ptr1) != x2(ptr2));
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    BOOST_TEST(x1(x) == BOOST_HASH_TEST_NAMESPACE::hash_value(x));
+#endif
+}
+
+#endif
+
+int main()
+{
+#ifdef TEST_SMART_PTRS
+    shared_ptr_tests();
+    unique_ptr_tests();
+#endif
+
+    return boost::report_errors();
+}
diff --git a/test/hash_std_tuple_test.cpp b/test/hash_std_tuple_test.cpp
new file mode 100644
index 0000000..df4ef37
--- /dev/null
+++ b/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 BOOST_HASH_TEST_EXTENSIONS
+#  ifdef BOOST_HASH_TEST_STD_INCLUDES
+#    include <functional>
+#  else
+#    include <boost/container_hash/hash.hpp>
+#  endif
+#endif
+
+#include <boost/config.hpp>
+#include <boost/core/lightweight_test.hpp>
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_NO_CXX11_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, 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/test/hash_string_test.cpp b/test/hash_string_test.cpp
new file mode 100644
index 0000000..712c639
--- /dev/null
+++ b/test/hash_string_test.cpp
@@ -0,0 +1,184 @@
+
+// Copyright 2005-2009 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 BOOST_HASH_TEST_STD_INCLUDES
+#  include <functional>
+#else
+#  include <boost/container_hash/hash.hpp>
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+#include <string>
+#include "./compile_time.hpp"
+
+void string_tests()
+{
+    compile_time_tests((std::string*) 0);
+
+    BOOST_HASH_TEST_NAMESPACE::hash<std::string> x1;
+    BOOST_HASH_TEST_NAMESPACE::hash<std::string> x2;
+
+    BOOST_TEST(x1("Hello") == x2(std::string("Hel") + "lo"));
+    BOOST_TEST(x1("") == x2(std::string()));
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    std::string value1;
+    std::string value2("Hello");
+
+    BOOST_TEST(x1(value1) == BOOST_HASH_TEST_NAMESPACE::hash_value(value1));
+    BOOST_TEST(x1(value2) == BOOST_HASH_TEST_NAMESPACE::hash_value(value2));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value1) ==
+            BOOST_HASH_TEST_NAMESPACE::hash_range(value1.begin(), value1.end()));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value2) ==
+            BOOST_HASH_TEST_NAMESPACE::hash_range(value2.begin(), value2.end()));
+#endif
+}
+
+void string0_tests()
+{
+    std::string x1(1, '\0');
+    std::string x2(2, '\0');
+    std::string x3(3, '\0');
+    std::string x4(10, '\0');
+
+    BOOST_HASH_TEST_NAMESPACE::hash<std::string> hasher;
+
+    BOOST_TEST(hasher(x1) != hasher(x2));
+    BOOST_TEST(hasher(x1) != hasher(x3));
+    BOOST_TEST(hasher(x1) != hasher(x4));
+    BOOST_TEST(hasher(x2) != hasher(x3));
+    BOOST_TEST(hasher(x2) != hasher(x4));
+    BOOST_TEST(hasher(x3) != hasher(x4));
+}
+
+#if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
+void wstring_tests()
+{
+    compile_time_tests((std::wstring*) 0);
+
+    BOOST_HASH_TEST_NAMESPACE::hash<std::wstring> x1;
+    BOOST_HASH_TEST_NAMESPACE::hash<std::wstring> x2;
+
+    BOOST_TEST(x1(L"Hello") == x2(std::wstring(L"Hel") + L"lo"));
+    BOOST_TEST(x1(L"") == x2(std::wstring()));
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    std::wstring value1;
+    std::wstring value2(L"Hello");
+
+    BOOST_TEST(x1(value1) == BOOST_HASH_TEST_NAMESPACE::hash_value(value1));
+    BOOST_TEST(x1(value2) == BOOST_HASH_TEST_NAMESPACE::hash_value(value2));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value1) ==
+            BOOST_HASH_TEST_NAMESPACE::hash_range(value1.begin(), value1.end()));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value2) ==
+            BOOST_HASH_TEST_NAMESPACE::hash_range(value2.begin(), value2.end()));
+#endif
+}
+#endif
+
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+void u16string_tests()
+{
+    compile_time_tests((std::u16string*) 0);
+
+    BOOST_HASH_TEST_NAMESPACE::hash<std::u16string> x1;
+    BOOST_HASH_TEST_NAMESPACE::hash<std::u16string> x2;
+
+    BOOST_TEST(x1(u"Hello") == x2(std::u16string(u"Hel") + u"lo"));
+    BOOST_TEST(x1(u"") == x2(std::u16string()));
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    std::u16string value1;
+    std::u16string value2(u"Hello");
+
+    BOOST_TEST(x1(value1) == BOOST_HASH_TEST_NAMESPACE::hash_value(value1));
+    BOOST_TEST(x1(value2) == BOOST_HASH_TEST_NAMESPACE::hash_value(value2));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value1) ==
+            BOOST_HASH_TEST_NAMESPACE::hash_range(value1.begin(), value1.end()));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value2) ==
+            BOOST_HASH_TEST_NAMESPACE::hash_range(value2.begin(), value2.end()));
+#endif
+}
+#endif
+
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+void u32string_tests()
+{
+    compile_time_tests((std::u32string*) 0);
+
+    BOOST_HASH_TEST_NAMESPACE::hash<std::u32string> x1;
+    BOOST_HASH_TEST_NAMESPACE::hash<std::u32string> x2;
+
+    BOOST_TEST(x1(U"Hello") == x2(std::u32string(U"Hel") + U"lo"));
+    BOOST_TEST(x1(U"") == x2(std::u32string()));
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+    std::u32string value1;
+    std::u32string value2(U"Hello");
+
+    BOOST_TEST(x1(value1) == BOOST_HASH_TEST_NAMESPACE::hash_value(value1));
+    BOOST_TEST(x1(value2) == BOOST_HASH_TEST_NAMESPACE::hash_value(value2));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value1) ==
+            BOOST_HASH_TEST_NAMESPACE::hash_range(value1.begin(), value1.end()));
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(value2) ==
+            BOOST_HASH_TEST_NAMESPACE::hash_range(value2.begin(), value2.end()));
+#endif
+}
+#endif
+
+template <typename StringType>
+void generic_string_tests(StringType*)
+{
+    std::string x1(1, '\0');
+    std::string x2(2, '\0');
+    std::string x3(3, '\0');
+    std::string x4(10, '\0');
+    std::string x5 = x2 + "hello" + x2;
+
+    StringType strings[] = {
+        "",
+        "hello",
+        x1,
+        x2,
+        x3,
+        x4,
+        x5
+    };
+
+    std::size_t const strings_length = sizeof(strings) / sizeof(StringType);
+    boost::hash<StringType> hash;
+
+    for (std::size_t i = 0; i < strings_length; ++i) {
+        std::size_t hash_i = hash(strings[i]);
+        for (std::size_t j = 0; j < strings_length; ++j) {
+            std::size_t hash_j = hash(strings[j]);
+            BOOST_TEST((hash_i == hash_j) == (i == j));
+        }
+    }
+}
+
+int main()
+{
+    string_tests();
+    string0_tests();
+#if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
+    wstring_tests();
+#endif
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+    u16string_tests();
+#endif
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+    u32string_tests();
+#endif
+
+    generic_string_tests((std::string*) 0);
+#if BOOST_HASH_HAS_STRING_VIEW
+    generic_string_tests((std::string_view*) 0);
+#endif
+
+    return boost::report_errors();
+}
diff --git a/test/hash_system_error_test.cpp b/test/hash_system_error_test.cpp
new file mode 100644
index 0000000..14228d1
--- /dev/null
+++ b/test/hash_system_error_test.cpp
@@ -0,0 +1,55 @@
+
+// Copyright 2018 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"
+
+#ifndef BOOST_HASH_TEST_STD_INCLUDES
+#  include <boost/container_hash/hash.hpp>
+#endif
+#include <boost/config.hpp>
+#include <boost/core/lightweight_test.hpp>
+
+#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
+
+#include <system_error>
+
+void test_error_code()
+{
+    std::error_code err1a = std::make_error_code(std::errc::argument_list_too_long);
+    std::error_code err1b = std::make_error_code(std::errc::argument_list_too_long);
+    std::error_code err2 = std::make_error_code(std::errc::bad_file_descriptor);
+
+    boost::hash<std::error_code> hasher;
+
+    BOOST_TEST(hasher(err1a) == hasher(err1a));
+    BOOST_TEST(hasher(err1a) == hasher(err1b));
+    BOOST_TEST(hasher(err1a) != hasher(err2));
+}
+
+void test_error_condition()
+{
+    std::error_condition err1a = std::make_error_condition(std::errc::directory_not_empty);
+    std::error_condition err1b = std::make_error_condition(std::errc::directory_not_empty);
+    std::error_condition err2 = std::make_error_condition(std::errc::filename_too_long);
+
+    boost::hash<std::error_condition> hasher;
+
+    BOOST_TEST(hasher(err1a) == hasher(err1a));
+    BOOST_TEST(hasher(err1a) == hasher(err1b));
+    BOOST_TEST(hasher(err1a) != hasher(err2));
+}
+
+#endif
+
+int main()
+{
+#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
+    test_error_code();
+    test_error_condition();
+#else
+    BOOST_LIGHTWEIGHT_TEST_OSTREAM << "<system_error> not available." << std::endl;
+#endif
+    return boost::report_errors();
+}
diff --git a/test/hash_type_index_test.cpp b/test/hash_type_index_test.cpp
new file mode 100644
index 0000000..f03750f
--- /dev/null
+++ b/test/hash_type_index_test.cpp
@@ -0,0 +1,53 @@
+
+// Copyright 2011 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 BOOST_HASH_TEST_STD_INCLUDES
+#  include <functional>
+#else
+#  include <boost/container_hash/hash.hpp>
+#endif
+#include <boost/config.hpp>
+#include <boost/core/lightweight_test.hpp>
+
+#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
+
+#include <typeindex>
+
+void test_type_index() {
+    BOOST_HASH_TEST_NAMESPACE::hash<std::type_index> hasher;
+
+#if defined(BOOST_NO_TYPEID)
+    std::cout<<"Unable to test std::type_index, as typeid isn't available"
+        <<std::endl;
+#else
+    std::type_index int_index = typeid(int);
+    std::type_index int2_index = typeid(int);
+    std::type_index char_index = typeid(char);
+    
+    BOOST_TEST(hasher(int_index) == int_index.hash_code());
+    BOOST_TEST(hasher(int_index) == int2_index.hash_code());
+    BOOST_TEST(hasher(char_index) == char_index.hash_code());
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(int_index) == int_index.hash_code());
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(int_index) == int2_index.hash_code());
+    BOOST_TEST(BOOST_HASH_TEST_NAMESPACE::hash_value(char_index) == char_index.hash_code());
+
+    BOOST_TEST(hasher(int_index) == hasher(int2_index));
+    BOOST_TEST(hasher(int_index) != hasher(char_index));
+#endif
+}
+#endif
+
+int main()
+{
+#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
+    test_type_index();
+#else
+    std::cout<<"<type_index> not available."<<std::endl;
+#endif
+
+    return boost::report_errors();
+}
diff --git a/test/hash_value_array_test.cpp b/test/hash_value_array_test.cpp
new file mode 100644
index 0000000..d0d7fe6
--- /dev/null
+++ b/test/hash_value_array_test.cpp
@@ -0,0 +1,64 @@
+
+// Copyright 2005-2009 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)
+
+// On some compilers hash_value isn't available for arrays, so I test it
+// separately from the main array tests.
+
+#include "./config.hpp"
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+#  ifdef BOOST_HASH_TEST_STD_INCLUDES
+#    include <functional>
+#  else
+#    include <boost/container_hash/hash.hpp>
+#  endif
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+
+void array_int_test()
+{
+    const int array1[25] = {
+        26, -43, 32, 65, 45,
+        12, 67, 32, 12, 23,
+        0, 0, 0, 0, 0,
+        8, -12, 23, 65, 45,
+        -1, 93, -54, 987, 3
+    };
+    BOOST_HASH_TEST_NAMESPACE::hash<int[25]> hasher1;
+
+    int array2[1] = {3};
+    BOOST_HASH_TEST_NAMESPACE::hash<int[1]> hasher2;
+
+    int array3[2] = {2, 3};
+    BOOST_HASH_TEST_NAMESPACE::hash<int[2]> hasher3;
+
+    BOOST_TEST(hasher1(array1) == BOOST_HASH_TEST_NAMESPACE::hash_value(array1));
+    BOOST_TEST(hasher2(array2) == BOOST_HASH_TEST_NAMESPACE::hash_value(array2));
+    BOOST_TEST(hasher3(array3) == BOOST_HASH_TEST_NAMESPACE::hash_value(array3));
+}
+
+void two_dimensional_array_test()
+{
+    int array[3][2] = {{-5, 6}, {7, -3}, {26, 1}};
+    BOOST_HASH_TEST_NAMESPACE::hash<int[3][2]> hasher;
+
+    BOOST_TEST(hasher(array) == BOOST_HASH_TEST_NAMESPACE::hash_value(array));
+}
+
+#endif
+
+int main()
+{
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+    array_int_test();
+    two_dimensional_array_test();
+#endif
+
+    return boost::report_errors();
+}
+
diff --git a/test/hash_variant_test.cpp b/test/hash_variant_test.cpp
new file mode 100644
index 0000000..31520f4
--- /dev/null
+++ b/test/hash_variant_test.cpp
@@ -0,0 +1,100 @@
+
+// Copyright 2018 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"
+
+#ifndef BOOST_HASH_TEST_STD_INCLUDES
+#  include <boost/container_hash/hash.hpp>
+#endif
+#include <boost/config.hpp>
+#include <boost/core/lightweight_test.hpp>
+
+#if BOOST_HASH_HAS_VARIANT
+
+#include <variant>
+#include <string>
+
+void test_monostate()
+{
+    std::monostate x1;
+    std::monostate x2;
+
+    boost::hash<std::monostate> hasher;
+
+    BOOST_TEST(hasher(x1) == hasher(x2));
+}
+
+void test_variant_int()
+{
+    std::variant<std::monostate, int> x1a;
+    std::variant<std::monostate, int> x1b;
+    std::variant<std::monostate, int> x2a(10);
+    std::variant<std::monostate, int> x2b(x2a);
+    std::variant<std::monostate, int> x3(20);
+
+    boost::hash<std::variant<std::monostate, int> > hasher;
+
+    BOOST_TEST(hasher(x1a) == hasher(x1a));
+    BOOST_TEST(hasher(x1a) == hasher(x1b));
+    BOOST_TEST(hasher(x1a) != hasher(x2a));
+    BOOST_TEST(hasher(x1a) != hasher(x3));
+    BOOST_TEST(hasher(x2a) == hasher(x2a));
+    BOOST_TEST(hasher(x2b) == hasher(x2b));
+    BOOST_TEST(hasher(x2a) != hasher(x3));
+    BOOST_TEST(hasher(x3) == hasher(x3));
+}
+
+struct custom1 {
+    int value;
+    friend std::size_t hash_value(custom1 v) { return boost::hash_value(v.value); }
+};
+
+struct custom2 {
+    int value;
+    friend std::size_t hash_value(custom2 v) { return boost::hash_value(v.value); }
+};
+
+void test_variant_unique_types()
+{
+    custom1 x11 = { 0 };
+    custom1 x12 = { 1 };
+    custom2 x21 = { 0 };
+    custom2 x22 = { 1 };
+
+    boost::hash<custom1> hasher1;
+    boost::hash<custom2> hasher2;
+
+    BOOST_TEST(hasher1(x11) == hasher2(x21));
+    BOOST_TEST(hasher1(x11) != hasher2(x22));
+    BOOST_TEST(hasher1(x12) != hasher2(x21));
+    BOOST_TEST(hasher1(x12) == hasher2(x22));
+
+    typedef std::variant<custom1, custom2> variant_type;
+
+    variant_type y11(x11);
+    variant_type y12(x12);
+    variant_type y21(x21);
+    variant_type y22(x22);
+
+    boost::hash<variant_type> hasher;
+
+    BOOST_TEST(hasher(y11) != hasher(y21));
+    BOOST_TEST(hasher(y11) != hasher(y22));
+    BOOST_TEST(hasher(y12) != hasher(y21));
+    BOOST_TEST(hasher(y12) != hasher(y22));
+}
+
+#endif
+
+int main()
+{
+#if BOOST_HASH_HAS_VARIANT
+    test_variant_int();
+    test_variant_unique_types();
+#else
+    BOOST_LIGHTWEIGHT_TEST_OSTREAM << "<variant> not available." << std::endl;
+#endif
+    return boost::report_errors();
+}
diff --git a/test/hash_vector_test.cpp b/test/hash_vector_test.cpp
new file mode 100644
index 0000000..9e63f5b
--- /dev/null
+++ b/test/hash_vector_test.cpp
@@ -0,0 +1,68 @@
+
+// Copyright 2005-2009 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 BOOST_HASH_TEST_EXTENSIONS
+#  ifdef BOOST_HASH_TEST_STD_INCLUDES
+#    include <functional>
+#  else
+#    include <boost/container_hash/hash.hpp>
+#  endif
+#endif
+
+#include <boost/core/lightweight_test.hpp>
+
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+
+#include <vector>
+
+using std::vector;
+#define CONTAINER_TYPE vector
+#include "./hash_sequence_test.hpp"
+
+#endif // BOOST_HASH_TEST_EXTENSIONS
+
+namespace vector_bool_tests
+{
+    void vector_bool_test() {
+        std::vector<bool> x_empty1,x_empty2,x1,x1a,x2,x3;
+
+        x1.push_back(0);
+        x1a.push_back(0);
+        x2.push_back(1);
+        x3.push_back(0);
+        x3.push_back(0);
+
+        BOOST_HASH_TEST_NAMESPACE::hash<std::vector<bool> > hasher;
+
+        BOOST_TEST_EQ(hasher(x_empty1), hasher(x_empty1));
+        BOOST_TEST_EQ(hasher(x_empty1), hasher(x_empty2));
+        BOOST_TEST_NE(hasher(x_empty1), hasher(x1));
+        BOOST_TEST_NE(hasher(x_empty1), hasher(x2));
+        BOOST_TEST_NE(hasher(x_empty1), hasher(x3));
+
+        BOOST_TEST_EQ(hasher(x1), hasher(x1));
+        BOOST_TEST_EQ(hasher(x1), hasher(x1a));
+        BOOST_TEST_NE(hasher(x1), hasher(x2));
+        BOOST_TEST_NE(hasher(x1), hasher(x3));
+
+        BOOST_TEST_EQ(hasher(x2), hasher(x2));
+        BOOST_TEST_NE(hasher(x2), hasher(x3));
+
+        BOOST_TEST_EQ(hasher(x3), hasher(x3));
+    }
+}
+
+int main()
+{
+#ifdef BOOST_HASH_TEST_EXTENSIONS
+    vector_tests::vector_hash_integer_tests();
+#endif
+
+    vector_bool_tests::vector_bool_test();
+
+    return boost::report_errors();
+}
diff --git a/test/implicit_test.cpp b/test/implicit_test.cpp
new file mode 100644
index 0000000..67859da
--- /dev/null
+++ b/test/implicit_test.cpp
@@ -0,0 +1,21 @@
+
+// Copyright 2010 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 <boost/container_hash/hash.hpp>
+
+namespace test
+{
+    struct base {};
+    std::size_t hash_value(base const&) { return 0; }
+    
+    struct converts { operator base() const { return base(); } };
+}
+
+int main() {
+    boost::hash<test::converts> hash;
+    test::converts x;
+    
+    hash(x);
+}
diff --git a/test/link_ext_test.cpp b/test/link_ext_test.cpp
new file mode 100644
index 0000000..de4964b
--- /dev/null
+++ b/test/link_ext_test.cpp
@@ -0,0 +1,33 @@
+
+// Copyright 2006-2009 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"
+
+#define BOOST_HASH_TEST_NAMESPACE boost
+#include <boost/container_hash/hash.hpp>
+#include <boost/core/lightweight_test.hpp>
+#include <vector>
+
+int f(std::size_t hash1, int* x1) {
+
+    // Check that BOOST_HASH_TEST_NAMESPACE::hash<int*> works in both files.
+    BOOST_HASH_TEST_NAMESPACE::hash<int*> ptr_hasher;
+    BOOST_TEST(hash1 == ptr_hasher(x1));
+
+#if defined(BOOST_HASH_TEST_EXTENSIONS)
+
+    // Check that std::vector<std::size_t> is avaiable in this file.
+    std::vector<std::size_t> x;
+    x.push_back(static_cast<std::size_t>(*x1));
+    BOOST_HASH_TEST_NAMESPACE::hash<std::vector<std::size_t> > vector_hasher;
+    return vector_hasher(x) != BOOST_HASH_TEST_NAMESPACE::hash_value(x);
+    
+#else
+
+    return 0;
+
+#endif
+}
+
diff --git a/test/link_no_ext_test.cpp b/test/link_no_ext_test.cpp
new file mode 100644
index 0000000..b325bd6
--- /dev/null
+++ b/test/link_no_ext_test.cpp
@@ -0,0 +1,20 @@
+
+// Copyright 2005-2009 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"
+
+#define BOOST_HASH_TEST_NAMESPACE boost
+#define BOOST_HASH_NO_EXTENSIONS
+#include <boost/container_hash/hash.hpp>
+#include <boost/core/lightweight_test.hpp>
+
+extern int f(std::size_t, int*);
+
+int main() {
+    BOOST_HASH_TEST_NAMESPACE::hash<int*> ptr_hasher;
+    int x = 55;
+    BOOST_TEST(!f(ptr_hasher(&x), &x));
+    return boost::report_errors();
+}
diff --git a/test/link_test.cpp b/test/link_test.cpp
new file mode 100644
index 0000000..4acc301
--- /dev/null
+++ b/test/link_test.cpp
@@ -0,0 +1,11 @@
+
+// Copyright 2005-2009 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"
+
+#include <boost/container_hash/hash.hpp>
+
+extern int f();
+int main() { return f(); }
diff --git a/test/link_test_2.cpp b/test/link_test_2.cpp
new file mode 100644
index 0000000..ff50e52
--- /dev/null
+++ b/test/link_test_2.cpp
@@ -0,0 +1,10 @@
+
+// Copyright 2005-2009 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"
+
+#include <boost/container_hash/hash.hpp>
+
+int f() { return 0; }
diff --git a/test/namespace_fail_test.cpp b/test/namespace_fail_test.cpp
new file mode 100644
index 0000000..700d074
--- /dev/null
+++ b/test/namespace_fail_test.cpp
@@ -0,0 +1,16 @@
+
+// Copyright 2009 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)
+
+// Check that I haven't inadvertantly pulled namespace std into the global
+// namespace.
+
+#include "./config.hpp"
+
+#include <list>
+#include <boost/container_hash/hash.hpp>
+
+typedef list<int> foo;
+
+int main() {}