1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 03 дек. 2015 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #ifndef DATA_CVECTOR_H_
23 #define DATA_CVECTOR_H_
24 
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 
30 #define CVECTOR_GROW        16
31 
32 namespace lsp
33 {
34     class basic_vector
35     {
36         protected:
37             void      **pvItems;
38             size_t      nCapacity;
39             size_t      nItems;
40 
41         protected:
add_item(const void * ptr)42             inline bool add_item(const void *ptr)
43             {
44                 if (nItems >= nCapacity)
45                 {
46                     void *data      = ::realloc(pvItems, sizeof(void *) * (nCapacity + CVECTOR_GROW));
47                     if (data == NULL)
48                         return false;
49 
50                     pvItems         = static_cast<void **>(data);
51                     nCapacity      += CVECTOR_GROW;
52                 }
53 
54                 pvItems[nItems++]   = const_cast<void *>(ptr);
55                 return true;
56             }
57 
add_unique(const void * ptr)58             inline bool add_unique(const void *ptr)
59             {
60                 for (size_t i=0; i<nItems; ++i)
61                     if (pvItems[i] == ptr)
62                         return true;
63                 return add_item(ptr);
64             }
65 
insert_item(const void * ptr,size_t idx)66             inline bool insert_item(const void *ptr, size_t idx)
67             {
68                 if (nItems >= nCapacity)
69                 {
70                     void *data      = ::realloc(pvItems, sizeof(void *) * (nCapacity + CVECTOR_GROW));
71                     if (data == NULL)
72                         return false;
73 
74                     pvItems         = static_cast<void **>(data);
75                     nCapacity      += CVECTOR_GROW;
76                 }
77 
78                 if (idx >= nItems)
79                 {
80                     if (idx > nItems)
81                         return false;
82                     pvItems[nItems] = const_cast<void *>(ptr);
83                 }
84                 else
85                 {
86                     ::memmove(&pvItems[idx+1], &pvItems[idx], (nItems - idx) * sizeof(void *));
87                     pvItems[idx]    = const_cast<void *>(ptr);
88                 }
89                 ++nItems;
90                 return true;
91             }
92 
get_item(size_t index)93             inline void *get_item(size_t index) const
94             {
95                 return (index < nItems) ? const_cast<void *>(pvItems[index]) : NULL;
96             }
97 
set_item(size_t index,void * ptr)98             inline bool set_item(size_t index, void *ptr)
99             {
100                 if (index >= nItems)
101                     return false;
102                 pvItems[index] = ptr;
103                 return true;
104             }
105 
do_remove(size_t i,bool fast)106             inline bool do_remove(size_t i, bool fast)
107             {
108                 if (i < (--nItems))
109                 {
110                     if (fast)
111                         pvItems[i]  = pvItems[nItems];
112                     else
113                         ::memmove(&pvItems[i], &pvItems[i+1], (nItems - i) * sizeof(void *));
114                 }
115 
116                 pvItems[nItems] = NULL;
117                 return true;
118             }
119 
remove_item(const void * item,bool fast)120             inline bool remove_item(const void *item, bool fast)
121             {
122                 for (size_t i=0; i<nItems; ++i)
123                 {
124                     if (pvItems[i] == item)
125                         return do_remove(i, fast);
126                 }
127                 return false;
128             }
129 
remove_items(size_t first,size_t count)130             inline bool remove_items(size_t first, size_t count)
131             {
132                 size_t last = first + count;
133                 if (last == nItems)
134                 {
135                     nItems  = first;
136                     return true;
137                 }
138                 else if (last > nItems)
139                     return false;
140 
141                 ::memmove(&pvItems[first], &pvItems[last], (nItems - last) * sizeof(void *));
142                 nItems  -= count;
143                 return true;
144             }
145 
remove_item(size_t index,bool fast)146             inline bool remove_item(size_t index, bool fast)
147             {
148                 if (index >= nItems)
149                     return false;
150                 return do_remove(index, fast);
151             }
152 
do_swap_data(basic_vector * src)153             inline void do_swap_data(basic_vector *src)
154             {
155                 void **ptr      = src->pvItems;
156                 size_t cap      = src->nCapacity;
157                 size_t n        = src->nItems;
158 
159                 src->pvItems    = pvItems;
160                 src->nCapacity  = nCapacity;
161                 src->nItems     = nItems;
162 
163                 pvItems         = ptr;
164                 nCapacity       = cap;
165                 nItems          = n;
166             }
167 
do_take_from(basic_vector * src)168             inline void do_take_from(basic_vector *src)
169             {
170                 flush();
171 
172                 pvItems         = src->pvItems;
173                 nCapacity       = src->nCapacity;
174                 nItems          = src->nItems;
175 
176                 src->pvItems    = NULL;
177                 src->nCapacity  = 0;
178                 src->nItems     = 0;
179             }
180 
do_copy_from(const basic_vector * src)181             inline bool do_copy_from(const basic_vector *src)
182             {
183                 if (nCapacity < src->nItems)
184                 {
185                     size_t cap      = ((src->nItems + CVECTOR_GROW - 1) / CVECTOR_GROW) * CVECTOR_GROW;
186                     void *data      = ::realloc(pvItems, sizeof(void *) * (cap));
187                     if (data == NULL)
188                         return false;
189 
190                     pvItems         = static_cast<void **>(data);
191                     nCapacity       = cap;
192                 }
193                 ::memcpy(pvItems, src->pvItems, sizeof(void *) * src->nItems);
194                 nItems          = src->nItems;
195                 return true;
196             }
197 
add_all(const void * const * src,size_t count)198             inline bool add_all(const void *const *src, size_t count)
199             {
200                 size_t n = nItems + count;
201                 if (nCapacity < n)
202                 {
203                     size_t cap      = ((n + CVECTOR_GROW - 1) / CVECTOR_GROW) * CVECTOR_GROW;
204                     void *data      = ::realloc(pvItems, sizeof(void *) * (cap));
205                     if (data == NULL)
206                         return false;
207 
208                     pvItems         = static_cast<void **>(data);
209                     nCapacity       = cap;
210                 }
211 
212                 ::memcpy(&pvItems[nItems], src, sizeof(void *) * count);
213                 nItems          = n;
214                 return true;
215             }
216 
do_index_of(const void * ptr)217             inline ssize_t do_index_of(const void *ptr) const
218             {
219                 for (size_t i=0; i<nItems; ++i)
220                 {
221                     if (pvItems[i] == ptr)
222                         return i;
223                 }
224                 return -1;
225             }
226 
pop_last(void ** ptr)227             inline bool pop_last(void **ptr)
228             {
229                 if (nItems <= 0)
230                     return false;
231 
232                 void *p = pvItems[--nItems];
233                 if (ptr != NULL)
234                     *ptr = p;
235                 pvItems[nItems] = NULL; // Replace with NULL
236                 return true;
237             }
238 
pop()239             inline bool pop()
240             {
241                 if (nItems <= 0)
242                     return false;
243 
244                 pvItems[--nItems] = NULL;
245                 return true;
246             }
247 
248         public:
basic_vector()249             explicit inline basic_vector()
250             {
251                 pvItems     = NULL;
252                 nCapacity   = 0;
253                 nItems      = 0;
254             }
255 
~basic_vector()256             inline ~basic_vector()
257             {
258                 flush();
259             }
260 
size()261             inline size_t size() const  { return nItems; }
262 
capacity()263             inline size_t capacity() const { return nCapacity; }
264 
clear()265             inline void clear() { nItems = 0; }
266 
swap(size_t a,size_t b)267             inline bool swap(size_t a, size_t b)
268             {
269                 if ((a >= nItems) || (b >= nItems))
270                     return false;
271 
272                 void *ptr   = pvItems[a];
273                 pvItems[a]  = pvItems[b];
274                 pvItems[b]  = ptr;
275                 return true;
276             }
277 
swap_unsafe(size_t a,size_t b)278             inline void swap_unsafe(size_t a, size_t b)
279             {
280                 void *ptr   = pvItems[a];
281                 pvItems[a]  = pvItems[b];
282                 pvItems[b]  = ptr;
283             }
284 
flush()285             void flush()
286             {
287                 if (pvItems != NULL)
288                 {
289                     ::free(pvItems);
290                     pvItems      = NULL;
291                 }
292                 nCapacity   = 0;
293                 nItems      = 0;
294             }
295 
move(size_t a,size_t b)296             inline bool move(size_t a, size_t b)
297             {
298                 if ((a >= nItems) || (b >= nItems))
299                     return false;
300                 else if (a == b)
301                     return true;
302 
303                 void *ptr   = pvItems[a];
304                 if (a < b)
305                     ::memmove(&pvItems[a], &pvItems[a+1], (b-a) * sizeof(void *));
306                 else
307                     ::memmove(&pvItems[b+1], &pvItems[b], (a-b) * sizeof(void *));
308                 pvItems[b]  = ptr;
309 
310                 return true;
311             }
312     };
313 
314     // Generalize pointers with templates
315     template <class T>
316         class cvector: public basic_vector
317         {
318             private:
319                 cvector(const cvector<T> &src);                         // Disable copying
320                 cvector<T> & operator = (const cvector<T> & src);       // Disable copying
321 
322             public:
cvector()323                 explicit inline cvector() {}
324 
325             public:
get_array()326                 inline T **get_array() { return (nItems > 0) ? reinterpret_cast<T **>(pvItems) : NULL; }
327 
get_const_array()328                 inline const T * const *get_const_array() const { return (nItems > 0) ? reinterpret_cast<const T * const *>(pvItems) : NULL; }
329 
add(T * item)330                 inline bool add(T *item) { return basic_vector::add_item(item); }
331 
add_all(const T * const * items,size_t count)332                 inline bool add_all(const T * const *items, size_t count) {
333                     union {
334                         const T * const *titems;
335                         const void * const *vitems;
336                     } x;
337                     x.titems = items;
338                     return basic_vector::add_all(x.vitems, count);
339                 }
340 
add_all(const cvector<T> * items)341                 inline bool add_all(const cvector<T> *items) {
342                     union {
343                         const T * const *titems;
344                         const void * const *vitems;
345                     } x;
346                     x.titems = items->get_const_array();
347                     return basic_vector::add_all(x.vitems, items->size());
348                 }
349 
push(T * item)350                 inline bool push(T *item) { return basic_vector::add_item(item); }
351 
pop()352                 inline bool pop() { return basic_vector::pop(); }
353 
pop(T ** item)354                 inline bool pop(T **item)
355                 {
356                     void *ptr;
357                     if (!basic_vector::pop_last(&ptr))
358                         return false;
359                     *item = reinterpret_cast<T *>(ptr);
360                     return true;
361                 }
362 
pop_last(T ** item)363                 inline bool pop_last(T **item)
364                 {
365                     void *ptr;
366                     if (!basic_vector::pop_last(&ptr))
367                         return false;
368                     *item = reinterpret_cast<T *>(ptr);
369                     return true;
370                 }
371 
last()372                 inline T *last() { return (nItems > 0) ? reinterpret_cast<T *>(pvItems[nItems-1]) : NULL; }
373 
last()374                 inline T *last() const { return (nItems > 0) ? reinterpret_cast<const T *>(pvItems[nItems-1]) : NULL; }
375 
first()376                 inline T *first() { return (nItems > 0) ? reinterpret_cast<T *>(pvItems[0]) : NULL; }
377 
first()378                 inline T *first() const { return (nItems > 0) ? reinterpret_cast<const T *>(pvItems[0]) : NULL; }
379 
add_unique(T * item)380                 inline bool add_unique(T *item) { return basic_vector::add_unique(item); }
381 
insert(T * item,size_t index)382                 inline bool insert(T *item, size_t index) { return basic_vector::insert_item(item, index); }
383 
get(size_t index)384                 inline T *get(size_t index) const { return reinterpret_cast<T *>(basic_vector::get_item(index)); }
385 
set(size_t index,T * item)386                 inline bool set(size_t index, T *item) { return basic_vector::set_item(index, item); }
387 
388                 inline bool remove(const T *item, bool fast = false) { return basic_vector::remove_item(item, fast); }
389 
390                 inline bool remove(size_t index, bool fast = false) { return basic_vector::remove_item(index, fast); };
391 
remove_n(size_t index,size_t count)392                 inline bool remove_n(size_t index, size_t count) { return basic_vector::remove_items(index, count); };
393 
394                 inline T *operator[](size_t index) { return reinterpret_cast<T *>(basic_vector::get_item(index)); }
395 
at(size_t index)396                 inline T *at(size_t index) const { return reinterpret_cast<T *>(pvItems[index]); }
397 
release()398                 inline T **release()
399                 {
400                     if (nItems <= 0)
401                     {
402                         flush();
403                         return NULL;
404                     }
405                     T **res     = (nItems > 0) ? reinterpret_cast<T **>(pvItems) : NULL;
406                     pvItems     = NULL;
407                     nCapacity   = 0;
408                     nItems      = 0;
409                     return res;
410                 }
411 
swap_data(cvector<T> * src)412                 inline void swap_data(cvector<T> *src) { do_swap_data(src); }
413 
take_from(cvector<T> * src)414                 inline void take_from(cvector<T> *src) { do_take_from(src); }
415 
index_of(const T * item)416                 inline ssize_t index_of(const T *item) const { return do_index_of(item); }
417 
copy_from(const cvector<T> * src)418                 inline bool copy_from(const cvector<T> *src) { return do_copy_from(src); }
419         };
420 
421 }
422 
423 
424 
425 #endif /* DATA_CVECTOR_H_ */
426