Created
May 10, 2023 16:06
-
-
Save razielanarki/e7554d7a725a2a99a5c5fec6d556a33d to your computer and use it in GitHub Desktop.
C++23 GUID parsing + literals
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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