From 4399497ff8a7251d87b35284aeab53789c9b8ad3 Mon Sep 17 00:00:00 2001
From: Ben Cumming <bcumming@cscs.ch>
Date: Wed, 26 May 2021 13:18:26 +0200
Subject: [PATCH] Fix issue with cached labels in python label_dict wrapper
 (#1541)

The `label_dict` Python wrapper caches label strings and their descriptions in order to
provide a convenient Python iterator interface and `[]` access. These were not being
properly updated or set when the label_dict was constructed from a C++ label_dict.
---
 python/proxy.hpp | 48 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 34 insertions(+), 14 deletions(-)

diff --git a/python/proxy.hpp b/python/proxy.hpp
index 1d4d0599..3750cc1b 100644
--- a/python/proxy.hpp
+++ b/python/proxy.hpp
@@ -24,12 +24,7 @@ struct label_dict_proxy {
     }
 
     label_dict_proxy(const arb::label_dict& label_dict): dict(label_dict) {
-        for (const auto& [l, reg]: dict.regions()) {
-            regions.push_back(l);
-        }
-        for (const auto& [l, ls]: dict.locsets()) {
-            locsets.push_back(l);
-        }
+        update_cache();
     }
 
     std::size_t size() const  {
@@ -37,15 +32,10 @@ struct label_dict_proxy {
     }
 
     void import(const label_dict_proxy& other, std::string prefix) {
-        regions.clear();
-        locsets.clear();
         dict.import(other.dict, prefix);
-        for (const auto& [l, reg]: dict.regions()) {
-            regions.push_back(l);
-        }
-        for (const auto& [l, ls]: dict.locsets()) {
-            locsets.push_back(l);
-        }
+
+        clear_cache();
+        update_cache();
     }
 
     void set(const char* name, const char* desc) {
@@ -117,5 +107,35 @@ struct label_dict_proxy {
         s += ")";
         return s;
     }
+
+    private:
+
+    void clear_cache() {
+        regions.clear();
+        locsets.clear();
+        cache.clear();
+    }
+
+    void update_cache() {
+        for (const auto& [lab, reg]: dict.regions()) {
+            if (!cache.count(lab)) {
+                std::stringstream s;
+                s << reg;
+                regions.push_back(lab);
+                cache[lab] = s.str();
+            }
+        }
+        for (const auto& [lab, ls]: dict.locsets()) {
+            if (!cache.count(lab)) {
+                std::stringstream s;
+                s << ls;
+                locsets.push_back(lab);
+                cache[lab] = s.str();
+            }
+        }
+        // Sort the region and locset names
+        std::sort(regions.begin(), regions.end());
+        std::sort(locsets.begin(), locsets.end());
+    }
 };
 }
-- 
GitLab