dvec.c (10684B)
1#include "dvec.h" 2 3#include <stddef.h> 4#include <string.h> 5 6#define ERR(x) ((x) >= 0 ? DVEC_BAD : (x)) 7 8struct sort_order_user_proxy { 9 dvec_sort_order_fn order_fn; 10 const void *user; 11}; 12 13int 14dvec_init(struct dvec *dvec, size_t dsize, size_t cap, 15 const struct allocator *allocator) 16{ 17 int rc = 0; 18 19 LIBDVEC_ABORT_ON_ARGS(!dvec || !dsize || !allocator); 20 21 dvec->allocator = allocator; 22 dvec->dsize = dsize; 23 dvec->cap = cap; 24 dvec->len = 0; 25 dvec->data = NULL; 26 dvec->locked = false; 27 dvec->fused = false; 28 if (dvec->cap) { 29 dvec->data = allocator->alloc(allocator, cap * dsize, &rc); 30 LIBDVEC_ABORT_ON_ALLOC(!dvec->data); 31 if (!dvec->data) return ERR(rc); 32 } 33 34 return DVEC_OK; 35} 36 37int 38dvec_deinit(struct dvec *dvec) 39{ 40 int rc; 41 42 LIBDVEC_ABORT_ON_ARGS(!dvec); 43 44 rc = dvec->allocator->free(dvec->allocator, dvec->data); 45 LIBDVEC_ABORT_ON_ALLOC(rc); 46 47 return rc >= 0 ? DVEC_OK : ERR(rc); 48} 49 50struct dvec * 51dvec_alloc(size_t dsize, size_t cap, 52 const struct allocator *allocator, int *rc) 53{ 54 struct dvec *dvec; 55 int _rc; 56 57 LIBDVEC_ABORT_ON_ARGS(!allocator); 58 59 dvec = allocator->alloc(allocator, sizeof(struct dvec), &_rc); 60 LIBDVEC_ABORT_ON_ALLOC(!dvec); 61 if (!dvec) { 62 if (rc) *rc = ERR(_rc); 63 return NULL; 64 } 65 66 _rc = dvec_init(dvec, dsize, cap, allocator); 67 if (_rc < 0) { 68 if (rc) *rc = _rc; 69 allocator->free(allocator, dvec); 70 return NULL; 71 } 72 73 return dvec; 74} 75 76static size_t 77aligned_size(size_t size, size_t dsize) 78{ 79 return size + (size % dsize ? dsize - size % dsize : 0); 80} 81 82struct dvec * 83dvec_alloc_fused(size_t dsize, size_t cap, 84 const struct allocator *allocator, int *rc) 85{ 86 struct dvec *dvec; 87 size_t off; 88 int _rc = 0; 89 90 LIBDVEC_ABORT_ON_ARGS(!allocator); 91 92 off = aligned_size(sizeof(struct dvec), dsize); 93 dvec = allocator->alloc(allocator, off + cap * dsize, &_rc); 94 if (!dvec) { 95 if (_rc) *rc = ERR(_rc); 96 return NULL; 97 } 98 99 dvec->allocator = allocator; 100 dvec->dsize = dsize; 101 dvec->cap = cap; 102 dvec->len = 0; 103 dvec->data = (uint8_t *) dvec + off; 104 dvec->locked = false; 105 dvec->fused = true; 106 107 return dvec; 108} 109 110int 111dvec_free(struct dvec *dvec) 112{ 113 const struct allocator *allocator; 114 int rc; 115 116 if (!dvec) return DVEC_OK; 117 118 allocator = dvec->allocator; 119 120 if (dvec->fused) { 121 rc = allocator->free(allocator, dvec); 122 if (rc < 0) return rc; 123 } else { 124 rc = dvec_deinit(dvec); 125 if (rc) return rc; 126 127 rc = allocator->free(allocator, dvec); 128 LIBDVEC_ABORT_ON_ALLOC(rc); 129 if (rc < 0) return rc; 130 } 131 132 return DVEC_OK; 133} 134 135int 136dvec_copy(struct dvec *dst, struct dvec *src) 137{ 138 int rc; 139 140 LIBDVEC_ABORT_ON_ARGS(!dst || !src || dst->dsize != src->dsize); 141 142 rc = dvec_reserve(dst, src->len); 143 if (rc) return rc; 144 145 dst->len = src->len; 146 memcpy(dst->data, src->data, src->len * src->dsize); 147 148 return DVEC_OK; 149} 150 151void 152dvec_move(struct dvec *dst, struct dvec *src) 153{ 154 LIBDVEC_ABORT_ON_ARGS(!dst || !src); 155 156 memcpy(dst, src, sizeof(struct dvec)); 157} 158 159void 160dvec_swap(struct dvec *dst, struct dvec *src) 161{ 162 struct dvec tmp; 163 164 LIBDVEC_ABORT_ON_ARGS(!dst || !src); 165 166 memcpy(&tmp, dst, sizeof(struct dvec)); 167 memcpy(dst, src, sizeof(struct dvec)); 168 memcpy(src, &tmp, sizeof(struct dvec)); 169} 170 171void 172dvec_clear(struct dvec *dvec) 173{ 174 LIBDVEC_ABORT_ON_ARGS(!dvec); 175 176 dvec->len = 0; 177} 178 179int 180dvec_reserve(struct dvec *dvec, size_t len) 181{ 182 void *data; 183 size_t cap, off; 184 int rc = 1; 185 186 LIBDVEC_ABORT_ON_ARGS(!dvec); 187 188 if (len <= dvec->cap) return DVEC_OK; 189 190 if (dvec->locked) return DVEC_LOCKED; 191 192 cap = 2 * dvec->cap; 193 if (len > cap) cap = len; 194 195 if (dvec->fused) { 196 off = aligned_size(sizeof(struct dvec), dvec->dsize); 197 data = dvec->allocator->realloc(dvec->allocator, dvec, 198 off + dvec->cap * dvec->dsize, &rc); 199 LIBDVEC_ABORT_ON_ALLOC(!data); 200 if (!data) return ERR(rc); 201 dvec = data; 202 dvec->data = (uint8_t *) dvec + off; 203 } else { 204 data = dvec->allocator->realloc(dvec->allocator, 205 dvec->data, cap * dvec->dsize, &rc); 206 LIBDVEC_ABORT_ON_ALLOC(!data); 207 if (!data) return ERR(rc); 208 dvec->data = data; 209 } 210 211 dvec->cap = cap; 212 213 return DVEC_OK; 214} 215 216int 217dvec_shrink(struct dvec *dvec) 218{ 219 void *data; 220 size_t cap, off; 221 int rc = 0; 222 223 LIBDVEC_ABORT_ON_ARGS(!dvec); 224 225 if (dvec->locked) return DVEC_LOCKED; 226 227 cap = dvec->len; 228 229 if (dvec->fused) { 230 off = aligned_size(sizeof(struct dvec), dvec->dsize); 231 data = dvec->allocator->realloc(dvec->allocator, dvec, 232 off + cap * dvec->dsize, &rc); 233 LIBDVEC_ABORT_ON_ALLOC(!data); 234 if (!data) return ERR(rc); 235 dvec = data; 236 dvec->data = (uint8_t *) dvec + off; 237 } else if (!dvec->len) { 238 rc = dvec->allocator->free(dvec->allocator, dvec->data); 239 LIBDVEC_ABORT_ON_ALLOC(rc); 240 if (rc < 0) return rc; 241 } else { 242 data = dvec->allocator->realloc(dvec->allocator, 243 &dvec->data, cap * dvec->dsize, &rc); 244 LIBDVEC_ABORT_ON_ALLOC(!data); 245 if (!data) return ERR(rc); 246 dvec->data = data; 247 } 248 249 dvec->cap = cap; 250 251 return DVEC_OK; 252} 253 254int 255dvec_add(struct dvec *dvec, size_t index, size_t len) 256{ 257 int rc; 258 259 LIBDVEC_ABORT_ON_ARGS(!dvec || index > dvec->len); 260 261 rc = dvec_reserve(dvec, dvec->len + len); 262 if (rc) return rc; 263 264 if (index < dvec->len) { 265 memmove(dvec->data + (index + len) * dvec->dsize, 266 dvec->data + index * dvec->dsize, 267 (dvec->len - index) * dvec->dsize); 268 } 269 270 dvec->len += len; 271 272 return DVEC_OK; 273} 274 275void 276dvec_rm(struct dvec *dvec, size_t index, size_t count) 277{ 278 LIBDVEC_ABORT_ON_ARGS(!dvec || index + count > dvec->len); 279 280 if (index + count < dvec->len) { 281 memmove(dvec->data + index * dvec->dsize, 282 dvec->data + (index + count) * dvec->dsize, 283 (dvec->len - (index + count)) * dvec->dsize); 284 } 285 286 dvec->len -= count; 287} 288 289void 290dvec_replace(struct dvec *dvec, size_t index, const void *data, size_t count) 291{ 292 LIBDVEC_ABORT_ON_ARGS(!dvec || !data || index + count > dvec->len); 293 294 memcpy(dvec->data + index * dvec->dsize, data, count * dvec->dsize); 295} 296 297void * 298dvec_iter_fwd(const struct dvec *dvec, const void *p) 299{ 300 LIBDVEC_ABORT_ON_ARGS(!dvec); 301 LIBDVEC_ABORT_ON_ARGS(p && (p < dvec->data)); 302 LIBDVEC_ABORT_ON_ARGS(p && (p >= dvec->data + dvec->len * dvec->dsize)); 303 LIBDVEC_ABORT_ON_ARGS(p && ((size_t) (p - dvec->data) % dvec->dsize)); 304 305 if (p == NULL) { 306 if (dvec->len > 0) 307 return dvec->data; 308 else 309 return NULL; 310 } else if ((uint8_t *) p < dvec->data + dvec->dsize * (dvec->len - 1)) { 311 return (uint8_t *) p + dvec->dsize; 312 } else { 313 return NULL; 314 } 315} 316 317void * 318dvec_iter_bwd(const struct dvec *dvec, const void *p) 319{ 320 LIBDVEC_ABORT_ON_ARGS(!dvec); 321 LIBDVEC_ABORT_ON_ARGS(p && (p < dvec->data)); 322 LIBDVEC_ABORT_ON_ARGS(p && (p >= dvec->data + dvec->len * dvec->dsize)); 323 LIBDVEC_ABORT_ON_ARGS(p && ((size_t) (p - dvec->data) % dvec->dsize)); 324 325 if (p == NULL) { 326 if (dvec->len > 0) 327 return dvec->data + (dvec->len - 1) * dvec->dsize; 328 else 329 return NULL; 330 } else if ((uint8_t *) p > dvec->data) { 331 return (uint8_t *) p - dvec->dsize; 332 } else { 333 return NULL; 334 } 335} 336 337static void 338dvec_quick_sort_swap(void *a, void *b, void *tmp, size_t dsize) 339{ 340 memcpy(tmp, a, dsize); 341 memcpy(a, b, dsize); 342 memcpy(b, tmp, dsize); 343} 344 345int 346dvec_quick_sort(struct dvec *dvec, const struct allocator *allocator, 347 void *tmp, bool reverse, dvec_sort_order_fn in_order, const void *user) 348{ 349 const size_t dsize = dvec->dsize; 350 struct dvec stack; 351 uint8_t *start, *end; 352 uint8_t *lo, *hi, *pivot; 353 bool lo_order, hi_order; 354 bool modified = false; 355 int rc; 356 357 if (!dvec->len) return DVEC_OK; 358 359 rc = dvec_init(&stack, sizeof(uint8_t *), 32, allocator); 360 if (rc) return rc; 361 362 *(uint8_t **)dvec_push(&stack) = dvec_front(dvec); 363 *(uint8_t **)dvec_push(&stack) = dvec_back(dvec); 364 365 while (!dvec_empty(&stack)) { 366 end = *(uint8_t **)dvec_pop(&stack); 367 start = *(uint8_t **)dvec_pop(&stack); 368 369 if (start == end) continue; 370 371 if (start + dsize >= end) { 372 if (!in_order(start, end, user)) { 373 dvec_quick_sort_swap(start, end, tmp, dsize); 374 modified = true; 375 } 376 continue; 377 } 378 379 lo = start; 380 hi = end; 381 pivot = start + (size_t) (end - start) / dsize / 2 * dsize; 382 383 while (lo < hi) { 384 lo_order = lo != pivot && in_order(lo, pivot, user); 385 hi_order = hi != pivot && in_order(pivot, hi, user); 386 if (!lo_order && !hi_order) { 387 if (lo == pivot) pivot = hi; 388 else if (hi == pivot) pivot = lo; 389 dvec_quick_sort_swap(lo, hi, tmp, dsize); 390 modified = true; 391 } 392 if (lo_order) lo += dsize; 393 if (hi_order) hi -= dsize; 394 } 395 396 if (start != pivot) { 397 *(uint8_t **)dvec_push(&stack) = start; 398 *(uint8_t **)dvec_push(&stack) = pivot - dsize; 399 } 400 401 if (end != pivot) { 402 *(uint8_t **)dvec_push(&stack) = pivot + dsize; 403 *(uint8_t **)dvec_push(&stack) = end; 404 } 405 } 406 407 dvec_deinit(&stack); 408 409 return modified ? DVEC_MODIFIED : DVEC_OK; 410} 411 412static bool 413dvec_quick_sort_ex_order(const void *p1, const void *p2, const void *user) 414{ 415 const struct sort_order_user_proxy *user_proxy = user; 416 const void *d1 = *(void **)p1, *d2 = *(void **)p2; 417 418 return user_proxy->order_fn(d1, d2, user_proxy->user); 419} 420 421int 422dvec_quick_sort_ex(struct dvec *dvec, const struct allocator *allocator, 423 void *tmp, bool reverse, dvec_sort_order_fn in_order, const void *user) 424{ 425 const struct sort_order_user_proxy user_proxy = { 426 .order_fn = in_order, 427 .user = user 428 }; 429 struct dvec ptrmap; 430 void *p, **pp, **dst, **src; 431 size_t dsize; 432 int rc; 433 434 if (!dvec->len) return DVEC_OK; 435 436 dsize = dvec->dsize; 437 438 rc = dvec_init(&ptrmap, sizeof(void *), dvec->len, allocator); 439 if (rc) return rc; 440 441 for (DVEC_ITER(dvec, p)) 442 *(void **)dvec_push(&ptrmap) = p; 443 444 rc = dvec_quick_sort(&ptrmap, allocator, tmp, reverse, 445 dvec_quick_sort_ex_order, &user_proxy); 446 if (rc) return rc; 447 448 for (DVEC_ITER(&ptrmap, pp)) { 449 if (!*pp || dvec_idx(&ptrmap, pp) == dvec_idx(dvec, *pp)) 450 continue; 451 dst = pp; 452 memcpy(tmp, *dst, dsize); 453 while (1) { 454 src = dvec_at(&ptrmap, dvec_idx(dvec, *dst)); 455 if (!*src) break; 456 memcpy(*dst, *src, dsize); 457 *dst = NULL; 458 dst = src; 459 } 460 memcpy(*dst, tmp, dsize); 461 } 462 463 rc = dvec_deinit(&ptrmap); 464 if (rc) return rc; 465 466 return DVEC_OK; 467} 468 469ssize_t 470dvec_binary_search(struct dvec *dvec, dvec_search_cmp_fn search_cmp, 471 void *user, ssize_t *lower, ssize_t *higher) 472{ 473 size_t min, max, pos; 474 int rc; 475 476 min = 0; 477 max = dvec->len; 478 if (lower) *lower = -1; 479 if (higher) *higher = -1; 480 481 while (min < max) { 482 pos = min + (max - min) / 2; 483 rc = search_cmp(dvec_at(dvec, pos), user); 484 if (!rc) { 485 if (lower && pos > 0) 486 *lower = (ssize_t) pos - 1; 487 if (higher && pos < dvec->len - 1) 488 *higher = (ssize_t) pos + 1; 489 return (ssize_t) pos; 490 } else if (rc > 0) { 491 if (pos + 1 == max) { 492 if (lower) *lower = (ssize_t) min; 493 if (higher && min < dvec->len - 1) 494 *higher = (ssize_t) min + 1; 495 break; 496 } 497 min = pos + 1; 498 } else { 499 if (min == pos) { 500 if (higher) *higher = (ssize_t) min; 501 if (lower && min > 0) 502 *lower = (ssize_t) min - 1; 503 break; 504 } 505 max = pos; 506 } 507 } 508 509 return -1; 510}