Skip to content

Instantly share code, notes, and snippets.

@razielanarki
Created May 10, 2023 16:06
Show Gist options
  • Save razielanarki/e7554d7a725a2a99a5c5fec6d556a33d to your computer and use it in GitHub Desktop.
Save razielanarki/e7554d7a725a2a99a5c5fec6d556a33d to your computer and use it in GitHub Desktop.
C++23 GUID parsing + literals
#pragma once
#include <concepts> // std::integral
#include <charconv> // std::from_chars, std::from_chars_result
#include <system_error> // std::errc, std::make_error_condition
#include <format> // std::format
#ifndef GUID_DEFINED
#define GUID_DEFINED
typedef struct _GUID
{
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
} GUID;
#endif
namespace util::guid
{
namespace details
{
template<std::integral I>
inline constexpr std::errc parse( const char*&ptr, I &value )
{
std::from_chars_result result = std::from_chars( ptr, ptr + ( sizeof( I ) * 2 ), value, 16 );
ptr = result.ptr;
return result.ec;
}
inline constexpr bool peek( const char*&ptr, const char expect )
{
return ( *ptr == expect );
}
inline constexpr std::errc expect( const char*&ptr, const char expect )
{
return ( *ptr++ == expect ) ? std::errc() : std::errc::invalid_argument;
}
} // namespace details
#define _EXPECT( _char ) \
{ \
auto errc = details::expect( pos, _char ); \
if ( errc != std::errc() ) \
throw std::domain_error( std::format( \
"parse_guid: expected '{}' at pos {} in \"{}\"", \
#_char, \
pos - string, string \
) ); \
}
#define _PARSE( _member ) \
{ \
auto errc = details::parse( pos, _member ); \
if ( errc != std::errc() ) \
throw std::domain_error( std::format( \
"parse_guid: '{}' parsing member '{}' at pos {} in '{}'", \
std::make_error_condition( errc ).message(), \
#_member, \
pos - string, string \
) ); \
}
constexpr GUID parse_guid( const char *string )
{
GUID guid{};
const char* pos = string;
bool longform = details::peek( pos, '{' );
if( longform ) _EXPECT ( '{' );
_PARSE( guid.Data1 );
_EXPECT( '-' );
_PARSE( guid.Data2 );
_EXPECT( '-' );
_PARSE( guid.Data3 );
_EXPECT( '-' );
_PARSE( guid.Data4[0] );
_PARSE( guid.Data4[1] );
_EXPECT( '-' );
_PARSE( guid.Data4[2] );
_PARSE( guid.Data4[3] );
_PARSE( guid.Data4[4] );
_PARSE( guid.Data4[5] );
_PARSE( guid.Data4[6] );
_PARSE( guid.Data4[7] );
if( longform )
_EXPECT( '}' );
_EXPECT( '\0' );
return guid;
}
#undef _EXPECT
#undef _PARSE
constexpr GUID operator"" _guid(const char* string, size_t)
{
return parse_guid( string );
}
/** /
inline auto l = "{01234567-0123-0123-0123-010203040506}"_guid;
inline auto s = "01234567-0123-0123-0123-010203040506"_guid;
inline auto p = parse_guid( "{01234567-0123-0123-0123-010203040506}" );
inline auto x = "{01234567-0123-0123-0123-010203040506"_guid;
inline auto y = "{01234567-0123-0123-0123-010203040506}andsome"_guid;
inline auto z = "thisisnotaguid"_guid;
/**/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment