-
Notifications
You must be signed in to change notification settings - Fork 0
/
linklist.c
executable file
·491 lines (411 loc) · 16.4 KB
/
linklist.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "linklist.h"
#include "utils.h"
//ListElement is a struct (this is also a datatype for ease of use) contains
// implementations of this library should not touch ListElements
// value : a pointer to allocated memory of size LinkedList->elementSize
// prevElement : a pointer to the ListElement directly before IT in the linked list
// and is NULL if THIS is the first element in the list
// nextElement : a pointer to the ListElement directly after IT it the linked list
// and is NULL if THIS is the last element in the list
struct ListElement;
typedef struct ListElement ListElement;
struct ListElement {
void* value;
ListElement* prevElement;
ListElement* nextElement;
};
//LinkedList is a struct which contains the guts of the linked list.
// and is also defined as a datatype in linklist.h
//begining : a pointer to the first ListElement in the list
//end : a pointer to the last ListElement in the list
// if the list is Empty, begining and end both point to NULL
// if the list has one element, begining and end point to the same ListElement
//elementSize : the size of the elements being stored in the LinkedList
// user supplied and assumed to be correct for the data they are storing
struct LinkedList {
ListElement* begining;
ListElement* end;
size_t elementSize;
};
//private helper functions *not to be forward facing*///////////////////////////////
//iterate() provides the ith element of a LinkedList
//list : a pointer to the LinkedList
//i : an integer number of elements to traverse before returning
//returns : a pointer to the ith ListElement
// if i<=0, returns list->begining
// if i>number of elements, returns NULL
static ListElement* iterate(const LinkedList list, int i){
int n;
ListElement* holder = NULL;
holder = list->begining;
for(n=1;n<=i; n++){
if(holder==NULL) return holder;
holder = holder->nextElement;
}
return holder;
}
//createElement() creates a new ListElement for insertion in to the LinkedList
//data : a pointer to the data to be added
// assumes that data is correctly sized based on size
//returns : a new ListElement with NULL pointers to the previous and next elements
// fails fatally if memory cannot be allocated
static ListElement* createElement(const void* data, size_t size){
ListElement* newElement = ec_malloc(sizeof(ListElement));
newElement->value = ec_malloc(size);
bcopy(data, newElement->value, size);
newElement->nextElement = NULL;
newElement->prevElement = NULL;
return newElement;
}
//readElement() reads a ListElement
//e : ListElement to read
//data : a pointer to memory allocated to accept the data from the list
// assumes that data is correctly sized based on list->elementSize
//size : the size of the data element to be read
//returns : a status code as defined in linklist.h
// if e==null, data is not changed and returns LLFAIL
static int readElement(const ListElement* e, void* data, size_t size){
if(e==NULL) return LLFAIL;
bcopy(e->value, data, size);
return LLSUCCESS;
}
//deleteElement() deletes an existing ListElement
//toDelete : a pointer to the ListElement to delete
//returns : a status code as defined in linklist.h
// fails fatally if pointer toDelete is NULL
static int deleteElement(ListElement* toDelete){
if(toDelete==NULL) return LLFAIL;
ListElement* beforeDelete = toDelete->prevElement;
ListElement* afterDelete = toDelete->nextElement;
if(beforeDelete!=NULL) {
beforeDelete->nextElement = afterDelete;
}
if(afterDelete!=NULL){
afterDelete->prevElement = beforeDelete;
}
ec_free(toDelete->value);
ec_free(toDelete);
return LLSUCCESS;
}
//who ever calls swapElements needs to check for and clean up the list
//begining and end pointers. otherwise, segfaults, lost data, and memoryleaks...
static int swapElements(ListElement* elementA, ListElement* elementB){
if(elementA==NULL||elementB==NULL) return LLFAIL;
ListElement* prevHolder = elementA->prevElement;
ListElement* nextHolder = elementA->nextElement;
elementA->prevElement = elementB->prevElement;
elementA->nextElement = elementB->nextElement;
elementB->prevElement = prevHolder;
elementB->nextElement = nextHolder;
//set the prevElement's next for both A and B
if(elementA->prevElement!=NULL) elementA->prevElement->nextElement = elementA;
if(elementB->prevElement!=NULL) elementB->prevElement->nextElement = elementB;
//set the nextElement's prev for both A and B
if(elementA->nextElement!=NULL) elementA->nextElement->prevElement = elementA;
if(elementA->prevElement!=NULL) elementB->nextElement->prevElement = elementB;
return LLSUCCESS;
}
//PUBLIC FUNCTIONS//////////////////////////////////////////////////////////////////
//makeList() initalizes a LinkedList
//size : the size of the elements which will go in the list
// this is user supplied and is assumed to be correct
//returns : a pointer to a LinkedList with 0 elements
// fails fatally if it cannot allocate memory
LinkedList makeList(size_t size){
LinkedList newList = ec_malloc(sizeof(LinkedList));
newList->elementSize=size;
newList->begining = NULL;
newList->end = NULL;
return newList;
}
//breakList() deallocates all memory used in a LinkedList
//list : a pointer to the LinkedList to be deallocated
//returns : a status code as defined in linklist.h
int breakList(LinkedList list){
while(isEmpty(list)==LLSUCCESS){
deleteLastElement(list);
}
ec_free(list);
return LLSUCCESS;
}
//addElementI() adds data at an arbitraty location, i, in the list
//list : a pointer to the LinkedList to add the data to
//data : a pointer to the data to be added
// assumes that data is correctly sized based on list->elementSize
//i : the data added becomes the ith ListElement
// if i>number of elements, returns LLOVERRUN
// if i<=0, element is inserted at the begining of the list
//returns : a status code as defined in linklist.h
int addElementI(LinkedList list, const void* data, int i){
ListElement* oldIthElement = iterate(list, i);
if(oldIthElement==NULL) {
oldIthElement = iterate(list,i-1);
if(oldIthElement==NULL) return LLOVERRUN;
//case for inserting at end of list
return addLastElement(list, data);
}
ListElement* newElement = createElement(data, list->elementSize);
newElement->prevElement = oldIthElement->prevElement;
newElement->nextElement = oldIthElement;
oldIthElement->prevElement = newElement;
if(newElement->prevElement==NULL) list->begining = newElement;
else{
ListElement* beforeInsert = newElement->prevElement;
beforeInsert->nextElement = newElement;
}
return LLSUCCESS;
}
//addLastElement() adds data to the end of the list
//list : a pointer to the LinkedList to add the data to
//data : a pointer to the data to be added
// assumes that data is correctly sized based on list->elementSize
//returns : a status code as defined in linklist.h
int addLastElement(LinkedList list, const void* data){
ListElement* newElement = createElement(data, list->elementSize);
newElement->nextElement = NULL;
newElement->prevElement = list->end;
if(list->end!=NULL) list->end->nextElement = newElement;
list->end = newElement;
if(list->begining == NULL){
list->begining = list->end;
}
return LLSUCCESS;
}
//addFirstElement() adds data to the begining of the list
//list : a pointer to the LinkedList to add the data to
//data : a pointer to the data to be added
// assumes that data is correctly sized based on list->elementSize
//returns : a status code as defined in linklist.h
int addFirstElement(LinkedList list, const void* data){
ListElement* newElement = createElement(data, list->elementSize);
newElement->prevElement = NULL;
newElement->nextElement = list->begining;
if(list->begining!=NULL) list->begining->nextElement = newElement;
list->begining = newElement;
if(list->end == NULL){
list->end= list->begining;
}
return LLSUCCESS;
}
//readElementI() provides a copy of the data in ListElement i
//list : a pointer to the LinkedList to read the data from
//data : a pointer to memory allocated to accept the data from the list
// assumes that data is correctly sized based on list->elementSize
//i : the data will be read from the ith element of the list
//returns : a status code as defined in linklist.h
// if i>number of elements, data is not changed and returns LLUNDERRUN
int readElementI(const LinkedList list, void* data, int i){
ListElement* toRead = iterate(list,i);
if(readElement(toRead, data, list->elementSize)==LLFAIL) return LLOVERRUN;
return LLSUCCESS;
}
int readLastElement(const LinkedList list, void* data){
ListElement* toRead = list->end;
if(readElement(toRead, data, list->elementSize)==LLFAIL) return LLOVERRUN;
return LLSUCCESS;
}
int readFirstElement(const LinkedList list, void* data){
ListElement* toRead = list->begining;
if(readElement(toRead, data, list->elementSize)==LLFAIL) return LLUNDERRUN;
return LLSUCCESS;
}
//deleteElementI() removes the ith element of the list
//list : a pointer to the LinkedList to delete the data from
//i : the data will be deleted from the ith element of the list
//returns : a status code as defined in linklist.h
int deleteElementI(LinkedList list, int i){
ListElement* toDelete = iterate(list,i);
if(toDelete==NULL) return LLOVERRUN;
if(toDelete->prevElement==NULL) list->begining = toDelete->nextElement;
if(toDelete->nextElement==NULL) list->end = toDelete->prevElement;
return deleteElement(toDelete);
}
//deleteLastElement() removes the last element of the list
//list : a pointer to the LinkedList to delete the data from
//returns : a status code as defined in linklist.h
int deleteLastElement(LinkedList list) {
ListElement* toDelete = list->end;
if(toDelete == NULL) return LLOVERRUN;
list->end = list->end->prevElement;
if(list->end!=NULL) list->end->nextElement = NULL;
if(list->end==NULL) list->begining = NULL;
return deleteElement(toDelete);;
}
//deleteFirstElement() removes the first element of the list
//list : a pointer to the LinkedList to delete the data from
//returns : a status code as defined in linklist.h
int deleteFirstElement(LinkedList list) {
ListElement* toDelete = list->begining;
if(toDelete == NULL) return LLUNDERRUN;
list->begining = toDelete->nextElement;
if(list->begining!=NULL) list->begining->prevElement = NULL;
if(list->begining==NULL) list->end = NULL;
return deleteElement(toDelete);
}
//isEmpty() determines if the list is empty or not
//list : a pointer to the LinkedList to check
//returns : LLSUCCESS if list still has elements
// or LLUNDERRUN if list is empty
int isEmpty(const LinkedList list){
if(list->begining == NULL) return LLUNDERRUN;
else return LLSUCCESS;
}
//Iterator system to speed up sequential reads
//The iterator itself has a pointer to the LinkedList it serves.
struct LLIterator {
ListElement* marker;
LinkedList list;
};
LLIterator initLLIterator(const LinkedList list){
LLIterator newIterator = ec_malloc(sizeof(LLIterator));;
newIterator->marker = list->begining;
newIterator->list = list;
return newIterator;
}
int breakLLIterator(LLIterator iterator){
ec_free(iterator);
iterator = NULL;
return LLSUCCESS;
}
int IterateSetFront(LLIterator iterator){
iterator->marker = iterator->list->begining;
if(iterator->marker==NULL) return LLUNDERRUN;
return LLSUCCESS;
}
int IterateSetBack(LLIterator iterator){
iterator->marker = iterator->list->end;
if(iterator->marker==NULL) return LLUNDERRUN;
return LLSUCCESS;
}
int IterateForward(LLIterator iterator){
if(iterator->marker->nextElement==NULL) return LLOVERRUN;
else iterator->marker = iterator->marker->nextElement;
return LLSUCCESS;
}
int IterateBackward(LLIterator iterator){
if(iterator->marker->prevElement==NULL) return LLUNDERRUN;
else iterator->marker = iterator->marker->prevElement;
return LLSUCCESS;
}
int IterateRead(const LLIterator iterator, void* data){
if(iterator->marker==NULL) return LLUNDERRUN;
return readElement(iterator->marker, data, iterator->list->elementSize);
}
int IterateDelete(LLIterator iterator){
if(iterator==NULL) return LLFAIL;
if(iterator->marker==NULL) return LLFAIL;
ListElement* newNextElement= iterator->marker->nextElement;
if(iterator->marker==iterator->list->begining){
iterator->list->begining = newNextElement;
}
if(iterator->marker==iterator->list->end){
newNextElement = iterator->marker->prevElement;
iterator->list->end = newNextElement;
}
ListElement* toDelete = iterator->marker;
iterator->marker = newNextElement;
return deleteElement(toDelete);
}
int IterateInsertBefore(LLIterator iterator, const void* data){
ListElement* newElement = createElement(data, iterator->list->elementSize);
newElement->prevElement = iterator->marker->prevElement;
iterator->marker->prevElement = newElement;
newElement->nextElement = iterator->marker;
if(newElement->prevElement!=NULL)
newElement->prevElement->nextElement = newElement;
else
iterator->list->begining = newElement;
return LLSUCCESS;
}
int IterateInsertAfter(LLIterator iterator, const void* data){
ListElement* newElement = createElement(data, iterator->list->elementSize);
newElement->nextElement = iterator->marker->nextElement;
iterator->marker->nextElement = newElement;
newElement->prevElement = iterator->marker;
if(newElement->nextElement!=NULL)
newElement->nextElement->prevElement = newElement;
else
iterator->list->end = newElement;
return LLSUCCESS;
}
//IterateSwap() exchanges the position of two elements from the _same list_
//the iterators continue to point to the same memory addresses, but thier
//position in the list is changed. e.g. iteratorA points to 5 at position 3
//& iteratorB points to 10 at position 7. after the swap, iteratorA will point
//to 5 at position 7 and iteratorB will point to 10 at position 3.
//iteratorA : an LLIterator to the first value to swap
//iteratorB : an LLIterator to the second value to swap
//returns : a status code as defined in linklist.h
// if iterators are not from the same list, they are not exchanged
// and returns LLFAIL
// if either iterator has a NULL element, they elements are not
// exchanged, and returns LLFAIL
int IterateSwap(LLIterator iteratorA, LLIterator iteratorB){
if(iteratorA->list!=iteratorB->list) return LLFAIL;
int retval = swapElements(iteratorA->marker, iteratorB->marker);
//if the elements we are swaping are at the begining or end of the list,
//then we need to adjust the pointers in the list appropriatly
if(retval==LLSUCCESS){
if(iteratorA->list->begining == iteratorA->marker){
iteratorA->list->begining = iteratorB->marker;
} else if(iteratorA->list->begining == iteratorB->marker){
iteratorA->list->begining = iteratorA->marker;
}
if(iteratorA->list->end == iteratorA->marker){
iteratorA->list->end = iteratorB->marker;
} else if(iteratorA->list->end == iteratorB->marker){
iteratorA->list->end = iteratorA->marker;
}
}
return retval;
}
//sortList() puts the list in increasing order based on the > operator
// if the data is not suitable for sorting in this way,
// do not use this method if your data cannot be sorted this way
//list : a pointer to the LinkedList to sort
//returns : a status code as defined in linklist.h
// not implemented yet. always returns LLFAIL if called
int sortList(LinkedList list){
return LLFAIL;
}
//sort list based on user supplied function
int sortListUserFunction(LinkedList list, LinkedListComparator compare){
return LLFAIL;
}
/*
//debugging functions
void printListElement(ListElement* element){
printf("Printing ListElement 0x%08X:\n", element);
printf("{ value = 0x%08X}\n", element->value);
printf("{prevElement = 0x%08X}\n", element->prevElement);
printf("{nextElement = 0x%08X}\n", element->nextElement);
}
void printLinkedList(LinkedList list, uint8_t printelement){
printf("Printing LinkedList 0x%08X:\n", list);
printf("{ begining = 0x%08X}\n", list->begining);
printf("{ end = 0x%08X}\n", list->end);
printf("{elementSize = 0x%08d}\n", list->elementSize);
if(printelement){
printf("ListElement at begining:\n");
printListElement(list->begining);
printf("ListElement at end:\n");
printListElement(list->end);
}
}
void printLLIterator(LLIterator iterator, uint8_t printmarker, uint8_t printlist, uint8_t printelement){
printf("Printing LLIterator 0x%08X:\n", iterator);
printf("{ marker = 0x%08X}\n", iterator->marker);
printf("{ list = 0x%08X}\n", iterator->list);
if(printmarker){
printf("ListElement at marker:\n");
printListElement(iterator->marker);
}
if(printlist){
printf("LinkedList at list:\n");
printLinkedList(iterator->list, printelement);
}
}
*/