allow basic_string_view parameter

- uuid::is_valid_uuid
- uuid::from_string
- uuid_name_generator::operator()
This commit is contained in:
Tushar Maheshwari 2021-05-16 13:18:21 +05:30
parent 5890c94bfa
commit b16884a774
3 changed files with 189 additions and 79 deletions

View File

@ -82,9 +82,19 @@ namespace uuids
} }
template <typename TChar> template <typename TChar>
constexpr inline unsigned char hexpair2char(TChar const a, TChar const b) constexpr std::basic_string_view<TChar> to_string_view(TChar const * str)
{ {
return (hex2char(a) << 4) | hex2char(b); if (str) return str;
return {};
}
template <typename StringType>
constexpr std::basic_string_view<
typename StringType::value_type,
typename StringType::traits_type>
to_string_view(StringType const & str)
{
return str;
} }
class sha1 class sha1
@ -348,17 +358,14 @@ namespace uuids
public: public:
using value_type = uint8_t; using value_type = uint8_t;
constexpr uuid() noexcept : data({}) {}; constexpr uuid() noexcept = default;
uuid(value_type(&arr)[16]) noexcept uuid(value_type(&arr)[16]) noexcept
{ {
std::copy(std::cbegin(arr), std::cend(arr), std::begin(data)); std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
} }
uuid(std::array<value_type, 16> const & arr) noexcept constexpr uuid(std::array<value_type, 16> const & arr) noexcept : data{arr} {}
{
std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
}
explicit uuid(span<value_type, 16> bytes) explicit uuid(span<value_type, 16> bytes)
{ {
@ -416,29 +423,25 @@ namespace uuids
return span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16); return span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16);
} }
template<class CharT = char> template <typename StringType>
static bool is_valid_uuid(CharT const * str) noexcept constexpr static bool is_valid_uuid(StringType const & in_str) noexcept
{ {
auto str = detail::to_string_view(in_str);
bool firstDigit = true; bool firstDigit = true;
int hasBraces = 0; int hasBraces = 0;
size_t index = 0; size_t index = 0;
size_t size = 0;
if constexpr(std::is_same_v<CharT, char>)
size = strlen(str);
else
size = wcslen(str);
if (str == nullptr || size == 0) if (str.empty())
return false; return false;
if (str[0] == static_cast<CharT>('{')) if (str.front() == '{')
hasBraces = 1; hasBraces = 1;
if (hasBraces && str[size - 1] != static_cast<CharT>('}')) if (hasBraces && str.back() != '}')
return false; return false;
for (size_t i = hasBraces; i < size - hasBraces; ++i) for (size_t i = hasBraces; i < str.size() - hasBraces; ++i)
{ {
if (str[i] == static_cast<CharT>('-')) continue; if (str[i] == '-') continue;
if (index >= 16 || !detail::is_hex(str[i])) if (index >= 16 || !detail::is_hex(str[i]))
{ {
@ -464,39 +467,26 @@ namespace uuids
return true; return true;
} }
template<class CharT = char, template <typename StringType>
class Traits = std::char_traits<CharT>, constexpr static std::optional<uuid> from_string(StringType const & in_str) noexcept
class Allocator = std::allocator<CharT>>
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator> const & str) noexcept
{ {
return is_valid_uuid(str.c_str()); auto str = detail::to_string_view(in_str);
}
template<class CharT = char>
static std::optional<uuid> from_string(CharT const * str) noexcept
{
CharT digit = 0;
bool firstDigit = true; bool firstDigit = true;
int hasBraces = 0; int hasBraces = 0;
size_t index = 0; size_t index = 0;
size_t size = 0;
if constexpr(std::is_same_v<CharT, char>)
size = strlen(str);
else
size = wcslen(str);
std::array<uint8_t, 16> data{ { 0 } }; std::array<uint8_t, 16> data{ { 0 } };
if (str == nullptr || size == 0) return {}; if (str.empty()) return {};
if (str[0] == static_cast<CharT>('{')) if (str.front() == '{')
hasBraces = 1; hasBraces = 1;
if (hasBraces && str[size - 1] != static_cast<CharT>('}')) if (hasBraces && str.back() != '}')
return {}; return {};
for (size_t i = hasBraces; i < size - hasBraces; ++i) for (size_t i = hasBraces; i < str.size() - hasBraces; ++i)
{ {
if (str[i] == static_cast<CharT>('-')) continue; if (str[i] == '-') continue;
if (index >= 16 || !detail::is_hex(str[i])) if (index >= 16 || !detail::is_hex(str[i]))
{ {
@ -505,12 +495,12 @@ namespace uuids
if (firstDigit) if (firstDigit)
{ {
digit = str[i]; data[index] = detail::hex2char(str[i]) << 4;
firstDigit = false; firstDigit = false;
} }
else else
{ {
data[index++] = detail::hexpair2char(digit, str[i]); data[index++] |= detail::hex2char(str[i]);
firstDigit = true; firstDigit = true;
} }
} }
@ -520,7 +510,7 @@ namespace uuids
return {}; return {};
} }
return uuid{ std::cbegin(data), std::cend(data) }; return uuid{ data };
} }
template<class CharT = char, template<class CharT = char,
@ -769,27 +759,11 @@ namespace uuids
: nsuuid(namespace_uuid) : nsuuid(namespace_uuid)
{} {}
template<class CharT = char> template <typename StringType>
uuid operator()(CharT const * name) uuid operator()(StringType const & name)
{
size_t size = 0;
if constexpr (std::is_same_v<CharT, char>)
size = strlen(name);
else
size = wcslen(name);
reset();
process_characters(name, size);
return make_uuid();
}
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
uuid operator()(std::basic_string<CharT, Traits, Allocator> const & name)
{ {
reset(); reset();
process_characters(name.data(), name.size()); process_characters(detail::to_string_view(name));
return make_uuid(); return make_uuid();
} }
@ -802,24 +776,20 @@ namespace uuids
std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes); std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes);
hasher.process_bytes(bytes, 16); hasher.process_bytes(bytes, 16);
} }
template <typename char_type,
typename = std::enable_if_t<std::is_integral<char_type>::value>>
void process_characters(char_type const * const characters, size_t const count)
{
for (size_t i = 0; i < count; i++)
{
uint32_t c = characters[i];
hasher.process_byte(static_cast<unsigned char>((c >> 0) & 0xFF));
hasher.process_byte(static_cast<unsigned char>((c >> 8) & 0xFF));
hasher.process_byte(static_cast<unsigned char>((c >> 16) & 0xFF));
hasher.process_byte(static_cast<unsigned char>((c >> 24) & 0xFF));
}
}
void process_characters(const char * const characters, size_t const count) template <typename CharT, typename Traits>
void process_characters(std::basic_string_view<CharT, Traits> const str)
{ {
hasher.process_bytes(characters, count); for (uint32_t c : str)
{
hasher.process_byte(static_cast<uint8_t>(c & 0xFF));
if constexpr (!std::is_same_v<CharT, char>)
{
hasher.process_byte(static_cast<uint8_t>((c >> 8) & 0xFF));
hasher.process_byte(static_cast<uint8_t>((c >> 16) & 0xFF));
hasher.process_byte(static_cast<uint8_t>((c >> 24) & 0xFF));
}
}
} }
uuid make_uuid() uuid make_uuid()

