]> git.ipfire.org Git - location/libloc.git/blame - src/network-list.c
export: Change back to use Network objects
[location/libloc.git] / src / network-list.c
CommitLineData
e0b9ff5f
MT
1/*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2020 IPFire Development Team <info@ipfire.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15*/
16
17#include <errno.h>
18#include <stdlib.h>
19
20#include <loc/libloc.h>
21#include <loc/network.h>
22#include <loc/private.h>
23
24struct loc_network_list {
25 struct loc_ctx* ctx;
26 int refcount;
27
3b44e421
MT
28 struct loc_network** elements;
29 size_t elements_size;
30
e0b9ff5f 31 size_t size;
e0b9ff5f
MT
32};
33
3b44e421
MT
34static int loc_network_list_grow(struct loc_network_list* list, size_t size) {
35 DEBUG(list->ctx, "Growing network list %p by %zu to %zu\n",
36 list, size, list->elements_size + size);
37
38 struct loc_network** elements = reallocarray(list->elements,
39 list->elements_size + size, sizeof(*list->elements));
40 if (!elements)
41 return -errno;
42
43 list->elements = elements;
44 list->elements_size += size;
45
46 return 0;
47}
48
e0b9ff5f
MT
49LOC_EXPORT int loc_network_list_new(struct loc_ctx* ctx,
50 struct loc_network_list** list) {
51 struct loc_network_list* l = calloc(1, sizeof(*l));
52 if (!l)
53 return -ENOMEM;
54
55 l->ctx = loc_ref(ctx);
56 l->refcount = 1;
57
e0b9ff5f
MT
58 DEBUG(l->ctx, "Network list allocated at %p\n", l);
59 *list = l;
60 return 0;
61}
62
63LOC_EXPORT struct loc_network_list* loc_network_list_ref(struct loc_network_list* list) {
64 list->refcount++;
65
66 return list;
67}
68
69static void loc_network_list_free(struct loc_network_list* list) {
70 DEBUG(list->ctx, "Releasing network list at %p\n", list);
71
72 for (unsigned int i = 0; i < list->size; i++)
3b44e421 73 loc_network_unref(list->elements[i]);
e0b9ff5f
MT
74
75 loc_unref(list->ctx);
76 free(list);
77}
78
79LOC_EXPORT struct loc_network_list* loc_network_list_unref(struct loc_network_list* list) {
80 if (!list)
81 return NULL;
82
83 if (--list->refcount > 0)
84 return list;
85
86 loc_network_list_free(list);
87 return NULL;
88}
89
90LOC_EXPORT size_t loc_network_list_size(struct loc_network_list* list) {
91 return list->size;
92}
93
94LOC_EXPORT int loc_network_list_empty(struct loc_network_list* list) {
95 return list->size == 0;
96}
97
98LOC_EXPORT void loc_network_list_clear(struct loc_network_list* list) {
99 for (unsigned int i = 0; i < list->size; i++)
3b44e421 100 loc_network_unref(list->elements[i]);
e0b9ff5f
MT
101
102 list->size = 0;
103}
104
105LOC_EXPORT void loc_network_list_dump(struct loc_network_list* list) {
106 struct loc_network* network;
107 char* s;
108
109 for (unsigned int i = 0; i < list->size; i++) {
3b44e421 110 network = list->elements[i];
e0b9ff5f
MT
111
112 s = loc_network_str(network);
113
114 INFO(list->ctx, "%s\n", s);
115 free(s);
116 }
117}
118
119LOC_EXPORT struct loc_network* loc_network_list_get(struct loc_network_list* list, size_t index) {
120 // Check index
121 if (index >= list->size)
122 return NULL;
123
3b44e421 124 return loc_network_ref(list->elements[index]);
e0b9ff5f
MT
125}
126
127LOC_EXPORT int loc_network_list_push(struct loc_network_list* list, struct loc_network* network) {
128 // Do not add networks that are already on the list
129 if (loc_network_list_contains(list, network))
130 return 0;
131
132 // Check if we have space left
3b44e421
MT
133 if (list->size >= list->elements_size) {
134 int r = loc_network_list_grow(list, 64);
135 if (r)
136 return r;
e0b9ff5f
MT
137 }
138
139 DEBUG(list->ctx, "%p: Pushing network %p onto stack\n", list, network);
140
3b44e421 141 list->elements[list->size++] = loc_network_ref(network);
e0b9ff5f
MT
142
143 return 0;
144}
145
146LOC_EXPORT struct loc_network* loc_network_list_pop(struct loc_network_list* list) {
147 // Return nothing when empty
148 if (loc_network_list_empty(list)) {
149 DEBUG(list->ctx, "%p: Popped empty stack\n", list);
150 return NULL;
151 }
152
3b44e421 153 struct loc_network* network = list->elements[--list->size];
e0b9ff5f
MT
154
155 DEBUG(list->ctx, "%p: Popping network %p from stack\n", list, network);
156
157 return network;
158}
159
160LOC_EXPORT struct loc_network* loc_network_list_pop_first(struct loc_network_list* list) {
161 // Return nothing when empty
162 if (loc_network_list_empty(list)) {
163 DEBUG(list->ctx, "%p: Popped empty stack\n", list);
164 return NULL;
165 }
166
3b44e421 167 struct loc_network* network = list->elements[0];
e0b9ff5f
MT
168
169 // Move all elements to the top of the stack
170 for (unsigned int i = 0; i < --list->size; i++) {
3b44e421 171 list->elements[i] = list->elements[i+1];
e0b9ff5f
MT
172 }
173
174 DEBUG(list->ctx, "%p: Popping network %p from stack\n", list, network);
175
176 return network;
177}
178
179LOC_EXPORT int loc_network_list_contains(struct loc_network_list* list, struct loc_network* network) {
180 for (unsigned int i = 0; i < list->size; i++) {
3b44e421 181 if (loc_network_eq(list->elements[i], network))
e0b9ff5f
MT
182 return 1;
183 }
184
185 return 0;
186}
187
188static void loc_network_list_swap(struct loc_network_list* list, unsigned int i1, unsigned int i2) {
189 // Do nothing for invalid indices
190 if (i1 >= list->size || i2 >= list->size)
191 return;
192
3b44e421
MT
193 struct loc_network* network1 = list->elements[i1];
194 struct loc_network* network2 = list->elements[i2];
e0b9ff5f 195
3b44e421
MT
196 list->elements[i1] = network2;
197 list->elements[i2] = network1;
e0b9ff5f
MT
198}
199
200LOC_EXPORT void loc_network_list_reverse(struct loc_network_list* list) {
201 unsigned int i = 0;
202 unsigned int j = list->size - 1;
203
204 while (i < j) {
205 loc_network_list_swap(list, i++, j--);
206 }
207}
208
209LOC_EXPORT void loc_network_list_sort(struct loc_network_list* list) {
210 unsigned int n = list->size;
211 int swapped;
212
213 do {
214 swapped = 0;
215
216 for (unsigned int i = 1; i < n; i++) {
3b44e421 217 if (loc_network_gt(list->elements[i-1], list->elements[i]) > 0) {
e0b9ff5f
MT
218 loc_network_list_swap(list, i-1, i);
219 swapped = 1;
220 }
221 }
222
223 n--;
224 } while (swapped);
225}
226
227LOC_EXPORT int loc_network_list_merge(
228 struct loc_network_list* self, struct loc_network_list* other) {
229 int r;
230
231 for (unsigned int i = 0; i < other->size; i++) {
3b44e421 232 r = loc_network_list_push(self, other->elements[i]);
e0b9ff5f
MT
233 if (r)
234 return r;
235 }
236
237 return 0;
238}