UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
list.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 2002-2020 UFO: Alien Invasion.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 
24 */
25 
26 #include "list.h"
27 #include "common.h"
28 #include "mem.h"
29 #include <assert.h>
30 #include <string.h>
31 
32 static linkedList_t* LIST_AllocateEntry(void* const data, linkedList_t* const next = 0)
33 {
35  e->data = data;
36  e->next = next;
37  return e;
38 }
39 
41 static void LIST_AppendEntry(linkedList_t** list, linkedList_t* const entry)
42 {
43  while (*list) list = &(*list)->next;
44  *list = entry;
45 }
46 
54 linkedList_t* LIST_Add (linkedList_t** listDest, void const* data, size_t length)
55 {
56  assert(listDest);
57  assert(data);
58 
59  void* const dataCopy = memcpy(Mem_PoolAllocTypeN(byte, length, com_genericPool), data, length);
60  linkedList_t* const newEntry = LIST_AllocateEntry(dataCopy);
61 
62  LIST_AppendEntry(listDest, newEntry);
63 
64  return newEntry;
65 }
66 
73 const linkedList_t* LIST_ContainsString (const linkedList_t* list, const char* string)
74 {
75  while ((string != nullptr) && (list != nullptr)) {
76  if (Q_streq(static_cast<char const*>(list->data), string))
77  return list;
78  list = list->next;
79  }
80 
81  return nullptr;
82 }
83 
92 {
93  while ((data != nullptr) && (list != nullptr)) {
94  if (list->data == data)
95  return list;
96  list = list->next;
97  }
98 
99  return nullptr;
100 }
101 
102 static linkedList_t* LIST_AllocateString(char const* data, linkedList_t* const next = 0)
103 {
104  return LIST_AllocateEntry(Mem_StrDup(data), next);
105 }
106 
107 void LIST_AddStringSorted (linkedList_t** listDest, const char* data)
108 {
109  assert(listDest);
110  assert(data);
111 
112  for (; *listDest; listDest = &(*listDest)->next) {
113  if (Q_StringSort(data, static_cast<char const*>((*listDest)->data)) < 0)
114  break;
115  }
116 
117  *listDest = LIST_AllocateString(data, *listDest);
118 }
119 
127 void LIST_PrependString (linkedList_t** listDest, const char* data)
128 {
129  *listDest = LIST_AllocateString(data, *listDest);
130 }
131 
139 void LIST_AddString (linkedList_t** listDest, const char* data)
140 {
141  assert(listDest);
142  assert(data);
143 
144  LIST_AppendEntry(listDest, LIST_AllocateString(data));
145 }
146 
153 void LIST_AddPointer (linkedList_t** listDest, void* data)
154 {
155  assert(listDest);
156  assert(data);
157 
158  linkedList_t* const newEntry = LIST_AllocateEntry(data);
159  newEntry->ptr = true;
160 
161  LIST_AppendEntry(listDest, newEntry);
162 }
163 
173 {
174  assert(list);
175  assert(entry);
176 
177  for (; *list; list = &(*list)->next) {
178  if (*list == entry) {
179  /* Unlink the entry. */
180  *list = entry->next;
181  /* Delete the entry. */
182  if (!entry->ptr) Mem_Free(entry->data);
183  Mem_Free(entry);
184  return true;
185  }
186  }
187 
188  return false;
189 }
190 
196 {
197  linkedList_t* l = *list;
198 
199  while (l) {
200  linkedList_t* next = l->next;
201  if (!l->ptr)
202  Mem_Free(l->data);
203  Mem_Free(l);
204  l = next;
205  }
206  *list = nullptr;
207 }
208 
213 bool LIST_Remove (linkedList_t** list, const void* data)
214 {
215  linkedList_t* l = LIST_GetPointer(*list, data);
216  if (l != nullptr)
217  return LIST_RemoveEntry(list, l);
218  return false;
219 }
220 
227 static linkedList_t* _LIST_Sort (linkedList_t* list, linkedListSort_t sorter, const void* userData)
228 {
229  linkedList_t* e;
230 
231  /*
232  * Silly special case: if `list' was passed in as nullptr, return
233  * nullptr immediately.
234  */
235  if (!list)
236  return nullptr;
237 
238  int insize = 1;
239 
240  while (1) {
241  linkedList_t* p = list;
242  list = nullptr;
243  linkedList_t* tail = nullptr;
244  int nmerges = 0; /* count number of merges we do in this pass */
245 
246  while (p) {
247  nmerges++; /* there exists a merge to be done */
248  /* step `insize' places along from p */
249  linkedList_t* q = p;
250  int psize = 0;
251  for (int i = 0; i < insize; i++) {
252  psize++;
253  q = q->next;
254  if (!q)
255  break;
256  }
257 
258  /* if q hasn't fallen off end, we have two lists to merge */
259  int qsize = insize;
260 
261  /* now we have two lists; merge them */
262  while (psize > 0 || (qsize > 0 && q)) {
263  /* decide whether next element of merge comes from p or q */
264  if (psize == 0) {
265  /* p is empty; e must come from q. */
266  e = q;
267  q = q->next;
268  qsize--;
269  } else if (qsize == 0 || !q) {
270  /* q is empty; e must come from p. */
271  e = p;
272  p = p->next;
273  psize--;
274  } else if (sorter(p, q, userData) <= 0) {
275  /* First element of p is lower (or same);
276  * e must come from p. */
277  e = p;
278  p = p->next;
279  psize--;
280  } else {
281  /* First element of q is lower; e must come from q. */
282  e = q;
283  q = q->next;
284  qsize--;
285  }
286 
287  /* add the next element to the merged list */
288  if (tail) {
289  tail->next = e;
290  } else {
291  list = e;
292  }
293  tail = e;
294  }
295 
296  /* now p has stepped `insize' places along, and q has too */
297  p = q;
298  }
299  tail->next = nullptr;
300 
301  /* If we have done only one merge, we're finished. */
302  if (nmerges <= 1) /* allow for nmerges==0, the empty list case */
303  return list;
304 
305  /* Otherwise repeat, merging lists twice the size */
306  insize *= 2;
307  }
308 }
309 
310 void LIST_Sort (linkedList_t** list, linkedListSort_t sorter, const void* userData)
311 {
312  if (LIST_IsEmpty(*list))
313  return;
314  *list = _LIST_Sort(*list, sorter, userData);
315 }
316 
322 {
323  linkedList_t* dest = nullptr;
324  LIST_Foreach(src, void, data) {
325  LIST_AddPointer(&dest, data);
326  }
327  return dest;
328 }
329 
335 bool LIST_IsEmpty (const linkedList_t* list)
336 {
337  return list == nullptr;
338 }
339 
344 int LIST_Count (const linkedList_t* list)
345 {
346  const linkedList_t* l = list;
347  int count = 0;
348 
349  while (l) {
350  count++;
351  l = l->next;
352  }
353  return count;
354 }
355 
362 void* LIST_GetByIdx (linkedList_t* list, int index)
363 {
364  if (LIST_IsEmpty(list))
365  return nullptr;
366 
367  if (index < 0)
368  return nullptr;
369 
370  int i = 0;
371  while (list) {
372  if (i == index)
373  return list->data;
374  i++;
375  list = list->next;
376  }
377 
378  return nullptr;
379 }
380 
382 {
383  const int elements = LIST_Count(list);
384  if (elements == 0)
385  return nullptr;
386 
387  const int element = rand() % elements;
388  return LIST_GetByIdx(list, element);
389 }
Memory handling with sentinel checking and pools with tags for grouped free'ing.
void LIST_PrependString(linkedList_t **listDest, const char *data)
Adds a string as first entry to a linked list.
Definition: list.cpp:127
linkedList_t * LIST_Add(linkedList_t **listDest, void const *data, size_t length)
Adds an entry to a new or to an already existing linked list.
Definition: list.cpp:54
static linkedList_t * _LIST_Sort(linkedList_t *list, linkedListSort_t sorter, const void *userData)
This is the actual sort function. Notice that it returns the new head of the list. (It has to, because the head will not generally be the same element after the sort.)
Definition: list.cpp:227
void LIST_AddStringSorted(linkedList_t **listDest, const char *data)
Definition: list.cpp:107
void * LIST_GetByIdx(linkedList_t *list, int index)
Get an entry of a linked list by its index in the list.
Definition: list.cpp:362
void * data
Definition: list.h:31
static void LIST_AppendEntry(linkedList_t **list, linkedList_t *const entry)
Definition: list.cpp:41
int(* linkedListSort_t)(linkedList_t *entry1, linkedList_t *entry2, const void *userData)
Definition: list.h:36
bool ptr
Definition: list.h:33
static linkedList_t * LIST_AllocateString(char const *data, linkedList_t *const next=0)
Definition: list.cpp:102
#define Mem_StrDup(in)
Definition: mem.h:48
void LIST_Delete(linkedList_t **list)
Definition: list.cpp:195
int LIST_Count(const linkedList_t *list)
Definition: list.cpp:344
static linkedList_t * LIST_AllocateEntry(void *const data, linkedList_t *const next=0)
Definition: list.cpp:32
bool LIST_Remove(linkedList_t **list, const void *data)
Definition: list.cpp:213
void LIST_AddString(linkedList_t **listDest, const char *data)
Adds an string to a new or to an already existing linked list. The string is copied here...
Definition: list.cpp:139
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition: r_gl.h:110
memPool_t * com_genericPool
Definition: common.cpp:73
LINKED LIST interface.
linkedList_t * LIST_CopyStructure(linkedList_t *src)
Copies the list structure data - but not the content from the original list. We are only using pointe...
Definition: list.cpp:321
const linkedList_t * LIST_ContainsString(const linkedList_t *list, const char *string)
Searches for the first occurrence of a given string.
Definition: list.cpp:73
QGL_EXTERN GLenum GLuint * dest
Definition: r_gl.h:101
bool LIST_RemoveEntry(linkedList_t **list, linkedList_t *entry)
Removes one entry from the linked list.
Definition: list.cpp:172
QGL_EXTERN GLuint index
Definition: r_gl.h:110
QGL_EXTERN GLuint count
Definition: r_gl.h:99
#define Mem_PoolAllocTypeN(type, n, pool)
Definition: mem.h:42
QGL_EXTERN GLint i
Definition: r_gl.h:113
#define Mem_Free(ptr)
Definition: mem.h:35
linkedList_t * LIST_GetPointer(linkedList_t *list, const void *data)
Searches for the first occurrence of a given pointer.
Definition: list.cpp:91
#define LIST_Foreach(list, type, var)
Iterates over a linked list, it's safe to delete the returned entry from the list while looping over ...
Definition: list.h:41
linkedList_t * next
Definition: list.h:32
definitions common between client and server, but not game lib
int Q_StringSort(const void *string1, const void *string2)
Compare two strings.
Definition: shared.cpp:385
GLsizei const GLvoid * data
Definition: r_gl.h:152
#define Q_streq(a, b)
Definition: shared.h:136
bool LIST_IsEmpty(const linkedList_t *list)
Checks whether the given list is empty.
Definition: list.cpp:335
#define Mem_PoolAllocType(type, pool)
Definition: mem.h:43
uint8_t byte
Definition: ufotypes.h:34
void LIST_Sort(linkedList_t **list, linkedListSort_t sorter, const void *userData)
Definition: list.cpp:310
void * LIST_GetRandom(linkedList_t *list)
Definition: list.cpp:381
void LIST_AddPointer(linkedList_t **listDest, void *data)
Adds just a pointer to a new or to an already existing linked list.
Definition: list.cpp:153