master
1#include "doubly_linked_list.h"
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5
6/**
7 * The equivalent of a constructor
8 * to initialize a new node in a doubly linked list.
9 *
10 * @param data The data to initialize the head node with.
11 * @return new Node bound to the data specified
12 */
13Node *initialize(int data) {
14 Node *node = malloc(sizeof(Node));
15 node->data = data;
16 node->next = NULL;
17 node->prev = NULL;
18 return node;
19}
20
21/**
22 * Returns the tail of the list.
23 *
24 * @param head The head of the linked list
25 * @return The tail of the linked list
26 */
27Node *tail(Node *head) {
28 Node *tmp = head;
29 while (tmp) {
30 if (!tmp->next)
31 break;
32 tmp = tmp->next;
33 }
34 return tmp;
35}
36
37/**
38 * Adds data to the tail of a doubly linked list.
39 *
40 * @param head The head of the doubly linked list
41 * @param data The data to append to the list
42 * @return Returns the new node.
43 */
44Node *add(Node *head, int data) {
45 Node *t = tail(head);
46 t->next = initialize(data);
47 t->next->prev = t;
48 return t->next;
49}
50
51/**
52 * Returns a specific node in the list by index starting from 0.
53 *
54 * @param from The node to start scanning from.
55 * @param index The zero based index of the node to retrieve.
56 * @return The node at the specified index.
57 */
58Node *get(Node *from, int index) {
59 if (!from || index < 0)
60 return NULL;
61
62 while (index > 0 && from) {
63 from = from->next;
64 index--;
65 }
66 return from;
67}
68
69/**
70 * Returns the number of items in the linked list.
71 *
72 * @param head The head of the linked list
73 * @return The number of items in the list.
74 */
75static int size(Node *head) {
76 int i = 0;
77 for (Node *tmp = head; tmp && tmp != NULL; tmp = tmp->next)
78 i++;
79 return i;
80}
81
82/**
83 * Assigns the next pointer of a node.
84 *
85 * @param self The node struct to alter.
86 * @param other The other node to point to.
87 */
88static void assign_next(Node *self, Node *other) {
89 if (self)
90 self->next = other;
91
92 if (other)
93 other->prev = self;
94}
95
96/**
97 * Assigns the previous pointer of a node.
98 *
99 * @param self The node struct to alter.
100 * @param other The other node to point to.
101 */
102static void assign_prev(Node *self, Node *other) {
103 if (self)
104 self->prev = other;
105
106 if (other)
107 other->next = self;
108}
109
110/**
111 * Swaps two different nodes in the same linked list.
112 *
113 * @param x A node to swap
114 * @param y Another node to swap
115 */
116void swap(Node *x, Node *y) {
117 if (x == y)
118 return;
119 if (!x || !y)
120 return;
121 if (x->prev == y && y->next == x)
122 return swap(y, x);
123
124 Node *xp = x->prev, *xn = x->next, *yp = y->prev, *yn = y->next;
125
126 // if adjacent
127 if (x->next == y && y->prev == x) {
128 assign_next(x, yn);
129 assign_prev(x, y);
130 assign_prev(y, xp);
131 } else {
132 assign_prev(x, yp);
133 assign_next(x, yn);
134 assign_prev(y, xp);
135 assign_next(y, xn);
136 }
137}
138
139/**
140 * Generates a string representation of the Node usable for printing to stdout
141 *
142 * @param node The node to represent as a string
143 * @return The string that represents the node
144 */
145char *to_s(Node *node) {
146 const int buffer_size = 32;
147 char *buffer = malloc(buffer_size);
148 memset(buffer, buffer_size, '\0');
149
150 if (node->prev && node->next)
151 snprintf(buffer, buffer_size, "(%d<%d>%d) ", node->prev->data, node->data,
152 node->next->data);
153 else if (node->next)
154 snprintf(buffer, buffer_size, "(nil<%d>%d) ", node->data, node->next->data);
155 else
156 snprintf(buffer, buffer_size, "(%d<%d>nil) ", node->prev->data, node->data);
157 return buffer;
158}
159
160/**
161 * Prints the previous, data and next pointers for a node
162 *
163 * @param node The node to print
164 */
165static void print(Node *node) {
166 char *message = to_s(node);
167 printf("%s", message);
168 free(message);
169}
170
171/**
172 * Iterates through each node in a linked list.
173 *
174 * @param self The node to start iterating from.
175 * @param block The callback function to invoke on each node.
176 */
177void each(Node *self, Visitor block) {
178 Node *tmp = self;
179
180 while (tmp) {
181 block(tmp);
182 tmp = tmp->next;
183 }
184}
185
186/**
187 * Renders a visual output of a full linked list.
188 *
189 * @param node The head of the linked list
190 */
191void inspect(Node *node) {
192 printf("[ ");
193 each(node, &print);
194 printf("]\n");
195}