Merge lp:~stefan.goetz-deactivatedaccount/hipl/hip-ll-cleanup into lp:hipl
- hip-ll-cleanup
- Merge into trunk
Status: | Rejected |
---|---|
Rejected by: | Stefan Götz |
Proposed branch: | lp:~stefan.goetz-deactivatedaccount/hipl/hip-ll-cleanup |
Merge into: | lp:hipl |
Diff against target: |
736 lines (+245/-210) 8 files modified
hipd/hip_socket.c (+5/-5) hipd/maintenance.c (+2/-2) hipd/pkt_handling.c (+2/-2) hipd/registration.c (+9/-9) hipd/user.c (+1/-1) lib/core/linkedlist.c (+190/-159) lib/core/linkedlist.h (+16/-12) lib/core/modularization.c (+20/-20) |
To merge this branch: | bzr merge lp:~stefan.goetz-deactivatedaccount/hipl/hip-ll-cleanup |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Stefan Götz (community) | Disapprove | ||
Christof Mroz | Approve | ||
Review via email: mp+56058@code.launchpad.net |
Commit message
Description of the change
Improve const correctness and reduce code duplication in linked list implementation.
Reviewers may want to review individual commits.
Christof Mroz (christof-mroz) wrote : | # |
Mhh looks like I accidentally removed hipl-core from the reviewers list... you may need to add the team it again if there are problems.
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : | # |
> What's wrong with using utlist [2], btw?
> [2] http://
Ah, awesome. I'm all for re-using existing implementations such as this.
Would anyone object to using utlist as the preferred list
implementation in HIPL?
Stefan
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : | # |
I'll put this merge proposal on ice for now and create a branch for trying out utlist as a replacement for slist to see how that works out and whether utlist proves usable.
Diego Biurrun (diego-biurrun) wrote : | # |
On Mon, Apr 04, 2011 at 09:50:54AM +0000, Stefan Götz wrote:
> The proposal to merge lp:~stefan.goetz/hipl/hip-ll-cleanup into lp:hipl has been updated.
>
> Status: Needs review => Rejected
I'd like to suggest that you merge this. It is better than what we have
currently and the work is already done. If you decide to replace it by
something even better later on - fine. But in the meantime I would
suggest adding all improvements to HIPL, no matter how small.
Diego
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : | # |
>> The proposal to merge lp:~stefan.goetz/hipl/hip-ll-cleanup into lp:hipl has been updated.
>>
>> Status: Needs review => Rejected
>
> I'd like to suggest that you merge this. It is better than what we have
> currently and the work is already done. If you decide to replace it by
> something even better later on - fine. But in the meantime I would
> suggest adding all improvements to HIPL, no matter how small.
I will do that because I'd like to stick with hip_ll for now. However,
I will keep working on the branch a little before creating a merge
proposal again, both because Christof made outstanding suggestions and
because I changed my mind about the design of some of those
improvements.
Stefan
Diego Biurrun (diego-biurrun) wrote : | # |
On Tue, Apr 05, 2011 at 08:59:49PM +0000, Stefan Götz wrote:
> >> The proposal to merge lp:~stefan.goetz/hipl/hip-ll-cleanup into lp:hipl has been updated.
> >>
> >> Status: Needs review => Rejected
> >
> > I'd like to suggest that you merge this. It is better than what we have
> > currently and the work is already done. If you decide to replace it by
> > something even better later on - fine. But in the meantime I would
> > suggest adding all improvements to HIPL, no matter how small.
>
> I will do that because I'd like to stick with hip_ll for now. However,
> I will keep working on the branch a little before creating a merge
> proposal again, both because Christof made outstanding suggestions and
> because I changed my mind about the design of some of those
> improvements.
OK, I can live with that of course, I'd just like to reiterate that over
time I have become quite a fan of small iterative improvements.
If I hadn't manually merged those const correctness fixes of yours they
might now be lost in an abandoned branch somewhere on the internet.
So - merge early and merge often without sacrificing quality and split
off sensible parts as early as you can. That's my recipe for success :)
Diego
Diego Biurrun (diego-biurrun) wrote : | # |
On Sun, Apr 03, 2011 at 12:18:31PM +0000, Christof Mroz wrote:
>
> What's wrong with using utlist [2], btw?
>
> [2] http://
That's likely not the only viable list implementation we could leverage.
Others that have been pointed out to me are glib, gnulib and sys/queue.h.
Especially the latter should be available on every system that HIPL cares
about...
Diego
Diego Biurrun (diego-biurrun) wrote : | # |
On Wed, Apr 06, 2011 at 04:18:36PM +0200, Diego Biurrun wrote:
> On Sun, Apr 03, 2011 at 12:18:31PM +0000, Christof Mroz wrote:
> >
> > What's wrong with using utlist [2], btw?
> >
> > [2] http://
>
> That's likely not the only viable list implementation we could leverage.
>
> Others that have been pointed out to me are glib, gnulib and sys/queue.h.
> Especially the latter should be available on every system that HIPL cares
> about...
man 3 queue
Diego
Christof Mroz (christof-mroz) wrote : | # |
On Wed, 06 Apr 2011 16:18:36 +0200, Diego Biurrun <email address hidden> wrote:
> On Sun, Apr 03, 2011 at 12:18:31PM +0000, Christof Mroz wrote:
>>
>> What's wrong with using utlist [2], btw?
>>
>> [2] http://
>
> That's likely not the only viable list implementation we could leverage.
Yes, that was just one that came to my mind. But...
> Others that have been pointed out to me are glib, gnulib and sys/queue.h.
> Especially the latter should be available on every system that HIPL cares
> about...
...I haven't heard about sys/queue.h yet, thanks. queue(3) looks so
similar to utlist that there's probably no reason to even consider utlist
anymore.
As I've discussed with Stefan outside the mailinglist, the design is quite
different from hip_ll though (for the better in my opinion: type-safe,
simpler, memory-efficient considering cache coherency and space usage), so
incorporating it could be a lot of work.
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : | # |
> As I've discussed with Stefan outside the mailinglist, the design is quite
> different from hip_ll though (for the better in my opinion: type-safe,
> simpler, memory-efficient considering cache coherency and space usage)
That's what makes it not useful in HIPL. sys/queue.h and utlist allow
to manage only 'objects' in a list but not 'references'. Here's why:
sys/queue.h and utlist can store objects of the following type:
struct party {
struct party *next;
char *host;
char *street;
int houseno;
int date;
char *costume;
}
That's fine as long as we want only one single 'parties' list in which
all known party objects are to be stored. If however, we'd like to
reference some of those objects in an additional list, say the
'coolparties' list, what do we do?
a) We copy all those party objects that are cool parties and create
the 'coolparties' list from those copies. We often don't want that
because a change to the original party object (say, its date) should
be immediately visible in both party lists.
b) We create a new
struct coolparty {
struct coolparty *next;
struct party *party;
} and add those objects to the 'coolparties' list, referencing party
objects from the parties list. That, of course, means that we need to
allocate and free those additional coolparty objects on the fly. Now
if we get into the same situation for a number of different object
types, that's a lot of code duplication.
The coolparties scenario is fairly common in HIPL. So what we want in
HIPL is a list implementation where list nodes reference objects
instead of turning the objects into list nodes themselves. sys/queue.h
and utlist do the latter, not the former.
SimCList seems to be ok functionality-wise and license-wise, but is
not under a lot of development. glib is fairly awesome but also fairly
heavy-weight. Not sure if it's available reliable for scratchbox or
Android or friends.
hip_ll get's the job done pretty decently - a bit of cleanup, a few
extensions... I mean I'd love to reuse something else, but here,
hip_ll doesn't look like such a bad candidate for re-use. Any
opinions?
Stefan
Unmerged revisions
- 5817. By Stefan Götz
-
Add an internal, more generic function for deleting a list node from a linked list.
Simplify the hip_ll_del() function by re-using the new internal function. - 5816. By Stefan Götz
-
Add internal functions for retrieving list nodes.
Simplify the existing functions hip_ll_add() and hip_ll_get() by re-using the new functions. - 5815. By Stefan Götz
-
Simplify hip_ll_uninit() to re-use existing code instead of re-implementing it.
- 5814. By Stefan Götz
-
Improved const correctness of linked list implementation. Adapted code using linked lists where necessary.
Preview Diff
1 | === modified file 'hipd/hip_socket.c' |
2 | --- hipd/hip_socket.c 2011-02-25 15:18:27 +0000 |
3 | +++ hipd/hip_socket.c 2011-04-02 21:41:01 +0000 |
4 | @@ -251,8 +251,8 @@ |
5 | |
6 | int hip_get_highest_descriptor(void) |
7 | { |
8 | - int highest_descriptor = 0; |
9 | - struct hip_ll_node *iter = NULL; |
10 | + int highest_descriptor = 0; |
11 | + const struct hip_ll_node *iter = NULL; |
12 | |
13 | if (hip_sockets) { |
14 | while ((iter = hip_ll_iterate(hip_sockets, iter))) { |
15 | @@ -269,7 +269,7 @@ |
16 | |
17 | void hip_prepare_fd_set(fd_set *read_fdset) |
18 | { |
19 | - struct hip_ll_node *iter = NULL; |
20 | + const struct hip_ll_node *iter = NULL; |
21 | |
22 | FD_ZERO(read_fdset); |
23 | |
24 | @@ -296,8 +296,8 @@ |
25 | */ |
26 | void hip_run_socket_handles(fd_set *read_fdset, struct hip_packet_context *ctx) |
27 | { |
28 | - struct hip_ll_node *iter = NULL; |
29 | - int socketfd; |
30 | + const struct hip_ll_node *iter = NULL; |
31 | + int socketfd; |
32 | |
33 | if (hip_sockets) { |
34 | while ((iter = hip_ll_iterate(hip_sockets, iter))) { |
35 | |
36 | === modified file 'hipd/maintenance.c' |
37 | --- hipd/maintenance.c 2011-02-14 19:20:39 +0000 |
38 | +++ hipd/maintenance.c 2011-04-02 21:41:01 +0000 |
39 | @@ -224,8 +224,8 @@ |
40 | */ |
41 | static int hip_run_maint_functions(void) |
42 | { |
43 | - int err = 0; |
44 | - struct hip_ll_node *iter = NULL; |
45 | + int err = 0; |
46 | + const struct hip_ll_node *iter = NULL; |
47 | |
48 | if (hip_maintenance_functions) { |
49 | while ((iter = hip_ll_iterate(hip_maintenance_functions, iter))) { |
50 | |
51 | === modified file 'hipd/pkt_handling.c' |
52 | --- hipd/pkt_handling.c 2011-02-14 18:40:02 +0000 |
53 | +++ hipd/pkt_handling.c 2011-04-02 21:41:01 +0000 |
54 | @@ -139,8 +139,8 @@ |
55 | const uint32_t ha_state, |
56 | struct hip_packet_context *ctx) |
57 | { |
58 | - int err = 0; |
59 | - struct hip_ll_node *iter = NULL; |
60 | + int err = 0; |
61 | + const struct hip_ll_node *iter = NULL; |
62 | |
63 | HIP_IFEL(packet_type > HIP_MAX_PACKET_TYPE, |
64 | -1, |
65 | |
66 | === modified file 'hipd/registration.c' |
67 | --- hipd/registration.c 2011-03-29 19:46:16 +0000 |
68 | +++ hipd/registration.c 2011-04-02 21:41:01 +0000 |
69 | @@ -104,7 +104,7 @@ |
70 | { |
71 | int idx = 0; |
72 | time_t now = time(NULL); |
73 | - struct hip_ll_node *iter = NULL; |
74 | + const struct hip_ll_node *iter = NULL; |
75 | struct hip_pending_request *request = NULL; |
76 | |
77 | /* See hip_del_pending_request() for a comment. */ |
78 | @@ -241,8 +241,8 @@ |
79 | */ |
80 | int hip_del_pending_request(struct hip_hadb_state *entry) |
81 | { |
82 | - int idx = 0; |
83 | - struct hip_ll_node *iter = NULL; |
84 | + int idx = 0; |
85 | + const struct hip_ll_node *iter = NULL; |
86 | |
87 | /* Iterate through the linked list. The iterator itself can't be used |
88 | * for deleting nodes from the list. Therefore, we just get the index of |
89 | @@ -276,7 +276,7 @@ |
90 | uint8_t reg_type) |
91 | { |
92 | int idx = 0; |
93 | - struct hip_ll_node *iter = NULL; |
94 | + const struct hip_ll_node *iter = NULL; |
95 | struct hip_pending_request *request = NULL; |
96 | |
97 | /* See hip_del_pending_request() for a comment. */ |
98 | @@ -308,7 +308,7 @@ |
99 | int hip_replace_pending_requests(struct hip_hadb_state *entry_old, |
100 | struct hip_hadb_state *entry_new) |
101 | { |
102 | - struct hip_ll_node *iter = 0; |
103 | + const struct hip_ll_node *iter = 0; |
104 | |
105 | while ((iter = hip_ll_iterate(&pending_requests, iter)) != NULL) { |
106 | if (((struct hip_pending_request *) (iter->ptr))->entry == entry_old) { |
107 | @@ -338,8 +338,8 @@ |
108 | static int hip_get_pending_requests(struct hip_hadb_state *entry, |
109 | struct hip_pending_request *requests[]) |
110 | { |
111 | - struct hip_ll_node *iter = 0; |
112 | - int request_count = 0; |
113 | + const struct hip_ll_node *iter = 0; |
114 | + int request_count = 0; |
115 | |
116 | if (requests == NULL) { |
117 | return -1; |
118 | @@ -368,8 +368,8 @@ |
119 | */ |
120 | static int hip_get_pending_request_count(struct hip_hadb_state *entry) |
121 | { |
122 | - struct hip_ll_node *iter = 0; |
123 | - int request_count = 0; |
124 | + const struct hip_ll_node *iter = 0; |
125 | + int request_count = 0; |
126 | |
127 | while ((iter = hip_ll_iterate(&pending_requests, iter)) != NULL) { |
128 | if (((struct hip_pending_request *) (iter->ptr))->entry == entry) { |
129 | |
130 | === modified file 'hipd/user.c' |
131 | --- hipd/user.c 2011-03-24 17:34:21 +0000 |
132 | +++ hipd/user.c 2011-04-02 21:41:01 +0000 |
133 | @@ -185,7 +185,7 @@ |
134 | struct hip_common *msg, |
135 | struct sockaddr_in6 *src) |
136 | { |
137 | - struct hip_ll_node *iter = NULL; |
138 | + const struct hip_ll_node *iter = NULL; |
139 | |
140 | if (!hip_user_msg_handles[msg_type] || |
141 | !hip_ll_get_size(hip_user_msg_handles[msg_type])) { |
142 | |
143 | === modified file 'lib/core/linkedlist.c' |
144 | --- lib/core/linkedlist.c 2011-03-29 17:55:57 +0000 |
145 | +++ lib/core/linkedlist.c 2011-04-02 21:41:01 +0000 |
146 | @@ -43,7 +43,7 @@ |
147 | * |
148 | * @param linkedlist the list to init. |
149 | */ |
150 | -void hip_ll_init(struct hip_ll *linkedlist) |
151 | +void hip_ll_init(struct hip_ll *const linkedlist) |
152 | { |
153 | if (linkedlist != NULL) { |
154 | *linkedlist = (struct hip_ll) HIP_LL_INIT; |
155 | @@ -72,34 +72,15 @@ |
156 | * invoking this function, and then call this function with |
157 | * NULL as @c free_element. |
158 | */ |
159 | -void hip_ll_uninit(struct hip_ll *linkedlist, free_elem_fn free_element) |
160 | +void hip_ll_uninit(struct hip_ll *const linkedlist, free_elem_fn free_element) |
161 | { |
162 | - struct hip_ll_node *pointer = NULL; |
163 | - |
164 | - if (linkedlist == NULL || linkedlist->head == NULL) { |
165 | - return; |
166 | - } |
167 | - |
168 | - /* Free the node currently at list head and move the next item to list |
169 | - * head. Continue this until the item at list head is NULL. If |
170 | - * free_element() is non-NULL we also free the memory allocated for the |
171 | - * actual element. */ |
172 | - if (free_element != NULL) { |
173 | - while (linkedlist->head != NULL) { |
174 | - pointer = linkedlist->head->next; |
175 | - free_element(linkedlist->head->ptr); |
176 | - free(linkedlist->head); |
177 | - linkedlist->head = pointer; |
178 | - } |
179 | - } else { |
180 | - while (linkedlist->head != NULL) { |
181 | - pointer = linkedlist->head->next; |
182 | - free(linkedlist->head); |
183 | - linkedlist->head = pointer; |
184 | - } |
185 | - } |
186 | - |
187 | - linkedlist->element_count = 0; |
188 | + if (linkedlist) { |
189 | + while (linkedlist->head) { |
190 | + hip_ll_del_first(linkedlist, free_element); |
191 | + } |
192 | + HIP_ASSERT(!linkedlist->head); |
193 | + HIP_ASSERT(!linkedlist->element_count); |
194 | + } |
195 | } |
196 | |
197 | /** |
198 | @@ -108,7 +89,7 @@ |
199 | * @param linkedlist the list whose node count is to be returned. |
200 | * @return number of nodes in the list. |
201 | */ |
202 | -unsigned int hip_ll_get_size(const struct hip_ll *linkedlist) |
203 | +unsigned int hip_ll_get_size(const struct hip_ll *const linkedlist) |
204 | { |
205 | if (linkedlist == NULL) { |
206 | return 0; |
207 | @@ -118,77 +99,129 @@ |
208 | } |
209 | |
210 | /** |
211 | + * Get the list node with the specified index and its predecessor node. |
212 | + * |
213 | + * This function helps to avoid re-implementing the linear search for different |
214 | + * purposes. |
215 | + * |
216 | + * @param list points to the list to search. The result of calling this |
217 | + * function with list == NULL is undefined. |
218 | + * @param idx the index of the list node to retrieve. The first node element |
219 | + * has the index 0. The result of calling this function with an idx |
220 | + * value greater than or equal to the number of nodes in the list |
221 | + * is undefined. |
222 | + * @param prev points to a struct hip_ll_node pointer. If this function returns |
223 | + * successfully, the value of prev is set to point to the |
224 | + * predecessor node of the returned node. It is set to NULL if the |
225 | + * returned node is the first node in the list. |
226 | + * @return the list node with the index idx. |
227 | + */ |
228 | +static struct hip_ll_node *hip_ll_get_node_with_prev(const struct hip_ll *const list, |
229 | + const unsigned idx, |
230 | + struct hip_ll_node **const prev) |
231 | +{ |
232 | + unsigned i = 0; |
233 | + struct hip_ll_node *p = NULL; |
234 | + struct hip_ll_node *node; |
235 | + |
236 | + HIP_ASSERT(list); |
237 | + HIP_ASSERT((list->element_count == 0 && !list->head) || |
238 | + (list->element_count == 1 && list->head && !list->head->next) || |
239 | + (list->element_count > 1 && list->head && list->head->next)); |
240 | + HIP_ASSERT(idx < list->element_count); |
241 | + HIP_ASSERT(prev); |
242 | + |
243 | + for (node = list->head; node; node = node->next) { |
244 | + if (i != idx) { |
245 | + p = node; |
246 | + i += 1; |
247 | + } else { |
248 | + *prev = p; |
249 | + break; |
250 | + } |
251 | + } |
252 | + |
253 | + HIP_ASSERT(node && |
254 | + ((idx == 0 && !*prev) || (*prev && (*prev)->next == node))); |
255 | + |
256 | + return node; |
257 | +} |
258 | + |
259 | +/** |
260 | + * Get the list node with the specified index. |
261 | + * |
262 | + * @param list points to the list to search. The result of calling this |
263 | + * function with list == NULL is undefined. |
264 | + * @param idx the index of the list node to retrieve. The first node element |
265 | + * has the index 0. The result of calling this function with an idx |
266 | + * value greater than or equal to the number of nodes in the list |
267 | + * is undefined. |
268 | + * @return the list node with the index idx. |
269 | + */ |
270 | +static struct hip_ll_node *hip_ll_get_node(const struct hip_ll *const list, |
271 | + const unsigned idx) |
272 | +{ |
273 | + struct hip_ll_node *p = NULL; |
274 | + |
275 | + return hip_ll_get_node_with_prev(list, idx, &p); |
276 | +} |
277 | + |
278 | +/** |
279 | * Adds a new node to a linked list. Adds a new node at @c index to the |
280 | - * parameter @c linkedlist with payload data @c ptr. If there are less than |
281 | - * (<code>index -1</code>) elements in the list, the element will be added as |
282 | - * the last element of the list. |
283 | + * parameter @c linkedlist with payload data @c ptr. If there are exactly |
284 | + * <code>index</code> elements in the list, the element is added as the last |
285 | + * element of the list. |
286 | * |
287 | * <b>Example:</b> |
288 | * |
289 | - * <code>hip_ll_add(&mylist, 2, mydata);</code> will add @c mydata as the |
290 | - * third item of the list when there are more than two elements in @c mylist. |
291 | - * When there are less than two items in the list @c mydata will be added as |
292 | - * the last element of @c mylist. |
293 | + * <code>hip_ll_add(&mylist, 2, mydata);</code> adds @c mydata as the |
294 | + * third item of the list when there are two or more elements in @c mylist. |
295 | * |
296 | * @param linkedlist the list where to add the new node. |
297 | * @param index the list index where to store the node. Indexing starts |
298 | * from zero. |
299 | * @param ptr a pointer to the data to be stored. |
300 | * @return zero on success, -1 if @c linkedlist or @c ptr is NULL or |
301 | - * if there was an error when allocating memory to the new |
302 | - * node. |
303 | + * index is greater than the size of list or if there is an |
304 | + * error when allocating memory for the new node. |
305 | */ |
306 | -int hip_ll_add(struct hip_ll *linkedlist, const unsigned int index, void *ptr) |
307 | +int hip_ll_add(struct hip_ll *const linkedlist, |
308 | + const unsigned int index, |
309 | + void *const ptr) |
310 | { |
311 | - struct hip_ll_node *newnode = NULL, *pointer = NULL; |
312 | - unsigned int current_index = 0; |
313 | - |
314 | - if (linkedlist == NULL || ptr == NULL) { |
315 | - return -1; |
316 | - } |
317 | - |
318 | - if ((newnode = malloc(sizeof(struct hip_ll_node))) == NULL) { |
319 | - HIP_ERROR("Error on allocating memory for a linked list node.\n"); |
320 | - return -1; |
321 | - } |
322 | - |
323 | - newnode->ptr = ptr; |
324 | - pointer = linkedlist->head; |
325 | - |
326 | - /* Item to add is the first item of the list or it is to be added as the |
327 | - * first one. */ |
328 | - if (pointer == NULL || index == 0) { |
329 | - newnode->next = pointer; |
330 | - linkedlist->head = newnode; |
331 | - linkedlist->element_count++; |
332 | - } |
333 | - /* There exist at least one element in the list and the new element is |
334 | - * not to be added as the first one. */ |
335 | - else { |
336 | - struct hip_ll_node *previous = pointer; |
337 | - |
338 | - /* Loop until "pointer" is at the last item. */ |
339 | - while (pointer->next != NULL) { |
340 | - previous = pointer; |
341 | - pointer = pointer->next; |
342 | - current_index++; |
343 | - |
344 | - /* We have reached the target index and the index is not |
345 | - * the index of the last item in the list. */ |
346 | - if (current_index == index) { |
347 | - newnode->next = pointer; |
348 | - previous->next = newnode; |
349 | - linkedlist->element_count++; |
350 | - return 0; |
351 | + if (linkedlist && index <= linkedlist->element_count && ptr) { |
352 | + struct hip_ll_node *newnode; |
353 | + if ((newnode = malloc(sizeof(*newnode)))) { |
354 | + newnode->ptr = ptr; |
355 | + |
356 | + if (index == 0) { |
357 | + newnode->next = linkedlist->head; |
358 | + linkedlist->head = newnode; |
359 | + } else { |
360 | + // newnode is to be inserted after prev and before next |
361 | + struct hip_ll_node *next = NULL; |
362 | + struct hip_ll_node *prev = NULL; |
363 | + |
364 | + if (index != linkedlist->element_count) { |
365 | + next = hip_ll_get_node_with_prev(linkedlist, index, &prev); |
366 | + } else { |
367 | + prev = hip_ll_get_node(linkedlist, index - 1); |
368 | + next = NULL; |
369 | + } |
370 | + HIP_ASSERT(prev->next == next); |
371 | + prev->next = newnode; |
372 | + newnode->next = next; |
373 | } |
374 | + |
375 | + linkedlist->element_count += 1; |
376 | + |
377 | + return 0; |
378 | + } else { |
379 | + HIP_ERROR("Error on allocating memory for a linked list node.\n"); |
380 | } |
381 | - /* The node is to be added as the last item of the list. */ |
382 | - newnode->next = NULL; |
383 | - pointer->next = newnode; |
384 | - linkedlist->element_count++; |
385 | } |
386 | |
387 | - return 0; |
388 | + return -1; |
389 | } |
390 | |
391 | /** |
392 | @@ -201,7 +234,7 @@ |
393 | * if there was an error when allocating memory to the new |
394 | * node. |
395 | */ |
396 | -int hip_ll_add_first(struct hip_ll *linkedlist, void *ptr) |
397 | +int hip_ll_add_first(struct hip_ll *const linkedlist, void *const ptr) |
398 | { |
399 | return hip_ll_add(linkedlist, 0, ptr); |
400 | } |
401 | @@ -216,12 +249,55 @@ |
402 | * if there was an error when allocating memory to the new |
403 | * node. |
404 | */ |
405 | -int hip_ll_add_last(struct hip_ll *linkedlist, void *ptr) |
406 | +int hip_ll_add_last(struct hip_ll *const linkedlist, void *const ptr) |
407 | { |
408 | return hip_ll_add(linkedlist, linkedlist->element_count, ptr); |
409 | } |
410 | |
411 | /** |
412 | + * Remove a node from a list and free the node memory (not the payload data). |
413 | + * |
414 | + * Since this function expects to be given the predecessor of the node to |
415 | + * delete, this function has a runtime complexity of O(1). |
416 | + * |
417 | + * @param list the list from which to delete the node. The result of calling |
418 | + * this function with list == NULL is undefined. |
419 | + * @param node the node to delete. The result of calling this function with |
420 | + * list == NULL is undefined. |
421 | + * @param prev the predecessor node of the node to delete. prev must be NULL |
422 | + * iff node is the first node in the list. The result of calling |
423 | + * this function under the violation of this condition is |
424 | + * undefined. |
425 | + * @return pointer to the payload data the deleted list node was associated |
426 | + * with. |
427 | + */ |
428 | +static void *hip_ll_del_node(struct hip_ll *const list, |
429 | + struct hip_ll_node *const node, |
430 | + struct hip_ll_node *const prev) |
431 | +{ |
432 | + void *payload; |
433 | + |
434 | + HIP_ASSERT(list); |
435 | + HIP_ASSERT(node); |
436 | + HIP_ASSERT((prev && prev->next == node) || |
437 | + (!prev && list->head == node)); |
438 | + HIP_ASSERT((list->element_count == 1 && list->head && !list->head->next) || |
439 | + (list->element_count > 1 && list->head && list->head->next)); |
440 | + |
441 | + payload = node->ptr; |
442 | + |
443 | + if (prev) { |
444 | + prev->next = node->next; |
445 | + } else { |
446 | + list->head = node->next; |
447 | + } |
448 | + free(node); |
449 | + list->element_count -= 1; |
450 | + |
451 | + return payload; |
452 | +} |
453 | + |
454 | +/** |
455 | * Deletes a node from a linked list. Deletes a node at @c index and frees the |
456 | * memory allocated for the node from the parameter @c linkedlist. If there are |
457 | * less than (<code>index -1</code>) nodes in the list no action will be taken. If |
458 | @@ -244,58 +320,25 @@ |
459 | * element itself is deleted. NULL is also returned when |
460 | * the list @c linkedlist itself is NULL. |
461 | */ |
462 | -void *hip_ll_del(struct hip_ll *linkedlist, const unsigned int index, |
463 | +void *hip_ll_del(struct hip_ll *const linkedlist, const unsigned int index, |
464 | free_elem_fn free_element) |
465 | { |
466 | - struct hip_ll_node *pointer = NULL, *previous = NULL; |
467 | - void *ptr = NULL; |
468 | - unsigned int current_index = 0; |
469 | - |
470 | - if (linkedlist == NULL || linkedlist->head == NULL) { |
471 | - return NULL; |
472 | - } else if (index > (linkedlist->element_count - 1)) { |
473 | - return NULL; |
474 | - } |
475 | - |
476 | - if (index == 0) { |
477 | - ptr = linkedlist->head->ptr; |
478 | - pointer = linkedlist->head->next; |
479 | - if (free_element != NULL) { |
480 | - free_element(ptr); |
481 | - ptr = NULL; |
482 | - } |
483 | - free(linkedlist->head); |
484 | - linkedlist->head = pointer; |
485 | - linkedlist->element_count--; |
486 | - return ptr; |
487 | - } |
488 | - |
489 | - pointer = previous = linkedlist->head; |
490 | - |
491 | - while (pointer->next != NULL) { |
492 | - previous = pointer; |
493 | - pointer = pointer->next; |
494 | - current_index++; |
495 | - |
496 | - /* We have reached the target index. */ |
497 | - if (current_index == index) { |
498 | - if (pointer == NULL) { |
499 | - previous->next = NULL; |
500 | - } else { |
501 | - previous->next = pointer->next; |
502 | - } |
503 | - ptr = pointer->ptr; |
504 | - if (free_element != NULL) { |
505 | - free_element(ptr); |
506 | - ptr = NULL; |
507 | - } |
508 | - free(pointer); |
509 | - linkedlist->element_count--; |
510 | - break; |
511 | - } |
512 | - } |
513 | - |
514 | - return ptr; |
515 | + if (linkedlist && index < linkedlist->element_count) { |
516 | + struct hip_ll_node *node = NULL; |
517 | + struct hip_ll_node *prev = NULL; |
518 | + void *payload; |
519 | + |
520 | + node = hip_ll_get_node_with_prev(linkedlist, index, &prev); |
521 | + payload = hip_ll_del_node(linkedlist, node, prev); |
522 | + if (free_element) { |
523 | + free_element(payload); |
524 | + return NULL; |
525 | + } else { |
526 | + return payload; |
527 | + } |
528 | + } else { |
529 | + return NULL; |
530 | + } |
531 | } |
532 | |
533 | /** |
534 | @@ -317,7 +360,7 @@ |
535 | * deleted. NULL is also returned when the list |
536 | * @c linkedlist itself is NULL. |
537 | */ |
538 | -void *hip_ll_del_first(struct hip_ll *linkedlist, |
539 | +void *hip_ll_del_first(struct hip_ll *const linkedlist, |
540 | free_elem_fn free_element) |
541 | { |
542 | return hip_ll_del(linkedlist, 0, free_element); |
543 | @@ -334,27 +377,15 @@ |
544 | * @return the next element or NULL if the list end has been reached |
545 | * or if @c linkedlist is NULL. |
546 | */ |
547 | -void *hip_ll_get(struct hip_ll *linkedlist, const unsigned int index) |
548 | +void *hip_ll_get(const struct hip_ll *const linkedlist, const unsigned int index) |
549 | { |
550 | - struct hip_ll_node *pointer = linkedlist->head; |
551 | - unsigned int current_index = 0; |
552 | - |
553 | - if (linkedlist == NULL || linkedlist->head == NULL) { |
554 | - return NULL; |
555 | - } else if (index > (linkedlist->element_count - 1)) { |
556 | - return NULL; |
557 | - } |
558 | - |
559 | - while (pointer != NULL) { |
560 | - if (current_index == index) { |
561 | - break; |
562 | - } |
563 | - |
564 | - pointer = pointer->next; |
565 | - current_index++; |
566 | - } |
567 | - |
568 | - return pointer->ptr; |
569 | + if (linkedlist && index < linkedlist->element_count) { |
570 | + struct hip_ll_node *const node = hip_ll_get_node(linkedlist, index); |
571 | + HIP_ASSERT(node); |
572 | + return node->ptr; |
573 | + } else { |
574 | + return NULL; |
575 | + } |
576 | } |
577 | |
578 | /** |
579 | @@ -379,8 +410,8 @@ |
580 | * using this function.</span> Consider hip_ll_del() or |
581 | * hip_ll_uninit() for deleting nodes and elements. |
582 | */ |
583 | -struct hip_ll_node *hip_ll_iterate(const struct hip_ll *linkedlist, |
584 | - struct hip_ll_node *current) |
585 | +const struct hip_ll_node *hip_ll_iterate(const struct hip_ll *const linkedlist, |
586 | + const struct hip_ll_node *const current) |
587 | { |
588 | if (linkedlist == NULL) { |
589 | return NULL; |
590 | |
591 | === modified file 'lib/core/linkedlist.h' |
592 | --- lib/core/linkedlist.h 2011-03-29 16:48:08 +0000 |
593 | +++ lib/core/linkedlist.h 2011-04-02 21:41:01 +0000 |
594 | @@ -61,19 +61,23 @@ |
595 | #define HIP_LL_INIT { 0, NULL } |
596 | |
597 | /** Linked list element memory deallocator function pointer. */ |
598 | -typedef void (*free_elem_fn)(void *ptr); |
599 | +typedef void (*free_elem_fn)(void *const ptr); |
600 | |
601 | -void hip_ll_init(struct hip_ll *linkedlist); |
602 | -void hip_ll_uninit(struct hip_ll *linkedlist, free_elem_fn free_element); |
603 | -unsigned int hip_ll_get_size(const struct hip_ll *linkedlist); |
604 | -int hip_ll_add(struct hip_ll *linkedlist, const unsigned int index, void *ptr); |
605 | -int hip_ll_add_first(struct hip_ll *linkedlist, void *ptr); |
606 | -int hip_ll_add_last(struct hip_ll *linkedlist, void *ptr); |
607 | -void *hip_ll_del(struct hip_ll *linkedlist, const unsigned int index, |
608 | +void hip_ll_init(struct hip_ll *const linkedlist); |
609 | +void hip_ll_uninit(struct hip_ll *const linkedlist, free_elem_fn free_element); |
610 | +unsigned int hip_ll_get_size(const struct hip_ll *const linkedlist); |
611 | +int hip_ll_add(struct hip_ll *const linkedlist, |
612 | + const unsigned int index, |
613 | + void *const ptr); |
614 | +int hip_ll_add_first(struct hip_ll *const linkedlist, void *const ptr); |
615 | +int hip_ll_add_last(struct hip_ll *const linkedlist, void *const ptr); |
616 | +void *hip_ll_del(struct hip_ll *const linkedlist, const unsigned int index, |
617 | free_elem_fn free_element); |
618 | -void *hip_ll_del_first(struct hip_ll *linkedlist, free_elem_fn free_element); |
619 | -void *hip_ll_get(struct hip_ll *linkedlist, const unsigned int index); |
620 | -struct hip_ll_node *hip_ll_iterate(const struct hip_ll *linkedlist, |
621 | - struct hip_ll_node *current); |
622 | +void *hip_ll_del_first(struct hip_ll *const linkedlist, |
623 | + free_elem_fn free_element); |
624 | +void *hip_ll_get(const struct hip_ll *const linkedlist, |
625 | + const unsigned int index); |
626 | +const struct hip_ll_node *hip_ll_iterate(const struct hip_ll *const linkedlist, |
627 | + const struct hip_ll_node *const current); |
628 | |
629 | #endif /* HIP_LIB_CORE_LINKEDLIST_H */ |
630 | |
631 | === modified file 'lib/core/modularization.c' |
632 | --- lib/core/modularization.c 2011-04-01 12:30:35 +0000 |
633 | +++ lib/core/modularization.c 2011-04-02 21:41:01 +0000 |
634 | @@ -165,8 +165,8 @@ |
635 | */ |
636 | void lmod_init_state_items(struct modular_state *state) |
637 | { |
638 | - struct hip_ll_node *iter = NULL; |
639 | - int (*init_function)(struct modular_state *state) = NULL; |
640 | + const struct hip_ll_node *iter = NULL; |
641 | + int (*init_function)(struct modular_state *state) = NULL; |
642 | |
643 | while ((iter = hip_ll_iterate(&state_init_functions, iter))) { |
644 | init_function = iter->ptr; |
645 | @@ -300,9 +300,9 @@ |
646 | void *entry, |
647 | const uint16_t priority) |
648 | { |
649 | - int idx = 0; |
650 | - struct hip_ll *new_list = NULL; |
651 | - struct hip_ll_node *iter = NULL; |
652 | + int idx = 0; |
653 | + struct hip_ll *new_list = NULL; |
654 | + const struct hip_ll_node *iter = NULL; |
655 | |
656 | if (!list) { |
657 | if (!(new_list = malloc(sizeof(struct hip_ll)))) { |
658 | @@ -342,8 +342,8 @@ |
659 | */ |
660 | int lmod_unregister_function(struct hip_ll *list, const void *function) |
661 | { |
662 | - int idx = 0; |
663 | - struct hip_ll_node *iter = NULL; |
664 | + int idx = 0; |
665 | + const struct hip_ll_node *iter = NULL; |
666 | |
667 | if (!list) { |
668 | return -1; |
669 | @@ -440,8 +440,8 @@ |
670 | */ |
671 | int lmod_packet_type_exists(const uint8_t packet_type) |
672 | { |
673 | - int idx = 0; |
674 | - struct hip_ll_node *iter = NULL; |
675 | + int idx = 0; |
676 | + const struct hip_ll_node *iter = NULL; |
677 | |
678 | while ((iter = hip_ll_iterate(&packet_types, iter))) { |
679 | if (packet_type == ((struct packet_type *) iter->ptr)->num) { |
680 | @@ -461,7 +461,7 @@ |
681 | */ |
682 | const char *lmod_get_packet_identifier(const uint8_t packet_type) |
683 | { |
684 | - struct hip_ll_node *iter = NULL; |
685 | + const struct hip_ll_node *iter = NULL; |
686 | HIP_DEBUG("Name search for packet type %d \n", packet_type); |
687 | |
688 | while ((iter = hip_ll_iterate(&packet_types, iter))) { |
689 | @@ -489,9 +489,9 @@ |
690 | int lmod_register_packet_type(const uint8_t packet_type, |
691 | const char *const identifier) |
692 | { |
693 | - int idx = 0; |
694 | - struct hip_ll_node *iter = NULL; |
695 | - struct packet_type *new_entry = NULL; |
696 | + int idx = 0; |
697 | + const struct hip_ll_node *iter = NULL; |
698 | + struct packet_type *new_entry = NULL; |
699 | |
700 | if (!identifier || (lmod_packet_type_exists(packet_type) != -1)) { |
701 | return -1; |
702 | @@ -559,8 +559,8 @@ |
703 | */ |
704 | int lmod_parameter_type_exists(const uint16_t parameter_type) |
705 | { |
706 | - int index = 0; |
707 | - struct hip_ll_node *iter = NULL; |
708 | + int index = 0; |
709 | + const struct hip_ll_node *iter = NULL; |
710 | |
711 | while ((iter = hip_ll_iterate(¶meter_types, iter))) { |
712 | if (parameter_type == ((struct parameter_type *) iter->ptr)->num) { |
713 | @@ -589,10 +589,10 @@ |
714 | int lmod_register_parameter_type(const uint16_t parameter_type, |
715 | const char *const identifier) |
716 | { |
717 | - int index = 0; |
718 | - struct hip_ll_node *iter = NULL; |
719 | - struct parameter_type *new_entry = NULL; |
720 | - int err = 0; |
721 | + int index = 0; |
722 | + const struct hip_ll_node *iter = NULL; |
723 | + struct parameter_type *new_entry = NULL; |
724 | + int err = 0; |
725 | |
726 | HIP_IFEL(!identifier || (lmod_parameter_type_exists(parameter_type) != -1), |
727 | -1, "Missing identifier or parameter type already registered.\n"); |
728 | @@ -633,7 +633,7 @@ |
729 | */ |
730 | const char *lmod_get_parameter_identifier(const uint16_t parameter_type) |
731 | { |
732 | - struct hip_ll_node *iter = NULL; |
733 | + const struct hip_ll_node *iter = NULL; |
734 | HIP_DEBUG("Name search for parameter type %d \n", parameter_type); |
735 | |
736 | while ((iter = hip_ll_iterate(¶meter_types, iter))) { |
Approved because the implementation seems correct, but some possible improvements:
> +static struct hip_ll_node *hip_ll_ get_node_ with_prev( const struct hip_ll *const list,
> [...]
> + for (node = list->head; node; node = node->next) {
> + if (i != idx) {
> + p = node;
> + i += 1;
> + } else {
> + *prev = p;
> + break;
> + }
> + }
More concise (but see my next comment too):
*prev = NULL;
node = list->head;
for (unsigned i = 0; i < idx; ++i) {
*prev = node;
node = node->next;
}
> + HIP_ASSERT(node && get_node( const struct hip_ll *const list, get_node_ with_prev( list, idx, &p);
> + ((idx == 0 && !*prev) || (*prev && (*prev)->next == node)));
> +
> + return node;
> +}
> +
> +/**
> + * Get the list node with the specified index.
> + *
> + * @param list points to the list to search. The result of calling this
> + * function with list == NULL is undefined.
> + * @param idx the index of the list node to retrieve. The first node element
> + * has the index 0. The result of calling this function with an idx
> + * value greater than or equal to the number of nodes in the list
> + * is undefined.
> + * @return the list node with the index idx.
> + */
> +static struct hip_ll_node *hip_ll_
> + const unsigned idx)
> +{
> + struct hip_ll_node *p = NULL;
> +
> + return hip_ll_
> +}
> +
> +/**
I would implement the _with_prev() variant in terms of this function, not the other way around:
if (idx == 0) { get_node( list, idx-1);
*prev = NULL;
return list->head;
} else {
*prev = hip_ll_
return (*prev)->next;
}
> - * parameter @c linkedlist with payload data @c ptr. If there are less than
> - * (<code>index -1</code>) elements in the list, the element will be added as
> - * the last element of the list.
> + * parameter @c linkedlist with payload data @c ptr. If there are exactly
> + * <code>index</code> elements in the list, the element is added as the last
> + * element of the list.
Unrelated: Semantic markup: @a rather than <code>...</code> where possible.
> + if (index == 0) { >element_ count) { get_node_ with_prev( linkedlist, index, &prev); get_node( linkedlist, index - 1); prev->next == next);
> + newnode->next = linkedlist->head;
> + linkedlist->head = newnode;
> + } else {
> + // newnode is to be inserted after prev and before next
> + struct hip_ll_node *next = NULL;
> + struct hip_ll_node *prev = NULL;
> +
> + if (index != linkedlist-
> + next = hip_ll_
> + } else {
> + prev = hip_ll_
> + next = NULL;
> + }
> + HIP_ASSERT(
> + prev->next = newnode;
> + newnode->next = next;
> }
The index != 0 branch can be simplified:
- parent = node[index-1]
- new->next = parent->child
- parent->next = new
If we're two-star programmers [1] at HIPL, the following also gets rid of the
branching:
// find storage of in...