/* * C_lib Copyright (C) 2021 Wael Karram. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* This file contains the function implementations for queues. */ /* Include guards + includes. */ #ifndef QUEUE_C #define QUEUE_C #include "queue.h" #endif /* QUEUE_C */ /* Function implementations. */ /* This function initializes a new empty queue. */ /* Will return a pointer to the queue on success, otherwise will return NULL. */ queue_t *initialize_queue() { /* Variables. */ queue_t *result; /* Attempt to allocate. */ result = (queue_t*) malloc(sizeof(queue_t)); /* Check if the allocation failed. */ if (result == NULL) return NULL; /* Allocate the internal list struct. */ result->list = (list_t*) malloc(sizeof(list_t)); /* Check if the allocation failed. */ if (result->list == NULL) { free(result); return NULL; } /* Initialize the internal fields. */ result->tail = NULL; result->list->head = NULL; result->list->length = 0; /* Return the result. */ return result; } /* This function enqueues a node. */ /* This function attempts to enqueue a given node into the given queue, on success will return SUCCESS_CODE_QUEUE_C, otherwise will return FAILURE_CODE_QUEUE_C. */ /* Note that if either the queue or node pointer are NULL, the function will automatically fail. */ int enqueue(queue_t *queue, node_t *node) { /* Input sanity check. */ if (queue == NULL || queue->list == NULL || node == NULL || ((queue->list->head == NULL && queue->tail != NULL) || (queue->list->head != NULL && queue->tail == NULL))) return FAILURE_CODE_QUEUE_C; /* Attempt to enqueue the node. */ /* Check if the queue is empty. */ if (queue->list->head == NULL) { node->next = NULL; queue->tail = node; } else node->next = queue->list->head; /* Relink the head. */ queue->list->head = node; /* Increase the length. */ (queue->list->length)++; /* Success. */ return SUCCESS_CODE_QUEUE_C; } /* This function allocates and enqueues a node. */ /* This function attempts to create a node then enqueue it into the given queue, on success will return SUCCESS_CODE_QUEUE_C, otherwise will return FAILURE_CODE_QUEUE_C. */ /* Note that if either the queue pointer is NULL or node allocation fails, the function will automatically fail. */ int enqueue_data(queue_t *queue, void *data) { /* Variables. */ node_t *node; /* Input sanity check. */ if (queue == NULL || queue->list == NULL || ((queue->list->head == NULL && queue->tail != NULL) || (queue->list->head != NULL && queue->tail == NULL))) return FAILURE_CODE_QUEUE_C; /* Attempt to allocate the node. */ node = (node_t) malloc(sizeof(node)); if (node == NULL) return FAILURE_CODE_QUEUE_C; /* Attempt to enqueue the node. */ /* Check if the queue is empty. */ if (queue->list->head == NULL) { node->next = NULL; queue->tail = node; } else node->next = queue->list->head; /* Relink the head. */ queue->list->head = node; /* Increase the length. */ (queue->list->length)++; /* Success. */ return SUCCESS_CODE_QUEUE_C; } /* This function dequeues a node. */ /* This function attempts to dequeues a node from the given queue, on success will return a pointer to the dequeued node - otherwise returns NULL. */ /* Note that if either the queue or node pointer are NULL, the function will automatically fail. */ node_t *dequeue(queue_t *queue) { /* Variables. */ node_t *result, *replacement, *tmp; int i; /* Input sanity check. */ if (queue == NULL || queue->list == NULL || ((queue->list->head == NULL && queue->tail != NULL) || (queue->list->head != NULL && queue->tail == NULL))) return NULL; /* Attempt to dequeue the node. */ /* Check if the queue is empty. */ if (queue->list->head == NULL) return NULL; else if (queue->list->length == 1) { /* A queue that is of length 1. */ result = queue->list->head; queue->list->head = NULL; queue->tail = NULL; } else { /* This is the general case, move the tail and unlink. */ /* Set the result to be the tail. */ result = queue->tail; /* Attempt to find the new tail. */ tmp = queue->list->head; while (tmp->next != result) tmp = tmp->next; /* Unlink and set the new tail. */ tmp->next = NULL; queue->tail = tmp; } /* Decrease the length. */ (queue->list->length)--; /* Success. */ return SUCCESS_CODE_QUEUE_C; } /* This function frees all the nodes of the given queue and the queue itself (setting it to NULL). */ /* Note that it doesn't touch the data stored within the queue's nodes, returns 1 on success and 0 on failure - in the latter case might exhibit undefined behavior. */ int clear_queue(queue_t **queue) { /* Sanity check. */ if (queue == NULL || *queue == NULL) return FAILURE_CODE_QUEUE_C; /* Delegate to implementation (linked list). */ if (!clear_single_linked_list(&((*queue)->list))) return FAILURE_CODE_QUEUE_C; /* Successfully cleared the internal structure, just free the queue struct and set the pointer to NULL. */ free(*queue); *queue = NULL; return SUCCESS_CODE_QUEUE_C; } /* This function frees all the nodes of the given queue and the queue itself (setting it to NULL).*/ /* Note that it does free the stored data, returns 1 on success and 0 on failure - in the latter case might exhibit undefined behavior. */ /* If free_function is NULL, then it the standard library's free() call is used. */ int clear_queue(queue_t **queue, void (*free_func)()) { /* Sanity check. */ if (queue == NULL || *queue == NULL) return FAILURE_CODE_QUEUE_C; /* Delegate to implementation (linked list). */ if (!clear_single_linked_list(&((*queue)->list), free_function)) return FAILURE_CODE_QUEUE_C; /* Successfully cleared the internal structure, just free the queue struct and set the pointer to NULL. */ free(*queue); *queue = NULL; return SUCCESS_CODE_QUEUE_C; } /* This function serializes the queue. */ /* Note that it'll return NULL on allocation failure or invalid input - in the former case it'll set the correct length in the specified pointer, in the second it will set -1. */ void **serialize_queue(queue_t *queue, int *length) { /* Sanity check. */ if (queue == NULL) { *length = -1; return NULL; } /* Delegate. */ return serialize_list(queue->list, length); }