10017
|
1 |
/*
|
|
2 |
* Hedgewars, a free turn based strategy game
|
|
3 |
* Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.com>
|
|
4 |
*
|
|
5 |
* This program is free software; you can redistribute it and/or
|
|
6 |
* modify it under the terms of the GNU General Public License
|
|
7 |
* as published by the Free Software Foundation; either version 2
|
|
8 |
* of the License, or (at your option) any later version.
|
|
9 |
*
|
|
10 |
* This program is distributed in the hope that it will be useful,
|
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13 |
* GNU General Public License for more details.
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU General Public License
|
|
16 |
* along with this program; if not, write to the Free Software
|
|
17 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
18 |
*/
|
|
19 |
|
|
20 |
#include "buffer.h"
|
|
21 |
#include "logging.h"
|
|
22 |
#include "util.h"
|
|
23 |
|
|
24 |
#include <stdlib.h>
|
|
25 |
#include <limits.h>
|
|
26 |
#include <string.h>
|
|
27 |
|
|
28 |
#define MIN_VECTOR_CAPACITY 16
|
|
29 |
|
|
30 |
struct _flib_vector {
|
|
31 |
void *data;
|
|
32 |
size_t size;
|
|
33 |
size_t capacity;
|
|
34 |
};
|
|
35 |
|
|
36 |
flib_vector *flib_vector_create() {
|
|
37 |
flib_vector *result = NULL;
|
|
38 |
flib_vector *tmpVector = flib_calloc(1, sizeof(flib_vector));
|
|
39 |
if(tmpVector) {
|
|
40 |
tmpVector->data = flib_malloc(MIN_VECTOR_CAPACITY);
|
|
41 |
if(tmpVector->data) {
|
|
42 |
tmpVector->size = 0;
|
|
43 |
tmpVector->capacity = MIN_VECTOR_CAPACITY;
|
|
44 |
result = tmpVector;
|
|
45 |
tmpVector = NULL;
|
|
46 |
}
|
|
47 |
}
|
|
48 |
flib_vector_destroy(tmpVector);
|
|
49 |
return result;
|
|
50 |
}
|
|
51 |
|
|
52 |
void flib_vector_destroy(flib_vector *vec) {
|
|
53 |
if(vec) {
|
|
54 |
free(vec->data);
|
|
55 |
free(vec);
|
|
56 |
}
|
|
57 |
}
|
|
58 |
|
|
59 |
static int setCapacity(flib_vector *vec, size_t newCapacity) {
|
|
60 |
if(newCapacity == vec->capacity) {
|
|
61 |
return 0;
|
|
62 |
}
|
|
63 |
void *newData = realloc(vec->data, newCapacity);
|
|
64 |
if(newData) {
|
|
65 |
vec->data = newData;
|
|
66 |
vec->capacity = newCapacity;
|
|
67 |
return 0;
|
|
68 |
} else {
|
|
69 |
return -1;
|
|
70 |
}
|
|
71 |
}
|
|
72 |
|
|
73 |
static int allocateExtraCapacity(flib_vector *vec, size_t extraCapacity) {
|
|
74 |
if(extraCapacity <= SIZE_MAX - vec->capacity) {
|
|
75 |
return setCapacity(vec, vec->capacity + extraCapacity);
|
|
76 |
} else {
|
|
77 |
return -1;
|
|
78 |
}
|
|
79 |
}
|
|
80 |
|
|
81 |
int flib_vector_resize(flib_vector *vec, size_t newSize) {
|
|
82 |
if(log_badargs_if(vec==NULL)) {
|
|
83 |
return -1;
|
|
84 |
}
|
|
85 |
|
|
86 |
if(vec->capacity < newSize) {
|
|
87 |
// Resize exponentially for constant amortized time,
|
|
88 |
// But at least by as much as we need of course
|
|
89 |
size_t extraCapacity = (vec->capacity)/2;
|
|
90 |
size_t minExtraCapacity = newSize - vec->capacity;
|
|
91 |
if(extraCapacity < minExtraCapacity) {
|
|
92 |
extraCapacity = minExtraCapacity;
|
|
93 |
}
|
|
94 |
|
|
95 |
if(allocateExtraCapacity(vec, extraCapacity)) {
|
|
96 |
allocateExtraCapacity(vec, minExtraCapacity);
|
|
97 |
}
|
|
98 |
} else if(vec->capacity/2 > newSize) {
|
|
99 |
size_t newCapacity = newSize+newSize/4;
|
|
100 |
if(newCapacity < MIN_VECTOR_CAPACITY) {
|
|
101 |
newCapacity = MIN_VECTOR_CAPACITY;
|
|
102 |
}
|
|
103 |
setCapacity(vec, newCapacity);
|
|
104 |
}
|
|
105 |
|
|
106 |
if(vec->capacity >= newSize) {
|
|
107 |
vec->size = newSize;
|
|
108 |
return 0;
|
|
109 |
} else {
|
|
110 |
return -1;
|
|
111 |
}
|
|
112 |
}
|
|
113 |
|
|
114 |
int flib_vector_append(flib_vector *vec, const void *data, size_t len) {
|
|
115 |
if(!log_badargs_if2(vec==NULL, data==NULL && len>0)
|
|
116 |
&& !log_oom_if(len > SIZE_MAX-vec->size)) {
|
|
117 |
size_t oldSize = vec->size;
|
|
118 |
if(!log_oom_if(flib_vector_resize(vec, vec->size+len))) {
|
|
119 |
memmove(((uint8_t*)vec->data) + oldSize, data, len);
|
|
120 |
return 0;
|
|
121 |
}
|
|
122 |
}
|
|
123 |
return -1;
|
|
124 |
}
|
|
125 |
|
|
126 |
int flib_vector_appendf(flib_vector *vec, const char *fmt, ...) {
|
|
127 |
int result = -1;
|
|
128 |
if(!log_badargs_if2(vec==NULL, fmt==NULL)) {
|
|
129 |
va_list argp;
|
|
130 |
va_start(argp, fmt);
|
|
131 |
char *formatted = flib_vasprintf(fmt, argp);
|
|
132 |
va_end(argp);
|
|
133 |
|
|
134 |
|
|
135 |
if(formatted) {
|
|
136 |
size_t len = strlen(formatted);
|
|
137 |
result = flib_vector_append(vec, formatted, len);
|
|
138 |
}
|
|
139 |
}
|
|
140 |
return result;
|
|
141 |
}
|
|
142 |
|
|
143 |
flib_buffer flib_vector_as_buffer(flib_vector *vec) {
|
|
144 |
if(log_badargs_if(vec==NULL)) {
|
|
145 |
flib_buffer result = {NULL, 0};
|
|
146 |
return result;
|
|
147 |
} else {
|
|
148 |
flib_buffer result = {vec->data, vec->size};
|
|
149 |
return result;
|
|
150 |
}
|
|
151 |
}
|
|
152 |
|
|
153 |
flib_constbuffer flib_vector_as_constbuffer(flib_vector *vec) {
|
|
154 |
if(log_badargs_if(vec==NULL)) {
|
|
155 |
flib_constbuffer result = {NULL, 0};
|
|
156 |
return result;
|
|
157 |
} else {
|
|
158 |
flib_constbuffer result = {vec->data, vec->size};
|
|
159 |
return result;
|
|
160 |
}
|
|
161 |
}
|
|
162 |
|
|
163 |
void *flib_vector_data(flib_vector *vec) {
|
|
164 |
if(log_badargs_if(vec==NULL)) {
|
|
165 |
return NULL;
|
|
166 |
} else {
|
|
167 |
return vec->data;
|
|
168 |
}
|
|
169 |
}
|
|
170 |
|
|
171 |
size_t flib_vector_size(flib_vector *vec) {
|
|
172 |
if(log_badargs_if(vec==NULL)) {
|
|
173 |
return 0;
|
|
174 |
} else {
|
|
175 |
return vec->size;
|
|
176 |
}
|
|
177 |
}
|