list: Decide the entry eliminator of list at its initialization.
[L-SMASH.git] / common / list.c
blob10f6799666f84b45fa29c5dda138a7ad5fa19289
1 /*****************************************************************************
2 * list.c
3 *****************************************************************************
4 * Copyright (C) 2010-2017 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #include "internal.h" /* must be placed first */
25 #include <string.h>
27 static void lsmash_list_clear
29 lsmash_entry_list_t *list
32 list->head = NULL;
33 list->tail = NULL;
34 list->last_accessed_entry = NULL;
35 list->last_accessed_number = 0;
36 list->entry_count = 0;
37 list->eliminator = NULL;
40 void lsmash_list_init_orig
42 lsmash_entry_list_t *list,
43 lsmash_entry_data_eliminator eliminator
46 assert( eliminator != NULL );
47 list->head = NULL;
48 list->tail = NULL;
49 list->last_accessed_entry = NULL;
50 list->last_accessed_number = 0;
51 list->entry_count = 0;
52 list->eliminator = eliminator;
55 lsmash_entry_list_t *lsmash_list_create_orig
57 lsmash_entry_data_eliminator eliminator
60 lsmash_entry_list_t *list = lsmash_malloc( sizeof(lsmash_entry_list_t) );
61 if( !list )
62 return NULL;
63 lsmash_list_init( list, eliminator );
64 return list;
67 void lsmash_list_destroy
69 lsmash_entry_list_t *list
72 lsmash_list_remove_entries( list );
73 lsmash_free( list );
76 int lsmash_list_add_entry
78 lsmash_entry_list_t *list,
79 void *data
82 if( !list )
83 return LSMASH_ERR_FUNCTION_PARAM;
84 lsmash_entry_t *entry = lsmash_malloc( sizeof(lsmash_entry_t) );
85 if( !entry )
86 return LSMASH_ERR_MEMORY_ALLOC;
87 entry->next = NULL;
88 entry->prev = list->tail;
89 entry->data = data;
90 if( list->head )
91 list->tail->next = entry;
92 else
93 list->head = entry;
94 list->tail = entry;
95 list->entry_count += 1;
96 return 0;
99 int lsmash_list_remove_entry_direct
101 lsmash_entry_list_t *list,
102 lsmash_entry_t *entry
105 if( !list || !entry )
106 return LSMASH_ERR_FUNCTION_PARAM;
107 assert( !entry->data || list->eliminator );
108 lsmash_entry_t *next = entry->next;
109 lsmash_entry_t *prev = entry->prev;
110 if( entry == list->head )
111 list->head = next;
112 else
113 prev->next = next;
114 if( entry == list->tail )
115 list->tail = prev;
116 else
117 next->prev = prev;
118 if( entry->data )
119 list->eliminator( entry->data );
120 if( entry == list->last_accessed_entry )
122 if( next )
123 list->last_accessed_entry = next;
124 else if( prev )
126 list->last_accessed_entry = prev;
127 list->last_accessed_number -= 1;
129 else
131 list->last_accessed_entry = NULL;
132 list->last_accessed_number = 0;
135 else
137 /* We can't know the current entry number immediately,
138 * so discard the last accessed entry info because time is wasted to know it. */
139 list->last_accessed_entry = NULL;
140 list->last_accessed_number = 0;
142 lsmash_free( entry );
143 list->entry_count -= 1;
144 return 0;
147 int lsmash_list_remove_entry
149 lsmash_entry_list_t *list,
150 uint32_t entry_number
153 lsmash_entry_t *entry = lsmash_list_get_entry( list, entry_number );
154 return lsmash_list_remove_entry_direct( list, entry );
157 int lsmash_list_remove_entry_tail
159 lsmash_entry_list_t *list
162 return lsmash_list_remove_entry_direct( list, list->tail );
165 void lsmash_list_remove_entries
167 lsmash_entry_list_t *list
170 if( !list )
171 return;
172 /* Note that it's valid that list contain no entries or no data to be eliminated. */
173 for( lsmash_entry_t *entry = list->head; entry; )
175 lsmash_entry_t *next = entry->next;
176 if( entry->data )
177 list->eliminator( entry->data );
178 lsmash_free( entry );
179 entry = next;
181 lsmash_entry_data_eliminator eliminator = list->eliminator;
182 lsmash_list_clear( list );
183 list->eliminator = eliminator;
186 void lsmash_list_move_entries
188 lsmash_entry_list_t *dst,
189 lsmash_entry_list_t *src
192 *dst = *src;
193 lsmash_entry_data_eliminator eliminator = src->eliminator;
194 lsmash_list_clear( src );
195 src->eliminator = eliminator;
198 lsmash_entry_t *lsmash_list_get_entry
200 lsmash_entry_list_t *list,
201 uint32_t entry_number
204 if( !list || !entry_number || entry_number > list->entry_count )
205 return NULL;
206 int shortcut = 1;
207 lsmash_entry_t *entry = NULL;
208 if( list->last_accessed_entry )
210 if( entry_number == list->last_accessed_number )
211 entry = list->last_accessed_entry;
212 else if( entry_number == list->last_accessed_number + 1 )
213 entry = list->last_accessed_entry->next;
214 else if( entry_number == list->last_accessed_number - 1 )
215 entry = list->last_accessed_entry->prev;
216 else
217 shortcut = 0;
219 else
220 shortcut = 0;
221 if( !shortcut )
223 if( entry_number <= (list->entry_count >> 1) )
225 /* Look for from the head. */
226 uint32_t distance_plus_one = entry_number;
227 for( entry = list->head; entry && --distance_plus_one; entry = entry->next );
229 else
231 /* Look for from the tail. */
232 uint32_t distance = list->entry_count - entry_number;
233 for( entry = list->tail; entry && distance--; entry = entry->prev );
236 if( entry )
238 list->last_accessed_entry = entry;
239 list->last_accessed_number = entry_number;
241 return entry;
244 void *lsmash_list_get_entry_data
246 lsmash_entry_list_t *list,
247 uint32_t entry_number
250 lsmash_entry_t *entry = lsmash_list_get_entry( list, entry_number );
251 return entry ? entry->data : NULL;