Пример #1
0
void testDictErrorHandling() {
    struct dict *d = NULL;
    int e = dict_set(d, "hallo", "1");
    assert(e == -1);

    e = dict_del(d, "hallo");
    assert(e == -1);

    e = dict_has(d, "halo");
    assert(e == 0);

    const char *item = dict_get(d, "hallo");
    assert(item == NULL);


    d = dict_create();
    dict_set(d, "hallo", "1");
    dict_set(d, "hallo2", "1");
    dict_set(d, "hallo3", "2");

    e = dict_del(d, "halo");
    assert(e == -1);

    item = dict_get(d, "halo");
    assert(item == NULL);

    dict_free(d);
}
Пример #2
0
/**
 * _exp_file_insert -- Insert the exports directory into the file structure
 *                     using the directory as a dict. Also hashes the dirname,
 *                     stores it in a uuid type, converts the uuid type to a
 *                     string and uses that as the key to the exports map.
 *                     The exports map maps an export "uuid" to an export
 *                     directory struct.
 *
 * @file : Exports file struct to insert into
 * @dir  : Export directory to insert
 *
 * Not for external use.
 */
static void
_exp_file_insert(struct exports_file *file, struct export_dir *dir)
{
    data_t *dirdata = NULL;
    uint32_t hashedval = 0;
    uuid_t export_uuid = {
        0,
    };
    char export_uuid_str[512] = {
        0,
    };
    char *dirdup = NULL;

    GF_VALIDATE_OR_GOTO(GF_EXP, file, out);
    GF_VALIDATE_OR_GOTO(GF_EXP, dir, out);

    dirdata = bin_to_data(dir, sizeof(*dir));
    dict_set(file->exports_dict, dir->dir_name, dirdata);

    dirdup = strdupa(dir->dir_name);
    while (strlen(dirdup) > 0 && dirdup[0] == '/')
        dirdup++;

    hashedval = SuperFastHash(dirdup, strlen(dirdup));
    memset(export_uuid, 0, sizeof(export_uuid));
    memcpy(export_uuid, &hashedval, sizeof(hashedval));
    gf_uuid_unparse(export_uuid, export_uuid_str);

    dict_set(file->exports_map, export_uuid_str, dirdata);
out:
    return;
}
Пример #3
0
ui_elem* ui_elem_new_type_id(char* name, int type_id) {
  
  if ( dict_contains(ui_elems, name) ) {
    error("UI Manager already contains element called %s!", name);
  }
  
  debug("Creating UI Element %s (%s)", name, type_id_name(type_id));
  
  ui_elem* ui_e = NULL;
  
  for(int i = 0; i < num_ui_elem_handlers; i++) {
    ui_elem_handler ui_hand = ui_elem_handlers[i];
    if (ui_hand.type_id == type_id) {
      ui_e = ui_hand.new_func();
    }
  }
  
  if (ui_e == NULL) {
    error("Don't know how to create ui element %s. No handler for type %s!", name, type_id_name(type_id));
  }
  
  dict_set(ui_elems, name, ui_e);
  
  int* type_ptr = malloc(sizeof(int));
  *type_ptr = type_id;
  dict_set(ui_elem_types, name, type_ptr);
  
  char* name_copy = malloc(strlen(name) + 1);
  strcpy(name_copy, name);
  list_push_back(ui_elem_names, name_copy);
  
  return ui_e;
  
}
Пример #4
0
int main(){

	struct dictionary *d;
	int i;
	d = dict_new(1,0);
	int min;
	int nums[7];
	int keys[7];
	
	keys[0] = 9;
	nums[0] = 14; 
	
	keys[1] = 4;
	nums[1] = 7; 
	
	keys[2] = 12;
	nums[2] = 5; 
	
	keys[3] = 0;
	nums[3] = 15; 
	
	keys[4] = 2;
	nums[4] = 3; 
	
	keys[5] = 14;
	nums[5] = 4; 
	
	keys[6] = 5;
	nums[6] = 2; 
	
	printf("new\n");
	
	//~ printHash(d);
		
	for(i = 0; i < 7; i++){
		//~ printf("Inserting %d...\n",nums[i]);
		dict_set(d,keys[i],nums[i]);
		//~ printHash(d);
	}
	
	printHash(d);
	
	dict_set(d,2,8);
	printf("set key 2 con 8\n");
	printf("get key 2 = %d\n",dict_get(d,2));
	
	printf("delete key 2\n");
	dict_delete(d,2);
	printHash(d);
	
	printf("delete key 9\n");
	dict_delete(d,9);
	printHash(d);
	
	dict_free(d);


}
Пример #5
0
void
case_dict_clear()
{
    struct dict *dict = dict();
    assert(dict_set(dict, "key1", 4, "val1") == DICT_OK);
    assert(dict_set(dict, "key2", 4, "val2") == DICT_OK);
    assert(dict_set(dict, "key3", 4, "val3") == DICT_OK);
    assert(dict_set(dict, "key4", 4, "val4") == DICT_OK);
    assert(dict_len(dict) == 4);
    dict_clear(dict);
    assert(dict_len(dict) == 0);
    dict_free(dict);
}
Пример #6
0
void dictExample() {
	dict_t *d = (dict_t *)malloc(sizeof(dict_t));
	char *var; 
	
	
	char *key1 = strToHeap("key1");
	char *key2 = strToHeap("key2");
	char *key3 = strToHeap("key3");
	
	char *value1 = strToHeap("var1");
	char *value2 = strToHeap("var2");
	char *value3 = strToHeap("var3");
	
	dict_init(d); 
	dict_set(d, key1, value1); 
	dict_set(d, key2, value2); 
	dict_set(d, key3, value3); 
	
	dict_get(d, "key1", (void **)&var); 
	printf("key1=>%s\n", var);
	dict_get(d, "key2", (void **)&var); 
	printf("key1=>%s\n", var);
	dict_get(d, "key3", (void **)&var); 
	printf("key1=>%s\n", var);
	
	printf("dict size:%d\n", dict_size(d));
	
	
	
	if (1 == dict_del(d, key3)) {
		key3 = NULL;
		value3 = NULL;
		printf("del key3 done\n");
	}
	
	char **ks = (char **)malloc(dict_size(d)*sizeof(char*));
	int i; 
	dict_keys(d, ks); 
	for(i = 0; i < dict_size(d); i++)
		printf("%s ",*(ks+i) );
	printf("\n");
	
	char *k, *v; 
	while(dict_iter(d, &k, (void **)&v))
		printf("%s = >%s\n", k, v);
	
	dict_reset(d); 
	
	dict_destory(d); 
	free(d); 
}
Пример #7
0
void
case_dict_set()
{
    struct dict *dict = dict();
    char *key = "key", *val = "val";
    size_t len = strlen(key);
    assert(dict_set(dict, key, len, val) == DICT_OK);
    assert(dict_len(dict) == 1);
    char *val_ = "val_";
    assert(dict_get(dict, key, len) == val);
    assert(dict_set(dict, key, len, val_) == DICT_OK);
    assert(dict_get(dict, key, len) == val_);
    dict_free(dict);
}
Пример #8
0
config* cfg_load_file(const char* filename) {

  SDL_RWops* file = SDL_RWFromFile(filename, "r");
  if(file == NULL) {
    error("Cannot load file %s", filename);
  }
  
  config* c = malloc(sizeof(config));
  c->entries = dict_new(512);
  
  char line[1024];
  while(SDL_RWreadline(file, line, 1024)) {
    
    if (line[0] == '#') continue;
    if (line[0] == '\r') continue;
    if (line[0] == '\n') continue;
    
    char key[1024];
    char val[1024];
    
    if (sscanf(line, "%[^ \r\n=] = %[^ \r\n=]", key, val) == 2) {
      char* val_cpy = malloc(strlen(val) + 1);
      strcpy(val_cpy, val);
      dict_set(c->entries, key, val_cpy);
    }
    
  }
  
  SDL_RWclose(file);
  
  return c;
  
}
Пример #9
0
static dict_t *search_with_bm25_score(fts_t *fts, robj *query) {
    int i, len, nonstopwords;
    sds *terms;
    /* dict of (title, fts_doc_score_t) */
    dict_t *scores = dict_create();
    dict_set_freecb(scores, dict_doc_score_free);
    dict_t *queried_terms = dict_create();

    terms = sds_tokenize(query->ptr, &len, &nonstopwords);
    if (!terms) return scores;
    for (i = 0; i < len; i++) {
        sds term = terms[i];
        list *idx;

        if (sdslen(term) == 0) {
            sdsfree(term);
            continue;
        }

        if (dict_contains(queried_terms, term)) goto free_term;
        dict_set(queried_terms, term, (void *)1);
        idx = dict_get(fts->index, term);
        if (!idx) goto free_term;
        calculate_bm25(fts, idx, scores);
free_term:
        sdsfree(term);
    }
    dict_free(queried_terms);
    rr_free(terms);
    return scores;
}
Пример #10
0
int
set_vn(struct fuse *f, struct fuse_vnode *v)
{
    struct fuse_vn_head *vn_head;
    struct fuse_vnode *vn;

    DPRINTF("%s: create or update vnode %llu@%llu = %s\n", __func__,
            (unsigned long long)v->ino, (unsigned long long)v->parent,
            v->path);

    if (tree_set(&f->vnode_tree, v->ino, v) == NULL)
        return (0);

    if (!dict_check(&f->name_tree, v->path)) {
        vn_head = malloc(sizeof(*vn_head));
        if (vn_head == NULL)
            return (0);
        SIMPLEQ_INIT(vn_head);
    } else {
        vn_head = dict_get(&f->name_tree, v->path);
        if (vn_head == NULL)
            return (0);
    }

    SIMPLEQ_FOREACH(vn, vn_head, node) {
        if (v->parent == vn->parent && v->ino == vn->ino)
            return (1);
    }

    SIMPLEQ_INSERT_TAIL(vn_head, v, node);
    dict_set(&f->name_tree, v->path, vn_head);

    return (1);
}
Пример #11
0
static struct connection *conn_create_server(struct context *ctx, struct address *addr, char *key)
{
    int fd = conn_create_fd();
    if (fd == -1) {
        LOG(ERROR, "conn_create_server: fail to create fd");
        return NULL;
    }
    struct connection *server = server_create(ctx, fd);
    struct conn_info *info = server->info;
    memcpy(&info->addr, addr, sizeof(info->addr));

