Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constructing UUIDs from 2 64 bit integers #113

Open
karlsosha opened this issue Apr 1, 2020 · 7 comments
Open

Constructing UUIDs from 2 64 bit integers #113

karlsosha opened this issue Apr 1, 2020 · 7 comments

Comments

@karlsosha
Copy link

As opened question in stackoverflow suggests it is occasionally highly useful to create UUIDs from a pair of 64 bit integers.

Java provides the mechanism to do so:

UUID test_uuid(long1, long2);

It would be very helpful to be able to do the same with boost::uuid

@Lastique
Copy link
Member

Lastique commented Apr 1, 2020

As noted in the answer on that SO question, I'm opposed to having such a constructor, because it is confusing as to what UUID is the result of such construction. Given the differences in endianness, either users or the UUID constructor would have to convert endianness, neither of which is a good solution.

Just use initialization from bytes or strings.

@Lastique
Copy link
Member

Lastique commented Apr 1, 2020

For reference, P0959R3 currently does not provide such a constructor for std::uuid.

@karlsosha
Copy link
Author

Technically you don't have to perform endianness conversion in order to construct the byte array:

for(size_t i = 0 ; i < 8 ; ++i) {
   upper_byte = (uint8_t) ((upper_64 >> (i*8)) && 0xff);
   lower_byte = (uint8_t) ((lower_64 >>(i*8)) && 0xff);
   uuid_bytes[i] = lower_byte; 
   uuid_bytes[i+8] = upper_byte;
}

Granted that constructing with bytes is faster and constructing from String is necessary but given the existing code base out there constructing from a pair of 64-bit integers is very useful.

@Lastique
Copy link
Member

Lastique commented Apr 1, 2020

The loop you presented is, effectively, endianness conversion. And on little-endian machines it gives the result that is different from the natural byte order. Because of the endianness issue, two 64-bit integers are a bad choice to represent a 128-bit UUID as a binary blob.

Also, as defined by RFC4122, UUID is not a pair of 64-bit integers, it has a number of fields with certain requirements on them. So the constructor from 64-bit integers would not represent the actual UUID structure.

I think, if a code base is constructing UUIDs from a pair of integers, that is not a good practice, and we should not advertise it.

@jeking3
Copy link
Collaborator

jeking3 commented Feb 4, 2022

You can make your own subclass which provides this functionality by writing into the bytes; it doesn't conform to the RFC specification so I am going to close this.

@jeking3 jeking3 closed this as completed Feb 4, 2022
@sutambe
Copy link

sutambe commented Oct 4, 2023

boost uuid uses big-endian storage format (regardless of what machine type it's running on)
The following code works on a little endian machine.

struct UUID {
  boost::uuids::uuid id;
  UUID(uint64_t lower64, uint64_t higher64) {
    for (size_t i = 0; i < 8; ++i) {
      id.data[i] = (higher64 >> ((7 - i) * 8)) & 0xFF;
      id.data[i + 8] = (lower64 >> ((7 - i) * 8)) & 0xFF;
    }
  }
}

@pdimov pdimov reopened this Apr 22, 2024
@pdimov
Copy link
Member

pdimov commented Apr 22, 2024

RFC 4122 is unambiguous that a UUID is big endian (stored with the Most Significant Byte first) when treated as a 128 bit integer, so I think the Java constructor UUID(uint64_t highPart, uint64_t lowPart) got it right, and we might consider adding it.

A constructor from __uint128_t (where available) might also make sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants