|
12 | 12 | #include <string> |
13 | 13 | #include <string_view> |
14 | 14 | #include <type_traits> |
| 15 | +#include <unordered_map> |
15 | 16 | #include <variant> |
16 | 17 | #include <vector> |
17 | 18 |
|
@@ -652,6 +653,43 @@ struct Decoder<std::map<K, V, Compare, Alloc>> { |
652 | 653 | }; |
653 | 654 | }; |
654 | 655 |
|
| 656 | +template <typename K, typename V, typename Hash, typename Pred, typename Alloc> |
| 657 | +struct Decoder<std::unordered_map<K, V, Hash, Pred, Alloc>> { |
| 658 | + static std::unordered_map<K, V, Hash, Pred, Alloc> |
| 659 | + decode(ErlNifEnv *env, const ERL_NIF_TERM &term) { |
| 660 | + std::unordered_map<K, V, Hash, Pred, Alloc> map; |
| 661 | + |
| 662 | + ERL_NIF_TERM key_term, value_term; |
| 663 | + ErlNifMapIterator iter; |
| 664 | + if (!enif_map_iterator_create(env, term, &iter, |
| 665 | + ERL_NIF_MAP_ITERATOR_FIRST)) { |
| 666 | + throw std::invalid_argument("decode failed, expected a map"); |
| 667 | + } |
| 668 | + |
| 669 | + // Define RAII cleanup for the iterator |
| 670 | + auto cleanup = IterCleanup{env, iter}; |
| 671 | + |
| 672 | + while (enif_map_iterator_get_pair(env, &iter, &key_term, &value_term)) { |
| 673 | + auto key = fine::decode<K>(env, key_term); |
| 674 | + auto value = fine::decode<V>(env, value_term); |
| 675 | + |
| 676 | + map.insert_or_assign(std::move(key), std::move(value)); |
| 677 | + |
| 678 | + enif_map_iterator_next(env, &iter); |
| 679 | + } |
| 680 | + |
| 681 | + return map; |
| 682 | + } |
| 683 | + |
| 684 | +private: |
| 685 | + struct IterCleanup { |
| 686 | + ErlNifEnv *env; |
| 687 | + ErlNifMapIterator iter; |
| 688 | + |
| 689 | + ~IterCleanup() { enif_map_iterator_destroy(env, &iter); } |
| 690 | + }; |
| 691 | +}; |
| 692 | + |
655 | 693 | template <typename T> struct Decoder<ResourcePtr<T>> { |
656 | 694 | static ResourcePtr<T> decode(ErlNifEnv *env, const ERL_NIF_TERM &term) { |
657 | 695 | void *ptr; |
@@ -875,10 +913,37 @@ struct Encoder<std::map<K, V, Compare, Alloc>> { |
875 | 913 | const std::map<K, V, Compare, Alloc> &map) { |
876 | 914 | auto keys = std::vector<ERL_NIF_TERM>(); |
877 | 915 | auto values = std::vector<ERL_NIF_TERM>(); |
| 916 | + keys.reserve(map.size()); |
| 917 | + values.reserve(map.size()); |
| 918 | + |
| 919 | + for (const auto &[key, value] : map) { |
| 920 | + keys.emplace_back(fine::encode(env, key)); |
| 921 | + values.emplace_back(fine::encode(env, value)); |
| 922 | + } |
| 923 | + |
| 924 | + ERL_NIF_TERM map_term; |
| 925 | + if (!enif_make_map_from_arrays(env, keys.data(), values.data(), keys.size(), |
| 926 | + &map_term)) { |
| 927 | + throw std::runtime_error("encode failed, failed to make a map"); |
| 928 | + } |
| 929 | + |
| 930 | + return map_term; |
| 931 | + } |
| 932 | +}; |
| 933 | + |
| 934 | +template <typename K, typename V, typename Hash, typename Pred, typename Alloc> |
| 935 | +struct Encoder<std::unordered_map<K, V, Hash, Pred, Alloc>> { |
| 936 | + static ERL_NIF_TERM |
| 937 | + encode(ErlNifEnv *env, |
| 938 | + const std::unordered_map<K, V, Hash, Pred, Alloc> &map) { |
| 939 | + auto keys = std::vector<ERL_NIF_TERM>(); |
| 940 | + auto values = std::vector<ERL_NIF_TERM>(); |
| 941 | + keys.reserve(map.size()); |
| 942 | + values.reserve(map.size()); |
878 | 943 |
|
879 | 944 | for (const auto &[key, value] : map) { |
880 | | - keys.push_back(fine::encode(env, key)); |
881 | | - values.push_back(fine::encode(env, value)); |
| 945 | + keys.emplace_back(fine::encode(env, key)); |
| 946 | + values.emplace_back(fine::encode(env, value)); |
882 | 947 | } |
883 | 948 |
|
884 | 949 | ERL_NIF_TERM map_term; |
@@ -1189,13 +1254,13 @@ inline int load(ErlNifEnv *env, void **, ERL_NIF_TERM) { |
1189 | 1254 |
|
1190 | 1255 | namespace std { |
1191 | 1256 | template <> struct hash<::fine::Term> { |
1192 | | - size_t operator()(const ::fine::Term &term) noexcept { |
| 1257 | + size_t operator()(const ::fine::Term &term) const noexcept { |
1193 | 1258 | return enif_hash(ERL_NIF_INTERNAL_HASH, term, 0); |
1194 | 1259 | } |
1195 | 1260 | }; |
1196 | 1261 |
|
1197 | 1262 | template <> struct hash<::fine::Atom> { |
1198 | | - size_t operator()(const ::fine::Atom &atom) noexcept { |
| 1263 | + size_t operator()(const ::fine::Atom &atom) const noexcept { |
1199 | 1264 | return std::hash<std::string_view>{}(atom.to_string()); |
1200 | 1265 | } |
1201 | 1266 | }; |
|
0 commit comments