File: list-private.h

package info (click to toggle)
graphviz 14.0.5-2
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 139,388 kB
  • sloc: ansic: 141,938; cpp: 11,957; python: 7,766; makefile: 4,043; yacc: 3,030; xml: 2,972; tcl: 2,495; sh: 1,388; objc: 1,159; java: 560; lex: 423; perl: 243; awk: 156; pascal: 139; php: 58; ruby: 49; cs: 31; sed: 1
file content (235 lines) | stat: -rw-r--r-- 9,115 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/// @file
/// @brief internal implementation details of list.h
/// @ingroup cgraph_utils
///
/// Everything in this header should be considered “private” in the sense that
/// it should not be called except by macros in list.h.

#pragma once

#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <util/api.h>

#ifdef __cplusplus
extern "C" {
#endif

/// generic list, agnostic to the list item type
///
/// There is no way to know the size of list items from this structure alone.
/// List item size is expected to be supplied externally.
typedef struct {
  void *base; ///< start of the allocation for backing memory
  ///< (base == NULL && capacity == 0) || (base != NULL && capacity > 0)
  size_t head; ///< index of the first element
  ///< (capacity == 0 && head == 0)  || (capacity > 0 && head < capacity)
  size_t size; ///< number of elements in the list
  ///< size <= capacity
  size_t capacity; ///< available storage slots
} list_t_;

/// get the number of elements in a list
///
/// @param list List to inspect
/// @return Size of the list
static inline size_t gv_list_size_(const list_t_ list) { return list.size; }

/// add an empty space for an item to the end of a list
///
/// This function calls `exit` on failure.
///
/// @param list List to operate on
/// @param item_size Byte size of each list item
/// @return Index of the new (empty) slot
UTIL_API size_t gv_list_append_slot_(list_t_ *list, size_t item_size);

/// try to append a new item to a list
///
/// @param list List to operate on
/// @param item Pointer to item to append
/// @param item_size Byte size of each list item
/// @return True if the append succeeded
UTIL_API bool gv_list_try_append_(list_t_ *list, const void *item,
                                  size_t item_size);

/// add an empty space for an item to the beginning of a list
///
/// This function calls `exit` on failure.
///
/// @param list List to operate on
/// @param item_size Byte size of each list item
/// @return Index of the new (empty) slot
UTIL_API size_t gv_list_prepend_slot_(list_t_ *list, size_t item_size);

/// get the slot index of a given list item index
///
/// @param list List to operate on
/// @param index Index of item to lookup
/// @return Slot index corresponding to the given index
UTIL_API size_t gv_list_get_(const list_t_ list, size_t index);

/// run the destructor of a list on a given slot
///
/// Though this uses the public type `LIST(<type>)` defined in list.h, this is
/// an internal API not expected to be called by anything other than the macros
/// in list.h.
///
/// You can think of this macro as having the following C type:
///
///   void LIST_DTOR_(LIST(<type>) *list, size_t slot);
///
/// @param list List to operate on
/// @param slot Slot to destruct
#define LIST_DTOR_(list, slot)                                                 \
  do {                                                                         \
    if ((list)->dtor == LIST_DTOR_FREE) {                                      \
      /* we need to juggle the element into a pointer to avoid compilation */  \
      /* errors from this (untaken) branch when the element type is not a  */  \
      /* pointer */                                                            \
      void *ptr_;                                                              \
      sizeof((list)->base[0]) == sizeof(ptr_)                                  \
          ? (void)0                                                            \
          : (void)(fprintf(stderr, "list element type is not a pointer, but "  \
                                   "`free` used as destructor\n"),             \
                   abort());                                                   \
      memcpy(&ptr_, &(list)->base[slot], sizeof(ptr_));                        \
      free(ptr_);                                                              \
    } else if ((list)->dtor != NULL) {                                         \
      (list)->dtor((list)->base[slot]);                                        \
    }                                                                          \
  } while (0)

/// find the slot containing the given item
///
/// @param list List to search
/// @param needle Item to search for
/// @param item_size Byte size of each list item
/// @return Slot index on success or `SIZE_MAX` if not found
UTIL_API size_t gv_list_find_(const list_t_ list, const void *needle,
                              size_t item_size);

/// remove a slot from a list
///
/// @param list List to operate on
/// @param index Slot index to remove
/// @param item_size Byte size of each list item
UTIL_API void gv_list_remove_(list_t_ *list, size_t index, size_t item_size);

/// remove all items from a list
///
/// @param list List to operate on
/// @param item_size Byte size of list items
UTIL_API void gv_list_clear_(list_t_ *list, size_t item_size);

/// reserve space for new items in a list
///
/// This function is a no-op if sufficient space is already available.
///
/// @param list List to operate on
/// @param capacity Total number of slots to make available
/// @param item_size Byte size of list items
UTIL_API void gv_list_reserve_(list_t_ *list, size_t capacity,
                               size_t item_size);

/// does a list contain a given item?
///
/// @param list List to search
/// @param needle Item to search for
/// @param item_size Byte size of each list item
/// @return True if the item was found
UTIL_API bool gv_list_contains_(const list_t_ list, const void *needle,
                                size_t item_size);

/// make a copy of a list
///
/// This function calls `exit` on failure.
///
/// @param list List to copy
/// @param item_size Byte size of each list item
/// @return A copy of the original list
UTIL_API list_t_ gv_list_copy_(const list_t_ list, size_t item_size);

/// does the list wrap past its end?
///
/// This checks whether the list is discontiguous in how its elements
/// appear in memory:
///
///                         ┌───┬───┬───┬───┬───┬───┬───┬───┐
///   a contiguous list:    │   │   │ w │ x │ y │ z │   │   │
///                         └───┴───┴───┴───┴───┴───┴───┴───┘
///                                   0   1   2   3
///
///                         ┌───┬───┬───┬───┬───┬───┬───┬───┐
///   a discontiguous list: │ y │ z │   │   │   │   │ x │ y │
///                         └───┴───┴───┴───┴───┴───┴───┴───┘
///                           2   3                   0   1
///
/// @param list List to inspect
/// @return True if the list is contiguous
UTIL_API bool gv_list_is_contiguous_(const list_t_ list);

/// shuffle the populated contents to reset `head` to 0
///
/// See the `gv_list_is_contiguous_` leading comment for a better understanding
/// of what it means for `head` to be non-zero.
///
/// @param list List to operate on
/// @param item_size Byte size of each list item
UTIL_API void gv_list_sync_(list_t_ *list, size_t item_size);

/// sort a list
///
/// @param list List to operate on
/// @param cmp Comparator for ordering list items
/// @param item_size Byte size of each list item
UTIL_API void gv_list_sort_(list_t_ *list,
                            int (*cmp)(const void *, const void *),
                            size_t item_size);

/// reverse the item order of a list
///
/// @param list List to operate on
/// @param item_size Byte size of each list item
UTIL_API void gv_list_reverse_(list_t_ *list, size_t item_size);

/// decrease the allocated capacity of a list to minimum
///
/// @param list List to operate on
/// @param item_size Byte size of list items
UTIL_API void gv_list_shrink_to_fit_(list_t_ *list, size_t item_size);

/// free resources associated with a list
///
/// @param list List to operate on
UTIL_API void gv_list_free_(list_t_ *list);

/// remove and return the first item of a list
///
/// @param list List to operate on
/// @param [out] into Destination to pop the item into
/// @param item_size Byte size of each list item
UTIL_API void gv_list_pop_front_(list_t_ *list, void *into, size_t item_size);

/// remove and return the last item of a list
///
/// @param list List to operate on
/// @param [out] into Destination to pop the item into
/// @param item_size Byte size of each list item
UTIL_API void gv_list_pop_back_(list_t_ *list, void *into, size_t item_size);

/// transform a managed list into a bare array
///
/// @param list List to operate on
/// @param [out] datap The list data on completion
/// @param [out] sizep The list size on completion; optional
/// @param item_size Byte size of each list item
UTIL_API void gv_list_detach_(list_t_ *list, void *datap, size_t *sizep,
                              size_t item_size);

#ifdef __cplusplus
}
#endif