Young Hyun
9/22/2006 5:52:00 PM
On Sep 22, 2006, at 8:56 AM, Francis Cianfrocca wrote:
> On 9/22/06, Francis Cianfrocca <garbagecat10@gmail.com> wrote:
>> All,
>> does Ruby have a way to convert 64-bit integers to and from network
>> order in a platform-independent way?
>>
>> For 32-bit ints, I can use [value].pack("N"). The conversion operator
>> for 64-bit ints ("Q") doesn't have a network-order variant. (I assume
>> this is because the underlying byte-order converters (htons/htonl)
>> don't
>> have a 64-bit version on 32-bit platforms.)
>>
>
> Thanks, guys. I sort of figured I'd have to hack it. Ara, I thought of
> your approach (detecting endian-ness locally) but really hoped I could
> avoid it! (Ghostbusters: "I feel so funky.")
>
> Combining your approach with Dave's (and passing both through several
> additional processing stages), I end up with:
>
> #--------------------------------------
> BigEndian = [1].pack("s") == [1].pack("n")
>
> def htonq value
> BigEndian ? val : ([val].pack("Q").reverse.unpack("Q").first)
> end
> #--------------------------------------
>
> and of course ntohq is identical to htonq.
Funny, I wrote almost exactly the above code just recently. But, it
may not be necessary. Depending on your situation, you might
consider using the "w" (BER-compressed integer) packing directive
instead. It guarantees that arbitrarily long integers are stored in
a standard way (big endian). The caveats are (1) it produces
variable-length packed strings and (2) it only supports positive
integers. However, because BER-compressed integers are self-
describing, in the sense that you can determine when you've reached
the end of the encoded string, you could get around the first
limitation (if it proves to be a limitation for your usage scenario)
by left justifying the BER-compressed integer in a fixed field. For
my situation, I just changed the definition of my wire protocol to
support variable-length "w"-encoded strings and didn't bother left
justifying.
--Young