1 // Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 //
6 // Contributor(s):
7 //   Marc Ume
8 //
9 
10 #include "GmshConfig.h"
11 #if !defined(HAVE_NO_STDINT_H)
12 #include <stdint.h>
13 #elif defined(HAVE_NO_INTPTR_T)
14 typedef unsigned long intptr_t;
15 #endif
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <sys/types.h>
21 #include "MallocUtils.h"
22 #include "ListUtils.h"
23 #include "TreeUtils.h"
24 #include "GmshMessage.h"
25 
fcmp_int(const void * a,const void * b)26 int fcmp_int(const void *a, const void *b) { return (*(int *)a - *(int *)b); }
27 
fcmp_absint(const void * a,const void * b)28 int fcmp_absint(const void *a, const void *b)
29 {
30   return (abs(*(int *)a) - abs(*(int *)b));
31 }
32 
fcmp_double(const void * a,const void * b)33 int fcmp_double(const void *a, const void *b)
34 {
35   double cmp;
36 
37   cmp = *(double *)a - *(double *)b;
38   if(cmp > 1.e-16)
39     return 1;
40   else if(cmp < -1.e-16)
41     return -1;
42   else
43     return 0;
44 }
45 
List_Create(int n,int incr,int size)46 List_T *List_Create(int n, int incr, int size)
47 {
48   List_T *liste;
49 
50   if(n <= 0) n = 1;
51   if(incr <= 0) incr = 1;
52 
53   liste = (List_T *)Malloc(sizeof(List_T));
54 
55   liste->nmax = 0;
56   liste->incr = incr;
57   liste->size = size;
58   liste->n = 0;
59   liste->isorder = 0;
60   liste->array = nullptr;
61 
62   List_Realloc(liste, n);
63   return (liste);
64 }
65 
List_Delete(List_T * liste)66 void List_Delete(List_T *liste)
67 {
68   if(!liste) return;
69   Free(liste->array);
70   Free(liste);
71 }
72 
List_Realloc(List_T * liste,int n)73 void List_Realloc(List_T *liste, int n)
74 {
75   if(!liste || n <= 0) return;
76 
77   if(liste->array == nullptr) {
78     // This does not permit to allocate lists smaller that liste->incr:
79     // liste->nmax = ((n - 1) / liste->incr + 1) * liste->incr;
80     // So this is much better
81     liste->nmax = n;
82     liste->array = (char *)Malloc(liste->nmax * liste->size);
83   }
84   else if(n > liste->nmax) {
85     liste->nmax = ((n - 1) / liste->incr + 1) * liste->incr;
86     liste->array = (char *)Realloc(liste->array, liste->nmax * liste->size);
87   }
88 }
89 
List_Add(List_T * liste,void * data)90 void List_Add(List_T *liste, void *data)
91 {
92   if(!liste) return;
93   liste->n++;
94 
95   List_Realloc(liste, liste->n);
96   liste->isorder = 0;
97   memcpy(&liste->array[(liste->n - 1) * liste->size], data, liste->size);
98 }
99 
List_Add(List_T * liste,int data)100 void List_Add(List_T *liste, int data)
101 {
102   if(!liste) return;
103   List_Add(liste, &data);
104 }
105 
List_Nbr(List_T * liste)106 int List_Nbr(List_T *liste)
107 {
108   return liste ? liste->n : 0;
109 }
110 
List_Read(List_T * liste,int index,void * data)111 void List_Read(List_T *liste, int index, void *data)
112 {
113   if(!liste || (index < 0) || (index >= liste->n)) {
114     Msg::Error("Wrong list index (read)");
115     index = 0;
116   }
117   memcpy(data, &liste->array[index * liste->size], liste->size);
118 }
119 
List_Write(List_T * liste,int index,void * data)120 void List_Write(List_T *liste, int index, void *data)
121 {
122   if(!liste || (index < 0) || (index >= liste->n))
123     Msg::Error("Wrong list index (write)");
124   else {
125     liste->isorder = 0;
126     memcpy(&liste->array[index * liste->size], data, liste->size);
127   }
128 }
129 
List_Put(List_T * liste,int index,void * data)130 void List_Put(List_T *liste, int index, void *data)
131 {
132   if(!liste || index < 0)
133     Msg::Error("Wrong list index (put)");
134   else {
135     if(index >= liste->n) {
136       liste->n = index + 1;
137       List_Realloc(liste, liste->n);
138       List_Write(liste, index, data);
139     }
140     else {
141       List_Write(liste, index, data);
142     }
143   }
144 }
145 
List_Pop(List_T * liste)146 void List_Pop(List_T *liste)
147 {
148   if(!liste) return;
149   if(liste->n > 0) liste->n--;
150 }
151 
List_Pointer(List_T * liste,int index)152 void *List_Pointer(List_T *liste, int index)
153 {
154   if(!liste || (index < 0) || (index >= liste->n)) {
155     Msg::Error("Wrong list index (pointer)");
156     index = 0;
157   }
158   liste->isorder = 0;
159   return (&liste->array[index * liste->size]);
160 }
161 
List_Pointer_NoChange(List_T * liste,int index)162 void *List_Pointer_NoChange(List_T *liste, int index)
163 {
164   if(!liste || (index < 0) || (index >= liste->n)) {
165     Msg::Error("Wrong list index (pointer)");
166     index = 0;
167   }
168   return (&liste->array[index * liste->size]);
169 }
170 
List_Pointer_Fast(List_T * liste,int index)171 void *List_Pointer_Fast(List_T *liste, int index)
172 {
173   return (&liste->array[index * liste->size]);
174 }
175 
List_Sort(List_T * liste,int (* fcmp)(const void * a,const void * b))176 void List_Sort(List_T *liste, int (*fcmp)(const void *a, const void *b))
177 {
178   if(!liste) return;
179   qsort(liste->array, liste->n, liste->size, fcmp);
180 }
181 
List_Unique(List_T * liste,int (* fcmp)(const void * a,const void * b))182 void List_Unique(List_T *liste, int (*fcmp)(const void *a, const void *b))
183 {
184   if(!liste) return;
185   if(liste->isorder != 1) {
186     List_Sort(liste, fcmp);
187     liste->isorder = 1;
188   }
189   if(!List_Nbr(liste)) return;
190   int write_index = 0;
191   for(int i = 1; i < List_Nbr(liste); i++) {
192     void *data = List_Pointer(liste, i);
193     if((fcmp(data, (void *)List_Pointer(liste, write_index))))
194       List_Write(liste, ++write_index, data);
195   }
196   liste->n = write_index + 1;
197 }
198 
List_Search(List_T * liste,void * data,int (* fcmp)(const void * a,const void * b))199 int List_Search(List_T *liste, void *data,
200                 int (*fcmp)(const void *a, const void *b))
201 {
202   if(!liste) return 0;
203   void *ptr;
204 
205   if(liste->isorder != 1) {
206     List_Sort(liste, fcmp);
207     liste->isorder = 1;
208   }
209   ptr = (void *)bsearch(data, liste->array, liste->n, liste->size, fcmp);
210   if(ptr == nullptr) return (0);
211   return (1);
212 }
213 
List_ISearchSeq(List_T * liste,void * data,int (* fcmp)(const void * a,const void * b))214 int List_ISearchSeq(List_T *liste, void *data,
215                     int (*fcmp)(const void *a, const void *b))
216 {
217   if(!liste) return -1;
218   int i = 0;
219   while((i < List_Nbr(liste)) && fcmp(data, (void *)List_Pointer(liste, i)))
220     i++;
221   if(i == List_Nbr(liste)) i = -1;
222   return i;
223 }
224 
List_PQuery(List_T * liste,void * data,int (* fcmp)(const void * a,const void * b))225 void *List_PQuery(List_T *liste, void *data,
226                   int (*fcmp)(const void *a, const void *b))
227 {
228   if(!liste) return nullptr;
229   void *ptr;
230   if(liste->isorder != 1) List_Sort(liste, fcmp);
231   liste->isorder = 1;
232   ptr = (void *)bsearch(data, liste->array, liste->n, liste->size, fcmp);
233   return (ptr);
234 }
235 
List_Suppress(List_T * liste,void * data,int (* fcmp)(const void * a,const void * b))236 int List_Suppress(List_T *liste, void *data,
237                   int (*fcmp)(const void *a, const void *b))
238 {
239   if(!liste) return 0;
240   char *ptr = (char *)List_PQuery(liste, data, fcmp);
241   if(ptr == nullptr) return (0);
242   liste->n--;
243   int len = liste->n - (((intptr_t)ptr - (intptr_t)liste->array) / liste->size);
244   if(len > 0) memmove(ptr, ptr + liste->size, len * liste->size);
245   return (1);
246 }
247 
List_PSuppress(List_T * liste,int index)248 int List_PSuppress(List_T *liste, int index)
249 {
250   if(!liste) return 0;
251   char *ptr = (char *)List_Pointer_NoChange(liste, index);
252   if(ptr == nullptr) return (0);
253   liste->n--;
254   int len = liste->n - (((intptr_t)ptr - (intptr_t)liste->array) / liste->size);
255   if(len > 0) memmove(ptr, ptr + liste->size, len * liste->size);
256   return (1);
257 }
258 
List_Invert(List_T * a,List_T * b)259 void List_Invert(List_T *a, List_T *b)
260 {
261   if(!a || !b) return;
262   int i, N;
263   N = List_Nbr(a);
264   for(i = 0; i < N; i++) {
265     List_Add(b, List_Pointer(a, N - i - 1));
266   }
267 }
268 
List_Reset(List_T * liste)269 void List_Reset(List_T *liste)
270 {
271   if(!liste) return;
272   liste->n = 0;
273 }
274 
List_Action(List_T * liste,void (* action)(void * data,void * dummy))275 void List_Action(List_T *liste, void (*action)(void *data, void *dummy))
276 {
277   if(!liste) return;
278   int i, dummy;
279   for(i = 0; i < List_Nbr(liste); i++)
280     (*action)(List_Pointer_NoChange(liste, i), &dummy);
281 }
282 
List_Copy(List_T * a,List_T * b)283 void List_Copy(List_T *a, List_T *b)
284 {
285   if(!a || !b) return;
286   int i, N;
287   N = List_Nbr(a);
288   for(i = 0; i < N; i++) {
289     List_Add(b, List_Pointer(a, i));
290   }
291 }
292 
List_Remove(List_T * a,int i)293 void List_Remove(List_T *a, int i)
294 {
295   if(!a) return;
296   memcpy(&a->array[i * a->size], &a->array[(i + 1) * a->size],
297          a->size * (a->n - i - 1));
298   a->n--;
299 }
300 
301 // insert a in b before i
List_Insert_In_List(List_T * a,int i,List_T * b)302 void List_Insert_In_List(List_T *a, int i, List_T *b)
303 {
304   if(!a || !b) return;
305   int oldn = b->n;
306   b->n += a->n;
307   List_Realloc(b, b->n);
308   for(int j = 0; j < oldn - i; j++)
309     memcpy(List_Pointer_Fast(b, b->n - j - 1),
310            List_Pointer_Fast(b, oldn - j - 1), b->size);
311   for(int j = 0; j < a->n; j++)
312     memcpy(List_Pointer_Fast(b, i + j), List_Pointer_Fast(a, j), b->size);
313 }
314 
ListOfDouble2ListOfInt(List_T * dList)315 List_T *ListOfDouble2ListOfInt(List_T *dList)
316 {
317   int n = List_Nbr(dList);
318   List_T *iList = List_Create(n, n, sizeof(int));
319   for(int i = 0; i < n; i++) {
320     double d;
321     List_Read(dList, i, &d);
322     int j = (int)d;
323     List_Add(iList, &j);
324   }
325   return iList;
326 }
327