-
Notifications
You must be signed in to change notification settings - Fork 0
/
mtm_set.c
225 lines (208 loc) · 5.82 KB
/
mtm_set.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
/*
* mtm_set.c
*
* Created on: Aug 18, 2015
* Author: Gal
*/
#include "mtm_set.h"
#include <stdio.h> // !!!! TODO: might need to remove !!!!
#include <stdlib.h>
#include <assert.h>
#define IF_NULL_RETURN_NULL(var) { \
if ( (var) == NULL) return NULL; }
#define IF_NULL_RETURN_SET_NULL_ARGUMENT(var) { \
if ( (var) == NULL) return SET_NULL_ARGUMENT; }
#define IS_SET_VALID(set) assert(set != NULL);
/*assert ( (set)->dummy != NULL && set->size >= 0 && (set)->copyFunc != NULL \
&& (set)->freeFunc != NULL && (set)->cmpFunc != NULL );*/
/* The set implementation will use a list, where every node saves setElement */
struct Node_t {
SetElement data;
struct Node_t* next;
};
typedef struct Node_t* Node;
struct Set_t {
Node dummy;
Node current;
int size;
copySetElements copyFunc;
freeSetElements freeFunc;
compareSetElements cmpFunc;
};
Set setCreate(copySetElements copyElement, freeSetElements freeElement,
compareSetElements compareElements) {
// if one of the client's function pointers is NULL return SET_NULL_ARGUMENT
IF_NULL_RETURN_NULL(copyElement)
IF_NULL_RETURN_NULL(freeElement)
IF_NULL_RETURN_NULL(compareElements)
Set set = malloc(sizeof(*set)); // allocated memory for the new set
IF_NULL_RETURN_NULL(set)
set->dummy = malloc(sizeof(*set->dummy)); // allocate memory for the list
if (set->dummy == NULL) { // if allocation fails free previous malloced mem
free(set);
return NULL;
}
set->dummy->data = NULL; // list is allocated, assign NULL to dummy node's data
set->dummy->next = NULL; // dummy's next is NULL
set->current = NULL; // current (set's iterator) is NULL when undefined
set->copyFunc = copyElement;
set->freeFunc = freeElement;
set->cmpFunc = compareElements;
set->size = 0;
return set;
}
Set setCopy(Set set) {
IF_NULL_RETURN_NULL(set)
IS_SET_VALID(set)
Set newSet = setCreate(set->copyFunc, set->freeFunc, set->cmpFunc);
IF_NULL_RETURN_NULL(newSet)
Node nodeToCopy = set->dummy->next;
Node lastCopiedNode = newSet->dummy;
newSet->current = NULL; // in case current was undefined in original set
while (nodeToCopy != NULL) {
Node currNode = malloc(sizeof(*currNode));
if (currNode == NULL) {
setDestroy(newSet);
return NULL;
}
if (nodeToCopy->data == NULL) {
currNode->data = NULL;
} else {
currNode->data = set->copyFunc(nodeToCopy->data);
if (currNode->data == NULL) {
free(currNode);
setDestroy(newSet);
return NULL;
}
}
if (nodeToCopy == set->current) {
newSet->current = currNode;
}
currNode->next = NULL;
lastCopiedNode->next = currNode;
lastCopiedNode = currNode;
nodeToCopy = nodeToCopy->next;
}
newSet->size = setGetSize(set);
return newSet;
}
int setGetSize(Set set) {
if (set == NULL) {
return -1;
}
assert(set->size >= 0);
return set->size;
}
SetElement setGetFirst(Set set) {
if (set == NULL || setGetSize(set) == 0) {
return NULL;
}
set->current = set->dummy->next;
return set->current->data;
}
SetElement setGetNext(Set set) {
if (set == NULL || set->current == NULL) {
return NULL;
}
set->current = set->current->next;
return set->current != NULL ? set->current->data : NULL;
}
SetElement setContains(Set set, SetElement element) {
IF_NULL_RETURN_NULL(set)
IF_NULL_RETURN_NULL(element)
IS_SET_VALID(set)
Node iteratingNode = set->dummy->next;
while (iteratingNode != NULL) {
if (iteratingNode->data != NULL
&& set->cmpFunc(iteratingNode->data, element) == 0) {
set->current = iteratingNode;
return iteratingNode->data;
}
iteratingNode = iteratingNode->next;
}
return NULL;
}
SetResult setAdd(Set set, SetElement element) {
IF_NULL_RETURN_SET_NULL_ARGUMENT(set)
IF_NULL_RETURN_SET_NULL_ARGUMENT(element)
Node iteratingNode = set->dummy->next;
Node beforeNode = set->dummy;
while (iteratingNode != NULL) {
assert(iteratingNode->data != NULL);
int cmpResult = set->cmpFunc(iteratingNode->data, element);
if (cmpResult > 0) {
break; // Need to add element before iteratingNode
}
if (cmpResult < 0) { // add element after iterating Node
iteratingNode = iteratingNode->next;
beforeNode = beforeNode->next;
continue;
}
return SET_ITEM_ALREADY_EXISTS; // cmpResult == 0
}
Node newNode = malloc(sizeof(*newNode));
if (newNode == NULL) {
return SET_OUT_OF_MEMORY;
}
newNode->data = set->copyFunc(element);
if (newNode->data == NULL) {
free(newNode);
return SET_OUT_OF_MEMORY;
}
newNode->next = iteratingNode;
beforeNode->next = newNode;
set->size++;
set->current = NULL;
return SET_SUCCESS;
}
SetResult setRemove(Set set, SetElement element) {
IF_NULL_RETURN_SET_NULL_ARGUMENT(set)
IF_NULL_RETURN_SET_NULL_ARGUMENT(element)
set->current = NULL; // iterator is undefined for every setRemove result
Node iteratingNode = set->dummy->next;
Node beforeNode = set->dummy;
while (iteratingNode != NULL) {
assert(iteratingNode->data != NULL);
int cmpResult = set->cmpFunc(iteratingNode->data, element);
if (cmpResult > 0) {
return SET_ITEM_DOES_NOT_EXIST; // current element greater
}
if (cmpResult < 0) { // add element after iterating Node
iteratingNode = iteratingNode->next;
beforeNode = beforeNode->next;
continue;
}
// cmpResult == 0 => delete the node
beforeNode->next = iteratingNode->next;
set->freeFunc(iteratingNode->data);
free(iteratingNode);
set->size--;
return SET_SUCCESS;
}
return SET_ITEM_DOES_NOT_EXIST;
}
SetResult setClear(Set set) {
IF_NULL_RETURN_SET_NULL_ARGUMENT(set)
IS_SET_VALID(set)
Node nodeToDelete = set->dummy->next;
while (nodeToDelete != NULL) {
if (nodeToDelete->data != NULL) {
set->freeFunc(nodeToDelete->data);
}
Node nextNode = nodeToDelete->next;
free(nodeToDelete);
nodeToDelete = nextNode;
}
set->dummy->next = NULL;
set->current = NULL;
set->size = 0;
return SET_SUCCESS;
}
void setDestroy(Set set) {
if (set == NULL) {
return; // mimic free() behavior
}
setClear(set);
free(set->dummy);
free(set);
}