From 0ab5ecea133cef5a009bc34ba42c4eaacde6a7dd Mon Sep 17 00:00:00 2001
From: Florent Le Coz <louiz@louiz.org>
Date: Mon, 24 Nov 2014 03:38:10 +0100
Subject: Cache the result of jidprep()

Avoid doing repetitive calculations, if we call jidprep() on the same JID multiple times
---
 src/test.cpp     |  5 +++++
 src/xmpp/jid.cpp | 18 +++++++++++++++---
 2 files changed, 20 insertions(+), 3 deletions(-)

(limited to 'src')

diff --git a/src/test.cpp b/src/test.cpp
index 59c0a1e..2f29e01 100644
--- a/src/test.cpp
+++ b/src/test.cpp
@@ -288,7 +288,12 @@ int main()
   // Jidprep
   const std::string& badjid("~zigougou™@EpiK-7D9D1FDE.poez.io/Boujour/coucou/slt™");
   const std::string correctjid = jidprep(badjid);
+  std::cout << correctjid << std::endl;
   assert(correctjid == "~zigougoutm@epik-7d9d1fde.poez.io/Boujour/coucou/sltTM");
+  // Check that the cache do not break things when we prep the same string
+  // multiple times
+  assert(jidprep(badjid) == "~zigougoutm@epik-7d9d1fde.poez.io/Boujour/coucou/sltTM");
+  assert(jidprep(badjid) == "~zigougoutm@epik-7d9d1fde.poez.io/Boujour/coucou/sltTM");
 
   const std::string& badjid2("Zigougou@poez.io");
   const std::string correctjid2 = jidprep(badjid2);
diff --git a/src/xmpp/jid.cpp b/src/xmpp/jid.cpp
index e3b0c8f..c51e011 100644
--- a/src/xmpp/jid.cpp
+++ b/src/xmpp/jid.cpp
@@ -1,6 +1,7 @@
 #include <xmpp/jid.hpp>
 #include <config.h>
 #include <cstring>
+#include <map>
 
 #ifdef LIBIDN_FOUND
  #include <stringprep.h>
@@ -35,7 +36,14 @@ static constexpr size_t max_jid_part_len = 1023;
 std::string jidprep(const std::string& original)
 {
 #ifdef LIBIDN_FOUND
-  // TODO: cache the result
+  using CacheType = std::map<std::string, std::string>;
+  static CacheType cache;
+  std::pair<CacheType::iterator, bool> cached = cache.insert({original, {}});
+  if (std::get<1>(cached) == false)
+    { // Insertion failed: the result is already in the cache, return it
+      return std::get<0>(cached)->second;
+    }
+
   const std::string error_msg("Failed to convert " + original + " into a valid JID:");
   Jid jid(original);
 
@@ -61,7 +69,10 @@ std::string jidprep(const std::string& original)
 
   // If there is no resource, stop here
   if (jid.resource.empty())
-    return std::string(local) + "@" + domain;
+    {
+      std::get<0>(cached)->second = std::string(local) + "@" + domain;
+      return std::get<0>(cached)->second;
+    }
 
   // Otherwise, also process the resource part
   char resource[max_jid_part_len] = {};
@@ -73,7 +84,8 @@ std::string jidprep(const std::string& original)
       log_error(error_msg + stringprep_strerror(rc));
       return "";
     }
-  return std::string(local) + "@" + domain + "/" + resource;
+  std::get<0>(cached)->second = std::string(local) + "@" + domain + "/" + resource;
+  return std::get<0>(cached)->second;
 
 #else
   (void)original;
-- 
cgit v1.2.3