    if (conn_connect(server) == CORVUS_ERR) {
        LOG(ERROR, "conn_create_server: fail to connect %s:%d",
                info->addr.ip, info->addr.port);
        conn_free(server);
        conn_buf_free(server);
        conn_recycle(ctx, server);
        return NULL;
    }

    strncpy(info->dsn, key, DSN_LEN);
    dict_set(&ctx->server_table, info->dsn, (void*)server);
    TAILQ_INSERT_TAIL(&ctx->servers, server, next);
    return server;
}
Пример #12
0
static struct connection *conn_create_server(struct context *ctx,
        struct address *addr, char *key, bool readonly)
{
    int fd = conn_create_fd();
    if (fd == -1) {
        LOG(ERROR, "conn_create_server: fail to create fd");
        return NULL;
    }
    struct connection *server = server_create(ctx, fd);
    struct conn_info *info = server->info;
    memcpy(&info->addr, addr, sizeof(info->addr));
    extern const size_t CMD_NUM;
    info->slow_cmd_counts = cv_calloc(CMD_NUM, sizeof(uint32_t));

    if (conn_connect(server) == CORVUS_ERR) {
        LOG(ERROR, "conn_create_server: fail to connect %s:%d",
                info->addr.ip, info->addr.port);
        conn_free(server);
        conn_buf_free(server);
        conn_recycle(ctx, server);
        return NULL;
    }

