In the standard, not the code. The standard's roundtrip
conversion guarantee guarantees uniqueness when the integer is
of sufficient of size.
So the standard guarantees something that isn't in the code. I
don't see how that affects the code. (There's also a slight
ambiguity in the standard---it says that after the round trip,
the pointer "will have its original value". I presume that this
means that it will compare equal to the original value, and
refer to the same place in memory. But I suppose that it could
be interpreted to mean that it would have the same bit pattern.
Either way, it's irrelevant here.)
The guarantee needed here is that two pointers which compare
equal will result in the same value when converted to an integer
(of sufficient size). Which has nothing to do with round trip.
Consider a very real case: on the Intel segmented architecture,
pointers consist of two parts: a segment and an offset. In real
mode (used at least until very recently in embedded processors),
the actual address is 16*segment+offset (all arithmetic
unsigned), so something like 0x1000:0x10 and 0x1001:0x0 point to
the same memory. And compare equal. When converted to a 32 bit
integer, however, one results in 0x10000010, and the other in
0x10010000. Two values which will not result in the same hash
code (although converting back to the initial pointer type will
result in the same value).
Also, machines with "large" pointers may not use all of the bits
in an address, masking out the irrelevant bits when comparing
pointers, but not when converting to integers. The classic
example of this is the IBM 360, which only used 24 bits of the
32 bits in a pointer for addressing---I believe that even the
latest IBM mainframes have a mode supporting this, to avoid
breaking old code. Comparing pointers masked off these bits,
converting them to an integer wouldn't (since it was common
practice back then to use them for additional information, to
save memory). And while I doubt you'll find such things in
modern 32 bit machines, it wouldn't surprise me if the still
existed in machines with larger word sizes (e.g. Unisys MP
series, etc.).
The standard again (direct quote). Whether the Boost code uses
integer types of "sufficient size" for all compilers
supported, is a different matter. But one would tend to think
that they do perform unit-testing?
On the few systems they support. Hopefully. (I don't know if
the issue has improved, but Boost didn't compile under Solaris,
on a Sparc, for a long time.)
Hm, I can't imagine that it didn't offer 32-bit integers.
They did.
And if did (or does, it it still exists) then all that's
needed for the Boost code is a platform-dependent typedef for
the integer type they cast to, plus a possible "gather the
significant bits" conversion "down" to size_t, if they choose
to still use size_t as the hash function result type.
The rest is then taken care of by the standard's guarantees.
Not at all. Where do you find a guarantee (direct or indirect)
that if two pointers compare equal, the resulting integers will
compare equal after conversions? It just isn't the case,
neither on Intel with far pointers, nor on IBM mainframes
running in compatibility mode.
Perhaps one should CC Dave Harris and Alberto Barbati.
However, I leave that to you.
Ah, portability. There is the formal portability, where one
writes standard C++ code and hopes for the boost, eh, beest.
And then there is in-practice portability, where one realizes
that with the possible exception of Comeau no current C++
compiler is sufficiently standard-conforming to make relying
on only formal portability realistic, so one adds compiler and
platform-dependent fixes.
Certainly. Practically all of my code assumes at least 32 bits
for int, for example. Although I know of (and have used)
implementations where this is not the case. In practice, it's
very, very rare to need to be portable to literally everything.
The standard libraries are an exception, of course. (One of the
justifications for putting something in the standard library is
that it cannot be implemented portably in the language: things
like offsetof, or std::less of a pointer---now that the standard
has hash tables, it probably should provide a "standard"
function to obtain a hash value of a pointer. For any given
implementation, it's certainly possible; for many, it's as
trivial as casting to std::size_t; but there's no way a user can
write it and be sure. But I see they did, §20.6.17 in the
draft.)
Chasing after the formal portability that would turn out to
also be in-practice portability is, IMHO, futile as a real
goal, for it can be (extremely) much more work to try to
shoehorn code into the straightjacket of formally portable;
instead it's only a strong guideline, something that can help
greatly with the in-practice portability *if* one understands
that going too far can have the opposite effect, not helping
but rather just generating extra, needless work.
Agreed. Different code has different portability requirements;
a lot of the code I write professionally makes extensive use of
pthread_mutex_t, for example, which isn't available on one of
the implementations I use at home.
If I raised the question of portability with regards to hashing
pointers, it's because it has been a real problem for me, in
practice. I've worked on implementations where simply
converting the pointer to an integer (of the appropriate size)
didn't work. And I'm aware of others where it won't work.
I gather that if your portability concern should turn out to
be a real issue, i.e. there is some commonly used C++ compiler
where the Boost code fails, then the Boost solution will be in
the direction I outlined above, purely practical.
I've used compilers where the Boost code fails. In practice, it
will work under Windows and Linux on a PC; it will probably work
on most, if not all, desktop computers. There are probably
mainframes, and almost certainly embedded processors, on which
it will fail.
And so it doesn't really matter if the standard supports
hashing of pointers in the same way for all compilers (formal
portability that is also practical portability with conforming
compilers), although it's nice that C++0x adds that.
Agreed. Let the standard library implementors worry about it,
not us.