Skip to content

Instantly share code, notes, and snippets.

@kennykerr
Last active Sep 30, 2021
Embed
What would you like to do?
#include <string_view>
#include <exception>
#include <assert.h>
using namespace std::literals;
struct guid
{
uint32_t Data1;
uint16_t Data2;
uint16_t Data3;
uint8_t Data4[8];
};
constexpr bool operator==(guid const& left, guid const& right) noexcept
{
return left.Data1 == right.Data1 &&
left.Data2 == right.Data2 &&
left.Data3 == right.Data3 &&
left.Data4[0] == right.Data4[0] &&
left.Data4[1] == right.Data4[1] &&
left.Data4[2] == right.Data4[2] &&
left.Data4[3] == right.Data4[3] &&
left.Data4[4] == right.Data4[4] &&
left.Data4[5] == right.Data4[5] &&
left.Data4[6] == right.Data4[6] &&
left.Data4[7] == right.Data4[7];
}
constexpr uint32_t to_uint(char const value) noexcept
{
if (value >= '0' && value <= '9')
{
return value - '0';
}
if (value >= 'A' && value <= 'F')
{
return 10 + value - 'A';
}
if (value >= 'a' && value <= 'f')
{
return 10 + value - 'a';
}
std::terminate();
}
constexpr guid make_guid(std::string_view const& value) noexcept
{
if (value.size() != 36 || value[8] != '-' || value[13] != '-' || value[18] != '-' || value[23] != '-')
{
std::terminate();
}
return
{
((to_uint(value[0]) * 16 + to_uint(value[1])) << 24) +
((to_uint(value[2]) * 16 + to_uint(value[3])) << 16) +
((to_uint(value[4]) * 16 + to_uint(value[5])) << 8) +
(to_uint(value[6]) * 16 + to_uint(value[7])),
static_cast<uint16_t>(((to_uint(value[9]) * 16 + to_uint(value[10])) << 8) +
(to_uint(value[11]) * 16 + to_uint(value[12]))),
static_cast<uint16_t>(((to_uint(value[14]) * 16 + to_uint(value[15])) << 8) +
(to_uint(value[16]) * 16 + to_uint(value[17]))),
{
static_cast<uint8_t>(to_uint(value[19]) * 16 + to_uint(value[20])),
static_cast<uint8_t>(to_uint(value[21]) * 16 + to_uint(value[22])),
static_cast<uint8_t>(to_uint(value[24]) * 16 + to_uint(value[25])),
static_cast<uint8_t>(to_uint(value[26]) * 16 + to_uint(value[27])),
static_cast<uint8_t>(to_uint(value[28]) * 16 + to_uint(value[29])),
static_cast<uint8_t>(to_uint(value[30]) * 16 + to_uint(value[31])),
static_cast<uint8_t>(to_uint(value[32]) * 16 + to_uint(value[33])),
static_cast<uint8_t>(to_uint(value[34]) * 16 + to_uint(value[35])),
}
};
}
static constexpr guid a
{ 0x8aa90cad, 0xfed1, 0x4c54, { 0x89, 0xdb, 0x9b, 0x75, 0x22, 0xd8, 0xaa, 0x92 } };
static constexpr guid b
{ make_guid("8AA90CAD-fed1-4c54-89db-9B7522D8AA92"sv) };
static_assert(a == b);
int main()
{
assert(a == b);
}
@DrusTheAxe

This comment has been minimized.

Copy link

@DrusTheAxe DrusTheAxe commented Nov 19, 2020

Any plans to add this to C++/WinRT?
And add wchar_t/wstring flavors?

@kennykerr

This comment has been minimized.

Copy link
Owner Author

@kennykerr kennykerr commented Nov 19, 2020

Hi Howard, if you have a need for this please create an issue and I'll try to knock it off when I get a moment. https://github.com/microsoft/cppwinrt/issues

@DrusTheAxe

This comment has been minimized.

Copy link

@DrusTheAxe DrusTheAxe commented Nov 19, 2020

Ask and ye shall receive :-)
microsoft/cppwinrt#797

@twhall-umich

This comment has been minimized.

Copy link

@twhall-umich twhall-umich commented Sep 30, 2021

Question: Based on the Wikipedia description here:

https://en.wikipedia.org/wiki/Universally_unique_identifier

in the test case above, the first 2 bits of 0x89 (10001001) identify this as "variant 1", which means that the integers should be stored in big-endian order, yes? The MSVC compiler on Intel will assemble the integers in little-endian order. The endianness doesn't matter if the UUIDs are all generated, stored, compared, etc., within a homogeneous MSVC environment, but might matter in some kind of heterogeneous environment -- maybe sending and receiving UUIDs generated on various platforms across the network. If I understand the Wikipedia article correctly, and if the article is correct, either:

  • that 0x89 should start with 0xc_ or 0xd_ (1100hhhh or 1101hhhh) to mark this is "variant 2", or
  • the integers should be swapped to big-endian order.

Yes? No?

The binary encoding of UUIDs varies between systems. Variant 1 UUIDs, nowadays the most common variant, are encoded in a big-endian format. For example, 00112233-4455-6677-8899-aabbccddeeff is encoded as the bytes 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff

Variant 2 UUIDs, historically used in Microsoft's COM/OLE libraries, use a mixed-endian format, whereby the first three components of the UUID are little-endian, and the last two are big-endian. For example, 00112233-4455-6677-8899-aabbccddeeff is encoded as the bytes 33 22 11 00 55 44 77 66 88 99 aa bb cc dd ee ff

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment