From e0eb6d5bafcebc1c24b0a538e50a1d55a3724f01 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= <egil@erlang.org>
Date: Fri, 8 Nov 2013 15:34:05 +0100
Subject: erts: Add NIFs for Maps

- int enif_is_map(ErlNifEnv* env, ERL_NIF_TERM map)
- int enif_get_map_size(ErlNifEnv *env, ERL_NIF_TERM, int*)
- ERL_NIF_TERM enif_make_new_map(ErlNifEnv *env)
- int enif_make_map_put(ErlNifEnv *env, ERL_NIF_TERM map_in, ERL_NIF_TERM key, ERL_NIF_TERM value, ERL_NIF_TERM* map_out)
- int enif_get_map_value(ErlNifEnv *env, ERL_NIF_TERM map, ERL_NIF_TERM key, ERL_NIF_TERM* value)
- int enif_find_map_value(ErlNifEnv *env, ERL_NIF_TERM map, ERL_NIF_TERM key, ERL_NIF_TERM* value)
- int enif_make_map_update(ErlNifEnv *env, ERL_NIF_TERM map_in, ERL_NIF_TERM key, ERL_NIF_TERM value, ERL_NIF_TERM* map_out)
- int enif_make_map_remove(ErlNifEnv *env, ERL_NIF_TERM map_in, ERL_NIF_TERM key, ERL_NIF_TERM* map_out)

- int  enif_map_iterator_create(ErlNifEnv *env, ERL_NIF_TERM map, ErlNifMapIterator *iter)
- void enif_map_iterator_destroy(ErlNifEnv *env, ErlNifMapIterator *iter)
- int  enif_map_iterator_next(ErlNifEnv *env, ErlNifMapIterator *iter)
- int  enif_map_iterator_get_pair(ErlNifEnv *env, ErlNifMapIterator *iter, ERL_NIF_TERM *key, ERL_NIF_TERM *value)
---
 erts/emulator/beam/erl_map.c           | 443 ++++++++++++++++++---------------
 erts/emulator/beam/erl_map.h           |   6 +
 erts/emulator/beam/erl_nif.c           | 209 ++++++++++++++++
 erts/emulator/beam/erl_nif.h           |  26 +-
 erts/emulator/beam/erl_nif_api_funcs.h |  33 +++
 5 files changed, 511 insertions(+), 206 deletions(-)

(limited to 'erts/emulator')

diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c
index 27734276f9..98aeee634b 100644
--- a/erts/emulator/beam/erl_map.c
+++ b/erts/emulator/beam/erl_map.c
@@ -111,28 +111,39 @@ BIF_RETTYPE maps_to_list_1(BIF_ALIST_1) {
  * return value if key *equals* a key in the map
  */
 
-BIF_RETTYPE maps_find_2(BIF_ALIST_2) {
-    if (is_map(BIF_ARG_2)) {
-	Eterm *hp, *ks,*vs, key, res;
-	map_t *mp;
-	Uint n,i;
+int erts_maps_find(Eterm key, Eterm map, Eterm *value) {
 
-	mp  = (map_t*)map_val(BIF_ARG_2);
-	key = BIF_ARG_1;
-	n   = map_get_size(mp);
-	ks  = map_get_keys(mp);
-	vs  = map_get_values(mp);
+    Eterm *ks,*vs;
+    map_t *mp;
+    Uint n,i;
 
-	for( i = 0; i < n; i++) {
-	    if (CMP(ks[i], key)==0) {
-		hp    = HAlloc(BIF_P, 3);
-		res   = make_tuple(hp);
-		*hp++ = make_arityval(2);
-		*hp++ = am_ok;
-		*hp++ = vs[i];
-		BIF_RET(res);
-	    }
+    mp  = (map_t*)map_val(map);
+    n   = map_get_size(mp);
+    ks  = map_get_keys(mp);
+    vs  = map_get_values(mp);
+
+    for( i = 0; i < n; i++) {
+	if (CMP(ks[i], key)==0) {
+	    *value = vs[i];
+	    return 1;
+	}
+    }
+    return 0;
+}
+
+BIF_RETTYPE maps_find_2(BIF_ALIST_2) {
+    if (is_map(BIF_ARG_2)) {
+	Eterm *hp, value,res;
+
+	if (erts_maps_find(BIF_ARG_1, BIF_ARG_2, &value)) {
+	    hp    = HAlloc(BIF_P, 3);
+	    res   = make_tuple(hp);
+	    *hp++ = make_arityval(2);
+	    *hp++ = am_ok;
+	    *hp++ = value;
+	    BIF_RET(res);
 	}
+
 	BIF_RET(am_error);
     }
     BIF_ERROR(BIF_P, BADARG);
@@ -142,43 +153,54 @@ BIF_RETTYPE maps_find_2(BIF_ALIST_2) {
  * exception bad_key if none matches
  */
 
-BIF_RETTYPE maps_get_2(BIF_ALIST_2) {
-    if (is_map(BIF_ARG_2)) {
-	Eterm *hp, *ks,*vs, key, error;
-	map_t *mp;
-	Uint n,i;
-	char *s_error;
 
-	mp  = (map_t*)map_val(BIF_ARG_2);
-	key = BIF_ARG_1;
-	n   = map_get_size(mp);
-	
-	if (n == 0)
-	    goto error;
+int erts_maps_get(Eterm key, Eterm map, Eterm *value) {
+    Eterm *ks,*vs;
+    map_t *mp;
+    Uint n,i;
 
-	ks  = map_get_keys(mp);
-	vs  = map_get_values(mp);
+    mp  = (map_t*)map_val(map);
+    n   = map_get_size(mp);
 
-	if (is_immed(key)) {
-	    for( i = 0; i < n; i++) {
-		if (ks[i] == key) {
-		    BIF_RET(vs[i]);
-		}
-	    }
-	}
+    if (n == 0)
+	return 0;
+
+    ks  = map_get_keys(mp);
+    vs  = map_get_values(mp);
 
+    if (is_immed(key)) {
 	for( i = 0; i < n; i++) {
-	    if (eq(ks[i], key)) {
-		BIF_RET(vs[i]);
+	    if (ks[i] == key) {
+		*value = vs[i];
+		return 1;
 	    }
 	}
-error:
+    }
+
+    for( i = 0; i < n; i++) {
+	if (eq(ks[i], key)) {
+	    *value = vs[i];
+	    return 1;
+	}
+    }
+    return 0;
+}
+
+BIF_RETTYPE maps_get_2(BIF_ALIST_2) {
+    if (is_map(BIF_ARG_2)) {
+	Eterm *hp;
+	Eterm value, error;
+	char *s_error;
+
+	if (erts_maps_get(BIF_ARG_1, BIF_ARG_2, &value)) {
+	    BIF_RET(value);
+	}
 
 	s_error = "bad_key";
 	error = am_atom_put(s_error, sys_strlen(s_error));
 
 	hp = HAlloc(BIF_P, 3);
-	BIF_P->fvalue = TUPLE2(hp, error, key);
+	BIF_P->fvalue = TUPLE2(hp, error, BIF_ARG_1);
 	BIF_ERROR(BIF_P, EXC_ERROR_2);
     }
     BIF_ERROR(BIF_P, BADARG);
@@ -460,7 +482,7 @@ BIF_RETTYPE maps_new_0(BIF_ALIST_0) {
     Eterm tup;
     map_t *mp;
 
-    hp    = HAlloc(BIF_P, (3 + 1));
+    hp    = HAlloc(BIF_P, (MAP_HEADER_SIZE + 1));
     tup   = make_tuple(hp);
     *hp++ = make_arityval(0);
 
@@ -475,183 +497,197 @@ BIF_RETTYPE maps_new_0(BIF_ALIST_0) {
 /* maps:put/3
  */
 
-BIF_RETTYPE maps_put_3(BIF_ALIST_3) {
-    if (is_map(BIF_ARG_3)) {
-	Sint n,i;
-	Sint c = 0;
-	Eterm* hp, *shp;
-	Eterm *ks,*vs, res, key, tup;
-	map_t *mp = (map_t*)map_val(BIF_ARG_3);
-
-	key = BIF_ARG_1;
-	n   = map_get_size(mp);
-
-	if (n == 0) {
-	    hp    = HAlloc(BIF_P, 4 + 2);
-	    tup   = make_tuple(hp);
-	    *hp++ = make_arityval(1);
-	    *hp++ = key;
-	    res   = make_map(hp);
-	    *hp++ = MAP_HEADER;
-	    *hp++ = 1;
-	    *hp++ = tup;
-	    *hp++ = BIF_ARG_2;
+Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map) {
+    Sint n,i;
+    Sint c = 0;
+    Eterm* hp, *shp;
+    Eterm *ks,*vs, res, tup;
+    map_t *mp = (map_t*)map_val(map);
 
-	    BIF_RET(res);
-	}
-
-	ks  = map_get_keys(mp);
-	vs  = map_get_values(mp);
-	/* only allocate for values,
-	 * assume key-tuple will be intact
-	 */
+    n = map_get_size(mp);
 
-	hp  = HAlloc(BIF_P, 3 + n);
-	shp = hp; /* save hp, used if optimistic update fails */
-	res = make_map(hp);
+    if (n == 0) {
+	hp    = HAlloc(p, MAP_HEADER_SIZE + 1 + 2);
+	tup   = make_tuple(hp);
+	*hp++ = make_arityval(1);
+	*hp++ = key;
+	res   = make_map(hp);
 	*hp++ = MAP_HEADER;
-	*hp++ = n;
-	*hp++ = mp->keys;
+	*hp++ = 1;
+	*hp++ = tup;
+	*hp++ = value;
 
-	if (is_immed(key)) {
-	    for( i = 0; i < n; i ++) {
-		if (ks[i] == key) {
-		    *hp++ = BIF_ARG_2;
-		    vs++;
-		    c = 1;
-		} else {
-		    *hp++ = *vs++;
-		}
+	return res;
+    }
+
+    ks  = map_get_keys(mp);
+    vs  = map_get_values(mp);
+
+    /* only allocate for values,
+     * assume key-tuple will be intact
+     */
+
+    hp  = HAlloc(p, MAP_HEADER_SIZE + n);
+    shp = hp; /* save hp, used if optimistic update fails */
+    res = make_map(hp);
+    *hp++ = MAP_HEADER;
+    *hp++ = n;
+    *hp++ = mp->keys;
+
+    if (is_immed(key)) {
+	for( i = 0; i < n; i ++) {
+	    if (ks[i] == key) {
+		*hp++ = value;
+		vs++;
+		c = 1;
+	    } else {
+		*hp++ = *vs++;
 	    }
-	} else {
-	    for( i = 0; i < n; i ++) {
-		if (eq(ks[i], key)) {
-		    *hp++ = BIF_ARG_2;
-		    vs++;
-		    c = 1;
-		} else {
-		    *hp++ = *vs++;
-		}
+	}
+    } else {
+	for( i = 0; i < n; i ++) {
+	    if (eq(ks[i], key)) {
+		*hp++ = value;
+		vs++;
+		c = 1;
+	    } else {
+		*hp++ = *vs++;
 	    }
 	}
+    }
 
-	if (c)
-	    BIF_RET(res);
+    if (c)
+	return res;
 
-	/* need to make a new tuple,
-	 * use old hp since it needs to be recreated anyway.
-	 */
-	tup    = make_tuple(shp);
-	*shp++ = make_arityval(n+1);
+    /* need to make a new tuple,
+     * use old hp since it needs to be recreated anyway.
+     */
+    tup    = make_tuple(shp);
+    *shp++ = make_arityval(n+1);
 
-	hp    = HAlloc(BIF_P, 3 + n + 1);
-	res   = make_map(hp);
-	*hp++ = MAP_HEADER;
-	*hp++ = n + 1;
-	*hp++ = tup;
+    hp    = HAlloc(p, 3 + n + 1);
+    res   = make_map(hp);
+    *hp++ = MAP_HEADER;
+    *hp++ = n + 1;
+    *hp++ = tup;
 
-	ks  = map_get_keys(mp);
-	vs  = map_get_values(mp);
+    ks  = map_get_keys(mp);
+    vs  = map_get_values(mp);
 
-	ASSERT(n >= 0);
+    ASSERT(n >= 0);
 
-	/* copy map in order */
-	while (n && ((c = CMP(*ks, key)) < 0)) {
-	    *shp++ = *ks++;
-	    *hp++  = *vs++;
-	    n--;
-	}
+    /* copy map in order */
+    while (n && ((c = CMP(*ks, key)) < 0)) {
+	*shp++ = *ks++;
+	*hp++  = *vs++;
+	n--;
+    }
 
-	*shp++ = key;
-	*hp++  = BIF_ARG_2;
+    *shp++ = key;
+    *hp++  = value;
 
-	ASSERT(n >= 0);
+    ASSERT(n >= 0);
 
-	while(n--) {
-	    *shp++ = *ks++;
-	    *hp++  = *vs++;
-	}
-	/* we have one word remaining
-	 * this will work out fine once we get the size word
-	 * in the header.
-	 */
-	*shp = make_pos_bignum_header(0);
-	BIF_RET(res);
+    while(n--) {
+	*shp++ = *ks++;
+	*hp++  = *vs++;
     }
+    /* we have one word remaining
+     * this will work out fine once we get the size word
+     * in the header.
+     */
+    *shp = make_pos_bignum_header(0);
+    return res;
+}
 
+BIF_RETTYPE maps_put_3(BIF_ALIST_3) {
+    if (is_map(BIF_ARG_3)) {
+	BIF_RET(erts_maps_put(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3));
+    }
     BIF_ERROR(BIF_P, BADARG);
 }
 
 /* maps:remove/3
  */
 
-BIF_RETTYPE maps_remove_2(BIF_ALIST_2) {
-    if (is_map(BIF_ARG_2)) {
-	Sint n;
-	Sint found = 0;
-	Uint need;
-	Eterm *thp, *mhp;
-	Eterm *ks, *vs, res, key,tup;
-	map_t *mp = (map_t*)map_val(BIF_ARG_2);
+int erts_maps_remove(Process *p, Eterm key, Eterm map, Eterm *res) {
+    Sint n;
+    Sint found = 0;
+    Uint need;
+    Eterm *thp, *mhp;
+    Eterm *ks, *vs, tup;
+    map_t *mp = (map_t*)map_val(map);
 
-	key = BIF_ARG_1;
-	n   = map_get_size(mp);
+    n = map_get_size(mp);
 
-	if (n == 0)
-	    BIF_RET(BIF_ARG_2);
+    if (n == 0) {
+	*res = map;
+	return 1;
+    }
 
-	ks  = map_get_keys(mp);
-	vs  = map_get_values(mp);
+    ks = map_get_keys(mp);
+    vs = map_get_values(mp);
 
-	/* Assume key exists.
-	 * Release allocated if it didn't.
-	 * Allocate key tuple first.
-	 */
+    /* Assume key exists.
+     * Release allocated if it didn't.
+     * Allocate key tuple first.
+     */
 
-	need   = n + 1 - 1 + 3 + n - 1; /* tuple - 1 + map - 1 */
-	thp    = HAlloc(BIF_P, need);
-	mhp    = thp + n;               /* offset with tuple heap size */
+    need   = n + 1 - 1 + 3 + n - 1; /* tuple - 1 + map - 1 */
+    thp    = HAlloc(p, need);
+    mhp    = thp + n;               /* offset with tuple heap size */
 
-	tup    = make_tuple(thp);
-	*thp++ = make_arityval(n - 1);
+    tup    = make_tuple(thp);
+    *thp++ = make_arityval(n - 1);
 
-	res    = make_map(mhp);
-	*mhp++ = MAP_HEADER;
-	*mhp++ = n - 1;
-	*mhp++ = tup;
+    *res   = make_map(mhp);
+    *mhp++ = MAP_HEADER;
+    *mhp++ = n - 1;
+    *mhp++ = tup;
 
-	if (is_immed(key)) {
-	    while(n--) {
-		if (*ks == key) {
-		    ks++;
-		    vs++;
-		    found = 1;
-		} else {
-		    *mhp++ = *vs++;
-		    *thp++ = *ks++;
-		}
+    if (is_immed(key)) {
+	while(n--) {
+	    if (*ks == key) {
+		ks++;
+		vs++;
+		found = 1;
+	    } else {
+		*mhp++ = *vs++;
+		*thp++ = *ks++;
 	    }
-	} else {
-	    while(n--) {
-		if (eq(*ks, key)) {
-		    ks++;
-		    vs++;
-		    found = 1;
-		} else {
-		    *mhp++ = *vs++;
-		    *thp++ = *ks++;
-		}
+	}
+    } else {
+	while(n--) {
+	    if (eq(*ks, key)) {
+		ks++;
+		vs++;
+		found = 1;
+	    } else {
+		*mhp++ = *vs++;
+		*thp++ = *ks++;
 	    }
 	}
+    }
 
-	if (found)
-	    BIF_RET(res);
+    if (found) {
+	return 1;
+    }
 
-	/* Not found, remove allocated memory
-	 * and return previous map.
-	 */
-	HRelease(BIF_P, thp + need, thp);
-	BIF_RET(BIF_ARG_2);
+    /* Not found, remove allocated memory
+     * and return previous map.
+     */
+    HRelease(p, thp + need, thp);
+
+    *res = map;
+    return 1;
+}
+
+BIF_RETTYPE maps_remove_2(BIF_ALIST_2) {
+    if (is_map(BIF_ARG_2)) {
+	Eterm res;
+	if (erts_maps_remove(BIF_P, BIF_ARG_1, BIF_ARG_2, &res)) {
+	    BIF_RET(res);
+	}
     }
     BIF_ERROR(BIF_P, BADARG);
 }
@@ -659,19 +695,15 @@ BIF_RETTYPE maps_remove_2(BIF_ALIST_2) {
 /* maps:update/3
  */
 
-BIF_RETTYPE maps_update_3(BIF_ALIST_3) {
-    if (is_map(BIF_ARG_3)) {
+int erts_maps_update(Process *p, Eterm key, Eterm value, Eterm map, Eterm *res) {
 	Sint n,i;
 	Sint found = 0;
 	Eterm* hp,*shp;
-	Eterm *ks,*vs, res, key;
-	map_t *mp = (map_t*)map_val(BIF_ARG_3);
+	Eterm *ks,*vs;
+	map_t *mp = (map_t*)map_val(map);
 
-	key = BIF_ARG_1;
-	n   = map_get_size(mp);
-
-	if (n == 0) {
-	    BIF_ERROR(BIF_P, BADARG);
+	if ((n = map_get_size(mp)) == 0) {
+	    return 0;
 	}
 
 	ks  = map_get_keys(mp);
@@ -681,9 +713,9 @@ BIF_RETTYPE maps_update_3(BIF_ALIST_3) {
 	 * assume key-tuple will be intact
 	 */
 
-	hp  = HAlloc(BIF_P, 3 + n);
+	hp  = HAlloc(p, MAP_HEADER_SIZE + n);
 	shp = hp;
-	res = make_map(hp);
+	*res = make_map(hp);
 	*hp++ = MAP_HEADER;
 	*hp++ = n;
 	*hp++ = mp->keys;
@@ -691,7 +723,7 @@ BIF_RETTYPE maps_update_3(BIF_ALIST_3) {
 	if (is_immed(key)) {
 	    for( i = 0; i < n; i ++) {
 		if (ks[i] == key) {
-		    *hp++ = BIF_ARG_2;
+		    *hp++ = value;
 		    vs++;
 		    found = 1;
 		} else {
@@ -701,7 +733,7 @@ BIF_RETTYPE maps_update_3(BIF_ALIST_3) {
 	} else {
 	    for( i = 0; i < n; i ++) {
 		if (eq(ks[i], key)) {
-		    *hp++ = BIF_ARG_2;
+		    *hp++ = value;
 		    vs++;
 		    found = 1;
 		} else {
@@ -710,10 +742,19 @@ BIF_RETTYPE maps_update_3(BIF_ALIST_3) {
 	    }
 	}
 
-	if (found)
-	    BIF_RET(res);
+	if (found) {
+	    return 1;
+	}
+	HRelease(p, shp + MAP_HEADER_SIZE + n, shp);
+	return 0;
+}
 
-	HRelease(BIF_P, shp + 3 + n, shp);
+BIF_RETTYPE maps_update_3(BIF_ALIST_3) {
+    if (is_map(BIF_ARG_3)) {
+	Eterm res;
+	if (erts_maps_update(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3, &res)) {
+	    BIF_RET(res);
+	}
     }
     BIF_ERROR(BIF_P, BADARG);
 }
diff --git a/erts/emulator/beam/erl_map.h b/erts/emulator/beam/erl_map.h
index 4f0d26e100..616ecd24ce 100644
--- a/erts/emulator/beam/erl_map.h
+++ b/erts/emulator/beam/erl_map.h
@@ -62,5 +62,11 @@ typedef struct map_s {
 #define MAP_HEADER             _make_header(1,_TAG_HEADER_MAP)
 #define MAP_HEADER_SIZE        (sizeof(map_t) / sizeof(Eterm))
 
+Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map);
+int   erts_maps_update(Process *p, Eterm key, Eterm value, Eterm map, Eterm *res);
+int   erts_maps_find(Eterm key, Eterm map, Eterm *value);
+int   erts_maps_get(Eterm key, Eterm map, Eterm *value);
+int   erts_maps_remove(Process *p, Eterm key, Eterm map, Eterm *res);
+
 #endif
 
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index e1e213c4eb..c683847aaa 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -31,6 +31,7 @@
 #include "bif.h"
 #include "error.h"
 #include "big.h"
+#include "erl_map.h"
 #include "beam_bp.h"
 #include "erl_thr_progress.h"
 #include "dtrace-wrapper.h"
@@ -1602,6 +1603,214 @@ enif_have_dirty_schedulers()
 
 #endif /* ERL_NIF_DIRTY_SCHEDULER_SUPPORT */
 
+/* Maps */
+
+int enif_is_map(ErlNifEnv* env, ERL_NIF_TERM term)
+{
+    return is_map(term);
+}
+
+int enif_get_map_size(ErlNifEnv* env, ERL_NIF_TERM term, int *size)
+{
+    if (is_map(term)) {
+	map_t *mp;
+	mp    = (map_t*)map_val(term);
+	*size = map_get_size(mp);
+	return 1;
+    }
+    return 0;
+}
+
+ERL_NIF_TERM enif_make_new_map(ErlNifEnv* env)
+{
+    Eterm* hp = alloc_heap(env,MAP_HEADER_SIZE+1);
+    Eterm tup;
+    map_t *mp;
+
+    tup   = make_tuple(hp);
+    *hp++ = make_arityval(0);
+    mp    = (map_t*)hp;
+    mp->thing_word = MAP_HEADER;
+    mp->size = 0;
+    mp->keys = tup;
+
+    return make_map(mp);
+}
+
+int enif_make_map_put(ErlNifEnv* env,
+	              Eterm map_in,
+		      Eterm key,
+		      Eterm value,
+		      Eterm *map_out)
+{
+    if (is_not_map(map_in)) {
+	return 0;
+    }
+    flush_env(env);
+    *map_out = erts_maps_put(env->proc, key, value, map_in);
+    cache_env(env);
+    return 1;
+}
+
+int enif_get_map_value(ErlNifEnv* env,
+	               Eterm map,
+		       Eterm key,
+		       Eterm *value)
+{
+    if (is_not_map(map)) {
+	return 0;
+    }
+    return erts_maps_get(key, map, value);
+}
+
+int enif_find_map_value(ErlNifEnv* env,
+	                Eterm map,
+			Eterm key,
+			Eterm *value)
+{
+    if (is_not_map(map)) {
+	return 0;
+    }
+    return erts_maps_get(key, map, value);
+}
+
+int enif_make_map_update(ErlNifEnv* env,
+	                 Eterm map_in,
+			 Eterm key,
+			 Eterm value,
+			 Eterm *map_out)
+{
+    int res;
+    if (is_not_map(map_in)) {
+	return 0;
+    }
+
+    flush_env(env);
+    res = erts_maps_update(env->proc, key, value, map_in, map_out);
+    cache_env(env);
+    return res;
+}
+
+int enif_make_map_remove(ErlNifEnv* env,
+	                 Eterm map_in,
+			 Eterm key,
+			 Eterm *map_out)
+{
+    int res;
+    if (is_not_map(map_in)) {
+	return 0;
+    }
+    flush_env(env);
+    res = erts_maps_remove(env->proc, key, map_in, map_out);
+    cache_env(env);
+    return res;
+}
+
+int enif_map_iterator_create(ErlNifEnv *env,
+	                     Eterm map,
+			     ErlNifMapIterator *iter,
+			     ErlNifMapIteratorEntry entry)
+{
+    if (is_map(map)) {
+	map_t *mp = (map_t*)map_val(map);
+	size_t offset;
+
+	switch (entry) {
+	    case ERL_NIF_MAP_ITERATOR_HEAD: offset = 0; break;
+	    case ERL_NIF_MAP_ITERATOR_TAIL: offset = map_get_size(mp) - 1; break;
+	    default: goto error;
+	}
+
+	/* empty maps are ok but will leave the iterator
+	 * in bad shape.
+	 */
+
+	iter->map     = map;
+	iter->ks      = ((Eterm *)map_get_keys(mp)) + offset;
+	iter->vs      = ((Eterm *)map_get_values(mp)) + offset;
+	iter->t_limit = map_get_size(mp) + 1;
+	iter->h_limit = 0;
+	iter->idx     = offset + 1;
+
+	return 1;
+    }
+
+error:
+    iter->map = THE_NON_VALUE;
+    return 0;
+}
+
+void enif_map_iterator_destroy(ErlNifEnv *env, ErlNifMapIterator *iter)
+{
+    /* not used */
+}
+
+int enif_map_iterator_is_tail(ErlNifEnv *env, ErlNifMapIterator *iter)
+{
+    ASSERT(iter->idx >= 0 && (iter->idx <= map_get_size(map_val(iter->map)) + 1));
+    if (is_map(iter->map) && (
+		(iter->t_limit - iter->h_limit) == 1 ||
+		 iter->idx == iter->t_limit)) {
+	return 1;
+    }
+    return 0;
+}
+
+int enif_map_iterator_is_head(ErlNifEnv *env, ErlNifMapIterator *iter)
+{
+    ASSERT(iter->idx >= 0 && (iter->idx <= map_get_size(map_val(iter->map)) + 1));
+    if (is_map(iter->map) && (
+		(iter->t_limit - iter->h_limit) == 1 ||
+		 iter->idx == iter->h_limit)) {
+	return 1;
+    }
+    return 0;
+}
+
+
+int enif_map_iterator_next(ErlNifEnv *env, ErlNifMapIterator *iter)
+{
+    if (is_map(iter->map) && iter->idx < iter->t_limit) {
+	iter->idx++;
+	if (iter->idx != iter->t_limit) {
+	    iter->ks++;
+	    iter->vs++;
+	}
+	return 1;
+    }
+    return 0;
+}
+
+int enif_map_iterator_prev(ErlNifEnv *env, ErlNifMapIterator *iter)
+{
+    if (is_map(iter->map) && iter->idx > iter->h_limit ) {
+	iter->idx--;
+	if (iter->idx != iter->h_limit ) {
+	    iter->ks--;
+	    iter->vs--;
+	}
+	return 1;
+    }
+    return 0;
+}
+
+int enif_map_iterator_get_pair(ErlNifEnv *env,
+			       ErlNifMapIterator *iter,
+			       Eterm *key,
+			       Eterm *value)
+{
+    if (is_map(iter->map) && iter->idx > iter->h_limit && iter->idx < iter->t_limit) {
+	ASSERT(iter->ks >= map_get_keys(map_val(iter->map)) &&
+	       iter->ks  < (map_get_keys(map_val(iter->map)) + map_get_size(map_val(iter->map))));
+	ASSERT(iter->vs >= map_get_values(map_val(iter->map)) &&
+	       iter->vs  < (map_get_values(map_val(iter->map)) + map_get_size(map_val(iter->map))));
+	*key   = *(iter->ks);
+	*value = *(iter->vs);
+	return 1;
+    }
+    return 0;
+}
+
 /***************************************************************************
  **                              load_nif/2                               **
  ***************************************************************************/
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index fb3c359ec9..3c1e13f8a4 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -38,14 +38,11 @@
 ** 2.2: R14B03 enif_is_exception
 ** 2.3: R15 enif_make_reverse_list, enif_is_number
 ** 2.4: R16 enif_consume_timeslice
-** 2.5: R17 dirty schedulers
+** 2.5: R17 Maps API additions
+**      R17 dirty schedulers
 */
 #define ERL_NIF_MAJOR_VERSION 2
-#ifdef ERL_NIF_DIRTY_SCHEDULER_SUPPORT
 #define ERL_NIF_MINOR_VERSION 5
-#else
-#define ERL_NIF_MINOR_VERSION 4
-#endif
 
 #include <stdlib.h>
 
@@ -168,6 +165,7 @@ typedef int ErlNifTSDKey;
 
 typedef ErlDrvThreadOpts ErlNifThreadOpts;
 
+<<<<<<< HEAD
 #ifdef ERL_NIF_DIRTY_SCHEDULER_SUPPORT
 typedef enum
 {
@@ -175,6 +173,24 @@ typedef enum
     ERL_NIF_DIRTY_JOB_IO_BOUND  = 2
 }ErlNifDirtyTaskFlags;
 #endif
+=======
+typedef struct
+{
+    /* use a lot of memory, structure may change */
+    ERL_NIF_TERM map;
+    ErlNifUInt64 h_limit;
+    ErlNifUInt64 t_limit;
+    ErlNifUInt64 idx;
+    ERL_NIF_TERM *ks;
+    ERL_NIF_TERM *vs;
+} ErlNifMapIterator;
+
+typedef enum {
+    ERL_NIF_MAP_ITERATOR_HEAD = 1,
+    ERL_NIF_MAP_ITERATOR_TAIL = 2
+} ErlNifMapIteratorEntry;
+
+>>>>>>> erts: Add NIFs for Maps
 
 #if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_))
 #  define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) RET_TYPE (*NAME) ARGS
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index f5b27dfdfa..2cabfd4ce1 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -149,6 +149,23 @@ ERL_NIF_API_FUNC_DECL(int,enif_is_on_dirty_scheduler,(ErlNifEnv*));
 ERL_NIF_API_FUNC_DECL(int,enif_have_dirty_schedulers,(void));
 #endif
 
+ERL_NIF_API_FUNC_DECL(int, enif_is_map, (ErlNifEnv* env, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int, enif_get_map_size, (ErlNifEnv* env, ERL_NIF_TERM term, int *size));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_make_new_map, (ErlNifEnv* env));
+ERL_NIF_API_FUNC_DECL(int, enif_make_map_put, (ErlNifEnv* env, ERL_NIF_TERM map_in, ERL_NIF_TERM key, ERL_NIF_TERM value, ERL_NIF_TERM* map_out));
+ERL_NIF_API_FUNC_DECL(int, enif_get_map_value, (ErlNifEnv* env, ERL_NIF_TERM map, ERL_NIF_TERM key, ERL_NIF_TERM* value));
+ERL_NIF_API_FUNC_DECL(int, enif_find_map_value, (ErlNifEnv* env, ERL_NIF_TERM map, ERL_NIF_TERM key, ERL_NIF_TERM* value));
+ERL_NIF_API_FUNC_DECL(int, enif_make_map_update, (ErlNifEnv* env, ERL_NIF_TERM map_in, ERL_NIF_TERM key, ERL_NIF_TERM value, ERL_NIF_TERM* map_out));
+ERL_NIF_API_FUNC_DECL(int, enif_make_map_remove, (ErlNifEnv* env, ERL_NIF_TERM map_in, ERL_NIF_TERM key, ERL_NIF_TERM* map_out));
+ERL_NIF_API_FUNC_DECL(int, enif_map_iterator_create, (ErlNifEnv *env, ERL_NIF_TERM map, ErlNifMapIterator *iter, ErlNifMapIteratorEntry entry));
+ERL_NIF_API_FUNC_DECL(void, enif_map_iterator_destroy, (ErlNifEnv *env, ErlNifMapIterator *iter));
+ERL_NIF_API_FUNC_DECL(int, enif_map_iterator_is_head, (ErlNifEnv *env, ErlNifMapIterator *iter));
+ERL_NIF_API_FUNC_DECL(int, enif_map_iterator_is_tail, (ErlNifEnv *env, ErlNifMapIterator *iter));
+ERL_NIF_API_FUNC_DECL(int, enif_map_iterator_next, (ErlNifEnv *env, ErlNifMapIterator *iter));
+ERL_NIF_API_FUNC_DECL(int, enif_map_iterator_prev, (ErlNifEnv *env, ErlNifMapIterator *iter));
+ERL_NIF_API_FUNC_DECL(int, enif_map_iterator_get_pair, (ErlNifEnv *env, ErlNifMapIterator *iter, ERL_NIF_TERM *key, ERL_NIF_TERM *value));
+
+
 /*
 ** Add new entries here to keep compatibility on Windows!!!
 */
@@ -281,6 +298,22 @@ ERL_NIF_API_FUNC_DECL(int,enif_have_dirty_schedulers,(void));
 #  define enif_have_dirty_schedulers ERL_NIF_API_FUNC_MACRO(enif_have_dirty_schedulers)
 #endif
 
+#  define enif_is_map ERL_NIF_API_FUNC_MACRO(enif_is_map)
+#  define enif_get_map_size ERL_NIF_API_FUNC_MACRO(enif_get_map_size)
+#  define enif_make_new_map ERL_NIF_FUNC_MACRO(enif_make_new_map)
+#  define enif_make_map_put ERL_NIF_FUNC_MACRO(enif_map_map_put)
+#  define enif_get_map_value ERL_NIF_FUNC_MACRO(enif_get_map_value)
+#  define enif_find_map_value ERL_NIF_FUNC_MACRO(enif_find_map_value)
+#  define enif_make_map_update ERL_NIF_FUNC_MACRO(enif_make_map_update)
+#  define enif_make_map_remove ERL_NIF_FUNC_MACRO(enif_make_map_remove)
+#  define enif_map_iterator_create ERL_NIF_FUNC_MACRO(enif_map_iterator_create)
+#  define enif_map_iterator_destroy ERL_NIF_FUNC_MACRO(enif_map_iterator_destroy)
+#  define enif_map_iterator_is_head ERL_NIF_FUNC_MACRO(enif_map_iterator_is_head)
+#  define enif_map_iterator_is_tail ERL_NIF_FUNC_MACRO(enif_map_iterator_is_tail)
+#  define enif_map_iterator_next ERL_NIF_FUNC_MACRO(enif_map_iterator_next)
+#  define enif_map_iterator_prev ERL_NIF_FUNC_MACRO(enif_map_iterator_prev)
+#  define enif_map_iterator_get_pair NIF_FUNC_MACRO(enif_map_iterator_get_pair)
+
 /*
 ** Add new entries here
 */
-- 
cgit v1.2.3