@@ -381,14 +381,14 @@ inline Term make_new_binary(ErlNifEnv *env, const char *data, size_t size) {
381381//
382382// The given type must have a specialized Decoder<T> implementation.
383383template <typename T> T decode (ErlNifEnv *env, const ERL_NIF_TERM &term) {
384- return Decoder<T >::decode (env, term);
384+ return Decoder<std:: remove_cv_t <T> >::decode (env, term);
385385}
386386
387387// Encodes the given value as a Erlang term.
388388//
389389// The value type must have a specialized Encoder<T> implementation.
390390template <typename T> ERL_NIF_TERM encode (ErlNifEnv *env, const T &value) {
391- return Encoder<T >::encode (env, value);
391+ return Encoder<std:: remove_cv_t <T> >::encode (env, value);
392392}
393393
394394// We want decode to return the value, and since the argument types
@@ -473,9 +473,10 @@ template <> struct Decoder<ErlNifPid> {
473473 }
474474 if (!enif_get_local_pid (env, term, &pid)) {
475475 // If the term is a PID and it is not local, it means it's a remote PID.
476- throw std::invalid_argument (
477- " decode failed, expected a local pid, but got a remote one. NIFs can "
478- " only send messages to local PIDs and remote PIDs cannot be decoded" );
476+ throw std::invalid_argument (" decode failed, expected a local pid, but "
477+ " got a remote one. NIFs can "
478+ " only send messages to local PIDs and "
479+ " remote PIDs cannot be decoded" );
479480 }
480481 return pid;
481482 }
@@ -591,6 +592,25 @@ template <typename... Args> struct Decoder<std::tuple<Args...>> {
591592 }
592593};
593594
595+ template <typename T1, typename T2> struct Decoder <std::pair<T1, T2>> {
596+ static std::pair<T1, T2> decode (ErlNifEnv *env, const ERL_NIF_TERM &term) {
597+ int size;
598+ const ERL_NIF_TERM *terms;
599+ if (!enif_get_tuple (env, term, &size, &terms)) {
600+ throw std::invalid_argument (" decode failed, expected a tuple" );
601+ }
602+
603+ if (size != 2 ) {
604+ throw std::invalid_argument (
605+ " decode failed, expected tuple to have 2 elements, but had " +
606+ std::to_string (size));
607+ }
608+
609+ return std::make_pair (fine::decode<T1>(env, terms[0 ]),
610+ fine::decode<T2>(env, terms[1 ]));
611+ }
612+ };
613+
594614template <typename T, typename Alloc> struct Decoder <std::vector<T, Alloc>> {
595615 static std::vector<T, Alloc> decode (ErlNifEnv *env,
596616 const ERL_NIF_TERM &term) {
@@ -690,6 +710,60 @@ struct Decoder<std::unordered_map<K, V, Hash, Pred, Alloc>> {
690710 };
691711};
692712
713+ template <typename K, typename V, typename Compare, typename Alloc>
714+ struct Decoder <std::multimap<K, V, Compare, Alloc>> {
715+ static std::multimap<K, V, Compare, Alloc> decode (ErlNifEnv *env,
716+ const ERL_NIF_TERM &term) {
717+ unsigned int length;
718+
719+ if (!enif_get_list_length (env, term, &length)) {
720+ throw std::invalid_argument (" decode failed, expected a list" );
721+ }
722+
723+ std::multimap<K, V, Compare, Alloc> map;
724+
725+ auto list = term;
726+
727+ ERL_NIF_TERM head, tail;
728+ while (enif_get_list_cell (env, list, &head, &tail)) {
729+ auto entry = fine::decode<std::pair<const K, V>>(env, head);
730+
731+ map.emplace (std::move (entry));
732+
733+ list = tail;
734+ }
735+
736+ return map;
737+ }
738+ };
739+
740+ template <typename K, typename V, typename Hash, typename Pred, typename Alloc>
741+ struct Decoder <std::unordered_multimap<K, V, Hash, Pred, Alloc>> {
742+ static std::unordered_multimap<K, V, Hash, Pred, Alloc>
743+ decode (ErlNifEnv *env, const ERL_NIF_TERM &term) {
744+ unsigned int length;
745+
746+ if (!enif_get_list_length (env, term, &length)) {
747+ throw std::invalid_argument (" decode failed, expected a list" );
748+ }
749+
750+ std::unordered_multimap<K, V, Hash, Pred, Alloc> map;
751+
752+ auto list = term;
753+
754+ ERL_NIF_TERM head, tail;
755+ while (enif_get_list_cell (env, list, &head, &tail)) {
756+ auto entry = fine::decode<std::pair<const K, V>>(env, head);
757+
758+ map.emplace (std::move (entry));
759+
760+ list = tail;
761+ }
762+
763+ return map;
764+ }
765+ };
766+
693767template <typename T> struct Decoder <ResourcePtr<T>> {
694768 static ResourcePtr<T> decode (ErlNifEnv *env, const ERL_NIF_TERM &term) {
695769 void *ptr;
@@ -892,6 +966,14 @@ template <typename... Args> struct Encoder<std::tuple<Args...>> {
892966 }
893967};
894968
969+ template <typename T1, typename T2> struct Encoder <std::pair<T1, T2>> {
970+ static ERL_NIF_TERM encode (ErlNifEnv *env, const std::pair<T1, T2> &pair) {
971+ const auto first = fine::encode<T1>(env, pair.first );
972+ const auto second = fine::encode<T2>(env, pair.second );
973+ return enif_make_tuple (env, 2 , first, second);
974+ }
975+ };
976+
895977template <typename T, typename Alloc> struct Encoder <std::vector<T, Alloc>> {
896978 static ERL_NIF_TERM encode (ErlNifEnv *env,
897979 const std::vector<T, Alloc> &vector) {
@@ -956,6 +1038,39 @@ struct Encoder<std::unordered_map<K, V, Hash, Pred, Alloc>> {
9561038 }
9571039};
9581040
1041+ template <typename K, typename V, typename Compare, typename Alloc>
1042+ struct Encoder <std::multimap<K, V, Compare, Alloc>> {
1043+ static ERL_NIF_TERM encode (ErlNifEnv *env,
1044+ const std::multimap<K, V, Compare, Alloc> &map) {
1045+ auto terms = std::vector<ERL_NIF_TERM>();
1046+ terms.reserve (map.size ());
1047+
1048+ for (const auto &entry : map) {
1049+ terms.emplace_back (fine::encode (env, entry));
1050+ }
1051+
1052+ return enif_make_list_from_array (env, terms.data (),
1053+ static_cast <unsigned int >(terms.size ()));
1054+ }
1055+ };
1056+
1057+ template <typename K, typename V, typename Hash, typename Pred, typename Alloc>
1058+ struct Encoder <std::unordered_multimap<K, V, Hash, Pred, Alloc>> {
1059+ static ERL_NIF_TERM
1060+ encode (ErlNifEnv *env,
1061+ const std::unordered_multimap<K, V, Hash, Pred, Alloc> &map) {
1062+ auto terms = std::vector<ERL_NIF_TERM>();
1063+ terms.reserve (map.size ());
1064+
1065+ for (const auto &entry : map) {
1066+ terms.emplace_back (fine::encode (env, entry));
1067+ }
1068+
1069+ return enif_make_list_from_array (env, terms.data (),
1070+ static_cast <unsigned int >(terms.size ()));
1071+ }
1072+ };
1073+
9591074template <typename T> struct Encoder <ResourcePtr<T>> {
9601075 static ERL_NIF_TERM encode (ErlNifEnv *env, const ResourcePtr<T> &resource) {
9611076 return enif_make_resource (env, reinterpret_cast <void *>(resource.get ()));
0 commit comments