Пример #1
0
static void test_hash_random_pool(pool_t pool)
{
#define KEYMAX 100000
	HASH_TABLE(void *, void *) hash;
	unsigned int *keys;
	unsigned int i, key, keyidx, delidx;

	keys = i_new(unsigned int, KEYMAX); keyidx = 0;
	hash_table_create_direct(&hash, pool, 0);
	for (i = 0; i < KEYMAX; i++) {
		key = (rand() % KEYMAX) + 1;
		if (rand() % 5 > 0) {
			if (hash_table_lookup(hash, POINTER_CAST(key)) == NULL) {
				hash_table_insert(hash, POINTER_CAST(key),
						  POINTER_CAST(1));
				keys[keyidx++] = key;
			}
		} else if (keyidx > 0) {
			delidx = rand() % keyidx;
			hash_table_remove(hash, POINTER_CAST(keys[delidx]));
			memmove(&keys[delidx], &keys[delidx+1],
				(keyidx-delidx-1) * sizeof(*keys));
			keyidx--;
		}
	}
	for (i = 0; i < keyidx; i++)
		hash_table_remove(hash, POINTER_CAST(keys[i]));
	hash_table_destroy(&hash);
	i_free(keys);
}
Пример #2
0
void chirp_alloc_flush()
{
	char *path, *root;
	struct alloc_state *s;

	if(!alloc_enabled)
		return;

	debug(D_ALLOC, "flushing allocation states...");

	if(!alloc_table)
		alloc_table = hash_table_create(0, 0);

	hash_table_firstkey(alloc_table);
	while(hash_table_nextkey(alloc_table, &path, (void **) &s)) {
		alloc_state_save(path, s);
		hash_table_remove(alloc_table, path);
	}

	if(!root_table)
		root_table = hash_table_create(0, 0);

	hash_table_firstkey(root_table);
	while(hash_table_nextkey(root_table, &path, (void **) &root)) {
		free(root);
		hash_table_remove(root_table, path);
	}

	last_flush_time = time(0);
}
Пример #3
0
void test_hash_table_remove(void)
{
	HashTable *hash_table;
	char buf[10];

	hash_table = generate_hash_table();

	assert(hash_table_num_entries(hash_table) == NUM_TEST_VALUES);
	sprintf(buf, "%i", 5000);
	assert(hash_table_lookup(hash_table, buf) != NULL);

	/* Remove an entry */

	hash_table_remove(hash_table, buf);

	/* Check entry counter */

	assert(hash_table_num_entries(hash_table) == 9999);

	/* Check that NULL is returned now */

	assert(hash_table_lookup(hash_table, buf) == NULL);

	/* Try removing a non-existent entry */

	sprintf(buf, "%i", -1);
	hash_table_remove(hash_table, buf);

	assert(hash_table_num_entries(hash_table) == 9999);

	hash_table_free(hash_table);
}
Пример #4
0
static int log_replay( struct nvpair_database *db, const char *filename, time_t snapshot)
{
	FILE *file = fopen(filename,"r");
	if(!file) return 0;
	
	time_t current = 0;
	struct nvpair *nv;

	char line[NVPAIR_LINE_MAX];
	char key[NVPAIR_LINE_MAX];
	char name[NVPAIR_LINE_MAX];
	char value[NVPAIR_LINE_MAX];
	char oper;
	
	while(fgets(line,sizeof(line),file)) {

		int n = sscanf(line,"%c %s %s %[^\n]",&oper,key,name,value);
		if(n<1) continue;

		switch(oper) {
			case 'C':
				nv = nvpair_create();
				nvpair_parse_stream(nv,file);
				nvpair_delete(hash_table_remove(db->table,name));
				hash_table_insert(db->table,key,nv);
				break;
			case 'D':
				nv = hash_table_remove(db->table,key);
				if(nv) nvpair_delete(nv);
				break;
			case 'U':
				nv = hash_table_lookup(db->table,key);
				if(nv) nvpair_insert_string(nv,name,value);
				break;
			case 'R':
				nv = hash_table_lookup(db->table,key);
				if(nv) nvpair_remove(nv,name);
				break;
			case 'T':
				current = atol(key);
				if(current>snapshot) break;
				break;
			default:
				debug(D_NOTICE,"corrupt log data in %s: %s",filename,line);
				break;
		}
	}
	
	fclose(file);

	return 1;
}
Пример #5
0
static int server_table_load(time_t stoptime)
{
	struct catalog_query *q;
	struct jx *j;
	char *key;
	void *item;

	if((last_update + update_interval) > time(0)) {
		return 1;
	}

	if(!server_table) {
		server_table = hash_table_create(0, 0);
		if(!server_table)
			return 0;
	}

	if(inhibit_catalog_queries) {
		debug(D_CHIRP, "catalog queries disabled\n");
		return 1;
	}

	hash_table_firstkey(server_table);
	while(hash_table_nextkey(server_table, &key, &item)) {
		hash_table_remove(server_table, key);
		jx_delete(item);
	}

	debug(D_CHIRP, "querying catalog at %s:%d", CATALOG_HOST, CATALOG_PORT);

	q = catalog_query_create(CATALOG_HOST, CATALOG_PORT, stoptime);
	if(!q)
		return 0;

	while((j = catalog_query_read(q, stoptime))) {
		char name[CHIRP_PATH_MAX];
		const char *type, *hname;
		int port;

		type = jx_lookup_string(j, "type");
		if(type && !strcmp(type, "chirp")) {
			hname = jx_lookup_string(j, "name");
			if(hname) {
				port = jx_lookup_integer(j, "port");
				if(!port)
					port = CHIRP_PORT;
				sprintf(name, "%s:%d", hname, port);
				hash_table_insert(server_table, name, j);
			} else {
				jx_delete(j);
			}
		} else {
			jx_delete(j);
		}
	}
	catalog_query_delete(q);
	last_update = time(0);

	return 1;
}
Пример #6
0
static void
trace_winsys_buffer_unmap(struct pipe_winsys *_winsys, 
                          struct pipe_buffer *buffer)
{
   struct trace_winsys *tr_ws = trace_winsys(_winsys);
   struct pipe_winsys *winsys = tr_ws->winsys;
   const void *map;
   
   map = hash_table_get(tr_ws->buffer_maps, buffer);
   if(map) {
      trace_dump_call_begin("pipe_winsys", "buffer_write");
      
      trace_dump_arg(ptr, winsys);
      
      trace_dump_arg(ptr, buffer);
      
      trace_dump_arg_begin("data");
      trace_dump_bytes(map, buffer->size);
      trace_dump_arg_end();

      trace_dump_arg_begin("size");
      trace_dump_uint(buffer->size);
      trace_dump_arg_end();
   
      trace_dump_call_end();

      hash_table_remove(tr_ws->buffer_maps, buffer);
   }
   
   winsys->buffer_unmap(winsys, buffer);
}
Пример #7
0
/** Process pending wait requests */
void process_pending_wait(void)
{
	task_exit_t texit;
	
loop:
	list_foreach(pending_wait, cur) {
		pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link);
		
		unsigned long keys[2] = {
			LOWER32(pr->id),
			UPPER32(pr->id)
		};
		
		link_t *link = hash_table_find(&task_hash_table, keys);
		if (!link)
			continue;
		
		hashed_task_t *ht = hash_table_get_instance(link, hashed_task_t, link);
		if (!ht->finished)
			continue;
		
		if (!(pr->callid & IPC_CALLID_NOTIFICATION)) {
			texit = ht->have_rval ? TASK_EXIT_NORMAL :
			    TASK_EXIT_UNEXPECTED;
			ipc_answer_2(pr->callid, EOK, texit,
			    ht->retval);
		}
		
		hash_table_remove(&task_hash_table, keys, 2);
		list_remove(cur);
		free(pr);
		goto loop;
	}
