Convert some ints into a byte array without allocations?
Samson Smith via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sat Jan 16 10:05:46 PST 2016
On Saturday, 16 January 2016 at 16:28:21 UTC, Jonathan M Davis
wrote:
> On Saturday, January 16, 2016 14:34:54 Samson Smith via
> Digitalmars-d-learn wrote:
>> I'm trying to make a fast little function that'll give me a
>> random looking (but deterministic) value from an x,y position
>> on a grid. I'm just going to run each co-ord that I need
>> through an FNV-1a hash function as an array of bytes since
>> that seems like a fast and easy way to go. I'm going to need
>> to do this a lot and quickly for a real time application so I
>> don't want to waste a lot of cycles converting data or
>> allocating space for an array.
>>
>> In a nutshell how do I cast an int into a byte array?
>>
>> I tried this:
>>
>> byte[] bytes = cast(byte[])x;
>> > Error: cannot cast expression x of type int to byte[]
>>
>> What should I be doing instead?
>
> For this particular case, since you're hashing rather than
> doing something like putting the resulting value on the wire,
> the cast that others suggested may very well be the way to go,
> but the typesafe way to do the conversion would be to use
> std.bitmanip.
>
> int i = 12345;
> auto arr = nativeToBigEndian(i);
>
> where the result is ubyte[4], because the argument was an int.
> If it had been a long, it would have been ubyte[8]. So, you
> avoid bugs where you get the sizes wrong. The only reason that
> I can think of to _not_ do this in your case would be speed,
> simply because you don't care about swapping the endianness
> like you would when sending the data via a socket or whatnot.
> Of course, if you knew that you were always going to be on
> little endian machines, you could also use nativeToLittleEndian
> to avoid the swap, though that still might be slower than a
> simple cast depending on the optimizer (it uses a union
> internally).
>
> But it will be less error-prone to use those functions, and if
> you _do_ actually need to swap endianness, then they're exactly
> what you should be using. We've had cases that have come up
> where using those functions prevented bugs precisely because
> the person writing the code got the sizes wrong (and the
> compiler complained, since nativeToBigEndian and friends deal
> with the sizes in a typesafe manner).
>
> - Jonathan M Davis
If I'm hoping to have my hash come out the same on both bigendian
and littleendian machines but not send the results between
machines, should I take these precautions? I want one machine to
send the other a seed (in an endian safe way) and have both
machines generate the same hashes.
Here's the relevant code:
uint coordHash(int x, int y, uint seed){
seed = FNV1a((cast(ubyte*) &x)[0 .. x.sizeof], seed);
return FNV1a((cast(ubyte*) &y)[0 .. y.sizeof], seed);
}
// Byte order matters for the below function
uint FNV1a(ubyte[] bytes, uint code){
for(int iii = 0; iii < bytes.length; ++iii){
code ^= bytes[iii];
code *= FNV_PRIME_32;
}
return code;
}
Am I going to get the same outcome on all machines or would a
byte array be divided up in reverse order to what I'd expect on
some machines? If it is... I don't mind writing separate versions
depending on endianness with
version(BigEndian)/version(LittleEndian) to get around a runtime
check... I'm just unsure of how endianness factors into the order
of an array...
More information about the Digitalmars-d-learn
mailing list