From 9d75ed14b4da0841cbf9a2a93107403ad6a4b5b8 Mon Sep 17 00:00:00 2001
From: Adrien Beraud <adrien.beraud@savoirfairelinux.com>
Date: Mon, 10 Apr 2017 15:44:06 +0200
Subject: [PATCH] infohash: add to_c_str(), improve toString() performance

---
 include/opendht/infohash.h |  2 ++
 src/infohash.cpp           | 34 +++++++++++++++++++++++++++-------
 2 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/include/opendht/infohash.h b/include/opendht/infohash.h
index 5e07ba1c..74186ed2 100644
--- a/include/opendht/infohash.h
+++ b/include/opendht/infohash.h
@@ -278,6 +278,8 @@ public:
     OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const InfoHash& h);
     OPENDHT_PUBLIC friend std::istream& operator>> (std::istream& s, InfoHash& h);
 
+    const char* to_c_str() const;
+
     std::string toString() const;
 
     template <typename Packer>
diff --git a/src/infohash.cpp b/src/infohash.cpp
index 5070abe4..7530ca1d 100644
--- a/src/infohash.cpp
+++ b/src/infohash.cpp
@@ -71,20 +71,40 @@ InfoHash::getRandom()
     return h;
 }
 
+struct HexMap : public std::array<std::array<char, 2>, 256> {
+    HexMap() {
+        for (size_t i=0; i<size(); i++) {
+            auto& e = (*this)[i];
+            e[0] = hex_digits[(i >> 4) & 0x0F];
+            e[1] = hex_digits[i & 0x0F];
+        }
+    }
+private:
+    static constexpr const char* hex_digits = "0123456789abcdef";
+};
+
+const char*
+InfoHash::to_c_str() const
+{
+    static const HexMap map;
+    thread_local std::array<char, HASH_LEN*2+1> buf;
+    for (size_t i=0; i<HASH_LEN; i++) {
+        auto b = buf.data()+i*2;
+        const auto& m = map[(*this)[i]];
+        *((uint16_t*)b) = *((uint16_t*)&m);
+    }
+    return buf.data();
+}
+
 std::string
 InfoHash::toString() const
 {
-    std::stringstream ss;
-    ss << *this;
-    return ss.str();
+    return std::string(to_c_str(), HASH_LEN*2);
 }
 
 std::ostream& operator<< (std::ostream& s, const InfoHash& h)
 {
-    s << std::hex;
-    for (unsigned i=0; i<HASH_LEN; i++)
-        s << std::setfill('0') << std::setw(2) << (unsigned)h[i];
-    s << std::dec;
+    s.write(h.to_c_str(), HASH_LEN*2);
     return s;
 }
 
-- 
GitLab