Skip to content

Instantly share code, notes, and snippets.

@AlexBAV AlexBAV/guid.h
Last active Jun 12, 2019

Embed
What would you like to do?
Constexpr GUID parsing (parsing string GUIDs at compile-time)
//-------------------------------------------------------------------------------------------------------
// constexpr GUID parsing
// Written by Alexander Bessonov
//
// Licensed under the MIT license.
//-------------------------------------------------------------------------------------------------------
#pragma once
#include <stdexcept>
#include <string>
#include <cassert>
#include <cstdint>
#if !defined(GUID_DEFINED)
#define GUID_DEFINED
struct GUID {
uint32_t Data1;
uint16_t Data2;
uint16_t Data3;
uint8_t Data4[8];
};
#endif
namespace guid_parse
{
namespace details
{
constexpr const size_t short_guid_form_length = 36; // XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
constexpr const size_t long_guid_form_length = 38; // {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
//
constexpr int parse_hex_digit(const char c)
{
using namespace std::string_literals;
if ('0' <= c && c <= '9')
return c - '0';
else if ('a' <= c && c <= 'f')
return 10 + c - 'a';
else if ('A' <= c && c <= 'F')
return 10 + c - 'A';
else
throw std::domain_error{ "invalid character in GUID"s };
}
template<class T>
constexpr T parse_hex(const char *ptr)
{
constexpr size_t digits = sizeof(T) * 2;
T result{};
for (size_t i = 0; i < digits; ++i)
result |= parse_hex_digit(ptr[i]) << (4 * (digits - i - 1));
return result;
}
constexpr GUID make_guid_helper(const char *begin)
{
GUID result{};
result.Data1 = parse_hex<uint32_t>(begin);
begin += 8 + 1;
result.Data2 = parse_hex<uint16_t>(begin);
begin += 4 + 1;
result.Data3 = parse_hex<uint16_t>(begin);
begin += 4 + 1;
result.Data4[0] = parse_hex<uint8_t>(begin);
begin += 2;
result.Data4[1] = parse_hex<uint8_t>(begin);
begin += 2 + 1;
for (size_t i = 0; i < 6; ++i)
result.Data4[i + 2] = parse_hex<uint8_t>(begin + i * 2);
return result;
}
template<size_t N>
constexpr GUID make_guid(const char(&str)[N])
{
using namespace std::string_literals;
static_assert(N == (long_guid_form_length + 1) || N == (short_guid_form_length + 1), "String GUID of the form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} or XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX is expected");
if constexpr(N == (long_guid_form_length + 1))
{
if (str[0] != '{' || str[long_guid_form_length - 1] != '}')
throw std::domain_error{ "Missing opening or closing brace"s };
}
return make_guid_helper(str + (N == (long_guid_form_length + 1) ? 1 : 0));
}
}
using details::make_guid;
namespace literals
{
constexpr GUID operator "" _guid(const char *str, size_t N)
{
using namespace std::string_literals;
using namespace details;
if (!(N == long_guid_form_length || N == short_guid_form_length))
throw std::domain_error{ "String GUID of the form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} or XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX is expected"s };
if (N == long_guid_form_length && (str[0] != '{' || str[long_guid_form_length - 1] != '}'))
throw std::domain_error{ "Missing opening or closing brace"s };
return make_guid_helper(str + (N == long_guid_form_length ? 1 : 0));
}
}
}
@AlexBAV

This comment has been minimized.

Copy link
Owner Author

AlexBAV commented Nov 24, 2017

Usage:

constexpr const GUID clsid = guid_parse::make_guid("{EFECF0A1-399E-40B8-A13C-ACE28DB40212}");
@AlexBAV

This comment has been minimized.

Copy link
Owner Author

AlexBAV commented Nov 24, 2017

UDL Usage:

using namespace guid_parse::literals;

constexpr const GUID clsid = "{EFECF0A1-399E-40B8-A13C-ACE28DB40212}"_guid;
@Xeverous

This comment has been minimized.

Copy link

Xeverous commented Nov 27, 2017

I'm concerned by the amount of hardcoded magic integers, and multiple 36 - 39. This looks bad. DRY.

@GamePad64

This comment has been minimized.

@dwcullop

This comment has been minimized.

Copy link

dwcullop commented Nov 13, 2018

Very nicely done. Thank you!

@tobias-loew

This comment has been minimized.

Copy link

tobias-loew commented Dec 21, 2018

Very nice. I used it to make a C++11 constexpr version (https://github.com/tobias-loew/constexpr-GUID-C-11-)

@tobias-loew

This comment has been minimized.

Copy link

tobias-loew commented Dec 21, 2018

I also added a make_uuid and ""_uuid to create boost-uuids. Do you have any objections if I propose this to the boost uuid library?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.