static ERL_NIF_TERM elibart_insert(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { art_tree* t; ErlNifBinary key, value; art_elem_struct *elem; unsigned char buffer[BUFF_SIZE]; // 256Kb buffer unsigned char *key_copy = buffer; // extract arguments atr_tree, key, value if (argc != 3) return enif_make_badarg(env); if(!enif_get_resource(env, argv[0], elibart_RESOURCE, (void**) &t)) return enif_make_badarg(env); if (!enif_inspect_binary(env, argv[1], &key)) return enif_make_badarg(env); if (!enif_inspect_binary(env, argv[2], &value)) return enif_make_badarg(env); // buffer size not enough, pay the price if (key.size > BUFF_SIZE) key_copy = malloc(key.size + 1); // TODO review -- is it possible not to copy the key just to add '\0'? memcpy(key_copy, key.data, key.size); key_copy[key.size] = '\0'; //create art element elem = malloc(sizeof(art_elem_struct)); if (elem == NULL) mk_error(env, "malloc_no_mem"); elem->data = malloc(value.size); elem->size = value.size; memcpy(elem->data, value.data, value.size); // insert the element in the art_tree art_elem_struct *old_elem = art_insert(t, key_copy, key.size + 1, elem); // buffer size not enough, pay the price if (key.size > BUFF_SIZE) free(key_copy); // the inserted key is new if (!old_elem) return enif_make_tuple2(env, mk_atom(env, "ok"), mk_atom(env, "empty")); // the inserted key already existed, return previous value ErlNifBinary res; enif_alloc_binary(old_elem->size, &res); memcpy(res.data, old_elem->data, old_elem->size); free(old_elem->data); free(old_elem); return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_binary(env, &res)); }
static ERL_NIF_TERM ex_has_colors(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if (argc != 0 ) return enif_make_badarg(env); if (has_colors()) return mk_atom(env, "true"); else return mk_atom(env, "false"); }
static ERL_NIF_TERM same_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { assert(argc == 2 && "same_term is a 2-arity function."); if(enif_is_identical(argv[0], argv[1])) { return mk_atom(env, "true"); } else { return mk_atom(env, "false"); } }
static ERL_NIF_TERM elibart_prefix_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { art_tree* t; ErlNifBinary key; callback_data cb_data; // extract arguments atr_tree, key if (argc != 4) return enif_make_badarg(env); if(!enif_get_resource(env, argv[0], elibart_RESOURCE, (void**) &t)) return enif_make_badarg(env); if (!enif_inspect_binary(env, argv[1], &key)) return enif_make_badarg(env); cb_data.env = env; if(!enif_is_pid(env, argv[3])) return mk_error(env, "not_a_pid"); if(!enif_get_local_pid(env, argv[3], &cb_data.pid)) return mk_error(env, "not_a_local_pid"); cb_data.caller_ref = argv[2]; // TODO this should be a worker thread since it's a long opearation (?) if (art_iter_prefix(t, key.data, key.size, prefix_cb, &cb_data)) return mk_error(env, "art_prefix_search"); ErlNifEnv *msg_env = enif_alloc_env(); if(msg_env == NULL) return mk_error(env, "env_alloc_error");; ERL_NIF_TERM caller_ref = enif_make_copy(msg_env, argv[2]); ERL_NIF_TERM res = enif_make_tuple2(msg_env, caller_ref, mk_atom(msg_env, "ok")); if (!enif_send(env, &cb_data.pid, msg_env, res)) { enif_free(msg_env); return mk_error(env, "art_prefix_search"); } enif_free(msg_env); return mk_atom(env, "ok"); }
static ERL_NIF_TERM cmp(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { assert(argc == 2 && "cmp is a 2-arity function."); int c = enif_compare(argv[0], argv[1]); if(c < 0) { return mk_atom(env, "lesser"); } else if(c == 0) { return mk_atom(env, "equal"); } else { return mk_atom(env, "greater"); } }
static ERL_NIF_TERM elibart_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { art_tree* t; ErlNifBinary key; unsigned char buffer[BUFF_SIZE]; // 256K buffer unsigned char *key_copy = buffer; // extract arguments atr_tree, key if(argc != 2) return enif_make_badarg(env); if(!enif_get_resource(env, argv[0], elibart_RESOURCE, (void**) &t)) return enif_make_badarg(env); if (!enif_inspect_binary(env, argv[1], &key)) return enif_make_badarg(env); // buffer size not enough, pay the price if (key.size > BUFF_SIZE) key_copy = malloc(key.size + 1); // TODO review -- is it possible not to copy the key just to add '\0'? memcpy(key_copy, key.data, key.size); key_copy[key.size] = '\0'; // search the art_tree for the given key art_elem_struct *value = art_search(t, key_copy, key.size + 1); // buffer size not enough, pay the price if (key.size > BUFF_SIZE) free(key_copy); // key does not exist in the art_tree if (!value) return mk_atom(env, "empty"); // key exixts, return the associated value ErlNifBinary res; enif_alloc_binary(value->size, &res); memcpy(res.data, value->data, value->size); return enif_make_tuple2(env, mk_atom(env, "ok"), enif_make_binary(env, &res)); }
static ERL_NIF_TERM done(ErlNifEnv* env, int code) { if(code == OK) { return mk_atom(env, "ok"); } else { return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, code)); } }
int parse_args(char** cmdline, ATERM *funcname, ATERM *args,int *arg_len) { char *str; int arg; *arg_len = 0; CHK((str = strsep(cmdline,"(")) == NULL); mk_atom(*funcname,str,strlen(str)); while (*arg_len < 10 && (str = strsep(cmdline, ",)")) != NULL) { sscanf(str,"%d",&arg); *(args+*arg_len) = mk_num((double)arg); (*arg_len)++; } return 0; }
static ERL_NIF_TERM elibart_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { art_tree* t = enif_alloc_resource(elibart_RESOURCE, sizeof(art_tree)); if (init_art_tree(t) != 0) return mk_error(env, "init_art_tree"); else { ERL_NIF_TERM res = enif_make_resource(env, t); enif_release_resource(t); return enif_make_tuple2(env, mk_atom(env, "ok"), res); } }
static ERL_NIF_TERM elibart_destroy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { art_tree *t; if (argc != 1) return enif_make_badarg(env); if(!enif_get_resource(env, argv[0], elibart_RESOURCE, (void**) &t)) return enif_make_badarg(env); art_iter(t, delete_cb, NULL); if (destroy_art_tree((art_tree*) argv[0]) != 0) return mk_error(env, "destroy_art_tree"); return mk_atom(env, "ok"); }
ERL_NIF_TERM mk_error(ErlNifEnv* env, const char* mesg) { return enif_make_tuple(env, mk_atom(env, "error"), mk_atom(env, mesg)); }