diff options
Diffstat (limited to 'ComLightLib/utils')
| -rw-r--r-- | ComLightLib/utils/guid_parse.hpp | 103 | ||||
| -rw-r--r-- | ComLightLib/utils/typeTraits.hpp | 43 |
2 files changed, 146 insertions, 0 deletions
diff --git a/ComLightLib/utils/guid_parse.hpp b/ComLightLib/utils/guid_parse.hpp new file mode 100644 index 0000000..435fcb3 --- /dev/null +++ b/ComLightLib/utils/guid_parse.hpp @@ -0,0 +1,103 @@ +// https://github.com/tobias-loew/constexpr-GUID-cpp-11 + +//------------------------------------------------------------------------------------------------------- +// constexpr GUID parsing +// Written by Alexander Bessonov +// Written by Tobias Loew +// +// 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 ComLight +{ + 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 uint8_t parse_hex_digit( const char c ) + { + using namespace std::string_literals; + return + ( '0' <= c && c <= '9' ) + ? c - '0' + : ( 'a' <= c && c <= 'f' ) + ? 10 + c - 'a' + : ( 'A' <= c && c <= 'F' ) + ? 10 + c - 'A' + : + throw std::domain_error{ "invalid character in GUID"s }; + } + + constexpr uint8_t parse_hex_uint8_t( const char *ptr ) + { + return ( parse_hex_digit( ptr[ 0 ] ) << 4 ) + parse_hex_digit( ptr[ 1 ] ); + } + + constexpr uint16_t parse_hex_uint16_t( const char *ptr ) + { + return ( parse_hex_uint8_t( ptr ) << 8 ) + parse_hex_uint8_t( ptr + 2 ); + } + + constexpr uint32_t parse_hex_uint32_t( const char *ptr ) + { + return ( parse_hex_uint16_t( ptr ) << 16 ) + parse_hex_uint16_t( ptr + 4 ); + } + + constexpr GUID parse_guid( const char *begin ) + { + return GUID{ + parse_hex_uint32_t( begin ), + parse_hex_uint16_t( begin + 8 + 1 ), + parse_hex_uint16_t( begin + 8 + 1 + 4 + 1 ), + { + parse_hex_uint8_t( begin + 8 + 1 + 4 + 1 + 4 + 1 ), + parse_hex_uint8_t( begin + 8 + 1 + 4 + 1 + 4 + 1 + 2 ), + parse_hex_uint8_t( begin + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 ), + parse_hex_uint8_t( begin + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 ), + parse_hex_uint8_t( begin + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2 ), + parse_hex_uint8_t( begin + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2 + 2 ), + parse_hex_uint8_t( begin + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2 + 2 + 2 ), + parse_hex_uint8_t( begin + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2 + 2 + 2 + 2 ) + } + }; + } + + constexpr GUID make_guid_helper( const char *str, size_t N ) + { + using namespace std::string_literals; + using namespace details; + + return ( !( 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 } + : ( N == long_guid_form_length && ( str[ 0 ] != '{' || str[ long_guid_form_length - 1 ] != '}' ) ) + ? throw std::domain_error{ "Missing opening or closing brace"s } + + : parse_guid( str + ( N == long_guid_form_length ? 1 : 0 ) ); + } + + + template<size_t N> + constexpr GUID make_guid( const char( &str )[ N ] ) + { + return make_guid_helper( str, N - 1 ); + } + } + using details::make_guid; +}
\ No newline at end of file diff --git a/ComLightLib/utils/typeTraits.hpp b/ComLightLib/utils/typeTraits.hpp new file mode 100644 index 0000000..c5ddb84 --- /dev/null +++ b/ComLightLib/utils/typeTraits.hpp @@ -0,0 +1,43 @@ +#pragma once +#include <type_traits> + +namespace ComLight +{ + namespace details + { + template<class TResult, class TValue> + constexpr bool pointersAssignable() + { + // See this for why `&` is required: https://stackoverflow.com/a/52429468/126995 + return std::is_assignable<TResult*&, TValue*>::value; + } + } +} + +// https://en.wikibooks.org/wiki/More_C++_Idioms/Member_Detector +#define GENERATE_HAS_MEMBER(member) \ + \ +template < class T > \ +class HasMember_##member \ +{ \ +private: \ + using Yes = char[2]; \ + using No = char[1]; \ + \ + struct Fallback { int member; }; \ + struct Derived : T, Fallback { }; \ + \ + template < class U > \ + static No& test ( decltype(U::member)* ); \ + template < typename U > \ + static Yes& test ( U* ); \ + \ +public: \ + static constexpr bool RESULT = sizeof(test<Derived>(nullptr)) == sizeof(Yes); \ +}; \ + \ +template < class T > \ +struct has_member_##member \ +: public std::integral_constant<bool, HasMember_##member<T>::RESULT> \ +{ \ +}; |
