Last active
November 4, 2019 16:01
-
-
Save cwchentw/d6e4d921e12ca2a417e30e4aea198a59 to your computer and use it in GitHub Desktop.
Generic Queue in Void Pointer (Apache 2.0)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdbool.h> | |
#include <stdlib.h> | |
#include "integer.h" | |
struct int_t { | |
int data; | |
}; | |
int_t* int_new(int n) | |
{ | |
int_t *i = malloc(sizeof(int_t)); | |
if (!i) | |
return i; | |
i->data = n; | |
return i; | |
} | |
bool int_copy(void **dest, void *src) | |
{ | |
*dest = malloc(sizeof(int_t)); | |
if (!dest) | |
return false; | |
((int_t *) (*dest))->data = int_value((int_t *) src); | |
return true; | |
} | |
int int_value(int_t *self) | |
{ | |
return self->data; | |
} | |
void int_delete(void *self) | |
{ | |
if (!self) | |
return; | |
free(self); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <stdbool.h> | |
typedef struct int_t int_t; | |
int_t* int_new(int n); | |
int int_value(int_t *self); | |
bool int_copy(void **, void *); | |
void int_delete(void *self); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <stdio.h> | |
#include "integer.h" // Home-made `int`-wrapping box class. | |
#include "queue.h" | |
#define ERROR(msg, ...) \ | |
fprintf(stderr, "(%s:%d) " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__); | |
int main() | |
{ | |
// queue_t: NULL | |
queue_t *queue = queue_new(int_copy, int_delete); | |
if (!queue) { | |
ERROR("Failed to allocate the queue"); | |
goto ERROR; | |
} | |
int_t *temp; | |
// queue_t: 9 -> NULL | |
temp = int_new(9); | |
if (!temp) { | |
ERROR("Failed to allocate the int object"); | |
goto ERROR; | |
} | |
queue_push_front(queue, temp); | |
temp = (int_t *) queue_peek_front(queue); | |
if (!(int_value(temp) == 9)) { | |
ERROR("Wrong value"); | |
goto ERROR; | |
} | |
temp = (int_t *) queue_peek_rear(queue); | |
if (!(int_value(temp) == 9)) { | |
ERROR("Wrong value"); | |
goto ERROR; | |
} | |
// queue_t: 4 -> 9 -> NULL | |
temp = int_new(4); | |
if (!temp) { | |
ERROR("Failed to allocate the int object"); | |
goto ERROR; | |
} | |
queue_push_front(queue, temp); | |
temp = (int_t *) queue_peek_front(queue); | |
if (!(int_value(temp) == 4)) { | |
ERROR("Wrong value"); | |
goto ERROR; | |
} | |
temp = (int_t *) queue_peek_rear(queue); | |
if (!(int_value(temp) == 9)) { | |
ERROR("Wrong value"); | |
goto ERROR; | |
} | |
// queue_t: 4 -> 9 -> 5 -> NULL | |
temp = int_new(5); | |
if (!temp) { | |
ERROR("Failed to allocate the int object"); | |
goto ERROR; | |
} | |
queue_push_rear(queue, temp); | |
temp = (int_t *) queue_peek_front(queue); | |
if (!(int_value(temp) == 4)) { | |
ERROR("Wrong value"); | |
goto ERROR; | |
} | |
temp = (int_t *) queue_peek_rear(queue); | |
if (!(int_value(temp) == 5)) { | |
ERROR("Wrong value"); | |
goto ERROR; | |
} | |
// queue_t: 9 -> 5 -> NULL | |
temp = (int_t *) queue_pop_front(queue); | |
if (!temp) { | |
ERROR("No valid value"); | |
goto ERROR; | |
} | |
if (!(int_value(temp) == 4)) { | |
ERROR("Wrong value"); | |
goto ERROR; | |
} | |
int_delete(temp); | |
temp = (int_t *) queue_peek_front(queue); | |
if (!(int_value(temp) == 9)) { | |
ERROR("Wrong value"); | |
goto ERROR; | |
} | |
temp = (int_t *) queue_peek_rear(queue); | |
if (!(int_value(temp) == 5)) { | |
ERROR("Wrong value"); | |
goto ERROR; | |
} | |
// queue_t: 9 -> NULL | |
temp = (int_t *) queue_pop_rear(queue); | |
if (!temp) { | |
ERROR("No valid value"); | |
goto ERROR; | |
} | |
if (!(int_value(temp) == 5)) { | |
ERROR("Wrong value"); | |
goto ERROR; | |
} | |
int_delete(temp); | |
temp = (int_t *) queue_peek_front(queue); | |
if (!(int_value(temp) == 9)) { | |
ERROR("Wrong value"); | |
goto ERROR; | |
} | |
temp = (int_t *) queue_peek_rear(queue); | |
if (!(int_value(temp) == 9)) { | |
ERROR("Wrong value"); | |
goto ERROR; | |
} | |
// queue_t: NULL | |
temp = (int_t *) queue_pop_rear(queue); | |
if (!temp) { | |
ERROR("No valid value"); | |
goto ERROR; | |
} | |
if (!(int_value(temp) == 9)) { | |
ERROR("Wrong value"); | |
goto ERROR; | |
} | |
int_delete(temp); | |
queue_delete(queue); | |
return 0; | |
ERROR: | |
if (queue) | |
queue_delete(queue); | |
return 1; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <assert.h> | |
#include <stdbool.h> | |
#include <stdlib.h> | |
#include "queue.h" | |
typedef struct node_t node_t; | |
struct node_t { | |
item_t data; | |
node_t *prev; | |
node_t *next; | |
}; | |
static node_t* node_new(item_t data); | |
struct queue_t { | |
copy_fn item_copy; | |
free_fn item_free; | |
node_t *head; | |
node_t *tail; | |
}; | |
static node_t* node_new(item_t data) | |
{ | |
node_t *node = malloc(sizeof(node_t)); | |
if (!node) | |
return node; | |
node->data = data; | |
node->prev = NULL; | |
node->next = NULL; | |
return node; | |
} | |
queue_t* queue_new(copy_fn item_copy, free_fn item_free) | |
{ | |
queue_t *lt = malloc(sizeof(queue_t)); | |
if (!lt) | |
return lt; | |
lt->item_copy = item_copy; | |
lt->item_free = item_free; | |
lt->head = NULL; | |
lt->tail = NULL; | |
return lt; | |
} | |
bool queue_is_empty(queue_t *self) | |
{ | |
return !(self->head); | |
} | |
item_t queue_peek_front(queue_t *self) | |
{ | |
if (!(self->head)) | |
return NULL; | |
return self->head->data; | |
} | |
item_t queue_peek_rear(queue_t *self) | |
{ | |
if (!(self->head)) | |
return NULL; | |
return self->tail->data; | |
} | |
bool queue_push_front(queue_t *self, item_t data) | |
{ | |
node_t *node = node_new(data); | |
if (!node) | |
return false; | |
if (!(self->head)) { | |
self->head = node; | |
self->tail = node; | |
return true; | |
} | |
node->next = self->head; | |
self->head->prev = node; | |
self->head = node; | |
return true; | |
} | |
item_t queue_pop_front(queue_t *self) | |
{ | |
assert(!queue_is_empty(self)); | |
if (self->head == self->tail) { | |
item_t popped; | |
self->item_copy(&popped, self->head->data); | |
self->item_free(self->head->data); | |
free(self->head); | |
self->head = NULL; | |
self->tail = NULL; | |
return popped; | |
} | |
node_t *curr = self->head; | |
item_t popped; | |
self->item_copy(&popped, curr->data); | |
self->head = self->head->next; | |
self->item_free(curr->data); | |
free(curr); | |
return popped; | |
} | |
bool queue_push_rear(queue_t *self, item_t data) | |
{ | |
node_t *node = node_new(data); | |
if (!node) | |
return false; | |
if (self->tail == NULL) { | |
self->head = node; | |
self->tail = node; | |
return true; | |
} | |
self->tail->next = node; | |
node->prev = self->tail; | |
self->tail = node; | |
return true; | |
} | |
item_t queue_pop_rear(queue_t *self) | |
{ | |
assert(!queue_is_empty(self)); | |
if (self->head == self->tail) { | |
item_t popped; | |
self->item_copy(&popped, self->tail->data); | |
self->item_free(self->tail->data); | |
free(self->tail); | |
self->head = NULL; | |
self->tail = NULL; | |
return popped; | |
} | |
node_t *curr = self->tail; | |
item_t popped; | |
self->item_copy(&popped, curr->data); | |
self->tail = self->tail->prev; | |
self->item_free(curr->data); | |
free(curr); | |
return popped; | |
} | |
void queue_delete(void *self) | |
{ | |
if (!self) | |
return; | |
free_fn fn = ((queue_t *) self)->item_free; | |
node_t *curr = ((queue_t *) self)->head; | |
node_t *temp = NULL; | |
while (curr) { | |
temp = curr; | |
curr = curr->next; | |
(*fn)(temp->data); | |
free(temp); | |
} | |
free(self); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <stdbool.h> | |
typedef void * item_t; | |
typedef bool (*copy_fn) (void **, void *); | |
typedef void (*free_fn) (void *); | |
typedef struct queue_t queue_t; | |
queue_t* queue_new(copy_fn, free_fn); | |
bool queue_is_empty(queue_t *self); | |
item_t queue_peek_front(queue_t *self); | |
item_t queue_peek_rear(queue_t *self); | |
bool queue_push_front(queue_t *self, item_t data); | |
item_t queue_pop_front(queue_t *self); | |
bool queue_push_rear(queue_t *self, item_t data); | |
item_t queue_pop_rear(queue_t *self); | |
void queue_delete(void *self); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment