aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_map.c
diff options
context:
space:
mode:
authorBjörn-Egil Dahlberg <[email protected]>2013-11-08 15:34:05 +0100
committerBjörn-Egil Dahlberg <[email protected]>2014-01-29 11:08:40 +0100
commite0eb6d5bafcebc1c24b0a538e50a1d55a3724f01 (patch)
tree5fddadbcc6100f4200e2e5d10fa7a505896736f5 /erts/emulator/beam/erl_map.c
parent1a234c9eba8ac2c78f97e5f3e33521b8cc5d3748 (diff)
downloadotp-e0eb6d5bafcebc1c24b0a538e50a1d55a3724f01.tar.gz
otp-e0eb6d5bafcebc1c24b0a538e50a1d55a3724f01.tar.bz2
otp-e0eb6d5bafcebc1c24b0a538e50a1d55a3724f01.zip
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)
Diffstat (limited to 'erts/emulator/beam/erl_map.c')
-rw-r--r--erts/emulator/beam/erl_map.c443
1 files changed, 242 insertions, 201 deletions
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);
}