diff options
author | notsecure <notsecure@marek.ca> | 2014-05-19 16:42:09 -0400 |
---|---|---|
committer | notsecure <notsecure@marek.ca> | 2014-05-19 16:42:09 -0400 |
commit | fe66fcc7e4053a7ec7e59d22a1e4847980c90d6a (patch) | |
tree | cca09285b2393ec98f85a5acc1d2cc6f83e285ec /toxcore/list.c | |
parent | d27a83820c6af2f0d6d813b9916d324e9ae3d137 (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.c | 178 |
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 | */ | ||
48 | static 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 | |||
103 | void 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 | |||
112 | void list_free(LIST *list) | ||
113 | { | ||
114 | //free both arrays | ||
115 | free(list->data); | ||
116 | free(list->ids); | ||
117 | } | ||
118 | |||
119 | int 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 | |||
130 | int 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 | |||
160 | void 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 | } | ||