Mstdlib-1.24.0
m_list.h
1/* The MIT License (MIT)
2 *
3 * Copyright (c) 2015 Monetra Technologies, LLC.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24#ifndef __M_LIST_H__
25#define __M_LIST_H__
26
27/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
28
29#include <mstdlib/base/m_defs.h>
30#include <mstdlib/base/m_types.h>
31#include <mstdlib/base/m_sort.h>
32
33/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
34
35__BEGIN_DECLS
36
37/*! \defgroup m_list Lists (Dynamic Arrays)
38 * \ingroup m_datastructures
39 *
40 * List (Dynamic Arrays)
41 */
42
43/*! \addtogroup m_list_generic List
44 * \ingroup m_list
45 *
46 * Dynamic list (array) for storing values.
47 *
48 * This should not be used directly. It is a base implementation that should
49 * be used by a type safe wrapper. For example: M_list_str.
50 *
51 * The list can uses a set of callback functions to determine behavior. Such
52 * as if it should duplicate or free values.
53 *
54 * The list can be used in multiple ways:
55 * - Unsorted.
56 * - Sorted.
57 * - Queue (FIFO) (really just unsorted).
58 * - Priority Queue (really just sorted).
59 * - Stack (LIFO) (which cannot be sorted).
60 * - Set.
61 *
62 * A list is indexable. Find is also supported.
63 *
64 * Indexes in the list are 0 at head to len-1 at end (head ... end).
65 * Functions like M_list_first will return head and M_list_last will return end.
66 *
67 * The index start changes in STACK mode. In STACK mode indexing is opposite.
68 * Head is len-1 and end is 0 (head ... end). Entries are still added to end.
69 * Functions like M_list_first will return end and M_list_last will return head.
70 * This is to accommodate STACKS where entries are inserted and removed from
71 * the same end.
72 *
73 * The list is designed for efficient head removal. A value removed from head
74 * will not cause a memmove. Instead a start offset will be noted. If there is
75 * space before head (due to removals) then additions at head will be efficient
76 * as the empty space will be used and a memmove will be avoided. memmoves
77 * will occur when the size (not necessarly number of elements) of the list
78 * changes (expand and shrink) and for removals in the middle of the list.
79 *
80 * Sorted notes:
81 * - Sorting can be set as stable. Insert will also be stable.
82 * - Sorting on insert and find (M_list_index_of()) is done using binary insert/search.
83 * - When M_list_insert_end() is called after M_list_insert_begin() mergesort/qsort will be
84 * used to sort the list.
85 * - Sorting can use an optional thunk parameter but it can only be set by using
86 * M_list_change_sorting().
87 *
88 * @{
89 */
90
91struct M_list;
92typedef struct M_list M_list_t;
93
94
95/*! Function definition to duplicate a value. */
96typedef void *(*M_list_duplicate_func)(const void *);
97
98
99/*! Function definition to free a value. */
100typedef void (*M_list_free_func)(void *);
101
102
103/*! Structure of callbacks that can be registered to override default
104 * behavior for list implementation. */
106 M_sort_compar_t equality; /*!< Callback to check if two items in the list are equal.
107 If NULL unsorted list */
108 M_list_duplicate_func duplicate_insert; /*!< Callback to duplicate a value on insert.
109 If NULL is pass-thru pointer */
110 M_list_duplicate_func duplicate_copy; /*!< Callback to duplicate a value on copy.
111 If NULL is pass-thru pointer */
112 M_list_free_func value_free; /*!< Callback to free a value.
113 If NULL is pass-thru pointer */
114};
115
116
117/*! Flags for controlling the behavior of the list. */
118typedef enum {
119 M_LIST_NONE = 0, /*!< List (array) mode. Default unless M_LIST_STACK is specified. */
120 M_LIST_SORTED = 1 << 0, /*!< Whether the data in the list should be kept in sorted order. callbacks cannot
121 be NULL and the equality function must be set if this is M_TRUE.
122 Sorting cannot be combined with M_LIST_STACK. */
123 M_LIST_STABLE = 1 << 1, /*!< Make insert, search and sort stable. */
124 M_LIST_STACK = 1 << 2, /*!< Last in First out mode. */
125 M_LIST_SET_VAL = 1 << 3, /*!< All elements are unique based on their value.
126 Insert is increased by an additional O(n) operation (on top of the insert
127 itself) in order to determine if a value is a duplicate for unsorted.
128 Insert is increased by an additional O(log(n)) operation (on top of the insert
129 itself) in order to determine if a value is a duplicate for sorted. */
130 M_LIST_SET_PTR = 1 << 4, /*!< All elements are unique based on their pointer.
131 Insert is increased by an additional O(n) operation (on top of the insert
132 itself) in order to determine if a value is a duplicate for unsorted.
133 Insert is increased by an additional O(log(n)) operation (on top of the insert
134 itself) in order to determine if a value is a duplicate for sorted. */
135 M_LIST_NEVERSHRINK = 1 << 5 /*!< Never allow the list to shrink. */
137
138
139/*! Type of matching that should be used when searching/modifying a value in the list. */
140typedef enum {
141 M_LIST_MATCH_VAL = 0, /*!< Match based on the value (equality function). */
142 M_LIST_MATCH_PTR = 1 << 0, /*!< Math the pointer itself. */
143 M_LIST_MATCH_ALL = 1 << 1 /*!< Include all instances. */
145
146
147/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
148
149/*! Create a new dynamic list.
150 *
151 * A dynamic list is a dynamically expanding array. Meaning the array will expand to accommodate new elements.
152 * The list can be, optionally, kept in sorted order. The sorted order is determined by the equality callback
153 * function if sorting is enabled.
154 *
155 * \param[in] callbacks Register callbacks for overriding default behavior. May pass NULL
156 * if not overriding default behavior.
157 * \param[in] flags M_list_flags_t flags controlling behavior.
158 *
159 * \return Allocated dynamic list.
160 *
161 * \see M_list_destroy
162 */
163M_API M_list_t *M_list_create(const struct M_list_callbacks *callbacks, M_uint32 flags) M_MALLOC;
164
165
166/*! Destroy the list.
167 *
168 * \param[in] d The list to destory.
169 * \param[in] destroy_vals Whether the values held in the list should be destroyed.
170 * If the list is not duplicating the values it holds then
171 * destroying values may not be desirable.
172 */
173M_API void M_list_destroy(M_list_t *d, M_bool destroy_vals) M_FREE(1);
174
175
176/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
177
178/*! Change the sorting behavior of the list.
179 *
180 * The list cannot have been created as a queue.
181 *
182 * \param[in,out] d The list.
183 * \param[in] equality The equality function to use. Can be NULL to remove the equality function.
184 * \param[in] sorted_flags M_list_flags_t to specify how sorting should be handled. Allows the following:
185 * * M_LIST_SORTED
186 * * M_LIST_STACK
187 * Omitting one of these flags will disable it.
188 * \param[in] thunk Thunk passed to equality function.
189 */
190M_API void M_list_change_sorting(M_list_t *d, M_sort_compar_t equality, M_uint32 sorted_flags, void *thunk);
191
192
193/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
194
195/*! Insert a value into the list.
196 *
197 * If sorted the value will be inserted in sorted order. Otherwise it will be
198 * appended to the end of the list.
199 *
200 * \param[in,out] d The list.
201 * \param[in] val The value to insert.
202 *
203 * \return M_TRUE on success otherwise M_FALSE.
204 */
205M_API M_bool M_list_insert(M_list_t *d, const void *val);
206
207
208/*! Get the index a value would be insert into the list at.
209 *
210 * This does not actually insert the value into the list it only gets the position the value would
211 * be insert into the list if/when insert is called.
212 *
213 * \param[in] d The list.
214 * \param[in] val The value to get the insertion index for.
215 *
216 * \return The insertion index.
217 */
218M_API size_t M_list_insert_idx(const M_list_t *d, const void *val);
219
220
221/*! Insert a value into the list at a specific position.
222 *
223 * This is only supported for non-sorted lists.
224 *
225 * \param[in,out] d The list.
226 * \param[in] val The value to insert.
227 * \param[in] idx The position to insert at. An index larger than the number of
228 * elements in the list will result in the item being inserted
229 * at the end.
230 *
231 * \return M_TRUE on success otherwise M_FALSE.
232 */
233M_API M_bool M_list_insert_at(M_list_t *d, const void *val, size_t idx);
234
235
236/*! Start a grouped insertion.
237 *
238 * This is only useful for sorted lists. This will defer sorting until
239 * M_list_insert_end() is called. This is to allow many items to be inserted
240 * at once without the sorting overhead being called for every insertion.
241 *
242 * \param[in,out] d The list.
243 *
244 * \see M_list_insert_end
245 */
247
248
249/*! End a grouped insertion.
250 *
251 * This is only useful for sorted lists. Cause all elements in the list (if
252 * sorting is enabled) to be sorted.
253 *
254 * \param[in,out] d The list.
255 *
256 * \see M_list_insert_begin
257 */
259
260
261/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
262
263/*! The length of the list.
264 *
265 * \param[in] d The list.
266 *
267 * \return the length of the list.
268 */
269M_API size_t M_list_len(const M_list_t *d);
270
271
272/*! Count the number of times a value occurs in the list.
273 *
274 * \param[in] d The list.
275 * \param[in] val The value to search for.
276 * \param[in] type M_list_match_type_t type of how the val should be matched.
277 * valid values are:
278 * - M_LIST_MATCH_VAL
279 * - M_LIST_MATCH_PTR
280 *
281 * \return The number of times val appears in the list.
282 */
283M_API size_t M_list_count(const M_list_t *d, const void *val, M_uint32 type);
284
285
286/*! Get the location of a value within the list.
287 *
288 * This will return a location in the list which may not be the first occurrence in the list.
289 *
290 * \param[in] d The list.
291 * \param[in] val The value to search for.
292 * \param[in] type M_list_match_type_t type of how the val should be matched.
293 * valid values are:
294 * - M_LIST_MATCH_VAL
295 * - M_LIST_MATCH_PTR
296 * \param[out] idx The index of the value within the list. Optional, pass NULL if not needed.
297 *
298 * \return M_TRUE if the value was found within the list. Otherwise M_FALSE.
299 */
300M_API M_bool M_list_index_of(const M_list_t *d, const void *val, M_uint32 type, size_t *idx);
301
302
303/*! Get the first element.
304 *
305 * The element will remain a member of the list.
306 *
307 * \param[in] d The list.
308 *
309 * \return The element or NULL if there are no elements.
310 *
311 * \see M_list_at
312 * \see M_list_last
313 */
314M_API const void *M_list_first(const M_list_t *d);
315
316
317/*! Get the last element.
318 *
319 * The element will remain a member of the list.
320 *
321 * \param[in] d The list.
322 *
323 * \return The element or NULL if there are no elements.
324 *
325 * \see M_list_at
326 * \see M_list_first
327 */
328M_API const void *M_list_last(const M_list_t *d);
329
330
331/*! Get the element at a given index.
332 *
333 * The element will remain a member of the list.
334 *
335 * \param[in] d The list.
336 * \param[in] idx The location to retrieve the element from.
337 *
338 * \return The element or NULL if index is out range.
339 *
340 * \see M_list_first
341 * \see M_list_last
342 */
343M_API const void *M_list_at(const M_list_t *d, size_t idx);
344
345
346/*! Take the first element.
347 *
348 * The element will be removed from the list and returned. The caller is
349 * responsible for freeing the element.
350 *
351 * \param[in,out] d The list.
352 *
353 * \return The element or NULL if there are no elements.
354 *
355 * \see M_list_take_at
356 * \see M_list_last
357 */
359
360
361/*! Take the last element.
362 *
363 * The element will be removed from the list and returned. The caller is
364 * responsible for freeing the element.
365 *
366 * \param[in,out] d The list.
367 *
368 * \return The element or NULL if there are no elements.
369 *
370 * \see M_list_take_at
371 * \see M_list_take_first
372 */
374
375
376/*! Take the element at a given index.
377 *
378 * The element will be removed from the list and returned. The caller is
379 * responsible for freeing the element.
380 *
381 * \param[in,out] d The list.
382 * \param[in] idx The location to retrieve the element from.
383 *
384 * \return The element or NULL if index is out range.
385 *
386 * \see M_list_take_first
387 * \see M_list_take_last
388 */
389M_API void *M_list_take_at(M_list_t *d, size_t idx);
390
391
392/*! Remove the first element.
393 *
394 * The value will be free'd using the value_free callback.
395 *
396 * \param[in,out] d The list.
397 *
398 * \return M_TRUE if the element was removed. Otherwise M_FALSE.
399 *
400 * \see M_list_remove_at
401 * \see M_list_remove_last
402 */
404
405
406/*! Remove the last element.
407 *
408 * The value will be free'd using the value_free callback.
409 *
410 * \param[in,out] d The list.
411 *
412 * \return M_TRUE if the element was removed. Otherwise M_FALSE.
413 *
414 * \see M_list_remove_at
415 * \see M_list_remove_first
416 */
418
419
420/*! Remove an element at a given index from the list.
421 *
422 * The value will be free'd using the value_free callback.
423 *
424 * \param[in,out] d The list.
425 * \param[in] idx The index to remove.
426 *
427 * \return M_TRUE if the element was removed. Otherwise M_FALSE.
428 *
429 * \ see M_list_remove_first
430 * \ see M_list_remove_last
431 * \ see M_list_remove_val
432 * \ see M_list_remove_range
433 */
434M_API M_bool M_list_remove_at(M_list_t *d, size_t idx);
435
436
437/*! Remove element(s) from the list.
438 *
439 * Searches the list for the occurrence of val and removes it from the
440 * list. The value will be free'd using the value_free callback.
441 *
442 * Requires the equality callback to be set.
443 *
444 * \param[in,out] d The list.
445 * \param[in] val The val to remove
446 * \param[in] type M_list_match_type_t type of how the val should be matched.
447 *
448 * \return The number of elements removed.
449 *
450 * \see M_list_remove_at
451 */
452M_API size_t M_list_remove_val(M_list_t *d, const void *val, M_uint32 type);
453
454
455/*! Remove a range of elements form the list.
456 *
457 * The values will be free'd using the value_free callback.
458 *
459 * \param[in,out] d The list.
460 * \param[in] start The start index. Inclusive.
461 * \param[in] end The end index. Inclusive.
462 *
463 * \return M_TRUE if the range was removed. Otherwise M_FALSE.
464 *
465 * \see M_list_remove_at
466 */
467M_API M_bool M_list_remove_range(M_list_t *d, size_t start, size_t end);
468
469
470/*! Remove duplicate elements from the list.
471 *
472 * Requires the equality callback to be set.
473 * The values will be free'd using the value_free callback.
474 *
475 * \param[in] d The list.
476 * \param[in] type M_list_match_type_t type of how the val should be matched.
477 * valid values are:
478 * - M_LIST_MATCH_VAL
479 * - M_LIST_MATCH_PTR
480 */
481M_API void M_list_remove_duplicates(M_list_t *d, M_uint32 type);
482
483
484/*! Replace all matching values in the list with a different value.
485 *
486 * The replaced values in the list will be free'd using the value_free callback.
487 *
488 * \param[in,out] d The list.
489 * \param[in] val The val to be replaced.
490 * \param[in] new_val The value to be replaced with.
491 * \param[in] type M_list_match_type_t type of how the val should be matched.
492 *
493 * \return The number of elements replaced.
494 */
495M_API size_t M_list_replace_val(M_list_t *d, const void *val, const void *new_val, M_uint32 type);
496
497
498/*! Replace a value in the list with a different value.
499 *
500 * The replaced value in the list will be free'd using the value_free callback.
501 *
502 * \param[in,out] d The list.
503 * \param[in] val The val to that will appear in the list at the given idx.
504 * \param[in] idx The index to replace.
505 *
506 * \return M_TRUE if the value was replaced. Otherwise M_FALSE.
507 */
508M_API M_bool M_list_replace_at(M_list_t *d, const void *val, size_t idx);
509
510
511/*! Exchange the elements at the given locations.
512 *
513 * This only applies to unsorted lists.
514 *
515 * \param[in,out] d The list.
516 * \param[in] idx1 The first index.
517 * \param[in] idx2 The second index.
518 *
519 * \return M_TRUE if the elements were swapped.
520 */
521M_API M_bool M_list_swap(M_list_t *d, size_t idx1, size_t idx2);
522
523
524/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
525
526/*! Duplicate an existing list.
527 *
528 * Will copy all elements of the list as well as any callbacks, etc.
529 *
530 * \param[in] d list to duplicate.
531 *
532 * \return New list.
533 */
534M_API M_list_t *M_list_duplicate(const M_list_t *d) M_MALLOC;
535
536
537/*! Merge two lists together.
538 *
539 * The second (src) list will be destroyed automatically upon completion of this function. Any value pointers for the
540 * list will be directly copied over to the destination list, they will not be duplicated.
541 *
542 * \param[in,out] dest Pointer by reference to the list receiving the values.
543 * if this is NULL, the pointer will simply be switched out for src.
544 * \param[in,out] src Pointer to the list giving up its values.
545 * \param[in] include_duplicates When M_TRUE any values in 'dest' that also exist in
546 * 'src' will be included in 'dest'. When M_FALSE any
547 * duplicate values will not be added to 'dest'.
548 * \param[in] type M_list_match_type_t type of how the val should be matched.
549 * valid values are:
550 * - M_LIST_MATCH_VAL
551 * - M_LIST_MATCH_PTR
552 */
553M_API void M_list_merge(M_list_t **dest, M_list_t *src, M_bool include_duplicates, M_uint32 type) M_FREE(2);
554
555/*! @} */
556
557__END_DECLS
558
559#endif /* __M_LIST_H__ */
M_list_duplicate_func duplicate_insert
Definition: m_list.h:108
M_sort_compar_t equality
Definition: m_list.h:106
M_list_duplicate_func duplicate_copy
Definition: m_list.h:110
M_list_free_func value_free
Definition: m_list.h:112
M_bool M_list_remove_at(M_list_t *d, size_t idx)
void(* M_list_free_func)(void *)
Definition: m_list.h:100
M_list_t * M_list_duplicate(const M_list_t *d) M_MALLOC
void * M_list_take_first(M_list_t *d)
void M_list_merge(M_list_t **dest, M_list_t *src, M_bool include_duplicates, M_uint32 type) M_FREE(2)
M_list_t * M_list_create(const struct M_list_callbacks *callbacks, M_uint32 flags) M_MALLOC
void M_list_remove_duplicates(M_list_t *d, M_uint32 type)
size_t M_list_count(const M_list_t *d, const void *val, M_uint32 type)
void M_list_change_sorting(M_list_t *d, M_sort_compar_t equality, M_uint32 sorted_flags, void *thunk)
size_t M_list_len(const M_list_t *d)
const void * M_list_at(const M_list_t *d, size_t idx)
void M_list_insert_begin(M_list_t *d)
struct M_list M_list_t
Definition: m_list.h:92
const void * M_list_last(const M_list_t *d)
size_t M_list_replace_val(M_list_t *d, const void *val, const void *new_val, M_uint32 type)
size_t M_list_remove_val(M_list_t *d, const void *val, M_uint32 type)
M_bool M_list_swap(M_list_t *d, size_t idx1, size_t idx2)
const void * M_list_first(const M_list_t *d)
void * M_list_take_last(M_list_t *d)
void *(* M_list_duplicate_func)(const void *)
Definition: m_list.h:96
M_list_flags_t
Definition: m_list.h:118
void * M_list_take_at(M_list_t *d, size_t idx)
M_bool M_list_remove_last(M_list_t *d)
M_bool M_list_index_of(const M_list_t *d, const void *val, M_uint32 type, size_t *idx)
M_bool M_list_remove_first(M_list_t *d)
void M_list_insert_end(M_list_t *d)
M_bool M_list_replace_at(M_list_t *d, const void *val, size_t idx)
M_bool M_list_insert_at(M_list_t *d, const void *val, size_t idx)
M_bool M_list_remove_range(M_list_t *d, size_t start, size_t end)
M_list_match_type_t
Definition: m_list.h:140
M_bool M_list_insert(M_list_t *d, const void *val)
void M_list_destroy(M_list_t *d, M_bool destroy_vals) M_FREE(1)
size_t M_list_insert_idx(const M_list_t *d, const void *val)
@ M_LIST_SET_PTR
Definition: m_list.h:130
@ M_LIST_STABLE
Definition: m_list.h:123
@ M_LIST_NEVERSHRINK
Definition: m_list.h:135
@ M_LIST_SET_VAL
Definition: m_list.h:125
@ M_LIST_SORTED
Definition: m_list.h:120
@ M_LIST_STACK
Definition: m_list.h:124
@ M_LIST_NONE
Definition: m_list.h:119
@ M_LIST_MATCH_PTR
Definition: m_list.h:142
@ M_LIST_MATCH_ALL
Definition: m_list.h:143
@ M_LIST_MATCH_VAL
Definition: m_list.h:141
Definition: m_list.h:105
int(* M_sort_compar_t)(const void *arg1, const void *arg2, void *thunk)
Definition: m_sort.h:78