forked from abdullahemad12/Cranberry-Btree
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcranbtree.c
450 lines (405 loc) · 12.1 KB
/
cranbtree.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
/** MIT License
*
* Copyright (c) 2018 Abdullah Emad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <cranbtree.h>
/*
* library includes
*/
#include "lib/insert.c"
#include "lib/search.c"
#include "lib/delete.c"
#include "lib/node.c"
#include "lib/statistics.c"
#include "lib/helpers.c"
#include "lib/update.c"
#include "lib/clone.c"
#include "lib/visit.c"
/*
* prototypes
*/
static void destroy_bt_helper(cbt_node_t * root, int n, void (*done) (void *));
/*
* cranbtree_t* -> int
* Return last detected error code/number
*/
int cbt_errno(cranbtree_t * bt)
{
assert(bt != NULL);
return bt->op_errno;
}
/*
* cranbtree_t* -> const char*
* Return pointer to string describing last error. NULL if no error recorded.
*/
const char *cbt_errstr(cranbtree_t * bt)
{
assert(bt != NULL);
return errorMessages[bt->op_errno];
}
/*
* int -> bptree_t*
* Given the maximum number of entries in a node
* returns a pointer to an empty B-tree
*/
cranbtree_t *cbt_create(int n)
{
if (n < 2)
{
return NULL;
}
/*
* must be odd (reacts internally without informing the user)
*/
if (n % 2 == 0)
{
n++;
}
cranbtree_t *bt = malloc(sizeof(cranbtree_t));
if (bt == NULL)
{
return NULL;
}
bt->root = NULL;
bt->length = 0;
bt->min_key = -1;
bt->max_key = -1;
bt->n = n;
bt->is_clone = false;
bt->op_errno = CBT_NO_ERROR;
return bt;
}
/**
* cranbtree_t*, void* (*)(void*) -> cranbtree_t*
* EFFECTS: clones the given cranbtree_t and clones the user objects if the
* the passed function pointer is not NULL
* RETURNS: a pointer to the clone, or NULL if the given cbt is not valid
* NOTE: if the function is NULL, clone will copy the original object pointers to the new
* clone . This you must be careful in this case when manipulating the objects and destroying
* them. Otherwise, the tree will store copies of the objects
*/
cranbtree_t *cbt_clone(cranbtree_t * cbt)
{
if (cbt == NULL)
{
return NULL;
}
assert(cbt->n > 2);
assert(cbt->n % 2 != 0);
cranbtree_t *clone = malloc(sizeof(cranbtree_t));
if (clone == NULL)
{
return NULL;
}
cbt_copy_metadata(cbt, clone);
clone->root = cbt_copy_nodes(cbt->root, cbt->n);
return clone;
}
/**
* cranbtree_t*, int, void* -> void
* EFFECTS: Inserts an object in the btree in respect with the search key.
* Unless the tree is a clone, in which case it return immediately.
* Sets op_errno on any error.
* MODIFIES: cranbtree_t* bt
* RETURNS: Pointer to the inserted object or NULL on any error
*
* cranbtree_t* bt: Tree structs that will hold the object
* int key: search key (choosen by the user)
* void* object: pointer to the object to be inserted
*/
void *cbt_insert(cranbtree_t * bt, int key, void *object)
{
assert(bt != NULL);
assert(object != NULL);
if (bt->is_clone)
{
bt->op_errno = CBT_CLONE_BAD_OP;
return (cranbtree_t *) NULL;
}
cbt_entry_t *entry = bt_create_entry(key, object);
bt_insert_helper(bt, bt->root, entry);
/*
* updates the min and max if needed
*/
if (bt->length == 0)
{ /* first insertion */
bt->max_key = key;
bt->min_key = key;
}
else
{
bt->max_key = bt->max_key < key ? key : bt->max_key;
bt->min_key = bt->min_key > key ? key : bt->min_key;
}
bt->length++;
return object;
}
/**
* cranbtree_t*, int, void* -> void
* MODIFIES: cranbtree_t*
* EFFECTS: Updates the object of the entry that has the specified key with the new pointer. If
* no such entry was found a new entry is inserted. Returns immediately if the tree is
* a clone. Sets op_errno on any error.
* RETURNS: Pointer to the old object, NULL if it was not found.
* PARAMETERS:
* - cranbtree_t* cbt, pointer to the BTree struct
* - int key: the key of the entry to be updated
* - void* object: pointer to the object
*/
void *cbt_update(cranbtree_t * bt, int key, void *object)
{
assert(bt != NULL);
if (bt->is_clone)
{
bt->op_errno = CBT_CLONE_BAD_OP;
return (void *)NULL;
}
void *old_object = cbt_update_helper(bt->root, key, object, bt->n);
if (old_object == NULL)
{
bt->op_errno = CBT_KEY_NOT_FOUND;
cbt_insert(bt, key, object);
}
return old_object;
}
/**
* cranbtree_t*, int, void* -> void
* MODIFIES: cranbtree_t*
* EFFECTS: Updates the object of the entry that has the specified key with the new pointer only if it
* exists.
* PARAMETERS:
* - cranbtree_t* cbt, pointer to the BTree struct
* - int key: the key of the entry to be updated
* - void* object: pointer to the object
* RETURNS: pointer to the old object, or NULL if it does not exist
*/
void *cbt_update_if_exists(cranbtree_t * bt, int key, void *object)
{
return NULL;
}
/**
* cranbtree_t*, void* -> int
* REQUIRES: the object to be already inserted in the tree
* EFFECTS: Figures out the key of a given object in the tree
* RETURNS: the key of the object, or -1 if the object was not found
*
*/
int cbt_key_search(cranbtree_t * cbt, void *object)
{
return 0;
}
/**
* cranbtree_t*, int -> void*
* EFFECTS: search for an object given the search key
* RETURN: pointer to the object or NULL if the object was
* not found
*/
void *cbt_search(cranbtree_t * bt, int key)
{
assert(bt != NULL);
void *object = bt_search_helper(bt->root, key, bt->n);
if (object == NULL)
{
bt->op_errno = CBT_KEY_NOT_FOUND;
}
return object;
}
/**
* cranbtree_t*, void* key, int (*)(void*) -> void*
* EFFECTS: will navigate the tree searching for a specific item using the rules set by the visitor
* function
* REQUIRES: the function "visitor" to return an integer according to the following rules
* 1. positive: means the node to look at next is the right one.
* 2. negative: means the node to look at next is the left one.
* 3. zero: means the item was found, no further traversal is needed.
* the visitor will be passed the arguments in the following order: key, current object
* RETURNS: the item we are looking for, or NULL if the item was not found
* PARAMETERS:
* - cranbtree_t* cbt: cranberry tree to be traversed
* - void* key: a key that will be passed to visitor to make a decision
* - int (*visitor)(void*, void*): visitor function that will be invoked on every object in the tree
*/
void *cbt_navigation_search(cranbtree_t * cbt, void *key,
int (*visitor) (void *, void *))
{
assert(cbt != NULL);
assert(visitor != NULL);
return cbt_navigation_search_helper(cbt->root, key, visitor);
}
/**
* crabtree_t* , int (*) (void *) -> int
* EFFECTS: Calls the visitor function on every object pointer stored in the tree
* MODIFIES: cranbtree.objects
* REQUIRES: The visitor function to take a void* as an argument and to return an int
* the int should be zero indicating that the call success and the function
* should proceed to the other nodes, or nonzero, which will cause the function to
* terminate and return the error code value
* RETURNS:
* - 0 on success
* - nonzero returned by the visitor function on failure
* PARAMETERS:
* - cranbtree_t* cbt: the tree to be traversed
* - int (* visitor) (void *): the function that will be invoked on every object in the tree
*/
int cbt_visit_all(cranbtree_t * cbt, int (*visitor) (void *))
{
assert(cbt != NULL);
int err = cbt_visit_all_helper(cbt->root, visitor);
if (err)
{
cbt->op_errno = CBT_USER_ERROR;
}
return err;
}
/**
* cranbtree_t*, int -> void*
* EFFECTS: Given a key, removes an object from the tree. Sets errno on any error.
* MODIFIES: cranbtree_t*
* RETURNS: returns the object or NULL if no such a key was found.
*/
void *cbt_delete(cranbtree_t * bt, int key)
{
assert(bt != NULL);
if (bt->is_clone)
{
bt->op_errno = CBT_CLONE_BAD_OP;
return (void *)NULL;
}
void *object = bt_delete_helper(bt, bt->root, key);
if (object != NULL)
{
bt->max_key =
bt->max_key ==
key ? cbt_calculate_max_key(bt->root) : bt->max_key;
bt->min_key =
bt->min_key ==
key ? cbt_calculate_min_key(bt->root) : bt->min_key;
bt->length--;
}
else
{
bt->op_errno = CBT_KEY_NOT_FOUND;
}
return object;
}
/**
* cranbtree_t* -> int
* EFFECTS: gets the maximum key in the Tree
* RETURNS: the maximum key
*/
int cbt_get_max_key(cranbtree_t * cbt)
{
return cbt->max_key;
}
/**
* cranbtree_t* -> int
* EFFECTS: gets the minimum key in the Tree
* RETURNS: the minimum key
*/
int cbt_get_min_key(cranbtree_t * cbt)
{
return cbt->min_key;
}
/**
* cranbtree_t* -> int
* EFFECTS: gets the length of the B-tree
* RETURNS: the length of the B-tree
*/
unsigned int cbt_get_length(cranbtree_t * cbt)
{
return cbt->length;
}
/**
* cranbtree_t*, void* (* copy_object)(void*) -> void
* EFFECTS: detaches a cloned cranbtree_t from its parent. If copy_object is not NULL, cbt_detach_clone
* will use it to make a new copy of every object in the tree.
* MODIFIES: cranbtree_t* cbt
* PARAMETERS:
* - cranbtree_t* cbt: a pointer to a cloned cranbtree
* - void* (* copy_object)(void*): a pointer to a function (void* -> void*) that will take the old object as a parameter
* and returns a pointer to a copy of the object. This will be invoked on every object in the cranbtree
*
* NOTE: This should generally be used when your cloned cranbtree will start storing objects different
* then those of the original; However, when using it, it becomes your responsibility to free
* and manipulate objects correctly
*/
void cbt_detach_clone(cranbtree_t * cbt, void *(*copy_object) (void *))
{
/* if there is no tree do nothing */
if (cbt == NULL)
{
return;
}
/* this tree is no longer a clone, mark it as such */
cbt->is_clone = false;
/* copy the objects starting from the root node recursively */
cbt_copy_objects(cbt->root, cbt->n, copy_object);
}
/**
* cranbtree_t*, (void) destroy_object(void*) -> void
* MODIFIES: cranbtree_t* bt
* EFFECTS: Frees all the memory associated with the B tree
*
* (void) destroy_object(void*): a pointer to a function that will be invoked on every object
* i.e: object_destroy(object). In case the pointer is NULL, nothing is done
* on the object and it becomes the user's responsibility to free it
*/
void cbt_destroy(cranbtree_t * bt, void (*destroy_object) (void *))
{
if (bt->is_clone)
{
destroy_object = NULL;
}
destroy_bt_helper(bt->root, bt->n, destroy_object);
free(bt);
}
void printTree(cranbtree_t * bt)
{
printf("\n\n");
for (int i = 0, n = calculate_depth(bt->root); i < n; i++)
{
print_level(bt->root, bt->n, i, 0);
printf("\n\n");
}
}
/*******************************************
* *
* Static private Functions *
* *
*******************************************/
static void destroy_bt_helper(cbt_node_t * root, int n, void (*done) (void *))
{
if (root == NULL)
{
return;
}
for (int i = 0, n1 = n + 1; i < n1; i++)
{
destroy_bt_helper(root->children[i], n, done);
}
bt_destroy_node(root, n, done);
}