diff --git a/src/lib/hash-standard.hpp b/src/lib/hash-standard.hpp index bd8d73173..db3d13073 100644 --- a/src/lib/hash-standard.hpp +++ b/src/lib/hash-standard.hpp @@ -66,7 +66,7 @@ #ifndef LIB_HASH_STANDARD_H #define LIB_HASH_STANDARD_H #ifdef _FUNCTIONAL_HASH_H -#error "unable to hijack std::hash, since has already been included. \ +#error "unable to hijack std::hash, since has already been included. \ Please ensure that lib/hash_standard.hpp is included first, before including or " #endif diff --git a/tests/40core.tests b/tests/40core.tests index 4b2fa7f3f..b1bb40df1 100644 --- a/tests/40core.tests +++ b/tests/40core.tests @@ -361,6 +361,11 @@ return: 0 END +TEST "bridge boost::hash to std::hash" HashStandardToBoostBridge_test < + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +#include "lib/hash-standard.hpp" + +#include +#include +#include +#include +#include + +using std::vector; +using std::string; +using std::cout; +using std::endl; + + +namespace lib { +namespace test{ + + /* == custom data items, each with its own private hash function == */ + + /** + * Custom-Datatype 1: + * uses std::hash extension point + */ + class S + { + string s_; + + friend std::hash; + + public: + S(string ss ="") + : s_(ss) + { } + }; + +}} +// this is ugly: we have to close our own namespace and open namespace std +// for the sole purpose of placing our private hash function into the official extension point + +namespace std { + + using lib::test::S; + + template<> + struct hash + { + size_t + operator() (S const& val) const noexcept + { + hash string_hasher; + return string_hasher(val.s_); + } + }; + +} // and back again into our own namespace... +namespace lib { +namespace test{ + + + + + /** + * Custom-Datatype 2: + * uses boost::hash extension point + */ + class V + { + vector v_; + + public: + V(string ss ="") + { + v_.push_back(ss); + } + + friend size_t + hash_value (V const& v) + { + return boost::hash_value(v.v_); + } + }; + + + + + /***********************************************************************//** + * @test document and verify an automatic bridge to integrate boost-style + * hash functions with the new \c std::hash template. + * Currently (as of 2014) this requires us to "hijack" the standard + * library definition to defeat a static assertion, which otherwise + * would defeat any attempts based on SFINAE + * + * This test builds two custom types, one with a std::hash compliant + * hash function extension point, the other one with a boost::hash style + * custom hash function, to be picked up by ADL. By virtue of the automatic + * bridging template, we're able to use the boost-style definition at places + * where the std::hash is expected -- most notably in STL hashtable containers. + * + * @see hash-standard.hpp + * @see lib::HashIndexed + */ + class HashStandardToBoostBridge_test : public Test + { + + virtual void + run (Arg) + { + checkHashFunctionInvocation(); +// checkHashtableUsage(); + } + + + void + checkHashFunctionInvocation () + { + string p("Путин"), pp(p); + S s(p), ss(pp); + V v(p), vv(pp); + + std::hash std_stringHasher; + boost::hash boo_stringHasher; + + std::hash std_customHasher; + boost::hash boo_customHasher; + + CHECK(0 < std_stringHasher(p)); + CHECK(0 < boo_stringHasher(p)); + CHECK(0 < std_customHasher(p)); + CHECK(0 < boo_customHasher(p)); + + CHECK(std_stringHasher(p) == std_stringHasher(pp)); + CHECK(boo_stringHasher(p) == boo_stringHasher(pp)); + CHECK(std_customHasher(s) == std_customHasher(ss)); + CHECK(boo_customHasher(v) == boo_customHasher(vv)); + + // should be equal too, since the custom impl delegates to the standard string hasher + CHECK(std_stringHasher(p) == std_customHasher(s)); + + + // verify the trait used to build the automatic bridge + CHECK(! lib::meta::provides_BoostHashFunction::value); + CHECK( lib::meta::provides_BoostHashFunction::value); + + //verify the automatic bridge + std::hash boo2std_crossHar; + CHECK(0 < boo2std_crossHar(v)); + + // the std hash function delegates to the boost function... + CHECK(boo2std_crossHar(v) == boo_customHasher(v)); + +// Note: does not compile, +// since there is not automatic bridge to use std::hash from boost::hash +// +// boost::hash()(s); + } + + + + }; + + + /** Register this test class... */ + LAUNCHER (HashStandardToBoostBridge_test, "unit common"); + + +}} // namespace lib::test