Cleaned up usage of linked lists and added missing functionality.
- Added a list_remove_first() which is generally better than list_remove() provided you want to remove the first element. - Added a list_append_list() to append and move all nodes from one list to another.
This commit is contained in:
		
							parent
							
								
									b81bb2cbd9
								
							
						
					
					
						commit
						2d6f69d299
					
				| @ -516,6 +516,15 @@ int main(int argc, char** argv) | |||||||
| 	exotic_add_test(&handle, &exotic_test_list_get_last_prev_2, "list_get_last_prev_2"); | 	exotic_add_test(&handle, &exotic_test_list_get_last_prev_2, "list_get_last_prev_2"); | ||||||
| 	exotic_add_test(&handle, &exotic_test_list_get_last_prev_next_1, "list_get_last_prev_next_1"); | 	exotic_add_test(&handle, &exotic_test_list_get_last_prev_next_1, "list_get_last_prev_next_1"); | ||||||
| 	exotic_add_test(&handle, &exotic_test_list_clear, "list_clear"); | 	exotic_add_test(&handle, &exotic_test_list_clear, "list_clear"); | ||||||
|  | 	exotic_add_test(&handle, &exotic_test_list_remove_first_1_1, "list_remove_first_1_1"); | ||||||
|  | 	exotic_add_test(&handle, &exotic_test_list_remove_first_1_2, "list_remove_first_1_2"); | ||||||
|  | 	exotic_add_test(&handle, &exotic_test_list_remove_first_1_3, "list_remove_first_1_3"); | ||||||
|  | 	exotic_add_test(&handle, &exotic_test_list_remove_first_1_4, "list_remove_first_1_4"); | ||||||
|  | 	exotic_add_test(&handle, &exotic_test_list_remove_first_1_5, "list_remove_first_1_5"); | ||||||
|  | 	exotic_add_test(&handle, &exotic_test_list_append_list_1, "list_append_list_1"); | ||||||
|  | 	exotic_add_test(&handle, &exotic_test_list_append_list_2, "list_append_list_2"); | ||||||
|  | 	exotic_add_test(&handle, &exotic_test_list_append_list_3, "list_append_list_3"); | ||||||
|  | 	exotic_add_test(&handle, &exotic_test_list_clear_list_last, "list_clear_list_last"); | ||||||
| 	exotic_add_test(&handle, &exotic_test_list_destroy_1, "list_destroy_1"); | 	exotic_add_test(&handle, &exotic_test_list_destroy_1, "list_destroy_1"); | ||||||
| 	exotic_add_test(&handle, &exotic_test_list_destroy_2, "list_destroy_2"); | 	exotic_add_test(&handle, &exotic_test_list_destroy_2, "list_destroy_2"); | ||||||
| 	exotic_add_test(&handle, &exotic_test_test_message_refc_1, "test_message_refc_1"); | 	exotic_add_test(&handle, &exotic_test_test_message_refc_1, "test_message_refc_1"); | ||||||
| @ -951,7 +960,6 @@ int exotic_initialize(struct exotic_handle* handle, int argc, char** argv) | |||||||
| void exotic_add_test(struct exotic_handle* handle, exo_test_t func, const char* name) | void exotic_add_test(struct exotic_handle* handle, exo_test_t func, const char* name) | ||||||
| { | { | ||||||
| 	struct exo_test_data* test; | 	struct exo_test_data* test; | ||||||
| 
 |  | ||||||
| 	if (!handle) | 	if (!handle) | ||||||
| 	{ | 	{ | ||||||
| 		fprintf(stderr, "exotic_add_test: failed, no handle!\n"); | 		fprintf(stderr, "exotic_add_test: failed, no handle!\n"); | ||||||
|  | |||||||
| @ -1,10 +1,16 @@ | |||||||
| #include <uhub.h> | #include <uhub.h> | ||||||
| 
 | 
 | ||||||
| static struct linked_list* list = NULL; | static struct linked_list* list = NULL; | ||||||
|  | static struct linked_list* list2 = NULL; | ||||||
| 
 | 
 | ||||||
| static char A[2] = { 'A', 0 }; | static char A[2] = { 'A', 0 }; | ||||||
| static char B[2] = { 'B', 0 }; | static char B[2] = { 'B', 0 }; | ||||||
| static char C[2] = { 'C', 0 }; | static char C[2] = { 'C', 0 }; | ||||||
|  | static char A2[2] = { 'a', 0 }; | ||||||
|  | static char B2[2] = { 'b', 0 }; | ||||||
|  | static char C2[2] = { 'c', 0 }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| static void null_free(void* ptr) | static void null_free(void* ptr) | ||||||
| { | { | ||||||
| @ -124,6 +130,82 @@ EXO_TEST(list_clear, { | |||||||
| 	return list->size == 0 && list->first == 0 && list->last == 0 && list->iterator == 0; | 	return list->size == 0 && list->first == 0 && list->last == 0 && list->iterator == 0; | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  | static int g_remove_flag = 0; | ||||||
|  | static void null_free_inc_flag(void* ptr) | ||||||
|  | { | ||||||
|  | 	(void) ptr; | ||||||
|  | 	g_remove_flag++; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | EXO_TEST(list_remove_first_1_1, | ||||||
|  | { | ||||||
|  | 	list_append(list, A); | ||||||
|  | 	list_append(list, B); | ||||||
|  | 	list_append(list, C); | ||||||
|  | 	return list->size == 3; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | EXO_TEST(list_remove_first_1_2, | ||||||
|  | { | ||||||
|  | 	g_remove_flag = 0; | ||||||
|  | 	list_remove_first(list, null_free_inc_flag); | ||||||
|  | 	return list->size == 2 && g_remove_flag == 1; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | EXO_TEST(list_remove_first_1_3, | ||||||
|  | { | ||||||
|  | 	list_remove_first(list, NULL); | ||||||
|  | 	return list->size == 1; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | EXO_TEST(list_remove_first_1_4, | ||||||
|  | { | ||||||
|  | 	list_remove_first(list, NULL); | ||||||
|  | 	return list->size == 0; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | EXO_TEST(list_remove_first_1_5, | ||||||
|  | { | ||||||
|  | 	list_remove_first(list, NULL); | ||||||
|  | 	return list->size == 0; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | EXO_TEST(list_append_list_1, | ||||||
|  | { | ||||||
|  | 	list_append(list, A); | ||||||
|  | 	list_append(list, B); | ||||||
|  | 	list_append(list, C); | ||||||
|  | 	list2 = list_create(); | ||||||
|  | 	list_append(list2, A2); | ||||||
|  | 	list_append(list2, B2); | ||||||
|  | 	list_append(list2, C2); | ||||||
|  | 	return list->size == 3 && list2->size == 3; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | EXO_TEST(list_append_list_2, | ||||||
|  | { | ||||||
|  | 	list_append_list(list, list2); | ||||||
|  | 	return list->size == 6 && list2->size == 0; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | EXO_TEST(list_append_list_3, | ||||||
|  | { | ||||||
|  | 	list_destroy(list2); | ||||||
|  | 	return list_get_index(list, 0) == A && | ||||||
|  | 			list_get_index(list, 1) == B && | ||||||
|  | 			list_get_index(list, 2) == C && | ||||||
|  | 			list_get_index(list, 3) == A2 && | ||||||
|  | 			list_get_index(list, 4) == B2 && | ||||||
|  | 			list_get_index(list, 5) == C2; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | EXO_TEST(list_clear_list_last, | ||||||
|  | { | ||||||
|  | 	list_clear(list, &null_free); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| EXO_TEST(list_destroy_1, { | EXO_TEST(list_destroy_1, { | ||||||
| 	list_destroy(list); | 	list_destroy(list); | ||||||
|  | |||||||
| @ -92,13 +92,7 @@ int event_queue_process(struct event_queue* queue) | |||||||
| 	queue->locked = 0; | 	queue->locked = 0; | ||||||
| 
 | 
 | ||||||
| 	/* transfer from secondary queue to the primary queue. */ | 	/* transfer from secondary queue to the primary queue. */ | ||||||
| 	data = (struct event_data*) list_get_first(queue->q2); | 	list_append_list(queue->q1, queue->q2); | ||||||
| 	while (data) |  | ||||||
| 	{ |  | ||||||
| 		list_remove(queue->q2, data); |  | ||||||
| 		list_append(queue->q1, data); |  | ||||||
| 		data = (struct event_data*) list_get_first(queue->q2); |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/* if more events exist, schedule it */ | 	/* if more events exist, schedule it */ | ||||||
| 	if (list_size(queue->q1)) | 	if (list_size(queue->q1)) | ||||||
|  | |||||||
| @ -1320,9 +1320,7 @@ void hub_logout_log(struct hub_info* hub, struct hub_user* user) | |||||||
| 	list_append(hub->logout_info, loginfo); | 	list_append(hub->logout_info, loginfo); | ||||||
| 	while (list_size(hub->logout_info) > (size_t) hub->config->max_logout_log) | 	while (list_size(hub->logout_info) > (size_t) hub->config->max_logout_log) | ||||||
| 	{ | 	{ | ||||||
| 		struct hub_logout_info* entry = list_get_first(hub->logout_info); | 		list_remove_first(hub->logout_info, hub_free); | ||||||
| 		list_remove(hub->logout_info, entry); |  | ||||||
| 		hub_free(entry); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -229,16 +229,16 @@ int plugin_initialize(struct hub_config* config, struct hub_info* hub) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void plugin_unload_ptr(void* ptr) | ||||||
|  | { | ||||||
|  | 	struct plugin_handle* plugin = (struct plugin_handle*) ptr; | ||||||
|  | 	plugin_unload(plugin); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| void plugin_shutdown(struct uhub_plugins* handle) | void plugin_shutdown(struct uhub_plugins* handle) | ||||||
| { | { | ||||||
| 	struct plugin_handle* plugin = (struct plugin_handle*) list_get_first(handle->loaded); | 	list_clear(handle->loaded, plugin_unload_ptr); | ||||||
| 	while (plugin) |  | ||||||
| 	{ |  | ||||||
| 		list_remove(handle->loaded, plugin); |  | ||||||
| 		plugin_unload(plugin); |  | ||||||
| 		plugin = (struct plugin_handle*) list_get_first(handle->loaded); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	list_destroy(handle->loaded); | 	list_destroy(handle->loaded); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -50,9 +50,7 @@ static void history_add(struct plugin_handle* plugin, struct plugin_user* from, | |||||||
| 	list_append(data->chat_history, log); | 	list_append(data->chat_history, log); | ||||||
| 	while (list_size(data->chat_history) > data->history_max) | 	while (list_size(data->chat_history) > data->history_max) | ||||||
| 	{ | 	{ | ||||||
| 		char* msg = list_get_first(data->chat_history); | 		list_remove_first(data->chat_history, hub_free); | ||||||
| 		list_remove(data->chat_history, msg); |  | ||||||
| 		hub_free(msg); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -80,6 +80,35 @@ void list_append(struct linked_list* list, void* data_ptr) | |||||||
| 	list->size++; | 	list->size++; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void list_append_list(struct linked_list* list, struct linked_list* other) | ||||||
|  | { | ||||||
|  | 	/* Anything to move? */ | ||||||
|  | 	if (!other->size) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (!list->size) | ||||||
|  | 	{ | ||||||
|  | 		/* If the list is empty, just move the pointers */ | ||||||
|  | 		list->size = other->size; | ||||||
|  | 		list->first = other->first; | ||||||
|  | 		list->last = other->last; | ||||||
|  | 		list->iterator = other->iterator; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		other->first->prev = list->last; | ||||||
|  | 		list->last->next = other->first; | ||||||
|  | 		list->last = other->last; | ||||||
|  | 		list->size += other->size; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Make sure the original list appears empty */ | ||||||
|  | 	other->size = 0; | ||||||
|  | 	other->first = NULL; | ||||||
|  | 	other->last = NULL; | ||||||
|  | 	other->iterator = NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| void list_remove(struct linked_list* list, void* data_ptr) | void list_remove(struct linked_list* list, void* data_ptr) | ||||||
| { | { | ||||||
| @ -113,6 +142,30 @@ void list_remove(struct linked_list* list, void* data_ptr) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void list_remove_first(struct linked_list* list, void (*free_handle)(void* ptr)) | ||||||
|  | { | ||||||
|  | 	struct node* node = list->first; | ||||||
|  | 
 | ||||||
|  | 	list->iterator = NULL; | ||||||
|  | 
 | ||||||
|  | 	if (!node) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	list->first = node->next; | ||||||
|  | 
 | ||||||
|  | 	if (list->first) | ||||||
|  | 		list->first->prev = NULL; | ||||||
|  | 
 | ||||||
|  | 	if (list->last == node) | ||||||
|  | 		list->last = NULL; | ||||||
|  | 
 | ||||||
|  | 	list->size--; | ||||||
|  | 
 | ||||||
|  | 	if (free_handle) | ||||||
|  | 		free_handle(node->ptr); | ||||||
|  | 	hub_free(node); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| size_t list_size(struct linked_list* list) | size_t list_size(struct linked_list* list) | ||||||
| { | { | ||||||
|  | |||||||
| @ -42,6 +42,13 @@ extern void list_clear(struct linked_list*, void (*free_handle)(void* ptr) ); | |||||||
| 
 | 
 | ||||||
| extern void list_append(struct linked_list* list, void* data_ptr); | extern void list_append(struct linked_list* list, void* data_ptr); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * A special list append that moves all nodes from other_list to list. | ||||||
|  |  * The other list will be empty. | ||||||
|  |  */ | ||||||
|  | extern void list_append_list(struct linked_list* list, struct linked_list* other); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Remove data_ptr from the list. If multiple versions occur, only the first one is removed. |  * Remove data_ptr from the list. If multiple versions occur, only the first one is removed. | ||||||
|  */ |  */ | ||||||
| @ -57,6 +64,12 @@ extern void* list_get_prev(struct linked_list*); | |||||||
| extern struct node* list_get_first_node(struct linked_list*); | extern struct node* list_get_first_node(struct linked_list*); | ||||||
| extern struct node* list_get_last_node(struct linked_list*); | extern struct node* list_get_last_node(struct linked_list*); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Remove the first element, and call the free_handle function (if not NULL) | ||||||
|  |  * to ensure the data is freed also. | ||||||
|  |  */ | ||||||
|  | extern void list_remove_first(struct linked_list* list, void (*free_handle)(void* ptr)); | ||||||
|  | 
 | ||||||
| #define LIST_FOREACH(TYPE, ITEM, LIST, BLOCK) \ | #define LIST_FOREACH(TYPE, ITEM, LIST, BLOCK) \ | ||||||
| 		for (ITEM = (TYPE) list_get_first(LIST); ITEM; ITEM = (TYPE) list_get_next(LIST)) \ | 		for (ITEM = (TYPE) list_get_first(LIST); ITEM; ITEM = (TYPE) list_get_next(LIST)) \ | ||||||
| 			BLOCK | 			BLOCK | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user