Пример #8
0
static int compat_checkpoint_read( struct deltadb *db, const char *filename )
{
	FILE * file = fopen(filename,"r");
	if(!file) return 0;

	while(1) {
		struct nvpair *nv = nvpair_create();
		if(nvpair_parse_stream(nv,file)) {
			const char *key = nvpair_lookup_string(nv,"key");
			if(key) {
				nvpair_delete(hash_table_remove(db->table,key));
				struct jx *j = nvpair_to_jx(nv);
				/* skip objects that don't match the filter */
				if(deltadb_boolean_expr(db->filter_expr,j)) {
					hash_table_insert(db->table,key,j);
				} else {
					jx_delete(j);
				}
			}
			nvpair_delete(nv);
		} else {
			nvpair_delete(nv);
			break;
		}
	}

	fclose(file);

	return 1;
}
Пример #9
0
/* void close_database(id) */
static int cc_close_database(lua_State* L)
{
	int id;
	database_handler_t* database_handler;
	worker_handler_t* handler = find_handler_by_stack(L);
	int args = lua_gettop(L);
	if (args < 1)
	{
		error_log("`%s` parameter lack:%d\n", __FUNCTION__, args);
		return 0;
	}
	if (!lua_isnumber(L, -args))
	{
		error_log("`%s` parameter error:%s\n", __FUNCTION__, lua_typename(L, lua_type(L, -args)));
		return 0;
	}
	id = lua_tointeger(L, -args);
	database_handler = hash_table_find(handler->database_table, id);
	if (!database_handler)
	{
		error_log("`%s` not found database:%d\n", __FUNCTION__, id);
		return 0;
	}
	hash_table_remove(handler->database_table, id);
	database_handler_delete(database_handler);
	return 0;
}
void auth_request_handler_abort_requests(struct auth_request_handler *handler)
{
	struct hash_iterate_context *iter;
	void *key;
	struct auth_request *auth_request;

	iter = hash_table_iterate_init(handler->requests);
	while (hash_table_iterate(iter, handler->requests, &key, &auth_request)) {
		switch (auth_request->state) {
		case AUTH_REQUEST_STATE_NEW:
		case AUTH_REQUEST_STATE_MECH_CONTINUE:
		case AUTH_REQUEST_STATE_FINISHED:
			auth_request_unref(&auth_request);
			hash_table_remove(handler->requests, key);
			break;
		case AUTH_REQUEST_STATE_PASSDB:
		case AUTH_REQUEST_STATE_USERDB:
			/* can't abort a pending passdb/userdb lookup */
			break;
		case AUTH_REQUEST_STATE_MAX:
			i_unreached();
		}
	}
	hash_table_iterate_deinit(&iter);
}
Пример #11
0
static int compat_checkpoint_read( struct jx_database *db, const char *filename )
{
	FILE * file = fopen(filename,"r");
	if(!file) return 0;

	while(1) {
		struct nvpair *nv = nvpair_create();
		if(nvpair_parse_stream(nv,file)) {
			const char *key = nvpair_lookup_string(nv,"key");
			if(key) {
				nvpair_delete(hash_table_remove(db->table,key));
				struct jx *j = nvpair_to_jx(nv);
				hash_table_insert(db->table,key,j);
			}
			nvpair_delete(nv);
		} else {
			nvpair_delete(nv);
			break;
		}
	}

	fclose(file);

	return 1;
}
Пример #12
0
static void mail_session_free(struct mail_session *session)
{
	i_assert(session->refcount == 0);

	global_memory_free(mail_session_memsize(session));

	if (session->to_idle != NULL)
		timeout_remove(&session->to_idle);
	if (!session->disconnected)
		hash_table_remove(mail_sessions_hash, session->id);
	DLLIST_REMOVE_FULL(&stable_mail_sessions, session,
			   stable_prev, stable_next);
	DLLIST2_REMOVE_FULL(&mail_sessions_head, &mail_sessions_tail, session,
			    sorted_prev, sorted_next);
	DLLIST_REMOVE_FULL(&session->user->sessions, session,
			   user_prev, user_next);
	mail_user_unref(&session->user);
	if (session->ip != NULL) {
		DLLIST_REMOVE_FULL(&session->ip->sessions, session,
				   ip_prev, ip_next);
		mail_ip_unref(&session->ip);
	}

	str_table_unref(services, &session->service);
	i_free(session->id);
	i_free(session);
}
Пример #13
0
void service_process_destroy(struct service_process *process)
{
	struct service *service = process->service;
	struct service_list *service_list = service->list;

	DLLIST_REMOVE(&service->processes, process);
	hash_table_remove(service_pids, POINTER_CAST(process->pid));

	if (process->available_count > 0)
		service->process_avail--;
	service->process_count--;
	i_assert(service->process_avail <= service->process_count);

	if (process->to_status != NULL)
		timeout_remove(&process->to_status);
	if (process->to_idle != NULL)
		timeout_remove(&process->to_idle);
	if (service->list->log_byes != NULL)
		service_process_notify_add(service->list->log_byes, process);

	process->destroyed = TRUE;
	service_process_unref(process);

	if (service->process_count < service->process_limit &&
	    service->type == SERVICE_TYPE_LOGIN)
		service_login_notify(service, FALSE);

	service_list_unref(service_list);
}
Пример #14
0
int ast_program_execute( struct ast_group *program, time_t stoptime )
{
	struct ast_group *g;
	struct ast_function *f, *old;

	/*
	First, fill up the function table with all of the functions
	in this entire syntax tree.
	*/

	ftable = hash_table_create(127,hash_string);
	if(!ftable) ftsh_fatal(0,"out of memory");

	for( g=program; g; g=g->next ) {
		if(g->command->type==AST_COMMAND_FUNCTION) {
			f = g->command->u.function;
			old = hash_table_remove(ftable,f->name->text);
			if(old) {
				ftsh_error(FTSH_ERROR_SYNTAX,f->function_line,"function %s is defined twice (first at line %d)",f->name->text,old->function_line);
				return 0;
			}
			if(!hash_table_insert(ftable,f->name->text,f)) {
				ftsh_fatal(f->function_line,"out of memory");
			}
		}
	}

	return ast_group_execute(program,stoptime);
}
Пример #15
0
int
main (void)
{
  struct hash_table *ht = make_string_hash_table (0);
  char line[80];
  while ((fgets (line, sizeof (line), stdin)))
    {
      int len = strlen (line);
      if (len <= 1)
	continue;
      line[--len] = '\0';
      if (!hash_table_contains (ht, line))
	hash_table_put (ht, strdup (line), "here I am!");
#if 1
      if (len % 5 == 0)
	{
	  char *line_copy;
	  if (hash_table_get_pair (ht, line, &line_copy, NULL))
	    {
	      hash_table_remove (ht, line);
	      xfree (line_copy);
	    }
	}
#endif
    }
#if 0
  print_hash (ht);
#endif
#if 1
  printf ("%d %d\n", ht->count, ht->size);
#endif
  return 0;
}
Пример #16
0
static void checkpassword_request_finish(struct chkpw_auth_request *request,
					 enum userdb_result result)
{
	struct userdb_module *_module = request->request->userdb->userdb;
	struct checkpassword_userdb_module *module =
		(struct checkpassword_userdb_module *)_module;
	userdb_callback_t *callback =
		(userdb_callback_t *)request->callback;

