Skip to content

Commit

Permalink
Request: Compile-Time/Constexpr UUID with literal operator #31
Browse files Browse the repository at this point in the history
  • Loading branch information
chronoxor committed Mar 8, 2024
1 parent 579cf30 commit 0035354
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 60 deletions.
2 changes: 1 addition & 1 deletion documents/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ PROJECT_NAME = CppCommon
# could be handy for archiving the generated documentation or if some version
# control system is used.

PROJECT_NUMBER = 1.0.4.0
PROJECT_NUMBER = 1.0.4.1

# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
Expand Down
2 changes: 1 addition & 1 deletion include/common/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ GitHub: https://github.com/chronoxor/CppCommon
namespace CppCommon {

//! Project version
const char version[] = "1.0.4.0";
const char version[] = "1.0.4.1";

} // namespace CppCommon

Expand Down
7 changes: 7 additions & 0 deletions include/errors/exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ class ArgumentException : public Exception
using Exception::Exception;
};

//! Domain exception
class DomainException : public Exception
{
public:
using Exception::Exception;
};

//! Runtime exception
class RuntimeException : public Exception
{
Expand Down
26 changes: 24 additions & 2 deletions include/system/uuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,24 @@ class UUID
{
public:
//! Default constructor
UUID() : _data() { _data.fill(0); }
constexpr UUID() : _data() { _data.fill(0); }
//! Initialize UUID with a given string literal
/*!
\param uuid - UUID string literal
*/
template<size_t N>
explicit constexpr UUID(const char(&uuid)[N]) : UUID(uuid, N) {}
//! Initialize UUID with a given string literal
/*!
\param uuid - UUID string literal
\param size - UUID string literal size
*/
explicit constexpr UUID(const char* uuid, size_t size);
//! Initialize UUID with a given string
/*!
\param uuid - UUID string
*/
explicit UUID(const std::string& uuid);
explicit UUID(const std::string& uuid) : UUID(uuid.data(), uuid.size()) {}
//! Initialize UUID with a given 16 bytes data buffer
/*!
\param data - UUID 16 bytes data buffer
Expand Down Expand Up @@ -108,6 +120,16 @@ class UUID

} // namespace CppCommon

//! Initialize UUID with a given string literal
/*!
\param uuid - UUID string literal
\param size - UUID string literal size
*/
constexpr CppCommon::UUID operator ""_uuid(const char* uuid, size_t size)
{
return CppCommon::UUID(uuid, size);
}

#include "uuid.inl"

#endif // CPPCOMMON_SYSTEM_UUID_H
56 changes: 56 additions & 0 deletions include/system/uuid.inl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,62 @@

namespace CppCommon {

//! @cond INTERNALS
namespace Internals {

inline constexpr uint8_t unhex(char ch)
{
if ((ch >= '0') && (ch <= '9'))
return ch - '0';
else if ((ch >= 'a') && (ch <= 'f'))
return 10 + ch - 'a';
else if ((ch >= 'A') && (ch <= 'F'))
return 10 + ch - 'A';
else
throwex DomainException("Invalid UUID character");
}

} // namespace Internals
//! @endcond

inline constexpr UUID::UUID(const char* uuid, size_t size)
{
char v1 = 0;
char v2 = 0;
bool pack = false;
size_t index = 0;

// Parse UUID string
for (size_t i = 0; i < size; ++i)
{
char ch = uuid[i];
if ((ch == '-') || (ch == '{') || (ch == '}'))
continue;

if (pack)
{
v2 = ch;
pack = false;
uint8_t ui1 = Internals::unhex(v1);
uint8_t ui2 = Internals::unhex(v2);
if ((ui1 > 15) || (ui2 > 15))
throwex ArgumentException("Invalid UUID literal");
_data[index++] = ui1 * 16 + ui2;
if (index >= 16)
break;
}
else
{
v1 = ch;
pack = true;
}
}

// Fill remaining data with zeros
for (; index < 16; ++index)
_data[index++] = 0;
}

inline void UUID::swap(UUID& uuid) noexcept
{
using std::swap;
Expand Down
55 changes: 0 additions & 55 deletions source/system/uuid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,61 +19,6 @@

namespace CppCommon {

//! @cond INTERNALS
namespace Internals {

uint8_t unhex(char ch)
{
if ((ch >= '0') && (ch <= '9'))
return ch - '0';
else if ((ch >= 'a') && (ch <= 'f'))
return 10 + ch - 'a';
else if ((ch >= 'A') && (ch <= 'F'))
return 10 + ch - 'A';
else
return 255;
}

} // namespace Internals
//! @endcond

UUID::UUID(const std::string& uuid)
{
char v1 = 0;
char v2 = 0;
bool pack = false;
size_t index = 0;

// Parse UUID string
for (auto ch : uuid)
{
if ((ch == '-') || (ch == '{') || (ch == '}'))
continue;

if (pack)
{
v2 = ch;
pack = false;
uint8_t ui1 = Internals::unhex(v1);
uint8_t ui2 = Internals::unhex(v2);
if ((ui1 > 15) || (ui2 > 15))
throwex ArgumentException("Invalid UUID string: " + uuid);
_data[index++] = ui1 * 16 + ui2;
if (index >= 16)
break;
}
else
{
v1 = ch;
pack = true;
}
}

// Fill remaining data with zeros
for (; index < 16; ++index)
_data[index++] = 0;
}

std::string UUID::string() const
{
const char* digits = "0123456789abcdef";
Expand Down
3 changes: 2 additions & 1 deletion tests/test_system_uuid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ using namespace CppCommon;
TEST_CASE("UUID common", "[CppCommon][System]")
{
REQUIRE(UUID().string() == "00000000-0000-0000-0000-000000000000");
REQUIRE("{01234567-89ab-cdef-FEDC-BA9876543210}"_uuid.string() == "01234567-89ab-cdef-fedc-ba9876543210");
REQUIRE(UUID("01234567-89ab-cdef-fedc-ba9876543210").string() == "01234567-89ab-cdef-fedc-ba9876543210");
REQUIRE(UUID("{01234567-89ab-cdef-FEDC-BA9876543210}").string() == "01234567-89ab-cdef-fedc-ba9876543210");
REQUIRE(UUID(std::string("01234567-89ab-cdef-fedc-ba9876543210")).string() == "01234567-89ab-cdef-fedc-ba9876543210");
}

void test_uuid(const UUID& uuid)
Expand Down

0 comments on commit 0035354

Please sign in to comment.