/*
// Full copyright information is available in the file ../doc/CREDITS
*/
#define NATIVE_MODULE "$dictionary"
#include "cdc.h"
NATIVE_METHOD(dict_values) {
cList * list;
INIT_1_ARG(DICT);
list = dict_values(DICT1);
CLEAN_RETURN_LIST(list);
}
NATIVE_METHOD(dict_keys) {
cList * list;
INIT_1_ARG(DICT);
list = dict_keys(DICT1);
CLEAN_RETURN_LIST(list);
}
/* ugh; what we do to keep from copying */
NATIVE_METHOD(dict_add) {
cDict * dict;
cData arg1, arg2;
DEF_args;
INIT_ARGC(ARG_COUNT, 3, "three");
INIT_ARG1(DICT);
dict = dict_dup(DICT1);
data_dup(&arg1, &args[1]);
data_dup(&arg2, &args[2]);
CLEAN_STACK();
anticipate_assignment();
dict = dict_add(dict, &arg1, &arg2);
data_discard(&arg1);
data_discard(&arg2);
RETURN_DICT(dict);
}
NATIVE_METHOD(dict_del) {
cData arg1;
cDict * dict;
DEF_args;
INIT_ARGC(ARG_COUNT, 2, "two");
INIT_ARG1(DICT);
if (!dict_contains(DICT1, &args[1]))
THROW((keynf_id, "Key (%D) is not in the dictionary.", &args[1]));
dict = dict_dup(DICT1);
data_dup(&arg1, &args[1]);
CLEAN_STACK();
anticipate_assignment();
dict = dict_del(dict, &arg1);
data_discard(&arg1);
RETURN_DICT(dict);
}
NATIVE_METHOD(dict_contains) {
Int val;
DEF_args;
INIT_ARGC(ARG_COUNT, 2, "two");
INIT_ARG1(DICT);
val = dict_contains(DICT1, &args[1]);
CLEAN_RETURN_INTEGER(val);
}
NATIVE_METHOD(dict_add_elem) {
cDict * dict;
cData listd, d, key, value;
DEF_args;
INIT_ARGC(ARG_COUNT, 3, "three");
INIT_ARG1(DICT);
if (dict_find(DICT1, &args[1], &listd) == keynf_id) {
listd.type = LIST;
listd.u.list = list_new(0);
} else if (listd.type != LIST) {
cthrow(type_id, "Value for %D (%D) is not a list.", &args[0], &listd);
data_discard(&listd);
RETURN_FALSE;
}
/*
// set the list to zero to remove the reference to the list, then
// dup the dictionary so we can clear the stack and anticipate the
// assignmenent, all to keep references at their most minimal so we
// do not copy if we do not need to.
//
// also dup the key and the value being inserted.
*/
d.type = INTEGER;
d.u.val = 0;
dict = dict_add(DICT1, &args[1], &d);
dict = dict_dup(dict);
data_dup(&key, &args[1]);
data_dup(&value, &args[2]);
/* clean the stack and anticipate the assignment */
CLEAN_STACK();
anticipate_assignment();
/* Add the element to the list. */
listd.u.list = list_add(listd.u.list, &value);
dict = dict_add(dict, &key, &listd);
data_discard(&key);
data_discard(&value);
data_discard(&listd);
RETURN_DICT(dict);
}
NATIVE_METHOD(dict_del_elem) {
cDict * dict;
cData dlist, d, elem, key;
cList * list;
Int pos;
DEF_args;
INIT_ARGC(ARG_COUNT, 3, "three");
INIT_ARG1(DICT);
if (dict_find(DICT1, &args[1], &dlist) == keynf_id)
THROW((keynf_id, "Key (%D) is not in the dictionary.", &args[1]))
else if (dlist.type != LIST) {
cthrow(type_id, "Value for %D (%D) is not a list.", &args[0], &dlist);
data_discard(&dlist);
RETURN_FALSE;
}
dict = dict_dup(DICT1);
data_dup(&key, &args[1]);
data_dup(&elem, &args[2]);
list = dlist.u.list;
/* clean the stack and anticipate the assignment */
CLEAN_STACK();
anticipate_assignment();
/* find the element in the list */
pos = list_search(list, &elem);
/* we are finished with 'elem' */
data_discard(&elem);
/* the element is not in the list, simply return the dictionary */
if (pos == -1) {
data_discard(&dlist);
data_discard(&key);
RETURN_DICT(dict);
}
/* if the list length is one, then simply delete the dict element */
if (list_length(list) == 1) {
dict = dict_del(dict, &key);
data_discard(&dlist);
data_discard(&key);
RETURN_DICT(dict);
}
/*
// Temorarily set the dictionary's value for the key to zero, to
// remove the reference to the list.
*/
d.type = INTEGER;
d.u.val = 0;
dict = dict_add(dict, &key, &d);
/* Remove elem from the list */
dlist.u.list = list_delete(list, pos);
/* Set the new list as the value for the key in the dictionary */
dict = dict_add(dict, &key, &dlist);
/* clean up and return */
data_discard(&dlist);
data_discard(&key);
RETURN_DICT(dict);
}
NATIVE_METHOD(dict_union) {
cDict * dict1, * dict2;
INIT_2_ARGS(DICT, DICT)
dict1 = dict_dup(DICT1);
dict2 = dict_dup(DICT2);
CLEAN_STACK();
anticipate_assignment();
RETURN_DICT(dict_union(dict1, dict2));
}