/*
* %CopyrightBegin%
*
* Copyright Ericsson AB 2013. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* %CopyrightEnd%
*
* Author: Björn-Egil Dahlberg
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "sys.h"
#include "erl_vm.h"
#include "global.h"
#include "erl_process.h"
#include "error.h"
#include "bif.h"
#include "erl_map.h"
BIF_RETTYPE map_to_list_1(BIF_ALIST_1) {
if (is_map(BIF_ARG_1)) {
Uint n;
Eterm* hp;
Eterm *ks,*vs, res, tup;
map_t *mp = (map_t*)map_val(BIF_ARG_1);
ks = map_get_keys(mp);
vs = map_get_values(mp);
n = map_get_size(mp);
hp = HAlloc(BIF_P, (2 + 3) * n);
res = NIL;
while(n--) {
tup = TUPLE2(hp, ks[n], vs[n]); hp += 3;
res = CONS(hp, tup, res); hp += 2;
}
BIF_RET(res);
}
BIF_ERROR(BIF_P, BADARG);
}
BIF_RETTYPE map_new_0(BIF_ALIST_0) {
Eterm* hp;
Eterm tup;
map_t *mp;
hp = HAlloc(BIF_P, (3 + 1));
tup = make_tuple(hp);
*hp++ = make_arityval(0);
mp = (map_t*)hp;
mp->thing_word = MAP_HEADER;
mp->size = 0;
mp->keys = tup;
BIF_RET(make_map(mp));
}
BIF_RETTYPE map_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;
ks = map_get_keys(mp);
vs = map_get_values(mp);
if (is_immed(key)) {
for( i = 0; i < n; i++) {
if (ks[i] == key) {
BIF_RET(vs[i]);
}
}
}
for( i = 0; i < n; i++) {
if (eq(ks[i], key)) {
BIF_RET(vs[i]);
}
}
error:
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_ERROR(BIF_P, EXC_ERROR_2);
}
BIF_ERROR(BIF_P, BADARG);
}
BIF_RETTYPE map_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;
BIF_RET(res);
}
ks = map_get_keys(mp);
vs = map_get_values(mp);
/* only allocate for values,
* assume key-tuple will be intact
*/
hp = HAlloc(BIF_P, 3 + 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++ = BIF_ARG_2;
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++;
}
}
}
if (c)
BIF_RET(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);
hp = HAlloc(BIF_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);
ASSERT(n >= 0);
/* copy map in order */
while (n && ((c = CMP(*ks, key)) < 0)) {
*shp++ = *ks++;
*hp++ = *vs++;
n--;
}
*shp++ = key;
*hp++ = BIF_ARG_2;
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);
}
BIF_ERROR(BIF_P, BADARG);
}