	hash_table_remove(module->clients, POINTER_CAST(request->pid));

	if (result == USERDB_RESULT_OK) {
		if (strchr(str_c(request->input_buf), '\n') != NULL) {
			auth_request_log_error(request->request,
				"userdb-checkpassword",
				"LF characters in checkpassword reply");
			result = USERDB_RESULT_INTERNAL_FAILURE;
		} else {
			auth_request_init_userdb_reply(request->request);
			auth_request_set_fields(request->request,
				t_strsplit(str_c(request->input_buf), "\t"),
				NULL);
		}
	}

	callback(result, request->request);

	auth_request_unref(&request->request);
	checkpassword_request_free(request);
}
Пример #17
0
void test_hash_table_iterating_remove(void)
{
	HashTable *hash_table;
	HashTableIterator iterator;
	char buf[10];
	char *val;
	HashTablePair pair;
	int count;
	unsigned int removed;
	int i;

	hash_table = generate_hash_table();

	/* Iterate over all values in the table */

	count = 0;
	removed = 0;

	hash_table_iterate(hash_table, &iterator);

	while (hash_table_iter_has_more(&iterator)) {

		/* Read the next value */

		pair = hash_table_iter_next(&iterator);
		val = pair.value;

		/* Remove every hundredth entry */

		if ((atoi(val) % 100) == 0) {
			hash_table_remove(hash_table, val);
			++removed;
		}

		++count;
	}

	/* Check counts */

	assert(removed == 100);
	assert(count == NUM_TEST_VALUES);

	assert(hash_table_num_entries(hash_table)
	       == NUM_TEST_VALUES - removed);

	/* Check all entries divisible by 100 were really removed */

	for (i=0; i<NUM_TEST_VALUES; ++i) {
		sprintf(buf, "%i", i);

		if (i % 100 == 0) {
			assert(hash_table_lookup(hash_table, buf) == NULL);
		} else {
			assert(hash_table_lookup(hash_table, buf) != NULL);
		}
	}

	hash_table_free(hash_table);
}
Пример #18
0
void nvpair_insert_string(struct nvpair *n, const char *name, const char *value)
{
	void *old;
	old = hash_table_remove(n->table, name);
	if(old)
		free(old);
	hash_table_insert(n->table, name, xxstrdup(value));
}
Пример #19
0
static void mail_session_disconnect(struct mail_session *session)
{
	uint8_t *guid_p = session->guid;

	hash_table_remove(mail_sessions_hash, guid_p);
	session->disconnected = TRUE;
	timeout_remove(&session->to_idle);
	mail_session_unref(&session);
}
Пример #20
0
void delete_process_ht(hash_table_t * fd_mappings, int32_t pid) {
	item_t * process_ht_item;

	if ( (process_ht_item = hash_table_find(fd_mappings, &pid)) != NULL ) {
		hash_table_remove(fd_mappings, &pid);
	} else {
		ERRORPRINTF("Can not find pid %"PRIi32" when removing delete_process_ht\n", pid);
	}
}
Пример #21
0
static void passwd_file_free(struct passwd_file *pw)
{
	if (hash_table_is_created(pw->db->files))
		hash_table_remove(pw->db->files, pw->path);

	passwd_file_close(pw);
	i_free(pw->path);
	i_free(pw);
}
Пример #22
0
static void
dsync_mailbox_state_remove(struct dsync_brain *brain,
			   const guid_128_t mailbox_guid)
{
	const uint8_t *guid_p;

	guid_p = mailbox_guid;
	if (hash_table_lookup(brain->mailbox_states, guid_p) != NULL)
		hash_table_remove(brain->mailbox_states, guid_p);
}
Пример #23
0
static void
auth_cache_node_destroy(struct auth_cache *cache, struct auth_cache_node *node)
{
	char *key = node->data;

	auth_cache_node_unlink(cache, node);

	cache->size_left += node->alloc_size;
	hash_table_remove(cache->hash, key);
	i_free(node);
}
Пример #24
0
static void
init_interesting (void)
{
  /* Init the variables interesting_tags and interesting_attributes
     that are used by the HTML parser to know which tags and
     attributes we're interested in.  We initialize this only once,
     for performance reasons.

     Here we also make sure that what we put in interesting_tags
     matches the user's preferences as specified through --ignore-tags
     and --follow-tags.  */

  int i;
  interesting_tags = make_nocase_string_hash_table (countof (known_tags));

  /* First, add all the tags we know hot to handle, mapped to their
     respective entries in known_tags.  */
  for (i = 0; i < countof (known_tags); i++)
    hash_table_put (interesting_tags, known_tags[i].name, known_tags + i);

  /* Then remove the tags ignored through --ignore-tags.  */
  if (opt.ignore_tags)
    {
      char **ignored;
      for (ignored = opt.ignore_tags; *ignored; ignored++)
        hash_table_remove (interesting_tags, *ignored);
    }

  /* If --follow-tags is specified, use only those tags.  */
  if (opt.follow_tags)
    {
      /* Create a new table intersecting --follow-tags and known_tags,
         and use it as interesting_tags.  */
      struct hash_table *intersect = make_nocase_string_hash_table (0);
      char **followed;
      for (followed = opt.follow_tags; *followed; followed++)
        {
          struct known_tag *t = hash_table_get (interesting_tags, *followed);
          if (!t)
            continue;           /* ignore unknown --follow-tags entries. */
          hash_table_put (intersect, *followed, t);
        }
      hash_table_destroy (interesting_tags);
      interesting_tags = intersect;
    }

  /* Add the attributes we care about. */
  interesting_attributes = make_nocase_string_hash_table (10);
  for (i = 0; i < countof (additional_attributes); i++)
    hash_table_put (interesting_attributes, additional_attributes[i], "1");
  for (i = 0; i < countof (tag_url_attributes); i++)
    hash_table_put (interesting_attributes,
                    tag_url_attributes[i].attr_name, "1");
}
Пример #25
0
static void test_remove(void)
{
    Hash_table table;

    hash_table_init(&table);
    populate(&table);

    #define VERIFY_REMOVE_NOT_EXISTS(key)              \
      {                                                \
          int v = 234;                                 \
                                                       \
          VERIFY(!hash_table_get(&table, key, &v));    \
          VERIFY(!hash_table_remove(&table, key, &v)); \
          VERIFY(!hash_table_get(&table, key, &v));    \
          VERIFY(v == 234);                            \
      }

    #define VERIFY_REMOVE_EXISTS(key)                    \
      {                                                  \
          int v1, v2;                                    \
                                                         \
          VERIFY(hash_table_get(&table, key, &v1));      \
          VERIFY(hash_table_remove(&table, key, &v2));   \
          VERIFY(!hash_table_get(&table, key, NULL));    \
          VERIFY(!hash_table_remove(&table, key, NULL)); \
          VERIFY(v1 == v2);                              \
      }

    VERIFY_REMOVE_NOT_EXISTS("foo");
    VERIFY_REMOVE_NOT_EXISTS("on");
    VERIFY_REMOVE_NOT_EXISTS("tw");
    VERIFY_REMOVE_EXISTS("negative one");
    VERIFY_REMOVE_EXISTS("zero");
    VERIFY_REMOVE_EXISTS("one");
    VERIFY_REMOVE_EXISTS("two");
    VERIFY_REMOVE_EXISTS("three");
    VERIFY_REMOVE_EXISTS("four");
    VERIFY_REMOVE_EXISTS("five");
    VERIFY_REMOVE_EXISTS("six");
    VERIFY_REMOVE_EXISTS("seven");
    VERIFY_REMOVE_EXISTS("eight");
    VERIFY_REMOVE_EXISTS("nine");
    VERIFY_REMOVE_EXISTS("ten");
    VERIFY_REMOVE_EXISTS("");

    #undef VERIFY_REMOVE_NOT_EXISTS
    #undef VERIFY_REMOVE_EXISTS

    // The case where the key exists and val is NULL
    hash_table_set(&table, "foo", 3, NULL);
    VERIFY(hash_table_remove(&table, "foo", NULL));

    hash_table_free(&table);
}
Пример #26
0
struct jx * jx_database_remove( struct jx_database *db, const char *key )
{
	const char *nkey = strdup(key);

