Skip to content

Commit

Permalink
Add mixing of hash value to avoid funnels, without compromizing perfo…
Browse files Browse the repository at this point in the history
…rmance.
  • Loading branch information
greg7mdp committed Aug 31, 2016
1 parent 9503de7 commit 88936e2
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 60 deletions.
2 changes: 1 addition & 1 deletion bench.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ The table below display the maximum number of entries that could be added to eac

Both sparse hash implementations, as well as Google's btree_map are significantly more memory efficient than the classic unordered_maps. They are also significantly slower that [Sparsepp](https://github.com/greg7mdp/sparsepp).

If we are willing to sacrifice somea little bit of insertion performance for improved memory efficiency, it is easily done with a simple change in [Sparsepp](https://github.com/greg7mdp/sparsepp) header file `sparsepp.h`. Just change:
If we are willing to sacrifice a little bit of insertion performance for improved memory efficiency, it is easily done with a simple change in [Sparsepp](https://github.com/greg7mdp/sparsepp) header file `sparsepp.h`. Just change:

`#define SPP_ALLOC_SZ 0`

Expand Down
89 changes: 59 additions & 30 deletions sparsepp.h
Original file line number Diff line number Diff line change
Expand Up @@ -926,16 +926,20 @@ namespace SPP_NAMESPACE
{

template <class T>
struct spp_hash : public SPP_HASH_CLASS<T>
struct spp_hash
{
SPP_INLINE size_t operator()(T *__v) const SPP_NOEXCEPT
{
SPP_HASH_CLASS<T> hasher;
return hasher(__v);
}
};

template <class T>
struct spp_hash<T *>
{
static size_t spp_log2 (size_t val) SPP_NOEXCEPT
{
assert(val > 0);
size_t res = 0;
while (val > 1)
{
Expand Down Expand Up @@ -997,25 +1001,25 @@ struct spp_hash<unsigned short> : public std::unary_function<unsigned short, siz
template <>
struct spp_hash<int> : public std::unary_function<int, size_t>
{
SPP_INLINE size_t operator()(int __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v ^ 0xdeadbea6);}
SPP_INLINE size_t operator()(int __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
};

template <>
struct spp_hash<unsigned int> : public std::unary_function<unsigned int, size_t>
{
SPP_INLINE size_t operator()(unsigned int __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v ^ 0xdeadbea6);}
SPP_INLINE size_t operator()(unsigned int __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
};

template <>
struct spp_hash<long> : public std::unary_function<long, size_t>
{
SPP_INLINE size_t operator()(long __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v ^ 0xdeadbea6);}
SPP_INLINE size_t operator()(long __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
};

template <>
struct spp_hash<unsigned long> : public std::unary_function<unsigned long, size_t>
{
SPP_INLINE size_t operator()(unsigned long __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v ^ 0xdeadbea6);}
SPP_INLINE size_t operator()(unsigned long __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
};

template <>
Expand All @@ -1042,35 +1046,35 @@ struct spp_hash<double> : public std::unary_function<double, size_t>
};
#endif

template <class T, int sz> struct Combiner
{
inline void operator()(T& seed, T value);
};
template <class T, int sz> struct Combiner
{
inline void operator()(T& seed, T value);
};

template <class T> struct Combiner<T, 4>
template <class T> struct Combiner<T, 4>
{
inline void operator()(T& seed, T value)
{
inline void operator()(T& seed, T value)
{
seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
};
seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
};

template <class T> struct Combiner<T, 8>
template <class T> struct Combiner<T, 8>
{
inline void operator()(T& seed, T value)
{
inline void operator()(T& seed, T value)
{
seed ^= value + T(0xc6a4a7935bd1e995) + (seed << 6) + (seed >> 2);
}
};
seed ^= value + T(0xc6a4a7935bd1e995) + (seed << 6) + (seed >> 2);
}
};

template <class T>
inline void hash_combine(std::size_t& seed, T const& v)
{
spp::spp_hash<T> hasher;
Combiner<std::size_t, sizeof(std::size_t)> combiner;
template <class T>
inline void hash_combine(std::size_t& seed, T const& v)
{
spp::spp_hash<T> hasher;
Combiner<std::size_t, sizeof(std::size_t)> combiner;

combiner(seed, hasher(v));
}
combiner(seed, hasher(v));
}

};

Expand Down Expand Up @@ -1417,6 +1421,28 @@ namespace sparsehash_internal
typename SizeType, int HT_MIN_BUCKETS>
class sh_hashtable_settings : public HashFunc
{
private:
template <class T, int sz> struct Mixer
{
inline T operator()(T h) const;
};

template <class T> struct Mixer<T, 4>
{
inline T operator()(T h) const
{
return h + (h >> 7) + (h >> 13) + (h >> 23);
}
};

template <class T> struct Mixer<T, 8>
{
inline T operator()(T h) const
{
return h + (h >> 7) + (h >> 13) + (h >> 23) + (h >> 32);
}
};

public:
typedef Key key_type;
typedef HashFunc hasher;
Expand All @@ -1438,7 +1464,10 @@ namespace sparsehash_internal

size_t hash(const key_type& v) const
{
return hasher::operator()(v);
size_t h = hasher::operator()(v);
Mixer<size_t, sizeof(size_t)> mixer;

return mixer(h);
}

float enlarge_factor() const { return enlarge_factor_; }
Expand Down
63 changes: 34 additions & 29 deletions spp_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,19 @@ namespace SPP_NAMESPACE
{

template <class T>
struct spp_hash : public SPP_HASH_CLASS<T>
struct spp_hash
{
SPP_INLINE size_t operator()(T *__v) const SPP_NOEXCEPT
{
SPP_HASH_CLASS<T> hasher;
return hasher(__v);
}
};

template <class T>
struct spp_hash<T *>
{
static size_t spp_log2 (size_t val)
static size_t spp_log2 (size_t val) SPP_NOEXCEPT
{
size_t res = 0;
while (val > 1)
Expand Down Expand Up @@ -194,25 +199,25 @@ struct spp_hash<unsigned short> : public std::unary_function<unsigned short, siz
template <>
struct spp_hash<int> : public std::unary_function<int, size_t>
{
SPP_INLINE size_t operator()(int __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v ^ 0xdeadbea6);}
SPP_INLINE size_t operator()(int __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
};

template <>
struct spp_hash<unsigned int> : public std::unary_function<unsigned int, size_t>
{
SPP_INLINE size_t operator()(unsigned int __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v ^ 0xdeadbea6);}
SPP_INLINE size_t operator()(unsigned int __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
};

template <>
struct spp_hash<long> : public std::unary_function<long, size_t>
{
SPP_INLINE size_t operator()(long __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v ^ 0xdeadbea6);}
SPP_INLINE size_t operator()(long __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
};

template <>
struct spp_hash<unsigned long> : public std::unary_function<unsigned long, size_t>
{
SPP_INLINE size_t operator()(unsigned long __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v ^ 0xdeadbea6);}
SPP_INLINE size_t operator()(unsigned long __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
};

template <>
Expand All @@ -239,35 +244,35 @@ struct spp_hash<double> : public std::unary_function<double, size_t>
};
#endif

template <class T, int sz> struct Combiner
{
inline void operator()(T& seed, T value);
};
template <class T, int sz> struct Combiner
{
inline void operator()(T& seed, T value);
};

template <class T> struct Combiner<T, 4>
template <class T> struct Combiner<T, 4>
{
inline void operator()(T& seed, T value)
{
inline void operator()(T& seed, T value)
{
seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
};
seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
};

template <class T> struct Combiner<T, 8>
template <class T> struct Combiner<T, 8>
{
inline void operator()(T& seed, T value)
{
inline void operator()(T& seed, T value)
{
seed ^= value + T(0xc6a4a7935bd1e995) + (seed << 6) + (seed >> 2);
}
};
seed ^= value + T(0xc6a4a7935bd1e995) + (seed << 6) + (seed >> 2);
}
};

template <class T>
inline void hash_combine(std::size_t& seed, T const& v)
{
spp::spp_hash<T> hasher;
Combiner<std::size_t, sizeof(std::size_t)> combiner;
template <class T>
inline void hash_combine(std::size_t& seed, T const& v)
{
spp::spp_hash<T> hasher;
Combiner<std::size_t, sizeof(std::size_t)> combiner;

combiner(seed, hasher(v));
}
combiner(seed, hasher(v));
}

};

Expand Down

0 comments on commit 88936e2

Please sign in to comment.