35 free(vec->data); |
35 free(vec->data); |
36 free(vec); |
36 free(vec); |
37 } |
37 } |
38 } |
38 } |
39 |
39 |
40 static void try_realloc(flib_vector *vec, size_t newCapacity) { |
40 static int setCapacity(flib_vector *vec, size_t newCapacity) { |
|
41 if(newCapacity == vec->capacity) { |
|
42 return 0; |
|
43 } |
41 void *newData = realloc(vec->data, newCapacity); |
44 void *newData = realloc(vec->data, newCapacity); |
42 if(newData) { |
45 if(newData) { |
43 vec->data = newData; |
46 vec->data = newData; |
44 vec->capacity = newCapacity; |
47 vec->capacity = newCapacity; |
|
48 return 0; |
|
49 } else { |
|
50 return -1; |
45 } |
51 } |
46 } |
52 } |
47 |
53 |
48 static size_t getFreeCapacity(flib_vector *vec) { |
54 static int allocateExtraCapacity(flib_vector *vec, size_t extraCapacity) { |
49 return vec->capacity - vec->size; |
55 if(extraCapacity <= SIZE_MAX - vec->capacity) { |
|
56 return setCapacity(vec, vec->capacity + extraCapacity); |
|
57 } else { |
|
58 return -1; |
|
59 } |
|
60 } |
|
61 |
|
62 int flib_vector_resize(flib_vector *vec, size_t newSize) { |
|
63 if(!vec) { |
|
64 flib_log_e("null parameter in flib_vector_resize"); |
|
65 return -1; |
|
66 } |
|
67 |
|
68 if(vec->capacity < newSize) { |
|
69 // Resize exponentially for constant amortized time, |
|
70 // But at least by as much as we need of course, |
|
71 // and be extra careful with integer overflows... |
|
72 size_t extraCapacity = (vec->capacity)/2; |
|
73 size_t minExtraCapacity = newSize - vec->capacity; |
|
74 if(extraCapacity < minExtraCapacity) { |
|
75 extraCapacity = minExtraCapacity; |
|
76 } |
|
77 |
|
78 if(allocateExtraCapacity(vec, extraCapacity)) { |
|
79 allocateExtraCapacity(vec, minExtraCapacity); |
|
80 } |
|
81 } else if(vec->capacity/2 > newSize) { |
|
82 size_t newCapacity = newSize+newSize/4; |
|
83 if(newCapacity < MIN_VECTOR_CAPACITY) { |
|
84 newCapacity = MIN_VECTOR_CAPACITY; |
|
85 } |
|
86 setCapacity(vec, newCapacity); |
|
87 } |
|
88 |
|
89 if(vec->capacity >= newSize) { |
|
90 vec->size = newSize; |
|
91 return 0; |
|
92 } else { |
|
93 return -1; |
|
94 } |
50 } |
95 } |
51 |
96 |
52 int flib_vector_append(flib_vector *vec, const void *data, size_t len) { |
97 int flib_vector_append(flib_vector *vec, const void *data, size_t len) { |
53 if(!vec) { |
98 if(!vec) { |
54 flib_log_e("null parameter in flib_vector_append"); |
99 flib_log_e("null parameter in flib_vector_append"); |
55 return 0; |
100 return 0; |
56 } |
101 } |
57 |
102 |
58 if(getFreeCapacity(vec) < len) { |
103 if(len > SIZE_MAX-vec->size) { |
59 // Resize exponentially for constant amortized time, |
104 return 0; |
60 // But at least by as much as we need of course, |
|
61 // and be extra careful with integer overflows... |
|
62 size_t extraCapacity = (vec->capacity)/2; |
|
63 |
|
64 size_t minExtraCapacity = len - getFreeCapacity(vec); |
|
65 if(extraCapacity < minExtraCapacity) { |
|
66 extraCapacity = minExtraCapacity; |
|
67 } |
|
68 |
|
69 if(extraCapacity <= SIZE_MAX - vec->capacity) { |
|
70 try_realloc(vec, vec->capacity+extraCapacity); |
|
71 } |
|
72 |
|
73 // Check if we were able to resize. |
|
74 // If not, try to allocate at least what we need. |
|
75 if(getFreeCapacity(vec) < len) { |
|
76 try_realloc(vec, vec->capacity+minExtraCapacity); |
|
77 |
|
78 // Still not working? Then we fail. |
|
79 if(getFreeCapacity(vec) < len) { |
|
80 return 0; |
|
81 } |
|
82 } |
|
83 } |
105 } |
84 |
106 |
85 memmove(((uint8_t*)vec->data) + vec->size, data, len); |
107 size_t oldSize = vec->size; |
86 vec->size += len; |
108 if(flib_vector_resize(vec, vec->size+len)) { |
|
109 return 0; |
|
110 } |
|
111 |
|
112 memmove(((uint8_t*)vec->data) + oldSize, data, len); |
87 return len; |
113 return len; |
88 } |
114 } |
89 |
115 |
90 flib_buffer flib_vector_as_buffer(flib_vector *vec) { |
116 flib_buffer flib_vector_as_buffer(flib_vector *vec) { |
91 if(!vec) { |
117 if(!vec) { |