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