From fb461371613049539654c11aa52eedeefd2b9a60 Mon Sep 17 00:00:00 2001
From: Sean Farley <sean@farley.io>
Date: Fri, 5 May 2023 05:36:43 -0700
Subject: [PATCH] Fix GCMapAllocator not being used (#369)

* git: ignore clangd cache

* git: also ignore {build,install} dirs with dashes

* re2: fix GCMapAllocator definition

Previously, the GCMapAllocator specified the wrong template arguments
and, thus, would not actually be used. This can be verified by the fact
that `GCMapAllocator::deallocate` used an undefined symbol:
`seq_gc_free`.

C++20 makes this an error like so:

```
error: static assertion failed due to requirement 'is_same<GCMapAllocator<std::pair<seq_str_t, long long>, re2::RE2>, GCMapAllocator<std::pair<const std::pair<seq_str_t, long long>, re2::RE2>, re2::RE2>>::value': [allocator.requirements] states that rebinding an allocator to the same type should result in the original allocator
    static_assert(is_same<allocator_type, __rebind_alloc<__alloc_traits, value_type> >::value,
    ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 errors generated.
```

This patch fixes the undefined symbol of `seq_gc_free` with `seq_free`
along with fixing `<Key, Value>` -> `<std::pair<Key, Value>>`.
---
 .gitignore           |  3 +++
 codon/runtime/re.cpp | 23 ++++++++++++++---------
 2 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/.gitignore b/.gitignore
index d0cd885e..2bd58fd3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,8 +16,10 @@
 *.pyc
 build/
 build_*/
+build-*/
 install/
 install_*/
+install-*/
 extra/python/src/jit.cpp
 extra/jupyter/build/
 
@@ -55,6 +57,7 @@ Thumbs.db
 .idea
 .mypy_cache
 .vscode
+.cache
 
 extra/jupyter/share/jupyter/kernels/codon/kernel.json
 extra/python/codon/version.py
diff --git a/codon/runtime/re.cpp b/codon/runtime/re.cpp
index 4facd25c..86c9afc7 100644
--- a/codon/runtime/re.cpp
+++ b/codon/runtime/re.cpp
@@ -69,15 +69,20 @@ struct Span {
   seq_int_t end;
 };
 
-template <class Key, class Value>
-struct GCMapAllocator : public std::allocator<std::pair<const Key, Value>> {
-  using value_type = std::pair<const Key, Value>;
+template <typename KV> struct GCMapAllocator : public std::allocator<KV> {
+  GCMapAllocator() = default;
+  GCMapAllocator(GCMapAllocator<KV> const &) = default;
 
-  value_type *allocate(std::size_t n) {
-    return (value_type *)seq_alloc(n * sizeof(value_type));
-  }
+  template <typename KV1>
+  GCMapAllocator(const GCMapAllocator<KV1>&) noexcept {}
 
-  void deallocate(value_type *p, std::size_t n) { seq_gc_free(p); }
+  KV *allocate(std::size_t n) { return (KV *)seq_alloc(n * sizeof(KV)); }
+
+  void deallocate(KV *p, std::size_t n) { seq_free(p); }
+
+  template <typename U> struct rebind {
+    using other = GCMapAllocator<U>;
+  };
 };
 
 static inline seq_str_t convert(const std::string &p) {
@@ -106,8 +111,8 @@ struct KeyHash {
   }
 };
 
-static thread_local std::unordered_map<Key, Regex, KeyHash, KeyEqual,
-                                       GCMapAllocator<Key, Regex>>
+static thread_local std::unordered_map<const Key, Regex, KeyHash, KeyEqual,
+                                       GCMapAllocator<std::pair<const Key, Regex>>>
     cache;
 
 static inline Regex *get(const seq_str_t &p, seq_int_t flags) {