Author: Amin Tahmasebi
Release Date: 2023
License: ISC License
The Deque library provides a generic container in C that mimics the functionality of std::deque
in C++. It offers a dynamic-size double-ended queue (deque) that allows fast insertion and removal of elements from both ends. This library is part of a larger project to reimplement C++ standard library features in C.
To compile the Deque library along with your main program, use the following GCC command:
gcc -std=c11 -O3 -march=native -flto -funroll-loops -Wall -Wextra -pedantic -s -o main ./main.c ./deque/deque.c
Ensure you have the GCC compiler installed on your system and that all source files are in the correct directory structure as shown in the project.
To use the Deque library in your project, include the deque.h
header file in your source code:
#include "deque/deque.h"
-
Deque* deque_create(size_t itemSize)
Creates a new deque with elements of a specified size.itemSize
is the size of each element in the deque. Returns a pointer to the newly created deque. -
void deque_deallocate(Deque* deque)
Deallocates all memory associated with the deque, including all elements and blocks. It should be called when the deque is no longer needed to avoid memory leaks.
-
void deque_push_front(Deque* deque, void* item)
Inserts a new element at the front of the deque. Theitem
is a pointer to the data to be inserted. -
void deque_push_back(Deque* deque, const void* item)
Inserts a new element at the back of the deque. Theitem
is a pointer to the data to be inserted. -
void deque_pop_front(Deque* deque)
Removes the element at the front of the deque. -
void deque_pop_back(Deque* deque)
Removes the element at the back of the deque.
-
void* deque_front(const Deque* deque)
Returns a pointer to the element at the front of the deque. -
void* deque_back(const Deque* deque)
Returns a pointer to the element at the back of the deque. -
void* deque_at(const Deque* deque, size_t index)
Returns a pointer to the element at the specified index in the deque. If the index is out of bounds, an error message is printed.
-
size_t deque_length(const Deque* deque)
Returns the number of elements currently in the deque. -
size_t deque_max_size(const Deque* deque)
Returns the maximum possible number of elements that can be stored in the deque (limited bySIZE_MAX
). -
void deque_resize(Deque* deque, size_t newSize)
Resizes the deque to containnewSize
elements. IfnewSize
is greater than the current size, new elements are added at the back. IfnewSize
is smaller, elements are removed from the back. -
void deque_shrink_to_fit(Deque* deque)
Reduces the capacity of the deque to fit its current size, releasing any unused memory. -
bool deque_empty(const Deque* deque)
Returnstrue
if the deque is empty, otherwise returnsfalse
.
-
void deque_insert(Deque* deque, size_t index, void* item)
Inserts an element at the specified index in the deque. Elements at and after the index are shifted to the right. -
void deque_erase(Deque* deque, size_t index)
Removes the element at the specified index in the deque. Elements after the index are shifted to the left. -
void deque_clear(Deque* deque)
Removes all elements from the deque, resetting it to its initial state. -
void deque_assign(Deque* deque, size_t n, void* val)
Assignsn
copies ofval
to the deque, replacing its contents. -
void deque_emplace_back(Deque* deque, void* item)
Inserts a new element at the back of the deque without copying, constructing the element in place. -
void deque_emplace_front(Deque* deque, void* item)
Inserts a new element at the front of the deque without copying, constructing the element in place. -
void deque_emplace(Deque* deque, size_t index, void* item)
Inserts a new element at the specified index without copying, constructing the element in place.
-
bool deque_is_equal(const Deque* deque1, const Deque* deque2)
Returnstrue
if the contents ofdeque1
anddeque2
are equal, otherwise returnsfalse
. -
bool deque_is_less(const Deque* deque1, const Deque* deque2)
Returnstrue
ifdeque1
is lexicographically less thandeque2
. -
bool deque_is_greater(const Deque* deque1, const Deque* deque2)
Returnstrue
ifdeque1
is lexicographically greater thandeque2
. -
bool deque_is_not_equal(const Deque* deque1, const Deque* deque2)
Returnstrue
if the contents ofdeque1
anddeque2
are not equal. -
bool deque_is_less_or_equal(const Deque* deque1, const Deque* deque2)
Returnstrue
ifdeque1
is lexicographically less than or equal todeque2
. -
bool deque_is_greater_or_equal(const Deque* deque1, const Deque* deque2)
Returnstrue
ifdeque1
is lexicographically greater than or equal todeque2
.
-
DequeIterator deque_begin(const Deque* deque)
Returns an iterator pointing to the first element of the deque. -
DequeIterator deque_end(const Deque* deque)
Returns an iterator pointing just past the last element of the deque. -
DequeIterator deque_rbegin(const Deque* deque)
Returns a reverse iterator pointing to the last element of the deque. -
DequeIterator deque_rend(const Deque* deque)
Returns a reverse iterator pointing just before the first element of the deque. -
const DequeIterator* deque_cbegin(const Deque* deque)
Returns a constant iterator pointing to the first element of the deque. -
const DequeIterator* deque_cend(const Deque* deque)
Returns a constant iterator pointing just past the last element of the deque. -
const DequeIterator* deque_crbegin(const Deque* deque)
Returns a constant reverse iterator pointing to the last element of the deque. -
const DequeIterator* deque_crend(const Deque* deque)
Returns a constant reverse iterator pointing just before the first element of the deque. -
void iterator_increment(DequeIterator* it)
Moves the iteratorit
to the next element in the deque. -
void iterator_decrement(DequeIterator* it)
Moves the iteratorit
to the previous element in the deque. -
bool iterator_equals(const DequeIterator* it1, const DequeIterator* it2)
Returnstrue
if iteratorsit1
andit2
point to the same element, otherwise returnsfalse
. -
void* iterator_get(const DequeIterator* it)
Returns a pointer to the element at the iteratorit
's current position.
#include "deque/deque.h" // Include your bitset header file
#include "fmt/fmt.h"
int main() {
Deque* myDeque = deque_create(sizeof(int));
int val1 = 10, val2 = 20;
// Pushing elements
deque_push_back(myDeque, &val1); // Add to back
fmt_printf("Pushed %d to back\n", val1);
deque_push_front(myDeque, &val2); // Add to front
fmt_printf("Pushed %d to front\n", val2);
// Accessing elements
int* frontVal = (int*)deque_front(myDeque); // Access front element
int* backVal = (int*)deque_back(myDeque); // Access back element
fmt_printf("Front: %d, Back: %d\n", *frontVal, *backVal);
// Popping elements
deque_pop_front(myDeque); // Remove from front
fmt_printf("Popped from front\n");
deque_pop_back(myDeque); // Remove from back
fmt_printf("Popped from back\n");
deque_deallocate(myDeque);
return 0;
}
#include "deque/deque.h"
#include "fmt/fmt.h"
int main() {
Deque* myDeque = deque_create(sizeof(int));
int nums[] = {1, 2, 3, 4, 5};
// Pushing elements
for (int i = 0; i < 5; ++i) {
deque_push_back(myDeque, &nums[i]);
fmt_printf("Pushed %d to back\n", nums[i]);
}
// Accessing elements using deque_at
fmt_printf("Deque elements: ");
for (size_t i = 0; i < deque_length(myDeque); ++i) {
fmt_printf("%d ", *(int*)deque_at(myDeque, i));
}
fmt_printf("\n");
deque_deallocate(myDeque);
return 0;
}
#include "deque/deque.h" // Include your bitset header file
#include "fmt/fmt.h"
#include <stdlib.h>
int main() {
Deque* myDeque = deque_create(sizeof(int));
for (int i = 0; i < 10; ++i) {
int* ptr = malloc(sizeof(int));
if (ptr == NULL) {
fmt_fprintf(stderr, "Failed to allocate memory\n");
free(ptr);
break; // Exit the loop or return from function
}
*ptr = i; // Set the allocated integer to the value of i
deque_push_back(myDeque, ptr); // Push the pointer onto the deque
fmt_printf("Pushed %d to back\n", i);
}
fmt_printf("Size before resize: %zu\n", deque_length(myDeque));
// Resizing the deque
deque_resize(myDeque, 5); // Resize to smaller size
fmt_printf("Resized deque to 5 elements\n");
fmt_printf("Size after resize: %zu\n", deque_length(myDeque));
fmt_printf("Elements in resized deque: ");
for (size_t i = 0; i < deque_length(myDeque); ++i) {
fmt_printf("%d ", *(int*)deque_at(myDeque, i));
}
fmt_printf("\n");
deque_deallocate(myDeque);
return 0;
}
#include "deque/deque.h"
#include "fmt/fmt.h"
typedef struct {
int id;
char name[50];
} Person;
int main() {
Deque* personDeque = deque_create(sizeof(Person));
Person p1 = {1, "Alice"}, p2 = {2, "Bob"};
deque_push_back(personDeque, &p1);
deque_push_back(personDeque, &p2);
Person* frontPerson = (Person*)deque_front(personDeque);
fmt_printf("Front person: %d, %s\n", frontPerson->id, frontPerson->name);
deque_deallocate(personDeque);
return 0;
}
#include "deque/deque.h" // Include your bitset header file
#include "fmt/fmt.h"
typedef struct {
int id;
char name[50];
} Person;
int main(){
Deque* charDeque = deque_create(sizeof(char));
char a = 'A', b = 'B';
deque_push_back(charDeque, &a);
deque_push_back(charDeque, &b);
char* frontChar = (char*)deque_front(charDeque);
fmt_printf("Front char: %c\n", *frontChar);
deque_deallocate(charDeque);
return 0;
}
#include "deque/deque.h" // Include your bitset header file
#include "fmt/fmt.h"
int main() {
Deque* floatDeque = deque_create(sizeof(float));
float num1 = 1.5f, num2 = 2.5f;
deque_push_back(floatDeque, &num1);
deque_push_back(floatDeque, &num2);
float* backFloat = (float*)deque_back(floatDeque);
fmt_printf("Back float: %f\n", *backFloat);
deque_deallocate(floatDeque);
return 0;
}
#include "deque/deque.h" // Include your bitset header file
#include "fmt/fmt.h"
#include <stdlib.h>
int main(){
Deque* reverseDeque = deque_create(sizeof(int));
// Allocate and push back elements
for (int i = 0; i < 5; ++i) {
int* ptr = malloc(sizeof(int));
if (ptr == NULL) {
fmt_fprintf(stderr, "Failed to allocate memory\n");
free(ptr);
exit(-1);
}
*ptr = i;
deque_push_back(reverseDeque, ptr);
}
fmt_printf("Reversed Deque: ");
// Iterate using the length of the deque
for (size_t i = 0; i < deque_length(reverseDeque); ++i){
int* valPtr = (int*)deque_at(reverseDeque, deque_length(reverseDeque) - 1 - i);
fmt_printf("%d ", *valPtr);
free(valPtr); // Free the memory
}
fmt_printf("\n");
deque_deallocate(reverseDeque);
return 0;
}
#include "deque/deque.h" // Include your bitset header file
#include "fmt/fmt.h"
#include <stdlib.h>
int main() {
Deque* outerDeque = deque_create(sizeof(Deque*));
for (int i = 0; i < 3; ++i) {
Deque* innerDeque = deque_create(sizeof(int*));
for (int j = 0; j < 3; ++j) {
int* valPtr = malloc(sizeof(int));
if (valPtr == NULL) {
fmt_fprintf(stderr, "Failed to allocate memory\n");
free(valPtr);
exit(-1);
}
*valPtr = i * 3 + j;
deque_push_back(innerDeque, valPtr);
}
deque_push_back(outerDeque, &innerDeque);
}
// Access and print elements
for (size_t i = 0; i < deque_length(outerDeque); ++i) {
Deque* innerDeque = *(Deque**)deque_at(outerDeque, i);
for (size_t j = 0; j < deque_length(innerDeque); ++j) {
int* valPtr = (int*)deque_at(innerDeque, j);
fmt_printf("%d ", *valPtr);
free(valPtr); // Free the memory allocated for each integer
}
fmt_printf("\n");
deque_deallocate(innerDeque);
}
deque_deallocate(outerDeque);
return 0;
}
#include "deque/deque.h"
#include "fmt/fmt.h"
#include <stdlib.h>
int main() {
Deque* original = deque_create(sizeof(int));
for (int i = 0; i < 5; ++i) {
int* ptr = malloc(sizeof(int));
if (ptr == NULL) {
fprintf(stderr, "Failed to allocate memory\n");
free(ptr);
exit(-1);
}
*ptr = i;
deque_push_back(original, ptr);
}
// Copying the deque
Deque* copy = deque_create(sizeof(int));
for (size_t i = 0; i < deque_length(original); ++i) {
int* val = (int*)deque_at(original, i);
deque_push_back(copy, val);
}
// Print copied deque
fmt_printf("Copied Deque: ");
for (size_t i = 0; i < deque_length(copy); ++i) {
fmt_printf("%d ", *(int*)deque_at(copy, i));
}
fmt_printf("\n");
deque_deallocate(original);
deque_deallocate(copy);
return 0;
}
#include "deque/deque.h"
#include "fmt/fmt.h"
#include "string/string.h"
#include <stdlib.h>
typedef struct {
char* name;
int age;
} Person;
int main() {
Deque* people = deque_create(sizeof(Person));
char* names[] = {"Alice", "Bob", "Charlie"};
int ages[] = {25, 30, 35};
for (size_t i = 0; i < 3; ++i) {
Person* p = malloc(sizeof(Person)); // Dynamically allocate a Person
p->name = string_strdup(names[i]); // Duplicate the name string
p->age = ages[i];
deque_push_back(people, p); // Add the Person pointer to the deque
}
// Access and print people
for (size_t i = 0; i < deque_length(people); ++i) {
Person* p = (Person*)deque_at(people, i);
fmt_printf("Name: %s, Age: %d\n", p->name, p->age);
free(p->name); // Free the dynamically allocated name
free(p);
}
deque_deallocate(people);
return 0;
}
#include "deque/deque.h"
#include "fmt/fmt.h"
#include <stdlib.h>
int main() {
Deque* myDeque = deque_create(sizeof(int));
// Adding elements
for (int i = 0; i < 100; ++i) {
int* ptr = malloc(sizeof(int));
if (ptr == NULL) {
fmt_fprintf(stderr, "Failed to allocate memory\n");
free(ptr);
break; // Exit the loop or return from function
}
*ptr = i; // Set the allocated integer to the value of i
deque_push_back(myDeque, ptr); // Push the pointer onto the deque
}
deque_resize(myDeque, 10);
deque_shrink_to_fit(myDeque);
fmt_printf("Deque after shrink to fit (Size: %zu):\n", deque_length(myDeque));
for (size_t i = 0; i < deque_length(myDeque); ++i) {
fmt_printf("%d ", *(int*)deque_at(myDeque, i));
}
fmt_printf("\n");
deque_deallocate(myDeque);
return 0;
}
#include "deque/deque.h"
#include "fmt/fmt.h"
#include <stdlib.h>
int main() {
Deque* myDeque = deque_create(sizeof(int));
int insertVal = 99;
// Adding elements
for (int i = 0; i < 5; ++i) {
int* ptr = malloc(sizeof(int));
if (ptr == NULL) {
fmt_fprintf(stderr, "Failed to allocate memory\n");
free(ptr);
break; // Exit the loop or return from function
}
*ptr = i; // Set the allocated integer to the value of i
deque_push_back(myDeque, ptr); // Push the pointer onto the deque
}
deque_insert(myDeque, 2, &insertVal);
deque_erase(myDeque, 1);
fmt_printf("Deque after insert and erase:\n");
for (size_t i = 0; i < deque_length(myDeque); ++i) {
fmt_printf("%d ", *(int*)deque_at(myDeque, i));
}
fmt_printf("\n");
deque_deallocate(myDeque);
return 0;
}
This example demonstrates the use of emplace_back
, emplace_front
, and emplace
methods for in-place construction.
#include "deque/deque.h"
#include "fmt/fmt.h"
int main() {
Deque* myDeque = deque_create(sizeof(int));
int val = 10;
// Emplacing elements
deque_emplace_back(myDeque, &val);
deque_emplace_front(myDeque, &val);
deque_emplace(myDeque, 1, &val);
fmt_printf("Size of myQueue %zu\n", deque_length(myDeque));
fmt_printf("Deque after emplace operations:\n");
for (size_t i = 0; i < deque_length(myDeque); ++i) {
fmt_printf("%d ", *(int*)deque_at(myDeque, i));
}
fmt_printf("\n");
deque_deallocate(myDeque);
return 0;
}
This example illustrates how to compare two deques using relational operators.
#include "deque/deque.h"
#include "fmt/fmt.h"
#include <stdlib.h>
int main() {
Deque* deque1 = deque_create(sizeof(int));
Deque* deque2 = deque_create(sizeof(int));
int val = 5;
// Adding elements
for (int i = 0; i < 3; ++i) {
int *newInt1 = malloc(sizeof(int));
*newInt1 = i;
deque_push_back(deque1, newInt1);
int *newInt2 = malloc(sizeof(int));
*newInt2 = val;
deque_push_back(deque2, newInt2);
}
if (deque_is_less(deque1, deque2)) {
fmt_printf("Deque1 is less than Deque2\n");
}
for (size_t i = 0; i < 3; ++i) {
free(deque_at(deque1, i));
free(deque_at(deque2, i));
}
deque_deallocate(deque1);
deque_deallocate(deque2);
return 0;
}
This example demonstrates iterating over a deque using its iterators.
#include "deque/deque.h"
#include "fmt/fmt.h"
#include <stdlib.h>
int main() {
Deque* myDeque = deque_create(sizeof(int));
for (int i = 0; i < 3; ++i) {
int* newInt = malloc(sizeof(int));
*newInt = i;
deque_push_back(myDeque, newInt);
}
DequeIterator it = deque_begin(myDeque);
DequeIterator end = deque_end(myDeque);
fmt_printf("Deque elements: ");
while (!iterator_equals(&it, &end)) {
fmt_printf("%d ", *(int*)iterator_get(&it));
iterator_increment(&it);
}
fmt_printf("\n");
// Free the dynamically allocated integers
for (size_t i = 0; i < deque_length(myDeque); ++i) {
free(deque_at(myDeque, i));
}
deque_deallocate(myDeque);
return 0;
}
#include "deque/deque.h"
#include "fmt/fmt.h"
#include <stdlib.h>
int main() {
Deque* myDeque = deque_create(sizeof(int));
// Adding elements
for (int i = 0; i < 3; ++i) {
int* newInt = malloc(sizeof(int));
*newInt = i;
deque_push_back(myDeque, newInt);
}
// Reverse iteration
DequeIterator rit = deque_rbegin(myDeque);
DequeIterator rend = deque_rend(myDeque);
fmt_printf("Deque elements in reverse: ");
while (!iterator_equals(&rit, &rend)) {
fmt_printf("%d ", *(int*)iterator_get(&rit));
iterator_decrement(&rit);
}
fmt_printf("\n");
// Freeing allocated memory
for (size_t i = 0; i < deque_length(myDeque); ++i) {
free(deque_at(myDeque, i));
}
deque_deallocate(myDeque);
return 0;
}
#include "deque/deque.h"
#include "fmt/fmt.h"
#include <stdlib.h>
int main() {
Deque* myDeque = deque_create(sizeof(int));
int val = 42;
deque_emplace_back(myDeque, &val);
deque_emplace_back(myDeque, &val);
fmt_printf("Deque after emplacing elements: ");
for (size_t i = 0; i < deque_length(myDeque); ++i) {
fmt_printf("%d ", *(int*)deque_at(myDeque, i));
}
fmt_printf("\n");
deque_clear(myDeque);
fmt_printf("Deque after clearing: Length = %zu\n", deque_length(myDeque));
deque_deallocate(myDeque);
return 0;
}
Example 18 : Convert example in this url 'https://www.geeksforgeeks.org/deque-cpp-stl/' to Deque
#include "deque/deque.h"
#include "fmt/fmt.h"
void showdq(Deque* dq) {
for (size_t i = 0; i < deque_length(dq); ++i) {
int* elem = (int*)deque_at(dq, i);
fmt_printf("\t%d", *elem);
}
fmt_printf("\n");
}
int main() {
Deque* gquiz = deque_create(sizeof(int));
// Push elements
int val1 = 10, val2 = 20, val3 = 30, val4 = 15;
deque_push_back(gquiz, &val1);
deque_push_front(gquiz, &val2);
deque_push_back(gquiz, &val3);
deque_push_front(gquiz, &val4);
fmt_printf("The deque gquiz is : ");
showdq(gquiz);
fmt_printf("\ngquiz.max_size() : %zu", deque_max_size(gquiz));
fmt_printf("\ngquiz.at(2) : %d", *(int*)deque_at(gquiz, 2));
fmt_printf("\ngquiz.front() : %d", *(int*)deque_front(gquiz));
fmt_printf("\ngquiz.back() : %d", *(int*)deque_back(gquiz));
fmt_printf("\ngquiz.pop_front() : ");
deque_pop_front(gquiz);
showdq(gquiz);
fmt_printf("\ngquiz.pop_back() : ");
deque_pop_back(gquiz);
showdq(gquiz);
// Free the deque
deque_deallocate(gquiz);
return 0;
}
#include "deque/deque.h"
#include "fmt/fmt.h"
#include <stdlib.h>
int main() {
Deque* myDeque = deque_create(sizeof(int));
// Adding elements
for (int i = 0; i < 5; ++i) {
int* newInt = malloc(sizeof(int));
*newInt = i;
deque_push_back(myDeque, newInt);
}
// Constant reverse iteration
const DequeIterator crit = *deque_crbegin(myDeque);
const DequeIterator crend = *deque_crend(myDeque);
fmt_printf("Constant reverse iteration: ");
for (DequeIterator it = crit; !iterator_equals(&it, &crend); iterator_increment(&it)) {
fmt_printf("%d ", *(const int*)iterator_get(&it));
}
fmt_printf("\n");
// Freeing allocated memory
for (size_t i = 0; i < deque_length(myDeque); ++i) {
free(deque_at(myDeque, i));
}
deque_deallocate(myDeque);
return 0;
}