    if (readonly) {
        server->info->readonly = true;
    }

    strncpy(info->dsn, key, ADDRESS_LEN);
    dict_set(&ctx->server_table, info->dsn, (void*)server);
    TAILQ_INSERT_TAIL(&ctx->servers, server, next);
    return server;
}
Пример #13
0
static void calculate_bm25(fts_t *fts, list *indices, dict_t *scores) {
    listIter *iter;
    listNode *node;
    unsigned long doc_size = fts_size(fts);
    unsigned long list_size = listLength(indices);
    doc_size = doc_size ? doc_size : 1;
    double avgdl = (fts->len * 1.0) / doc_size;

    iter = listGetIterator(indices, AL_START_HEAD);
    while((node = listNext(iter)) != NULL) {
        index_item_t *idx = node->value;
        int dl = idx->doc->len;
        fts_doc_score_t *fds = dict_get(scores, idx->doc->title->ptr);
        if (!fds) {
            fds = rr_malloc(sizeof(*fds));
            fds->doc = idx->doc;
            fds->score = .0f;
            dict_set(scores, idx->doc->title->ptr, fds);
        }
        double idf = log((doc_size - list_size + 0.5) / (list_size + 0.5));
        double tf = idx->tf * (BM25_K + 1) / (idx->tf + BM25_K * (1 - BM25_B + BM25_B*dl/avgdl));
        fds->score += tf * idf;
    }
    listReleaseIterator(iter);
}
Пример #14
0
/**
 * cache_nfs_fh -- Places the nfs file handle in the underlying dict as we are
 *                 using as our cache. The key is "exportid:gfid:host_addr", the
 *                 value is an entry struct containing the export item that
 *                 was authorized for the operation and the file handle that was
 *                 authorized.
 *
 * @cache: The cache to place fh's in
 * @fh   : The fh to cache
 * @host_addr: The address of the host
 * @export_item: The export item that was authorized
 *
 */
