Re: [boost] Re: [review] hash functions

----- Mensaje original ----- De: Alberto Barbati <abarbati@iaanus.com> Fecha: Viernes, Marzo 11, 2005 9:01 pm Asunto: [boost] Re: [review] hash functions
Hi,
I have a doubt about the proposed implementation of hash_value() for pointers, which is:
template <class T> inline std::size_t hash_value(T* v) { return static_cast<std::size_t>(v - (T*)0); }
this code calls for undefined behaviour according to §5.7/6, each time v is a non-null pointer.
IMHO, the only reasonable way to map generic pointer values to integer values is through reinterpret_cast<>. The mapping would be implementation-defined, but it would be no worse than the intent of the proposed implementation (if it worked).
Agreed.
To be picky, in order to accomodate with implementations that may have sizeof(size_t) < sizeof(T*), we should use two casts:
template <class T> inline std::size_t hash_value(T* v) { return static_cast<std::size_t>( reinterpret_cast<boost::uintmax_t>(v)); }
(the right thing would be to use a C9X-ish uintptr_t type, but boost/cstdint.hpp does not provide such a type).
However, as the double cast may result in suboptimal code if size_t is large enough, a boost::enable_if trick might be used to provide an optimized version with just a single use of reinterpret_cast. The result would be something similar to:
[...] Please, no SFINAE! This would break not-so-conforming compilers. Let's stick to compilerwise macro-based branches. After all, for the vast majority of platforms (AFAIK) sizeof(size_t)==sizeof(T*)
Unfortunately, there's one more thing... even if p == q, reinterpret_cast<uintmax_t>(p) is not guaranteed to be equal to reinterpret_cast<uintmax_t>(q) on implementations that have multiple internal representations for the same address. I don't think much can be done (in a portable way) for such platforms.
Another reason for resorting to macro-based alternatives, and not to SFINAE. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo

JOAQUIN LOPEZ MU?Z wrote:
De: Alberto Barbati <abarbati@iaanus.com>
I have a doubt about the proposed implementation of hash_value() for pointers, which is:
template <class T> inline std::size_t hash_value(T* v) { return static_cast<std::size_t>(v - (T*)0); }
this code calls for undefined behaviour according to §5.7/6, each time v is a non-null pointer.
Ah... And even if it works, it isn't very good when sizeof(T) is greater than the alignment of T.
IMHO, the only reasonable way to map generic pointer values to integer values is through reinterpret_cast<>. The mapping would be implementation-defined, but it would be no worse than the intent of the proposed implementation (if it worked).
Agreed.
This hash value will have problems with alignment. Although, that won't matter with our containers because we use a prime number of buckets (unless your platform has 53-byte alignment...). But if this hash function is to be general purpose it's worth thinking about.
Please, no SFINAE! This would break not-so-conforming compilers. Let's stick to compilerwise macro-based branches. After all, for the vast majority of platforms (AFAIK) sizeof(size_t)==sizeof(T*)
It would be possible to implement Alberto's suggestion without SFINAE. Daniel
participants (2)
-
Daniel James
-
JOAQUIN LOPEZ MU?Z