diff --git a/libgnucash/engine/guid.cpp b/libgnucash/engine/guid.cpp index c65ae7261a..0fd36fd3d7 100644 --- a/libgnucash/engine/guid.cpp +++ b/libgnucash/engine/guid.cpp @@ -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;