chunkedvector.c 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #include "pocketpy/common/chunkedvector.h"
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "pocketpy/common/utils.h"
  5. #include "pocketpy/config.h"
  6. #if defined(_MSC_VER)
  7. #include <intrin.h>
  8. #endif
  9. inline static int c11_bit_length(unsigned long x) {
  10. #if(defined(__clang__) || defined(__GNUC__))
  11. return x == 0 ? 0 : (int)sizeof(unsigned long) * 8 - __builtin_clzl(x);
  12. #elif defined(_MSC_VER)
  13. static_assert(sizeof(unsigned long) <= 4, "unsigned long is greater than 4 bytes");
  14. unsigned long msb;
  15. if(_BitScanReverse(&msb, x)) { return (int)msb + 1; }
  16. return 0;
  17. #else
  18. const int BIT_LENGTH_TABLE[32] = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
  19. 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
  20. int msb = 0;
  21. while(x >= 32) {
  22. msb += 6;
  23. x >>= 6;
  24. }
  25. msb += BIT_LENGTH_TABLE[x];
  26. return msb;
  27. #endif
  28. }
  29. void c11_chunkedvector__ctor(c11_chunkedvector* self, int elem_size, int initial_chunks) {
  30. if(initial_chunks < 5) initial_chunks = 5;
  31. c11_vector__ctor(&self->chunks, sizeof(c11_chunkedvector_chunk));
  32. self->length = 0;
  33. self->capacity = (1U << (unsigned int)initial_chunks) - 1U;
  34. self->elem_size = elem_size;
  35. self->initial_chunks = initial_chunks;
  36. void* chunks_data = PK_MALLOC(elem_size * ((1U << (unsigned int)initial_chunks) - 1));
  37. for(int i = 0; i < initial_chunks; i++) {
  38. // TODO: optimize?
  39. c11_chunkedvector_chunk chunk = {.length = 0,
  40. .capacity = 1U << i,
  41. .data = (char*)chunks_data + elem_size * ((1U << i) - 1U)};
  42. c11_vector__push(c11_chunkedvector_chunk, &self->chunks, chunk);
  43. }
  44. }
  45. void c11_chunkedvector__dtor(c11_chunkedvector* self) {
  46. for(int index = self->initial_chunks; index < self->chunks.length; index++) {
  47. c11_chunkedvector_chunk* chunk = c11__at(c11_chunkedvector_chunk, &self->chunks, index);
  48. PK_FREE(chunk->data);
  49. }
  50. c11_chunkedvector_chunk* initial_chunk = c11__at(c11_chunkedvector_chunk, &self->chunks, 0);
  51. PK_FREE(initial_chunk->data);
  52. c11_vector__dtor(&self->chunks);
  53. }
  54. void* c11_chunkedvector__emplace(c11_chunkedvector* self) {
  55. if(self->length == self->capacity) {
  56. #ifndef NDEBUG
  57. c11_chunkedvector_chunk last_chunk = c11_vector__back(c11_chunkedvector_chunk, &self->chunks);
  58. assert(last_chunk.capacity == last_chunk.length);
  59. #endif
  60. c11_chunkedvector_chunk chunk = {
  61. .length = 0,
  62. .capacity = 1U << (unsigned int)self->chunks.length,
  63. .data = PK_MALLOC(self->elem_size * ((1U << (unsigned int)self->chunks.length)))};
  64. self->capacity += chunk.capacity;
  65. c11_vector__push(c11_chunkedvector_chunk, &self->chunks, chunk);
  66. }
  67. int last_chunk_index = c11_bit_length(self->length + 1) - 1;
  68. c11_chunkedvector_chunk* last_chunk =
  69. c11__at(c11_chunkedvector_chunk, &self->chunks, last_chunk_index);
  70. void* p = (char*)last_chunk->data + self->elem_size * last_chunk->length;
  71. last_chunk->length++;
  72. self->length++;
  73. return p;
  74. }
  75. void* c11_chunkedvector__at(c11_chunkedvector* self, int index) {
  76. int chunk_index = c11_bit_length(index + 1) - 1;
  77. c11_chunkedvector_chunk* chunk = c11__at(c11_chunkedvector_chunk, &self->chunks, chunk_index);
  78. return (char*)chunk->data + (index + 1 - (1U << (unsigned int)chunk_index)) * self->elem_size;
  79. }