Merge pull request #37 from tusharpm/string_view

Support string_view parameters
This commit is contained in:
Marius Bancila 2021-06-14 09:52:36 +03:00 committed by GitHub
commit 500cd57084
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 210 additions and 97 deletions

View File

@ -1,21 +1,24 @@
language: cpp
compiler: gcc
dist: trusty
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- cppcheck
- g++-8
- uuid-dev
before_install:
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-get update -qq
- sudo apt-cache search libuuid
install:
- sudo apt-get install -qq g++-8
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 90
- sudo apt-get install -qq cppcheck
- sudo apt-get install uuid-dev
before_script:
- cd ${TRAVIS_BUILD_DIR}
- cmake -H. -BBuild -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON -Wdev
- cmake -H. -BBuild -DCMAKE_BUILD_TYPE=Release -Wdev
- cd Build
script:

View File

@ -82,9 +82,19 @@ namespace uuids
}
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
@ -348,17 +358,14 @@ namespace uuids
public:
using value_type = uint8_t;
constexpr uuid() noexcept : data({}) {};
constexpr uuid() noexcept = default;
uuid(value_type(&arr)[16]) noexcept
{
std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
}
uuid(std::array<value_type, 16> const & arr) noexcept
{
std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
}
constexpr uuid(std::array<value_type, 16> const & arr) noexcept : data{arr} {}
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);
}
template<class CharT = char>
static bool is_valid_uuid(CharT const * str) noexcept
template <typename StringType>
constexpr static bool is_valid_uuid(StringType const & in_str) noexcept
{
auto str = detail::to_string_view(in_str);
bool firstDigit = true;
int hasBraces = 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;
if (str[0] == static_cast<CharT>('{'))
if (str.front() == '{')
hasBraces = 1;
if (hasBraces && str[size - 1] != static_cast<CharT>('}'))
if (hasBraces && str.back() != '}')
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]))
{
@ -464,39 +467,26 @@ namespace uuids
return true;
}
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator> const & str) noexcept
template <typename StringType>
constexpr static std::optional<uuid> from_string(StringType const & in_str) noexcept
{
return is_valid_uuid(str.c_str());
}
template<class CharT = char>
static std::optional<uuid> from_string(CharT const * str) noexcept
{
CharT digit = 0;
auto str = detail::to_string_view(in_str);
bool firstDigit = true;
int hasBraces = 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 } };
if (str == nullptr || size == 0) return {};
if (str.empty()) return {};
if (str[0] == static_cast<CharT>('{'))
if (str.front() == '{')
hasBraces = 1;
if (hasBraces && str[size - 1] != static_cast<CharT>('}'))
if (hasBraces && str.back() != '}')
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]))
{
@ -505,12 +495,12 @@ namespace uuids
if (firstDigit)
{
digit = str[i];
data[index] = detail::hex2char(str[i]) << 4;
firstDigit = false;
}
else
{
data[index++] = detail::hexpair2char(digit, str[i]);
data[index++] |= detail::hex2char(str[i]);
firstDigit = true;
}
}
@ -520,15 +510,7 @@ namespace uuids
return {};
}
return uuid{ std::cbegin(data), std::cend(data) };
}
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static std::optional<uuid> from_string(std::basic_string<CharT, Traits, Allocator> const & str) noexcept
{
return from_string(str.c_str());
return uuid{ data };
}
private:
@ -769,27 +751,11 @@ namespace uuids
: nsuuid(namespace_uuid)
{}
template<class CharT = char>
uuid operator()(CharT 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)
template <typename StringType>
uuid operator()(StringType const & name)
{
reset();
process_characters(name.data(), name.size());
process_characters(detail::to_string_view(name));
return make_uuid();
}
@ -802,24 +768,20 @@ namespace uuids
std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes);
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()

View File

@ -254,6 +254,49 @@ TEST_CASE("Test name generator (std::string)", "[gen][name]")
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
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]")
{
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]")
{
{
@ -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<wchar_t>(guid) == L"47183823-2574-4bfd-b411-99ed177d3e43");
}
@ -261,6 +287,73 @@ 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 constexpr from_string", "[const]")
{
constexpr uuid value = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value();
static_assert(!value.is_nil());
static_assert(value.variant() == uuid_variant::rfc);
static_assert(value.version() != uuid_version::none);
}
TEST_CASE("Test from_string(char*) invalid format", "[parse]")
{
REQUIRE(!uuids::uuid::from_string("").has_value());
@ -306,6 +399,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]")
{
using namespace std::string_literals;
@ -463,9 +568,9 @@ TEST_CASE("Test swap", "[ops]")
TEST_CASE("Test constexpr", "[const]")
{
constexpr uuid empty;
[[maybe_unused]] constexpr bool isnil = empty.is_nil();
[[maybe_unused]] constexpr uuids::uuid_variant variant = empty.variant();
[[maybe_unused]] constexpr uuid_version version = empty.version();
static_assert(empty.is_nil());
static_assert(empty.variant() == uuid_variant::ncs);
static_assert(empty.version() == uuid_version::none);
}
TEST_CASE("Test size", "[operators]")