Mstdlib-1.24.0
m_list_str.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_STR_H__
25#define __M_LIST_STR_H__
26
27/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
28
29#include <mstdlib/base/m_defs.h>
30#include <mstdlib/base/m_types.h>
31
32/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
33
34__BEGIN_DECLS
35
36/*! \addtogroup m_list_str List - String
37 * \ingroup m_list
38 * Dynamic list (array) for storing string values.
39 *
40 * References to the data will always be read-only.
41 * All items will be duplicated by the list.
42 *
43 * The list can be used in multiple ways:
44 * - Unsorted.
45 * - Sorted.
46 * - Queue (FIFO) (really just unsorted).
47 * - Stack (LIFO) (which cannot be sorted).
48 * - Set.
49 *
50 * A list is indexable. Find is also supported.
51 *
52 * Indexes in the list are 0 at head to len-1 at end (head ... end).
53 * Functions like M_list_first will return head and M_list_last will return end.
54 *
55 * The index start changes in STACK mode. In STACK mode indexing is opposite.
56 * Head is len-1 and end is 0 (head ... end). Entries are still added to end.
57 * Functions like M_list_first will return end and M_list_last will return head.
58 * This is to accommodate STACKS where entries are inserted and removed from
59 * the same end.
60 *
61 * The list is designed for efficient head removal. A value removed from head
62 * will not cause a memmove. Instead a start offset will be noted. If there is
63 * space before head (due to removals) then additions at head will be efficient
64 * as the empty space will be used and a memmove will be avoided. memmoves
65 * will occur when the size (not necessarly number of elements) of the list
66 * changes (expand and shink) and for removals in the middle of the list.
67 *
68 * Sorted notes:
69 * - Sorting on insert and find (M_list_str_index_of()) is done using binary insert/search.
70 * - When M_list_insert_end() is called after M_list_insert_begin() qsort will be
71 * used to sort the list.
72 *
73 * @{
74 */
75
76struct M_list_str;
77/* Currently a direct map to M_list private opaque type,
78 * simply using casting to prevent the 'wrap' overhead of mallocing when it
79 * is not necessary */
80typedef struct M_list_str M_list_str_t;
81
82
83/*! Flags for controlling the behavior of the list. */
84typedef enum {
85 M_LIST_STR_NONE = 1 << 0, /*!< Not sorting, asc compare. */
86 M_LIST_STR_SORTASC = 1 << 1, /*!< Sort asc. */
87 M_LIST_STR_SORTDESC = 1 << 2, /*!< Sort desc. */
88 M_LIST_STR_CASECMP = 1 << 3, /*!< Compare is case insensitive. */
89 M_LIST_STR_STABLE = 1 << 5, /*!< Make insert, search and sort stable. */
90 M_LIST_STR_STACK = 1 << 6, /*!< Last in First out mode. */
91 M_LIST_STR_SET = 1 << 7, /*!< Don't allow duplicates in the list.
92 Insert is increased by an additional O(n) operation (on top of the insert
93 itself) in order to determine if a value is a duplicate for unsorted.
94 Insert is increased by an additional O(log(n)) operation (on top of the
95 insert itself) in order to determine if a value is a duplicate for sorted. */
96 M_LIST_STR_NEVERSHRINK = 1 << 8 /*!< Never allow the list to shrink. */
98
99
100/*! Type of matching that should be used when searching/modifying a value in the list. */
101typedef enum {
102 M_LIST_STR_MATCH_VAL = 0, /*!< Match based on the value (equality function). */
103 M_LIST_STR_MATCH_PTR = 1 << 0, /*!< Math the pointer itself. */
104 M_LIST_STR_MATCH_ALL = 1 << 1 /*!< Include all instances. */
106
107
108/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
109
110/*! Create a new dynamic list.
111 *
112 * A dynamic list is a dynamically expanding array. Meaning the array will expand to accommodate new elements.
113 * The list can be, optionally, kept in sorted order.
114 *
115 * \param[in] flags M_list_str_flags_t flags for controlling behavior.
116 *
117 * \return Allocated dynamic list for storing strings.
118 *
119 * \see M_list_str_destroy
120 */
121M_API M_list_str_t *M_list_str_create(M_uint32 flags) M_MALLOC;
122
123
124/*! Destory the list.
125 *
126 * \param[in] d The list to destory.
127 */
128M_API void M_list_str_destroy(M_list_str_t *d) M_FREE(1);
129
130
131/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
132
133/*! Change the sorting behavior of the list.
134 *
135 * \param[in,out] d The list.
136 * \param[in] flags M_list_str_flags_t flags that control sorting.
137 */
138M_API void M_list_str_change_sorting(M_list_str_t *d, M_uint32 flags);
139
140
141/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
142
143/*! Insert a value into the list.
144 *
145 * If sorted the value will be inserted in sorted order. Otherwise it will be
146 * appended to the end of the list.
147 *
148 * \param[in,out] d The list.
149 * \param[in] val The value to insert.
150 *
151 * \return M_TRUE on success otherwise M_FALSE.
152 */
153M_API M_bool M_list_str_insert(M_list_str_t *d, const char *val);
154
155
156/*! Get the index a value would be insert into the list at.
157 *
158 * This does not actually insert the value into the list it only gets the position the value would
159 * be insert into the list if/when insert is called.
160 *
161 * \param[in] d The list.
162 * \param[in] val The value to get the insertion index for.
163 *
164 * \return The insertion index.
165 */
166M_API size_t M_list_str_insert_idx(const M_list_str_t *d, const char *val);
167
168
169/*! Insert a value into the list at a specific position.
170 *
171 * This is only supported for non-sorted lists.
172 *
173 * \param[in,out] d The list.
174 * \param[in] val The value to insert.
175 * \param[in] idx The position to insert at. An index larger than the number of
176 * elements in the list will result in the item being inserted
177 * at the end.
178 *
179 * \return M_TRUE on success otherwise M_FALSE.
180 */
181M_API M_bool M_list_str_insert_at(M_list_str_t *d, const char *val, size_t idx);
182
183
184/*! Start a grouped insertion.
185 *
186 * This is only useful for sorted lists. This will defer sorting until
187 * M_list_str_insert_end() is called. This is to allow many items to be inserted
188 * at once without the sorting overhead being called for every insertion.
189 *
190 * \param[in,out] d The list.
191 *
192 * \see M_list_str_insert_end
193 */
195
196
197/*! End a grouped insertion.
198 *
199 * This is only useful for sorted lists. Cause all elements in the list (if
200 * sorting is enabled) to be sorted.
201 *
202 * \param[in,out] d The list.
203 *
204 * \see M_list_str_insert_begin
205 */
207
208
209/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
210
211/*! The length of the list.
212 *
213 * \param[in] d The list.
214 *
215 * \return the length of the list.
216 */
217M_API size_t M_list_str_len(const M_list_str_t *d);
218
219
220/*! Count the number of times a value occurs in the list.
221 *
222 * \param[in] d The list.
223 * \param[in] val The value to search for.
224 * \param[in] type M_list_str_match_type_t type of how the val should be matched.
225 * valid values are:
226 * - M_LIST_STR_MATCH_VAL
227 * - M_LIST_STR_MATCH_PTR
228 *
229 * \return The number of times val appears in the list.
230 */
231M_API size_t M_list_str_count(const M_list_str_t *d, const char *val, M_uint32 type);
232
233
234/*! Get the location of a value within the list.
235 *
236 * This will return a location in the list which may not be the first occurrence in the list.
237 *
238 * \param[in] d The list.
239 * \param[in] val The value to search for.
240 * \param[in] type M_list_str_match_type_t type of how the val should be matched.
241 * valid values are:
242 * - M_LIST_STR_MATCH_VAL
243 * - M_LIST_STR_MATCH_PTR
244 * \param[out] idx The index of the value within the list. Optional, pass NULL if not needed.
245 *
246 * \return M_TRUE if the value was found within the list. Otherwise M_FALSE.
247 */
248M_API M_bool M_list_str_index_of(const M_list_str_t *d, const char *val, M_uint32 type, size_t *idx);
249
250
251/*! Get the first element.
252 *
253 * The element will remain a member of the list.
254 *
255 * \param[in] d The list.
256 *
257 * \return The element or NULL if there are no elements.
258 *
259 * \see M_list_str_at
260 * \see M_list_str_last
261 */
262M_API const char *M_list_str_first(const M_list_str_t *d);
263
264
265/*! Get the last element.
266 *
267 * The element will remain a member of the list.
268 *
269 * \param[in] d The list.
270 *
271 * \return The element or NULL if there are no elements.
272 *
273 * \see M_list_at
274 * \see M_list_first
275 */
276M_API const char *M_list_str_last(const M_list_str_t *d);
277
278
279/*! Get the element at a given index.
280 *
281 * The element will remain a member of the list.
282 *
283 * \param[in] d The list.
284 * \param[in] idx The location to retrieve the element from.
285 *
286 * \return The element or NULL if index is out range.
287 *
288 * \see M_list_str_first
289 * \see M_list_str_last
290 */
291M_API const char *M_list_str_at(const M_list_str_t *d, size_t idx);
292
293
294/*! Take the first element.
295 *
296 * The element will be removed from the list and returned. The caller is
297 * responsible for freeing the element.
298 *
299 * \param[in,out] d The list.
300 *
301 * \return The element or NULL if there are no elements.
302 *
303 * \see M_list_str_take_at
304 * \see M_list_str_last
305 */
307
308
309/*! Take the last element.
310 *
311 * The element will be removed from the list and returned. The caller is
312 * responsible for freeing the element.
313 *
314 * \param[in,out] d The list.
315 *
316 * \return The element or NULL if there are no elements.
317 *
318 * \see M_list_str_take_at
319 * \see M_list_str_take_first
320 */
322
323
324/*! Take the element at a given index.
325 *
326 * The element will be removed from the list and returned. The caller is
327 * responsible for freeing the element.
328 *
329 * \param[in,out] d The list.
330 * \param[in] idx The location to retrieve the element from.
331 *
332 * \return The element or NULL if index is out range.
333 *
334 * \see M_list_str_take_first
335 * \see M_list_str_take_last
336 */
337M_API char *M_list_str_take_at(M_list_str_t *d, size_t idx);
338
339
340/*! Remove the first element.
341 *
342 * \param[in,out] d The list.
343 *
344 * \return M_TRUE if the element was removed. Otherwise M_FALSE.
345 *
346 * \see M_list_str_remove_at
347 * \see M_list_str_remove_last
348 */
350
351
352/*! Remove the last element.
353 *
354 * \param[in,out] d The list.
355 *
356 * \return M_TRUE if the element was removed. Otherwise M_FALSE.
357 *
358 * \see M_list_str_remove_at
359 * \see M_list_str_remove_first
360 */
362
363
364/*! Remove an element at a given index from the list.
365 *
366 * \param[in,out] d The list.
367 * \param[in] idx The index to remove.
368 *
369 * \return M_TRUE if the element was removed. Otherwise M_FALSE.
370 *
371 * \ see M_list_str_remove_first
372 * \ see M_list_str_remove_last
373 * \ see M_list_str_remove_val
374 * \ see M_list_str_remove_range
375 */
376M_API M_bool M_list_str_remove_at(M_list_str_t *d, size_t idx);
377
378
379/*! Remove element(s) from the list.
380 *
381 * Searches the list for the occurrence of val and removes it from the
382 * list. The value will be free'd using the value_free callback.
383 *
384 * Requires the equality callback to be set.
385 *
386 * \param[in,out] d The list.
387 * \param[in] val The val to remove
388 * \param[in] type M_list_str_match_type_t type of how the val should be matched.
389 *
390 * \return The number of elements removed.
391 *
392 * \see M_list_str_remove_at
393 */
394M_API size_t M_list_str_remove_val(M_list_str_t *d, const char *val, M_uint32 type);
395
396
397/*! Remove a range of elements form the list.
398 *
399 * \param[in,out] d The list.
400 * \param[in] start The start index. Inclusive.
401 * \param[in] end The end index. Inclusive.
402 *
403 * \return M_TRUE if the range was removed. Otherwise M_FALSE.
404 *
405 * \see M_list_str_remove_at
406 */
407M_API M_bool M_list_str_remove_range(M_list_str_t *d, size_t start, size_t end);
408
409
410/*! Remove duplicate elements from the list.
411 *
412 * \param[in] d The list.
413 */
415
416
417/*! Replace all matching values in the list with a different value.
418 *
419 * \param[in,out] d The list.
420 * \param[in] val The val to be replaced.
421 * \param[in] new_val The value to be replaced with.
422 * \param[in] type M_list_str_match_type_t type of how the val should be matched.
423 *
424 * \return The number of elements replaced.
425 */
426M_API size_t M_list_str_replace_val(M_list_str_t *d, const char *val, const char *new_val, M_uint32 type);
427
428
429/*! Replace a value in the list with a different value.
430 *
431 * \param[in,out] d The list.
432 * \param[in] val The val to that will appear in the list at the given idx.
433 * \param[in] idx The index to replace.
434 *
435 * \return M_TRUE if the value was replaced. Otherwise M_FALSE.
436 */
437M_API M_bool M_list_str_replace_at(M_list_str_t *d, const char *val, size_t idx);
438
439
440/*! Exchange the elements at the given locations.
441 *
442 * This only applies to unsorted lists.
443 *
444 * \param[in,out] d The list.
445 * \param[in] idx1 The first index.
446 * \param[in] idx2 The second index.
447 *
448 * \return M_TRUE if the elements were swapped.
449 */
450M_API M_bool M_list_str_swap(M_list_str_t *d, size_t idx1, size_t idx2);
451
452
453/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
454
455/*! Duplicate an existing list.
456 *
457 * Will copy all elements of the list as well as any flags, etc.
458 *
459 * \param[in] d list to duplicate.
460 *
461 * \return New list.
462 */
464
465
466/*! Merge two lists together.
467 *
468 * The second (src) list will be destroyed automatically upon completion of this function. Any value pointers for the
469 * list will be directly copied over to the destination list, they will not be duplicated.
470 *
471 * \param[in,out] dest Pointer by reference to the list receiving the values.
472 * if this is NULL, the pointer will simply be switched out for src.
473 * \param[in,out] src Pointer to the list giving up its values.
474 * \param[in] include_duplicates When M_TRUE any values in 'dest' that also exist in
475 * 'src' will be included in 'dest'. When M_FALSE any
476 * duplicate values will not be added to 'dest'.
477 */
478M_API void M_list_str_merge(M_list_str_t **dest, M_list_str_t *src, M_bool include_duplicates) M_FREE(2);
479
480
481/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
482
483/*! Split a string into a list.
484 *
485 * The delim will be removed.
486 *
487 * \param[in] delim Delimiter.
488 * \param[in] s String to search.
489 * \param[in] flags M_list_str_flags_t flags for controlling behavior.
490 * \param[in] keep_empty_parts Control whether an empty part should be added to the list. The delim character
491 * will be an empty part. Meaning if "a:b" split on ':' will result in [a,b] if
492 * M_FALSE or [a,,b] if M_TRUE.
493 *
494 * \return Allocated dynamic list for storing strings.
495 */
496M_API M_list_str_t *M_list_str_split(unsigned char delim, const char *s, M_uint32 flags, M_bool keep_empty_parts) M_MALLOC;
497
498
499/*! Join all strs in the list into a single string separated by sep.
500 *
501 * \param[in] d The list.
502 * \param[in] sep The character to use as a separator between each string in the list.
503 *
504 * \return An allocated string.
505 */
506M_API char *M_list_str_join(const M_list_str_t *d, unsigned char sep);
507
508
509/*! Join all strs in the list into a single string separated by sep.
510 *
511 * \param[in] d The list.
512 * \param[in] sep The string to use as a separator between each string in the list.
513 *
514 * \return An allocated string.
515 */
516M_API char *M_list_str_join_str(const M_list_str_t *d, const char *sep);
517
518
519/*! Join a range of strs in the list into a single string separated by sep.
520 *
521 * \param[in] d The list.
522 * \param[in] sep The character to use as a separator between each string in the list.
523 * \param[in] start The start index. Inclusive.
524 * \param[in] end The end index. Inclusive.
525 *
526 * \return An allocated string.
527 */
528M_API char *M_list_str_join_range(const M_list_str_t *d, unsigned char sep, size_t start, size_t end);
529
530
531/*! Join a range of strs in the list into a single string separated by sep.
532 *
533 * \param[in] d The list.
534 * \param[in] sep The character to use as a separator between each string in the list.
535 * \param[in] start The start index. Inclusive.
536 * \param[in] end The end index. Inclusive.
537 *
538 * \return An allocated string.
539 */
540M_API char *M_list_str_join_range_str(const M_list_str_t *d, const char *sep, size_t start, size_t end);
541
542/*! @} */
543
544__END_DECLS
545
546#endif /* __M_LIST_STR_H__ */
char * M_list_str_join(const M_list_str_t *d, unsigned char sep)
M_bool M_list_str_replace_at(M_list_str_t *d, const char *val, size_t idx)
void M_list_str_merge(M_list_str_t **dest, M_list_str_t *src, M_bool include_duplicates) M_FREE(2)
M_list_str_t * M_list_str_split(unsigned char delim, const char *s, M_uint32 flags, M_bool keep_empty_parts) M_MALLOC
char * M_list_str_take_at(M_list_str_t *d, size_t idx)
char * M_list_str_join_str(const M_list_str_t *d, const char *sep)
M_list_str_match_type_t
Definition: m_list_str.h:101
char * M_list_str_take_first(M_list_str_t *d)
const char * M_list_str_at(const M_list_str_t *d, size_t idx)
M_list_str_flags_t
Definition: m_list_str.h:84
void M_list_str_insert_begin(M_list_str_t *d)
M_list_str_t * M_list_str_create(M_uint32 flags) M_MALLOC
M_bool M_list_str_remove_last(M_list_str_t *d)
struct M_list_str M_list_str_t
Definition: m_list_str.h:80
void M_list_str_change_sorting(M_list_str_t *d, M_uint32 flags)
M_bool M_list_str_swap(M_list_str_t *d, size_t idx1, size_t idx2)
size_t M_list_str_insert_idx(const M_list_str_t *d, const char *val)
void M_list_str_remove_duplicates(M_list_str_t *d)
void M_list_str_destroy(M_list_str_t *d) M_FREE(1)
void M_list_str_insert_end(M_list_str_t *d)
M_bool M_list_str_remove_range(M_list_str_t *d, size_t start, size_t end)
size_t M_list_str_len(const M_list_str_t *d)
M_list_str_t * M_list_str_duplicate(const M_list_str_t *d) M_MALLOC
size_t M_list_str_remove_val(M_list_str_t *d, const char *val, M_uint32 type)
size_t M_list_str_count(const M_list_str_t *d, const char *val, M_uint32 type)
char * M_list_str_join_range(const M_list_str_t *d, unsigned char sep, size_t start, size_t end)
const char * M_list_str_last(const M_list_str_t *d)
M_bool M_list_str_index_of(const M_list_str_t *d, const char *val, M_uint32 type, size_t *idx)
M_bool M_list_str_insert(M_list_str_t *d, const char *val)
char * M_list_str_take_last(M_list_str_t *d)
M_bool M_list_str_remove_at(M_list_str_t *d, size_t idx)
M_bool M_list_str_remove_first(M_list_str_t *d)
M_bool M_list_str_insert_at(M_list_str_t *d, const char *val, size_t idx)
char * M_list_str_join_range_str(const M_list_str_t *d, const char *sep, size_t start, size_t end)
const char * M_list_str_first(const M_list_str_t *d)
size_t M_list_str_replace_val(M_list_str_t *d, const char *val, const char *new_val, M_uint32 type)
@ M_LIST_STR_MATCH_VAL
Definition: m_list_str.h:102
@ M_LIST_STR_MATCH_PTR
Definition: m_list_str.h:103
@ M_LIST_STR_MATCH_ALL
Definition: m_list_str.h:104
@ M_LIST_STR_NONE
Definition: m_list_str.h:85
@ M_LIST_STR_CASECMP
Definition: m_list_str.h:88
@ M_LIST_STR_SORTDESC
Definition: m_list_str.h:87
@ M_LIST_STR_NEVERSHRINK
Definition: m_list_str.h:96
@ M_LIST_STR_SORTASC
Definition: m_list_str.h:86
@ M_LIST_STR_STACK
Definition: m_list_str.h:90
@ M_LIST_STR_STABLE
Definition: m_list_str.h:89
@ M_LIST_STR_SET
Definition: m_list_str.h:91