[guid.cpp] Specialise guid<->32-byte string

- string->guid has branch-lite unrollable loop, fallback to slow
  boost parser
- guid->string uses lookup table
- avoids creating several temporary heap-allocated std::strings
pull/2154/head
Christopher Lam 5 months ago
parent 3c5a1801e2
commit 534bea748f

@ -87,6 +87,41 @@ GncGUID * guid_convert_create (gnc::GUID const &);
static gnc::GUID s_null_guid {boost::uuids::uuid { {0}}};
static GncGUID * s_null_gncguid {guid_convert_create (s_null_guid)};
static inline int
char_to_num (unsigned char c) noexcept
{
unsigned int digit = c - '0';
unsigned int alpha = (c | 0x20) - 'a';
return digit <= 9 ? digit : alpha <= 6 ? alpha + 10 : -1;
}
static inline bool
fast_string_to_guid (const char* s, uint8_t* out) noexcept
{
if (strnlen (s, GUID_ENCODING_LENGTH + 1) != GUID_ENCODING_LENGTH) return false;
bool all_ok = true;
for (int i = 0; i < GUID_DATA_SIZE; i++)
{
int hi = char_to_num (*s++);
int lo = char_to_num (*s++);
all_ok &= (hi >= 0 && lo >= 0);
out[i] = (unsigned char)((hi << 4) | lo);
}
return all_ok;
}
static inline void
fast_guid_to_string (const uint8_t* src, char* dest) noexcept
{
static constexpr char hex[] = "0123456789abcdef";
for (size_t i = 0; i < 16; i++)
{
uint8_t b = src[i];
*dest++ = hex[b >> 4];
*dest++ = hex[b & 0x0F];
}
}
/* Memory management routines ***************************************/
/**
@ -164,23 +199,18 @@ gchar *
guid_to_string (const GncGUID * guid)
{
if (!guid) return nullptr;
gnc::GUID temp {*guid};
auto temp_str = temp.to_string ();
return g_strdup (temp_str.c_str ());
char* buffer = g_new (char, GUID_ENCODING_LENGTH + 1);
guid_to_string_buff (guid, buffer);
return buffer;
}
gchar *
guid_to_string_buff (const GncGUID * guid, gchar *str)
{
if (!str || !guid) return nullptr;
gnc::GUID temp {*guid};
auto val = temp.to_string ();
/*We need to be sure to copy the terminating null character.
* The standard guarantees that std::basic_string::c_str ()
* returns with a terminating null character, too.*/
std::copy (val.c_str (), val.c_str () + val.size () + 1, str);
return str + val.size ();
fast_guid_to_string (guid->reserved, str);
str[GUID_ENCODING_LENGTH] = '\0';
return str;
}
gboolean
@ -188,6 +218,9 @@ string_to_guid (const char * str, GncGUID * guid)
{
if (!guid || !str || !*str) return false;
if (fast_string_to_guid (str, guid->reserved))
return true;
try
{
guid_assign (*guid, gnc::GUID::from_string (str));
@ -323,12 +356,10 @@ GUID::null_guid () noexcept
std::string
GUID::to_string () const noexcept
{
auto const & val = boost::uuids::to_string (implementation);
std::string ret;
std::for_each (val.begin (), val.end (), [&ret] (char a) {
if (a != '-') ret.push_back (a);
});
return ret;
std::string out;
out.resize (implementation.size() * 2);
fast_guid_to_string (implementation.data, out.data());
return out;
}
GUID
@ -336,6 +367,14 @@ GUID::from_string (const char* str)
{
if (!str)
throw guid_syntax_exception {};
uint8_t bytes[16];
if (fast_string_to_guid(str, bytes))
{
boost::uuids::uuid u;
std::memcpy(u.data, bytes, 16);
return GUID{u};
}
try
{
static boost::uuids::string_generator strgen;
@ -350,6 +389,9 @@ GUID::from_string (const char* str)
bool
GUID::is_valid_guid (const char* str)
{
uint8_t bytes[16];
if (fast_string_to_guid(str, bytes))
return true;
try
{
static boost::uuids::string_generator strgen;

Loading…
Cancel
Save