int
cache_nfs_fh (struct auth_cache *cache, struct nfs3_fh *fh,
              const char *host_addr, struct export_item *export_item)
{
        int                      ret        = -EINVAL;
        char                    *hashkey    = NULL;
        data_t                  *entry_data = NULL;
        time_t                   timestamp  = 0;
        gf_boolean_t             can_write  = _gf_false;
        struct auth_cache_entry *entry      = NULL;

        GF_VALIDATE_OR_GOTO (GF_NFS, host_addr, out);
        GF_VALIDATE_OR_GOTO (GF_NFS, cache, out);
        GF_VALIDATE_OR_GOTO (GF_NFS, fh, out);

        /* If we could already find it in the cache, just return */
        ret = auth_cache_lookup (cache, fh, host_addr, &timestamp, &can_write);
        if (ret == 0) {
                gf_msg_trace (GF_NFS, 0, "found cached auth/fh for host "
                              "%s", host_addr);
                goto out;
        }

        hashkey = make_hashkey (fh, host_addr);
        if (!hashkey) {
                ret = -ENOMEM;
                goto out;
        }

        entry = auth_cache_entry_init ();
        if (!entry) {
                ret = -ENOMEM;
                goto out;
        }

        entry->timestamp = time (NULL);
        entry->item = export_item;

        /* The cache entry will simply be the time that the entry
         * was cached.
         */
        entry_data = bin_to_data (entry, sizeof (*entry));
        if (!entry_data) {
                GF_FREE (entry);
                goto out;
        }

        ret = dict_set (cache->cache_dict, hashkey, entry_data);
        if (ret == -1) {
                GF_FREE (entry);
                goto out;
        }
        gf_msg_trace (GF_NFS, 0, "Caching file-handle (%s)", host_addr);
        ret = 0;
out:
        GF_FREE (hashkey);

        return ret;
}
Пример #15
0
void ui_elem_add_type_id(char* name, int type_id, ui_elem* ui_elem) {

  if ( dict_contains(ui_elems, name) ) {
    error("UI Manager already contains element called %s!", name);
  }
  
  dict_set(ui_elems, name, ui_elem);
  
  int* type_ptr = malloc(sizeof(int));
  *type_ptr = type_id;
  dict_set(ui_elem_types, name, type_ptr);
  
  char* name_copy = malloc(strlen(name) + 1);
  strcpy(name_copy, name);
  list_push_back(ui_elem_names, name_copy);

}
Пример #16
0
int
main(int argc, char *argv[]) {
    dicthdl d = dict_new(false, 1, NULL);

    dict_set(d, "hola", "lola");
    dict_set(d, "pita", "chula");

    puts(dict_get(d, "hola"));
    puts(dict_get(d, "pita"));

    dict_unset(d, "hola");
    
    dict_get(d, "hola");
    puts(dict_get(d, "pita"));

    dict_free(d);

    return EXIT_SUCCESS;
}
Пример #17
0
void
case_dict_has()
{
    struct dict *dict = dict();
    char *key = "key", *val = "val";
    size_t len = strlen(key);
    assert(dict_set(dict, key, len, val) == DICT_OK);
    assert(!dict_has(dict, "not exist", 9));
    assert(dict_has(dict, key, len));
    dict_free(dict);
}
Пример #18
0
static void test_upgrade_dict(CuTest *tc) {
    attrib *a;
    
    a = a_new(&at_dict);

    dict_set(a, "embassy_muschel", 42);
    CuAssertPtrNotNull(tc, a->type->upgrade);
    a->type->upgrade(&a, a);
    CuAssertIntEquals(tc, 42, key_get(a, atoi36("mupL")));
    a_removeall(&a, NULL);
}
Пример #19
0
/**
 * SoX version
 */