	struct jx *j = hash_table_remove(db->table,key);
	if(db->logdir && j) {
		log_delete(db,nkey);
		log_flush(db);
	}
	return j;
}
Пример #27
0
struct nvpair * nvpair_database_remove( struct nvpair_database *db, const char *key )
{
	const char *nkey = strdup(key);

	struct nvpair *nv = hash_table_remove(db->table,nkey);
	if(db->logdir && nv) {
		log_delete(db,nkey);
		log_flush(db);
	}
	return nv;
} 
Пример #28
0
void batch_queue_set_feature (struct batch_queue *q, const char *what, const char *value)
{
    char *current = hash_table_remove(q->features, what);
    free(current);
    if(value) {
        hash_table_insert(q->features, what, xxstrdup(value));
        debug(D_BATCH, "set feature `%s' to `%s'", what, value);
    } else {
        debug(D_BATCH, "cleared feature `%s'", what);
    }
}
Пример #29
0
/* Free ressources used by a timer */
static inline void timer_free(timer_entry_t *timer,int take_lock)
{
   if (take_lock) TIMER_LOCK();

   /* Remove ID from hash table */
   hash_table_remove(timer_id_hash,&timer->id);

   if (take_lock) TIMER_UNLOCK();

   /* Free memory used by timer */
   free(timer);
}
Пример #30
0
void test_hash_table_free_functions(void)
{
	HashTable *hash_table;
	int *key;
	int *value;
	int i;

	/* Create a hash table, fill it with values */

	hash_table = hash_table_new(int_hash, int_equal);

	hash_table_register_free_functions(hash_table, free_key, free_value);

	allocated_values = 0;

	for (i=0; i<NUM_TEST_VALUES; ++i) {
		key = new_key(i);
		value = new_value(99);

		hash_table_insert(hash_table, key, value);
	}

	assert(allocated_keys == NUM_TEST_VALUES);
	assert(allocated_values == NUM_TEST_VALUES);

	/* Check that removing a key works */

	i = NUM_TEST_VALUES / 2;
	hash_table_remove(hash_table, &i);

	assert(allocated_keys == NUM_TEST_VALUES - 1);
	assert(allocated_values == NUM_TEST_VALUES - 1);

	/* Check that replacing an existing key works */

	key = new_key(NUM_TEST_VALUES / 3);
	value = new_value(999);

	assert(allocated_keys == NUM_TEST_VALUES);
	assert(allocated_values == NUM_TEST_VALUES);

	hash_table_insert(hash_table, key, value);

	assert(allocated_keys == NUM_TEST_VALUES - 1);
	assert(allocated_values == NUM_TEST_VALUES - 1);

	/* A free of the hash table should free all of the keys and values */

	hash_table_free(hash_table);

	assert(allocated_keys == 0);
	assert(allocated_values == 0);
}