View File

@ -254,6 +254,49 @@ TEST_CASE("Test name generator (std::string)", "[gen][name]")
REQUIRE(id3 != id4); REQUIRE(id3 != id4);
} }
TEST_CASE("Test name generator (std::string_view)", "[gen][name]")
{
using namespace std::string_view_literals;
uuids::uuid_name_generator dgen(uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value());
auto id1 = dgen("john"sv);
REQUIRE(!id1.is_nil());
REQUIRE(id1.version() == uuids::uuid_version::name_based_sha1);
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
auto id2 = dgen("jane"sv);
REQUIRE(!id2.is_nil());
REQUIRE(id2.version() == uuids::uuid_version::name_based_sha1);
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
auto id3 = dgen("jane"sv);
REQUIRE(!id3.is_nil());
REQUIRE(id3.version() == uuids::uuid_version::name_based_sha1);
REQUIRE(id3.variant() == uuids::uuid_variant::rfc);
auto id4 = dgen(L"jane"sv);
REQUIRE(!id4.is_nil());
REQUIRE(id4.version() == uuids::uuid_version::name_based_sha1);
REQUIRE(id4.variant() == uuids::uuid_variant::rfc);
REQUIRE(id1 != id2);
REQUIRE(id2 == id3);
REQUIRE(id3 != id4);
}
TEST_CASE("Test name generator equality (char const*, std::string, std::string_view)", "[gen][name]")
{
using namespace std::literals;
uuids::uuid_name_generator dgen(uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value());
auto id1 = dgen("john");
auto id2 = dgen("john"s);
auto id3 = dgen("john"sv);
REQUIRE(id1 == id2);
REQUIRE(id2 == id3);
}
#ifdef _WIN32 #ifdef _WIN32
TEST_CASE("Test time generator", "[gen][time]") TEST_CASE("Test time generator", "[gen][time]")
{ {

View File

@ -100,6 +100,20 @@ TEST_CASE("Test is_valid_uuid(basic_string)", "[parse]")
} }
} }
TEST_CASE("Test is_valid_uuid(basic_string_view)", "[parse]")
{
using namespace std::string_view_literals;
REQUIRE(uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e43"sv));
REQUIRE(uuids::uuid::is_valid_uuid("{47183823-2574-4bfd-b411-99ed177d3e43}"sv));
REQUIRE(uuids::uuid::is_valid_uuid(L"47183823-2574-4bfd-b411-99ed177d3e43"sv));
REQUIRE(uuids::uuid::is_valid_uuid(L"{47183823-2574-4bfd-b411-99ed177d3e43}"sv));
REQUIRE(uuids::uuid::is_valid_uuid("00000000-0000-0000-0000-000000000000"sv));
REQUIRE(uuids::uuid::is_valid_uuid("{00000000-0000-0000-0000-000000000000}"sv));
REQUIRE(uuids::uuid::is_valid_uuid(L"00000000-0000-0000-0000-000000000000"sv));
REQUIRE(uuids::uuid::is_valid_uuid(L"{00000000-0000-0000-0000-000000000000}"sv));
}
TEST_CASE("Test is_valid_uuid(char*) invalid format", "[parse]") TEST_CASE("Test is_valid_uuid(char*) invalid format", "[parse]")
{ {
REQUIRE(!uuids::uuid::is_valid_uuid("")); REQUIRE(!uuids::uuid::is_valid_uuid(""));
@ -145,6 +159,18 @@ TEST_CASE("Test is_valid_uuid(basic_string) invalid format", "[parse]")
} }
} }
TEST_CASE("Test is_valid_uuid(basic_string_view) invalid format", "[parse]")
{
using namespace std::string_view_literals;
REQUIRE(!uuids::uuid::is_valid_uuid(""sv));
REQUIRE(!uuids::uuid::is_valid_uuid("{}"sv));
REQUIRE(!uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e4"sv));
REQUIRE(!uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e430"sv));
REQUIRE(!uuids::uuid::is_valid_uuid("{47183823-2574-4bfd-b411-99ed177d3e43"sv));
REQUIRE(!uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e43}"sv));
}
TEST_CASE("Test from_string(char*)", "[parse]") TEST_CASE("Test from_string(char*)", "[parse]")
{ {
{ {
@ -219,7 +245,7 @@ TEST_CASE("Test from_string(basic_string)", "[parse]")
} }
{ {
auto guid = uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value(); auto guid = uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43"s).value();
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43"); REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
REQUIRE(uuids::to_string<wchar_t>(guid) == L"47183823-2574-4bfd-b411-99ed177d3e43"); REQUIRE(uuids::to_string<wchar_t>(guid) == L"47183823-2574-4bfd-b411-99ed177d3e43");
} }
@ -261,6 +287,65 @@ TEST_CASE("Test from_string(basic_string)", "[parse]")
} }
} }
TEST_CASE("Test from_string(basic_string_view)", "[parse]")
{
using namespace std::string_view_literals;
{
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"sv;
auto guid = uuids::uuid::from_string(str).value();
REQUIRE(uuids::to_string(guid) == str);
}
{
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43}"sv;
auto guid = uuids::uuid::from_string(str).value();
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
}
{
auto guid = uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43"sv).value();
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
REQUIRE(uuids::to_string<wchar_t>(guid) == L"47183823-2574-4bfd-b411-99ed177d3e43");
}
{
auto str = L"47183823-2574-4bfd-b411-99ed177d3e43"sv;
auto guid = uuids::uuid::from_string(str).value();
REQUIRE(uuids::to_string<wchar_t>(guid) == str);
}
{
auto str = "4718382325744bfdb41199ed177d3e43"sv;
REQUIRE_NOTHROW(uuids::uuid::from_string(str));
REQUIRE(uuids::uuid::from_string(str).has_value());
}
{
auto str = "00000000-0000-0000-0000-000000000000"sv;
auto guid = uuids::uuid::from_string(str).value();
REQUIRE(guid.is_nil());
}
{
auto str = "{00000000-0000-0000-0000-000000000000}"sv;
auto guid = uuids::uuid::from_string(str).value();
REQUIRE(guid.is_nil());
}
{
auto str = L"00000000-0000-0000-0000-000000000000"sv;
auto guid = uuids::uuid::from_string(str).value();
REQUIRE(guid.is_nil());
}
{
auto str = L"{00000000-0000-0000-0000-000000000000}"sv;
auto guid = uuids::uuid::from_string(str).value();
REQUIRE(guid.is_nil());
}
}
TEST_CASE("Test from_string(char*) invalid format", "[parse]") TEST_CASE("Test from_string(char*) invalid format", "[parse]")
{ {
REQUIRE(!uuids::uuid::from_string("").has_value()); REQUIRE(!uuids::uuid::from_string("").has_value());
@ -306,6 +391,18 @@ TEST_CASE("Test from_string(basic_string) invalid format", "[parse]")
} }
} }
TEST_CASE("Test from_string(basic_string_view) invalid format", "[parse]")
{
using namespace std::string_view_literals;
REQUIRE(!uuids::uuid::from_string(""sv).has_value());
REQUIRE(!uuids::uuid::from_string("{}"sv).has_value());
REQUIRE(!uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e4"sv).has_value());
REQUIRE(!uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e430"sv).has_value());
REQUIRE(!uuids::uuid::from_string("{47183823-2574-4bfd-b411-99ed177d3e43"sv).has_value());
REQUIRE(!uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43}"sv).has_value());
}
TEST_CASE("Test iterators constructor", "[ctors]") TEST_CASE("Test iterators constructor", "[ctors]")
{ {
using namespace std::string_literals; using namespace std::string_literals;