static PyObject* py_sox_version() {
  PyObject* retval = PyDict_New();
  if (!retval) return 0;
  auto retval_ = make_safe(retval);

# if defined(SOX_VERSION)
  if (std::strlen(SOX_VERSION) && !dict_set(retval, "sox", SOX_VERSION)) return 0;
# endif

  return Py_BuildValue("O", retval);
}
Пример #20
0
Dict* dict_rehash( Dict *d )
{
	Dict *new_dict = dict_new_size( d->size * 1.7, d->hash_func, d->comp_func );
	for( int i=0; i<d->size; i++ ){
		for( DictEntry *cur = d->entry[i]; cur; cur = cur->next ){
			dict_set( new_dict, cur->key, cur->val );
		}
	}
	dict_free( d );
	return new_dict;
}
Пример #21
0
int main(void)
{
	dict *d = dict_new();
	
	assert( dict_value(d, "a") == NULL );
	assert( dict_remove(d, "a") == 0 );

	assert( dict_set(d, "a", "01") == 1 );
	assert( strcmp(dict_value(d, "a"), "01") == 0 );

	assert( dict_set(d, "a", "10") == 0 );
	assert( strcmp(dict_value(d, "a"), "10") == 0 );

	assert( dict_remove(d, "b") == 0 );
	assert( dict_remove(d, "a") == 1 );

	assert( dict_value(d, "a") == NULL);

	d = dict_free(d);
	return EXIT_SUCCESS;
}
Пример #22
0
void testDict() {
    struct dict *d = dict_create(NULL);
    dict_set(d, "name", "drmaa2");
    dict_set(d, "language", "c");
    dict_set(d, "version", "2");
    dict_set(d, "age", "2 weeks");

    assert(dict_has(d, "language") != 0);

    dict_del(d, "age");
    dict_del(d, "language");

    assert(dict_has(d, "version") != 0);

    dict_del(d, "name");
    dict_set(d, "version", "3");
    const char *v = dict_get(d, "version");
    assert(strcmp(v, "3") == 0);

    dict_del(d, "version");
    dict_set(d, "new_version", "4");
    assert(dict_has(d, "version") == 0);
    assert(dict_has(d, "new_version") != 0);

    dict_free(d);
}
Пример #23
0
void
case_dict_iter()
{
    struct dict *dict = dict();
    char *key1 = "key1"; size_t len1 = 4;
    char *key2 = "key2"; size_t len2 = 4;
    char *key3 = "key3"; size_t len3 = 4;
    char *key4 = "key4"; size_t len4 = 4;
    char *key5 = "key5"; size_t len5 = 4;
    char *key6 = "key6"; size_t len6 = 4;
    assert(dict_set(dict, key1, len1, "val1") == DICT_OK);
    assert(dict_set(dict, key2, len2, "val2") == DICT_OK);
    assert(dict_set(dict, key3, len3, "val3") == DICT_OK);
    assert(dict_set(dict, key4, len4, "val4") == DICT_OK);
    assert(dict_set(dict, key5, len5, "val5") == DICT_OK);
    assert(dict_set(dict, key6, len6, "val6") == DICT_OK);

    struct dict_iter *iter = dict_iter(dict);

    assert(dict_iter_next(iter) != NULL);
    assert(dict_iter_next(iter) != NULL);
    assert(dict_iter_next(iter) != NULL);
    assert(dict_iter_next(iter) != NULL);
    assert(dict_iter_next(iter) != NULL);
    assert(dict_iter_next(iter) != NULL);
    assert(dict_iter_next(iter) == NULL);
    dict_iter_free(iter);
    dict_free(dict);
}
Пример #24
0
void testBasicDict() {
    struct dict *d = dict_create();

    dict_set(d, "name", "drmaa2");
    dict_del(d, "name");
    dict_set(d, "name", "drmaa2");
    assert(dict_has(d, "name") != 0);
    assert(dict_has(d, "language") == 0);

    const char *v = dict_get(d, "name");
    assert(strcmp(v, "drmaa2") == 0);

    dict_set(d, "language", "c");
    assert(dict_has(d, "language") != 0);

    dict_del(d, "name");
    assert(dict_has(d, "name") == 0);
    v = dict_get(d, "language");
    assert(strcmp(v, "c") == 0);

    dict_free(d);
}
Пример #25
0
static void cmd_dict_set(int argc, char *argv[])
{
	struct dict *dict;
	struct dict_transaction_context *trans;

	dict = cmd_dict_init(&argc, &argv, 2, 0, cmd_dict_set);
	trans = dict_transaction_begin(dict);
	dict_set(trans, argv[0], argv[1]);
	if (dict_transaction_commit(&trans) <= 0) {
		i_error("dict_transaction_commit() failed");
		doveadm_exit_code = EX_TEMPFAIL;
	}
	dict_deinit(&dict);
}
Пример #26
0
void tm_set( tm_obj self, tm_obj k, tm_obj v){
	switch( self.type ){
	case TM_LST:
	{
        if( TM_NUM != k.type){
            tm_raise("tm_set(), expect a number but see @", _tm_type(k));
        }
		int n = get_num(k);
		list_set( get_list(self), n, v);
	}return;
	case TM_DCT: dict_set( get_dict(self), k, v);return;
	}
	tm_raise(" tm_set: @[@] = @", self, k, v );
}
Пример #27
0
void dict_resize(struct dict *dict)
{
    struct bucket *bucket, *buckets = dict->buckets;
    uint32_t i, capacity = dict->capacity;

    dict->capacity += DICT_BASE_CAPACITY;
    _dict_init(dict);

    for (i = 0; i < capacity; i++) {
        bucket = &buckets[i];
        if (!bucket->deleted && bucket->setted) {
            dict_set(dict, bucket->key, bucket->data);
        }
    }
    free(buckets);
}
Пример #28
0
bool fts_add(fts_t *fts, robj *title, robj *doc) {
    if (dict_contains(fts->docs, title->ptr)) fts_del(fts, title);

    fts_doc_t *fd = fts_doc_create(title, doc);
    if (!dict_set(fts->docs, title->ptr, fd)) {
        fts_doc_free(fd);
        return false;
    }

    /* update the index for this doc */
    if (!fts_index_add(fts, fd)) {
        fts_doc_free(dict_del(fts->docs, title->ptr));
        return false;
    }
    return true;
}
Пример #29
0
static int
table_sqlite_fetch(int service, char *dst, size_t sz)
{
	const char	*k;
	int		 s;

	if (service != K_SOURCE)
		return (-1);

	if (stmt_fetch_source == NULL)
		return (-1);

	if (source_ncall < source_refresh &&
	    time(NULL) - source_update < source_expire)
	    goto fetch;

	source_iter = NULL;
	while (dict_poproot(&sources, NULL))
		;

	while ((s = sqlite3_step(stmt_fetch_source)) == SQLITE_ROW)
		dict_set(&sources, sqlite3_column_text(stmt_fetch_source, 0), NULL);

	if (s != SQLITE_DONE)
		log_warnx("warn: table-sqlite: sqlite3_step: %s",
		    sqlite3_errmsg(db));

	sqlite3_reset(stmt_fetch_source);

	source_update = time(NULL);
	source_ncall = 0;

    fetch:

	source_ncall += 1;

        if (! dict_iter(&sources, &source_iter, &k, (void **)NULL)) {
		source_iter = NULL;
		if (! dict_iter(&sources, &source_iter, &k, (void **)NULL))
			return (0);
	}

	if (strlcpy(dst, k, sz) >= sz)
		return (-1);

	return (1);
}
Пример #30
0
/**
 * Clone dict object, using key_clone_fn and value_clone_fn, function pointers.
 *
 * If the clone function pointer for key/value is NULL, then it will simply do a
 * static copy of the pointer. Doing this on heap allocated memory may lead to
 * memory errors.
 *
 * @param   struct dict *to_clone
 * @param   void *(*key_clone_fn)(void *)
 * @param   void *(*value_clone_fn)(void *)
 * @return  struct dict *
 *
 * Returns NULL on error.
 **/
struct dict *dict_clone(struct dict *to_clone, void *(*key_clone_fn)(void *), void *(*value_clone_fn)(void *))
{
    size_t i;
    void *key_clone;
    void *value_clone;
    struct dict_node *cur;
    struct dict *clone = dict_new(
        to_clone->seed,
        to_clone->capacity,
        to_clone->key_free_fn,
        to_clone->value_free_fn
    );
    
    if (clone == NULL) {
        return NULL;
    }
    
    if (key_clone_fn == NULL) {
        key_clone_fn = _dummy_clone_fn;
    }

    if (value_clone_fn == NULL) {
        value_clone_fn = _dummy_clone_fn;
    }
    
    for (i = 0; i < to_clone->capacity; i++) {
        cur = &to_clone->table[i];
        while (cur && cur->key) {
            key_clone = key_clone_fn(cur->key);
            value_clone = value_clone_fn(cur->value);
        
            if (dict_set(clone, key_clone, value_clone) == 0) {
                // Make sure key/value gets freed
                clone->key_free_fn(key_clone);
                clone->value_free_fn(value_clone);
                
                dict_delete(clone);
                return NULL;
            }
            
            cur = cur->next;
        }
    }
    
    return clone;
}