summaryrefslogtreecommitdiff
path: root/toxcore/list.c
diff options
context:
space:
mode:
authornotsecure <notsecure@marek.ca>2014-05-19 16:42:09 -0400
committernotsecure <notsecure@marek.ca>2014-05-19 16:42:09 -0400
commitfe66fcc7e4053a7ec7e59d22a1e4847980c90d6a (patch)
treecca09285b2393ec98f85a5acc1d2cc6f83e285ec /toxcore/list.c
parentd27a83820c6af2f0d6d813b9916d324e9ae3d137 (diff)
list
Simple struct with functions to create a list which associates ids with data
Diffstat (limited to 'toxcore/list.c')
-rw-r--r--toxcore/list.c178
1 files changed, 178 insertions, 0 deletions
diff --git a/toxcore/list.c b/toxcore/list.c
new file mode 100644
index 00000000..2ca9b175
--- /dev/null
+++ b/toxcore/list.c
@@ -0,0 +1,178 @@
1/* list.h
2 *
3 * Simple struct with functions to create a list which associates ids with data
4 * -Allows for finding ids associated with data such as IPs or public keys in a short time
5 * -Should only be used if there are relatively few add/remove calls to the list
6 *
7 * Copyright (C) 2014 Tox project All Rights Reserved.
8 *
9 * This file is part of Tox.
10 *
11 * Tox is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * Tox is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
23 *
24 */
25
26#include "list.h"
27
28/* Basically, the elements in the list are placed in order so that they can be searched for easily
29 * -each element is seen as a big-endian integer when ordering them
30 * -the ids array is maintained so that each id always matches
31 * -the search algorithm cuts down the time to find the id associated with a piece of data
32 * at the cost of slow add/remove functions for large lists
33 * -Starts at 1/2 of the array, compares the element in the array with the data,
34 * then moves +/- 1/4 of the array depending on whether the value is greater or lower,
35 * then +- 1/8, etc, until the value is matched or its position where it should be in the array is found
36 * -some considerations since the array size is never perfect
37 */
38
39 #define INDEX(i) (-i -1)
40
41/* Find data in list
42 *
43 * return value:
44 * >= 0 : id associated with data
45 * < 0 : no match, returns index (return value is INDEX(index)) where
46 * the data should be inserted
47 */
48static int find(LIST *list, void *data)
49{
50 //should work well, but could be improved
51 if(list->n == 0) {
52 return INDEX(0);
53 }
54
55 uint32_t i = list->n / 2; //current position in the array
56 uint32_t delta = i / 2; //how much we move in the array
57
58 int d = -1; //used to determine if closest match is found
59 //closest match is found if we move back to where we have already been
60
61 while(1) {
62 int r = memcmp(data, list->data + list->size * i, list->size);
63 if(r == 0) {
64 return list->ids[i];
65 }
66
67 if(r > 0) {
68 //data is greater
69 //move down
70 i += delta;
71
72 if(d == 0 || i == list->n) {
73 //reached bottom of list, or closest match
74 return INDEX(i);
75 }
76
77 delta = (delta) / 2;
78 if(delta == 0)
79 {
80 delta = 1;
81 d = 1;
82 }
83 } else {
84 //data is smaller
85 if(d == 1 || i == 0) {
86 //reached top or list or closest match
87 return INDEX(i);
88 }
89
90 //move up
91 i -= delta;
92
93 delta = (delta) / 2;
94 if(delta == 0) {
95 delta = 1;
96 d = 0;
97 }
98 }
99 }
100}
101
102
103void list_init(LIST *list, uint32_t element_size)
104{
105 //set initial values
106 list->n = 0;
107 list->size = element_size;
108 list->data = NULL;
109 list->ids = NULL;
110}
111
112void list_free(LIST *list)
113{
114 //free both arrays
115 free(list->data);
116 free(list->ids);
117}
118
119int list_find(LIST *list, void *data)
120{
121 int r = find(list, data);
122 //return only -1 and positive values
123 if(r < 0) {
124 r = -1;
125 }
126
127 return r;
128}
129
130int list_add(LIST *list, void *data, int id)
131{
132 //find where the new element should be inserted
133 //see: return value of find()
134 int i = find(list, data);
135 if(i >= 0) {
136 //already in list
137 return 0;
138 }
139
140 i = -i - 1;
141
142 //increase the size of the arrays by one
143 list->data = realloc(list->data, list->size * (list->n + 1));
144 list->ids = realloc(list->ids, sizeof(int) * (list->n + 1));
145
146 //insert data to element array
147 memmove(list->data + (i + 1) * list->size, list->data + i * list->size, (list->n - i) * list->size);
148 memcpy(list->data + i * list->size, data, list->size);
149
150 //insert id to id array
151 memmove(&list->ids[i + 1], &list->ids[i], (list->n - i) * sizeof(int));
152 list->ids[i] = id;
153
154 //increase n
155 list->n++;
156
157 return 1;
158}
159
160void list_remove(LIST *list, int id)
161{
162 int i;
163 for(i = 0; i < list->n; i++) {
164 if(list->ids[i] == id) {
165 //decrease number of elements
166 list->n--;
167
168 //move elements in both arrays down by one
169 memmove(list->data + i * list->size, list->data + (i + 1) * list->size, (list->n - i) * list->size);
170 memmove(&list->ids[i], &list->ids[i + 1], (list->n - i) * sizeof(int));
171
172 //return causes it to only remove the first element with the specified id
173 //(as opposed to all elements with that id if there are more than one - but there normally should not be)
174 //i--;
175 return;
176 }
177 }
178}