mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
* #227 Hash function for enums * Move enum hash definition to bottom, so gcc doesn't complain about it * Explicitly specify etl hash Co-authored-by: Jesse <jli@planarmotor.com>
This commit is contained in:
parent
5aa14f85aa
commit
a38a8fc33c
@ -86,13 +86,40 @@ namespace etl
|
||||
return fnv_1a_64(begin, end);
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
/// Primary definition of base hash class, by default is poisoned
|
||||
//*************************************************************************
|
||||
template<typename T, bool IsEnum=false>
|
||||
struct hash_base {
|
||||
private:
|
||||
hash_base(); // can't default construct
|
||||
hash_base(const hash_base& other); // can't copy construct
|
||||
hash_base& operator=(const hash_base& other); // can't copy assign
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
hash_base(hash_base&& other); // can't move construct
|
||||
hash_base& operator=(hash_base&& other); // can't move assign
|
||||
#endif
|
||||
};
|
||||
|
||||
// Specialization for enums depends on definitions for integers, so it comes later
|
||||
}
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
//***************************************************************************
|
||||
/// Generic declaration for etl::hash, including default for enums
|
||||
///\ingroup hash
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
struct hash : private_hash::hash_base<T, etl::is_enum<T>::value>{};
|
||||
#else
|
||||
//***************************************************************************
|
||||
/// Generic declaration for etl::hash
|
||||
///\ingroup hash
|
||||
//***************************************************************************
|
||||
template <typename T> struct hash;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
/// Specialisation for bool.
|
||||
@ -436,6 +463,23 @@ namespace etl
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
namespace private_hash {
|
||||
//*************************************************************************
|
||||
/// Specialization for enums
|
||||
//*************************************************************************
|
||||
template<typename T>
|
||||
struct hash_base<T, true>{
|
||||
size_t operator()(T v) const
|
||||
{
|
||||
if (sizeof(size_t) >= sizeof(T)) {
|
||||
return static_cast<size_t>(v);
|
||||
} else {
|
||||
return ::etl::hash<unsigned long long>{}(static_cast<unsigned long long>(v));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ETL_USING_8BIT_TYPES
|
||||
|
||||
@ -28,6 +28,7 @@ SOFTWARE.
|
||||
|
||||
#include "unit_test_framework.h"
|
||||
|
||||
#include <type_traits>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -35,8 +36,21 @@ SOFTWARE.
|
||||
|
||||
#include "etl/hash.h"
|
||||
|
||||
// for testing user-defined hash specializations
|
||||
namespace { class CustomType{}; }
|
||||
namespace etl
|
||||
{
|
||||
template <>
|
||||
struct hash<CustomType>
|
||||
{
|
||||
size_t operator()(CustomType) {return 0;}
|
||||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
||||
SUITE(test_hash)
|
||||
{
|
||||
//*************************************************************************
|
||||
@ -213,6 +227,56 @@ namespace
|
||||
|
||||
CHECK_EQUAL(size_t(&i), hash);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_hash_enums)
|
||||
{
|
||||
enum class MyEnumClass : char {
|
||||
OneE = 0x1E
|
||||
};
|
||||
enum MyEnum : char {
|
||||
MyEnum_TwoF = 0x2F
|
||||
};
|
||||
|
||||
size_t hash = etl::hash<MyEnumClass>()(MyEnumClass::OneE);
|
||||
CHECK_EQUAL(static_cast<size_t>(MyEnumClass::OneE), hash);
|
||||
|
||||
hash = etl::hash<MyEnum>()(MyEnum_TwoF);
|
||||
CHECK_EQUAL(0x2F, hash);
|
||||
}
|
||||
|
||||
TEST(test_hash_big_enums) {
|
||||
constexpr unsigned long long big_number = 0x5AA555AA3CC333CCULL;
|
||||
enum class MyBigEnumClass : unsigned long long {
|
||||
Big = big_number
|
||||
};
|
||||
size_t hash = etl::hash<MyBigEnumClass>()(MyBigEnumClass::Big);
|
||||
size_t expectedHash = etl::hash<unsigned long long>()(big_number);
|
||||
CHECK_EQUAL(expectedHash, hash);
|
||||
}
|
||||
|
||||
TEST(test_hash_poisoned) {
|
||||
// Unspecialized hash<> should be disabled (unusable) - see https://en.cppreference.com/w/cpp/utility/hash
|
||||
class A {};
|
||||
typedef etl::hash<A> general_hasher;
|
||||
|
||||
CHECK_FALSE(std::is_default_constructible<general_hasher>::value);
|
||||
CHECK_FALSE(std::is_copy_constructible<general_hasher>::value);
|
||||
CHECK_FALSE(std::is_move_constructible<general_hasher>::value);
|
||||
CHECK_FALSE(std::is_copy_assignable<general_hasher>::value);
|
||||
CHECK_FALSE(std::is_move_assignable<general_hasher>::value);
|
||||
}
|
||||
|
||||
|
||||
TEST(test_hash_custom) {
|
||||
typedef etl::hash<CustomType> custom_hasher;
|
||||
|
||||
CHECK_TRUE(std::is_default_constructible<custom_hasher>::value);
|
||||
CHECK_TRUE(std::is_copy_constructible<custom_hasher>::value);
|
||||
CHECK_TRUE(std::is_move_constructible<custom_hasher>::value);
|
||||
CHECK_TRUE(std::is_copy_assignable<custom_hasher>::value);
|
||||
CHECK_TRUE(std::is_move_assignable<custom_hasher>::value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user