Repository: randombit/botan
Pull request #3988 (2024-04-09 09:49:59)

Remove some obsolete and/or rarely used STL utilities


Patch:
diff --git a/src/cli/utils.cpp b/src/cli/utils.cpp
index 2761b0dd0..6fa42fd6f 100644
--- a/src/cli/utils.cpp
+++ b/src/cli/utils.cpp
@@ -66,12 +66,19 @@ class Print_Help final : public Command {
          oss << "Available commands:\n\n";
 
          for(const auto& commands : grouped_commands) {
-            std::string desc = commands.first;
-            if(desc.empty()) {
+            const std::string group = commands.first;
+            if(group.empty()) {
+               // ???
                continue;
             }
 
-            oss << Botan::search_map(groups_description, desc, desc) << ":\n";
+            auto descr = groups_description.find(group);
+            if(descr != groups_description.end()) {
+               oss << descr->second;
+            } else {
+               oss << group;
+            }
+            oss << ":\n";
             for(const auto& cmd : commands.second) {
                oss << "   " << std::setw(16) << std::left << cmd->cmd_name() << "   " << cmd->description() << "\n";
             }
diff --git a/src/lib/math/mp/mp_asmi.h b/src/lib/math/mp/mp_asmi.h
index 050ea8085..588a20dfd 100644
--- a/src/lib/math/mp/mp_asmi.h
+++ b/src/lib/math/mp/mp_asmi.h
@@ -17,8 +17,14 @@
 
 namespace Botan {
 
-#if defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_X86_64)
-   #define BOTAN_MP_USE_X86_64_ASM
+#if defined(BOTAN_USE_GCC_INLINE_ASM)
+   #if defined(BOTAN_TARGET_ARCH_IS_X86_FAMILY)
+      #define BOTAN_MP_USE_X86_32_ASM
+   #endif
+
+   #if defined(BOTAN_TARGET_ARCH_IS_X86_64)
+      #define BOTAN_MP_USE_X86_64_ASM
+   #endif
 #endif
 
 /*
@@ -62,6 +68,21 @@ struct WordInfo<uint64_t> {
 */
 template <WordType W>
 inline constexpr auto word_madd2(W a, W b, W* c) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(R"(
+         mull %[b]
+         addl %[c],%[a]
+         adcl $0,%[carry]
+         )"
+          : [a] "=a"(a), [b] "=rm"(b), [carry] "=&d"(*c)
+          : "0"(a), "1"(b), [c] "g"(*c)
+          : "cc");
+
+      return a;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(R"(
@@ -88,6 +109,25 @@ inline constexpr auto word_madd2(W a, W b, W* c) -> W {
 */
 template <WordType W>
 inline constexpr auto word_madd3(W a, W b, W c, W* d) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(R"(
+         mull %[b]
+
+         addl %[c],%[a]
+         adcl $0,%[carry]
+
+         addl %[d],%[a]
+         adcl $0,%[carry]
+         )"
+          : [a] "=a"(a), [b] "=rm"(b), [carry] "=&d"(*d)
+          : "0"(a), "1"(b), [c] "g"(c), [d] "g"(*d)
+          : "cc");
+
+      return a;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(R"(
@@ -113,19 +153,42 @@ inline constexpr auto word_madd3(W a, W b, W c, W* d) -> W {
    return static_cast<W>(s);
 }
 
-#if defined(BOTAN_MP_USE_X86_64_ASM)
+#if defined(BOTAN_MP_USE_X86_32_ASM)
 
-   #define ASM(x) x "\n\t"
+   #define ADDSUB2_OP(OPERATION, INDEX)        \
+      ASM("movl 4*" #INDEX "(%[y]), %[carry]") \
+      ASM(OPERATION " %[carry], 4*" #INDEX "(%[x])")
 
-   #define DO_8_TIMES(MACRO, ARG) \
-      MACRO(ARG, 0)               \
-      MACRO(ARG, 1)               \
-      MACRO(ARG, 2)               \
-      MACRO(ARG, 3)               \
-      MACRO(ARG, 4)               \
-      MACRO(ARG, 5)               \
-      MACRO(ARG, 6)               \
-      MACRO(ARG, 7)
+   #define ADDSUB3_OP(OPERATION, INDEX)              \
+      ASM("movl 4*" #INDEX "(%[x]), %[carry]")       \
+      ASM(OPERATION " 4*" #INDEX "(%[y]), %[carry]") \
+      ASM("movl %[carry], 4*" #INDEX "(%[z])")
+
+   #define LINMUL_OP(WRITE_TO, INDEX)      \
+      ASM("movl 4*" #INDEX "(%[x]),%%eax") \
+      ASM("mull %[y]")                     \
+      ASM("addl %[carry],%%eax")           \
+      ASM("adcl $0,%%edx")                 \
+      ASM("movl %%edx,%[carry]")           \
+      ASM("movl %%eax, 4*" #INDEX "(%[" WRITE_TO "])")
+
+   #define MULADD_OP(IGNORED, INDEX)       \
+      ASM("movl 4*" #INDEX "(%[x]),%%eax") \
+      ASM("mull %[y]")                     \
+      ASM("addl %[carry],%%eax")           \
+      ASM("adcl $0,%%edx")                 \
+      ASM("addl 4*" #INDEX "(%[z]),%%eax") \
+      ASM("adcl $0,%%edx")                 \
+      ASM("movl %%edx,%[carry]")           \
+      ASM("movl %%eax, 4*" #INDEX " (%[z])")
+
+   #define ADD_OR_SUBTRACT(CORE_CODE) \
+      ASM("rorl %[carry]")            \
+      CORE_CODE                       \
+      ASM("sbbl %[carry],%[carry]")   \
+      ASM("negl %[carry]")
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
 
    #define ADDSUB2_OP(OPERATION, INDEX)        \
       ASM("movq 8*" #INDEX "(%[y]), %[carry]") \
@@ -162,11 +225,37 @@ inline constexpr auto word_madd3(W a, W b, W c, W* d) -> W {
 
 #endif
 
+#if defined(ADD_OR_SUBTRACT)
+
+   #define ASM(x) x "\n\t"
+
+   #define DO_8_TIMES(MACRO, ARG) \
+      MACRO(ARG, 0)               \
+      MACRO(ARG, 1)               \
+      MACRO(ARG, 2)               \
+      MACRO(ARG, 3)               \
+      MACRO(ARG, 4)               \
+      MACRO(ARG, 5)               \
+      MACRO(ARG, 6)               \
+      MACRO(ARG, 7)
+
+#endif
+
 /*
 * Word Addition
 */
 template <WordType W>
 inline constexpr auto word_add(W x, W y, W* carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(ASM("adcl %[y],%[x]"))
+          : [x] "=r"(x), [carry] "=r"(*carry)
+          : "0"(x), [y] "rm"(y), "1"(*carry)
+          : "cc");
+      return x;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(ASM("adcq %[y],%[x]"))
@@ -189,6 +278,16 @@ inline constexpr auto word_add(W x, W y, W* carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_add2(W x[8], const W y[8], W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcl"))
+          : [carry] "=r"(carry)
+          : [x] "r"(x), [y] "r"(y), "0"(carry)
+          : "cc", "memory");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcq"))
@@ -215,6 +314,16 @@ inline constexpr auto word8_add2(W x[8], const W y[8], W carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_add3(W z[8], const W x[8], const W y[8], W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcl"))
+          : [carry] "=r"(carry)
+          : [x] "r"(x), [y] "r"(y), [z] "r"(z), "0"(carry)
+          : "cc", "memory");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcq"))
@@ -241,6 +350,16 @@ inline constexpr auto word8_add3(W z[8], const W x[8], const W y[8], W carry) ->
 */
 template <WordType W>
 inline constexpr auto word_sub(W x, W y, W* carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(ASM("sbbl %[y],%[x]"))
+          : [x] "=r"(x), [carry] "=r"(*carry)
+          : "0"(x), [y] "rm"(y), "1"(*carry)
+          : "cc");
+      return x;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(ASM("sbbq %[y],%[x]"))
@@ -263,6 +382,16 @@ inline constexpr auto word_sub(W x, W y, W* carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_sub2(W x[8], const W y[8], W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbl"))
+          : [carry] "=r"(carry)
+          : [x] "r"(x), [y] "r"(y), "0"(carry)
+          : "cc", "memory");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbq"))
@@ -289,6 +418,16 @@ inline constexpr auto word8_sub2(W x[8], const W y[8], W carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_sub2_rev(W x[8], const W y[8], W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl"))
+          : [carry] "=r"(carry)
+          : [x] "r"(y), [y] "r"(x), [z] "r"(x), "0"(carry)
+          : "cc", "memory");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq"))
@@ -315,6 +454,16 @@ inline constexpr auto word8_sub2_rev(W x[8], const W y[8], W carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_sub3(W z[8], const W x[8], const W y[8], W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl"))
+          : [carry] "=r"(carry)
+          : [x] "r"(x), [y] "r"(y), [z] "r"(z), "0"(carry)
+          : "cc", "memory");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq"))
@@ -341,6 +490,16 @@ inline constexpr auto word8_sub3(W z[8], const W x[8], const W y[8], W carry) ->
 */
 template <WordType W>
 inline constexpr auto word8_linmul2(W x[8], W y, W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(DO_8_TIMES(LINMUL_OP, "x")
+          : [carry] "=r"(carry)
+          : [x] "r"(x), [y] "rm"(y), "0"(carry)
+          : "cc", "%eax", "%edx");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(DO_8_TIMES(LINMUL_OP, "x")
@@ -367,6 +526,16 @@ inline constexpr auto word8_linmul2(W x[8], W y, W carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_linmul3(W z[8], const W x[8], W y, W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(DO_8_TIMES(LINMUL_OP, "z")
+          : [carry] "=r"(carry)
+          : [z] "r"(z), [x] "r"(x), [y] "rm"(y), "0"(carry)
+          : "cc", "%eax", "%edx");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(DO_8_TIMES(LINMUL_OP, "z")
@@ -393,6 +562,16 @@ inline constexpr auto word8_linmul3(W z[8], const W x[8], W y, W carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_madd3(W z[8], const W x[8], W y, W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(DO_8_TIMES(MULADD_OP, "")
+          : [carry] "=r"(carry)
+          : [z] "r"(z), [x] "r"(x), [y] "rm"(y), "0"(carry)
+          : "cc", "%eax", "%edx");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(DO_8_TIMES(MULADD_OP, "")
@@ -420,6 +599,24 @@ inline constexpr auto word8_madd3(W z[8], const W x[8], W y, W carry) -> W {
 */
 template <WordType W>
 inline constexpr void word3_muladd(W* w2, W* w1, W* w0, W x, W y) {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      W z0 = 0, z1 = 0;
+
+      asm("mull %[y]" : "=a"(z0), "=d"(z1) : "a"(x), [y] "rm"(y) : "cc");
+
+      asm(R"(
+          addl %[z0],%[w0]
+          adcl %[z1],%[w1]
+          adcl $0,%[w2]
+          )"
+          : [w0] "=r"(*w0), [w1] "=r"(*w1), [w2] "=r"(*w2)
+          : [z0] "r"(z0), [z1] "r"(z1), "0"(*w0), "1"(*w1), "2"(*w2)
+          : "cc");
+      return;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       W z0 = 0, z1 = 0;
@@ -450,6 +647,20 @@ inline constexpr void word3_muladd(W* w2, W* w1, W* w0, W x, W y) {
 */
 template <WordType W>
 inline constexpr void word3_add(W* w2, W* w1, W* w0, W x) {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(R"(
+         addl %[x],%[w0]
+         adcl $0,%[w1]
+         adcl $0,%[w2]
+         )"
+          : [w0] "=r"(*w0), [w1] "=r"(*w1), [w2] "=r"(*w2)
+          : [x] "r"(x), "0"(*w0), "1"(*w1), "2"(*w2)
+          : "cc");
+      return;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(R"(
@@ -477,6 +688,28 @@ inline constexpr void word3_add(W* w2, W* w1, W* w0, W x) {
 */
 template <WordType W>
 inline constexpr void word3_muladd_2(W* w2, W* w1, W* w0, W x, W y) {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      W z0 = 0, z1 = 0;
+
+      asm("mull %[y]" : "=a"(z0), "=d"(z1) : "a"(x), [y] "rm"(y) : "cc");
+
+      asm(R"(
+         addl %[z0],%[w0]
+         adcl %[z1],%[w1]
+         adcl $0,%[w2]
+
+         addl %[z0],%[w0]
+         adcl %[z1],%[w1]
+         adcl $0,%[w2]
+         )"
+          : [w0] "=r"(*w0), [w1] "=r"(*w1), [w2] "=r"(*w2)
+          : [z0] "r"(z0), [z1] "r"(z1), "0"(*w0), "1"(*w1), "2"(*w2)
+          : "cc");
+      return;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       W z0 = 0, z1 = 0;
diff --git a/src/lib/utils/http_util/http_util.cpp b/src/lib/utils/http_util/http_util.cpp
index 4c2dd35bd..c88c3894f 100644
--- a/src/lib/utils/http_util/http_util.cpp
+++ b/src/lib/utils/http_util/http_util.cpp
@@ -214,9 +214,9 @@ Response http_sync(const http_exch_fn& http_transact,
       resp_body.insert(resp_body.end(), buf.data(), &buf[got]);
    }
 
-   const std::string header_size = search_map(headers, std::string("Content-Length"));
-
-   if(!header_size.empty()) {
+   auto cl_hdr = headers.find("Content-Length");
+   if(cl_hdr != headers.end()) {
+      const std::string header_size = cl_hdr->second;
       if(resp_body.size() != to_u32bit(header_size)) {
          throw HTTP_Error(fmt("Content-Length disagreement, header says {} got {}", header_size, resp_body.size()));
       }
diff --git a/src/lib/utils/stl_util.h b/src/lib/utils/stl_util.h
index 26f624370..2629350f2 100644
--- a/src/lib/utils/stl_util.h
+++ b/src/lib/utils/stl_util.h
@@ -11,9 +11,7 @@
 
 #include <algorithm>
 #include <functional>
-#include <map>
 #include <optional>
-#include <set>
 #include <span>
 #include <string>
 #include <tuple>
@@ -54,63 +52,6 @@ RetT reduce(const std::vector<KeyT>& keys, RetT acc, ReducerT reducer)
    return acc;
 }
 
-/**
-* Return the keys of a map as a std::set
-*/
-template <typename K, typename V>
-std::set<K> map_keys_as_set(const std::map<K, V>& kv) {
-   std::set<K> s;
-   for(auto&& i : kv) {
-      s.insert(i.first);
-   }
-   return s;
-}
-
-/**
-* Return the keys of a multimap as a std::set
-*/
-template <typename K, typename V>
-std::set<K> map_keys_as_set(const std::multimap<K, V>& kv) {
-   std::set<K> s;
-   for(auto&& i : kv) {
-      s.insert(i.first);
-   }
-   return s;
-}
-
-/*
-* Searching through a std::map
-* @param mapping the map to search
-* @param key is what to look for
-* @param null_result is the value to return if key is not in mapping
-* @return mapping[key] or null_result
-*/
-template <typename K, typename V>
-inline V search_map(const std::map<K, V>& mapping, const K& key, const V& null_result = V()) {
-   auto i = mapping.find(key);
-   if(i == mapping.end()) {
-      return null_result;
-   }
-   return i->second;
-}
-
-template <typename K, typename V, typename R>
-inline R search_map(const std::map<K, V>& mapping, const K& key, const R& null_result, const R& found_result) {
-   auto i = mapping.find(key);
-   if(i == mapping.end()) {
-      return null_result;
-   }
-   return found_result;
-}
-
-/*
-* Insert a key/value pair into a multimap
-*/
-template <typename K, typename V>
-void multimap_insert(std::multimap<K, V>& multimap, const K& key, const V& value) {
-   multimap.insert(std::make_pair(key, value));
-}
-
 /**
 * Existence check for values
 */
diff --git a/src/lib/x509/asn1_alt_name.cpp b/src/lib/x509/asn1_alt_name.cpp
index 08bace9e3..8fff9145c 100644
--- a/src/lib/x509/asn1_alt_name.cpp
+++ b/src/lib/x509/asn1_alt_name.cpp
@@ -56,7 +56,7 @@ void AlternativeName::add_othername(const OID& oid, std::string_view value, ASN1
    if(value.empty()) {
       return;
    }
-   multimap_insert(m_othernames, oid, ASN1_String(value, type));
+   m_othernames.emplace(oid, ASN1_String{value, type});
 }
 
 /*
@@ -70,7 +70,7 @@ std::multimap<std::string, std::string> AlternativeName::contents() const {
    }
 
    for(const auto& othername : m_othernames) {
-      multimap_insert(names, othername.first.to_formatted_string(), othername.second.value());
+      names.emplace(othername.first.to_formatted_string(), othername.second.value());
    }
 
    return names;
diff --git a/src/lib/x509/x509_dn.cpp b/src/lib/x509/x509_dn.cpp
index bf2a53578..1f7a9e21c 100644
--- a/src/lib/x509/x509_dn.cpp
+++ b/src/lib/x509/x509_dn.cpp
@@ -113,7 +113,7 @@ std::multimap<OID, std::string> X509_DN::get_attributes() const {
    std::multimap<OID, std::string> retval;
 
    for(auto& i : m_rdn) {
-      multimap_insert(retval, i.first, i.second.value());
+      retval.emplace(i.first, i.second.value());
    }
    return retval;
 }
@@ -125,7 +125,7 @@ std::multimap<std::string, std::string> X509_DN::contents() const {
    std::multimap<std::string, std::string> retval;
 
    for(auto& i : m_rdn) {
-      multimap_insert(retval, i.first.to_formatted_string(), i.second.value());
+      retval.emplace(i.first.to_formatted_string(), i.second.value());
    }
    return retval;
 }


Test patch:
diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp
index c6ce80b78..683fb2c23 100644
--- a/src/tests/tests.cpp
+++ b/src/tests/tests.cpp
@@ -519,9 +519,21 @@ class Test_Registry {
          return nullptr;
       }
 
-      std::set<std::string> registered_tests() const { return Botan::map_keys_as_set(m_tests); }
+      std::set<std::string> registered_tests() const {
+         std::set<std::string> s;
+         for(auto&& i : m_tests) {
+            s.insert(i.first);
+         }
+         return s;
+      }
 
-      std::set<std::string> registered_test_categories() const { return Botan::map_keys_as_set(m_categories); }
+      std::set<std::string> registered_test_categories() const {
+         std::set<std::string> s;
+         for(auto&& i : m_categories) {
+            s.insert(i.first);
+         }
+         return s;
+      }
 
       std::vector<std::string> filter_registered_tests(const std::vector<std::string>& requested,
                                                        const std::set<std::string>& to_be_skipped) {