perf: avoid string allocations by using fixed-width hash strings (#5725)

This commit is contained in:
Charles Kerr 2023-07-04 13:04:03 -05:00 committed by GitHub
parent 0bb222b2cb
commit 0a6d1806f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 50 additions and 32 deletions

View File

@ -25,6 +25,7 @@ extern "C"
#include "libtransmission/crypto-utils.h"
#include "libtransmission/tr-assert.h"
#include "libtransmission/tr-strbuf.h"
#include "libtransmission/utils.h"
using namespace std::literals;
@ -150,24 +151,16 @@ namespace
namespace hex_impl
{
constexpr void tr_binary_to_hex(void const* vinput, void* voutput, size_t byte_length)
template<typename InIt, typename OutIt>
constexpr void tr_binary_to_hex(InIt begin, InIt end, OutIt out)
{
auto constexpr Hex = "0123456789abcdef"sv;
auto const* input = static_cast<uint8_t const*>(vinput);
auto* output = static_cast<char*>(voutput);
/* go from back to front to allow for in-place conversion */
input += byte_length;
output += byte_length * 2;
*output = '\0';
while (byte_length-- > 0)
while (begin != end)
{
unsigned int const val = *(--input);
*(--output) = Hex[val & 0xf];
*(--output) = Hex[val >> 4];
auto const val = static_cast<unsigned int>(*begin++);
*out++ = Hex[val >> 4];
*out++ = Hex[val & 0xF];
}
}
@ -188,21 +181,23 @@ constexpr void tr_hex_to_binary(char const* input, void* voutput, size_t byte_le
} // namespace hex_impl
} // namespace
std::string tr_sha1_to_string(tr_sha1_digest_t const& digest)
tr_sha1_string tr_sha1_to_string(tr_sha1_digest_t const& digest)
{
using namespace hex_impl;
auto str = std::string(std::size(digest) * 2, '?');
tr_binary_to_hex(digest.data(), str.data(), std::size(digest));
auto str = tr_sha1_string{};
tr_binary_to_hex(std::begin(digest), std::end(digest), std::back_inserter(str));
TR_ASSERT(std::size(str) == TrSha1DigestStrlen);
return str;
}
std::string tr_sha256_to_string(tr_sha256_digest_t const& digest)
tr_sha256_string tr_sha256_to_string(tr_sha256_digest_t const& digest)
{
using namespace hex_impl;
auto str = std::string(std::size(digest) * 2, '?');
tr_binary_to_hex(digest.data(), str.data(), std::size(digest));
auto str = tr_sha256_string{};
tr_binary_to_hex(std::begin(digest), std::end(digest), std::back_inserter(str));
TR_ASSERT(std::size(str) == TrSha256DigestStrlen);
return str;
}

View File

@ -16,7 +16,9 @@
#include <string>
#include <string_view>
#include "transmission.h" // tr_sha1_digest_t
#include "libtransmission/transmission.h" // tr_sha1_digest_t
#include "libtransmission/tr-strbuf.h"
/**
* @addtogroup utils Utilities
@ -133,20 +135,24 @@ T tr_rand_obj()
*/
[[nodiscard]] std::string tr_base64_decode(std::string_view input);
using tr_sha1_string = tr_strbuf<char, sizeof(tr_sha1_digest_t) * 2U + 1U>;
/**
* @brief Generate an ascii hex string for a sha1 digest.
*/
[[nodiscard]] std::string tr_sha1_to_string(tr_sha1_digest_t const&);
[[nodiscard]] tr_sha1_string tr_sha1_to_string(tr_sha1_digest_t const&);
/**
* @brief Generate a sha1 digest from a hex string.
*/
[[nodiscard]] std::optional<tr_sha1_digest_t> tr_sha1_from_string(std::string_view hex);
using tr_sha256_string = tr_strbuf<char, sizeof(tr_sha256_digest_t) * 2U + 1U>;
/**
* @brief Generate an ascii hex string for a sha256 digest.
*/
[[nodiscard]] std::string tr_sha256_to_string(tr_sha256_digest_t const&);
[[nodiscard]] tr_sha256_string tr_sha256_to_string(tr_sha256_digest_t const&);
/**
* @brief Generate a sha256 digest from a hex string.

View File

@ -13,6 +13,7 @@
#include "transmission.h"
#include "announce-list.h"
#include "crypto-utils.h"
#include "tr-strbuf.h" // tr_urlbuf
#include "utils.h" // tr_strv_convert_utf8()
@ -58,12 +59,12 @@ public:
return announce_list_;
}
[[nodiscard]] constexpr std::string const& info_hash_string() const noexcept
[[nodiscard]] constexpr auto const& info_hash_string() const noexcept
{
return info_hash_str_;
}
[[nodiscard]] constexpr std::string const& info_hash2_string() const noexcept
[[nodiscard]] constexpr auto const& info_hash2_string() const noexcept
{
return info_hash2_str_;
}
@ -80,7 +81,7 @@ protected:
std::vector<std::string> webseed_urls_;
tr_sha1_digest_t info_hash_ = {};
tr_sha256_digest_t info_hash2_ = {};
std::string info_hash_str_;
std::string info_hash2_str_;
tr_sha1_string info_hash_str_;
tr_sha256_string info_hash2_str_;
std::string name_;
};

View File

@ -33,8 +33,16 @@ public:
ensure_sz();
}
tr_strbuf(tr_strbuf const& other) = delete;
tr_strbuf& operator=(tr_strbuf const& other) = delete;
tr_strbuf(tr_strbuf const& other)
{
assign(other.sv());
}
tr_strbuf& operator=(tr_strbuf const& other)
{
assign(other.sv());
return *this;
}
tr_strbuf(tr_strbuf&& other)
: buffer_{ std::move(other.buffer_) }

View File

@ -43,7 +43,8 @@ QString getNameFromMagnet(QString const& magnet)
return QString::fromStdString(tmp.name());
}
return QString::fromStdString(tmp.info_hash_string());
auto const& hashstr = tmp.info_hash_string();
return QString::fromUtf8(std::data(hashstr), std::size(hashstr));
}
} // namespace

View File

@ -105,6 +105,7 @@ class TorrentHash
{
private:
tr_sha1_digest_t data_ = {};
QString data_str_;
public:
TorrentHash() = default;
@ -119,6 +120,9 @@ public:
if (auto const hash = tr_sha1_from_string(str != nullptr ? str : ""); hash)
{
data_ = *hash;
auto const tmpstr = tr_sha1_to_string(data_);
data_str_ = QString::fromUtf8(std::data(tmpstr), std::size(tmpstr));
}
}
@ -127,6 +131,9 @@ public:
if (auto const hash = tr_sha1_from_string(str.toStdString()); hash)
{
data_ = *hash;
auto const tmpstr = tr_sha1_to_string(data_);
data_str_ = QString::fromUtf8(std::data(tmpstr), std::size(tmpstr));
}
}
@ -145,9 +152,9 @@ public:
return data_ < that.data_;
}
QString toString() const
[[nodiscard]] constexpr auto& toString() const noexcept
{
return QString::fromStdString(tr_sha1_to_string(data_));
return data_str_;
}
};