We have a legacy requirement to store what are now newly migrated int
ID values into a guid
type for use on ID-agnostic data types (basically old code that took advantage of the "globally unique" part of guid
in order to contain all possible IDs in one column/field).
Due to this requirement, there was a follow-on requirement to embed the integer ID of entites into guid
in a human-readable manner. This is important and is currently what is stopping me from working against the byte values directly.
Currently, I have the following:
public static byte[] IntAsHexBytes(int value)
{
return BitConverter.GetBytes(Convert.ToInt64(value.ToString(), 16));
}
public static Guid EmbedInteger(int id)
{
var ib = IntAsHexBytes(id);
return new Guid(new byte[]
{
0,0,0,0,0,0,1,64,ib[7],ib[6],ib[5],ib[4],ib[3],ib[2],ib[1],ib[0]
});
}
It treats the visual representation of the int
as a hex value (value.ToString()
), converts that to a long
(Convert.ToInt64(value.ToString(), 16)
) and the grabs the bytes from the long
into a flattened byte[]
for creating a guid
in a particular structure.
So given an int
of 42, when you treat 42 as a hex and convert that to an long
you get 66, and on to the bytes of 66 gives, placing into a guid
gives:
"00000000-0000-4001-0000-000000000042"
And an int
of 379932126
gives:
"00000000-0000-4001-0000-000379932126"
So the end result is to place the integer into the guid
in the last 12 digits so it visually looks like the integer 42 (even though the underlying integer value was 66).
This is roughly 30%-40% faster than constructing a string using concatenation in order to feed into the new Guid(string)
constructor, but I feel I'm missing the solution that avoids having to do anything with strings in the first place.
The actual timings involved are quite small so as a performance improvement it probably won't justify the effort.
This is purely for the sake of my own curiosity to see if there are faster ways of tackling this problem. I posted here as I'm a long-standing SO user, but I'm torn as to whether this is a code-review-ish question, though I'm not asking for anything against my code directly, it just demonstrates what I want as output.
The integer range being supplied is 0 to int.MaxValue
.
Update: For completeness, this is what we currently have and what I'm testing against:
string s = string.Format("00000000-0000-4001-0000-{0:D12}", id);
return new Guid(s);
My other code above is faster than this by around 30%.
Ok, here's another version which completely avoids strings. Hopefully this might be better. :)
public static Guid EmbedInteger(int id)
{
byte[] bytes = new byte[8];
int i = 0;
while (id > 0)
{
int remainder = id%100;
bytes[i++] = (byte)(16*(remainder/10) + remainder%10);
id /= 100;
}
return new Guid(0, 0, 0x4001, bytes[7], bytes[6], bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]);
}
Adam Houldsworth: Update: This code can also be unrolled:
int remainder = id % 100;
bytes[0] = (byte)(16 * (remainder / 10) + remainder % 10);
id /= 100;
if (id == 0) return;
remainder = id % 100;
bytes[1] = (byte)(16 * (remainder / 10) + remainder % 10);
id /= 100;
if (id == 0) return;
remainder = id % 100;
bytes[2] = (byte)(16 * (remainder / 10) + remainder % 10);
id /= 100;
if (id == 0) return;
remainder = id % 100;
bytes[3] = (byte)(16 * (remainder / 10) + remainder % 10);
id /= 100;
if (id == 0) return;
remainder = id % 100;
bytes[4] = (byte)(16 * (remainder / 10) + remainder % 10);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With