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
flib_vector_create()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
flib_vector_destroy(flib_vector * vec)52 void flib_vector_destroy(flib_vector *vec) {
53 if(vec) {
54 free(vec->data);
55 free(vec);
56 }
57 }
58
setCapacity(flib_vector * vec,size_t newCapacity)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
allocateExtraCapacity(flib_vector * vec,size_t extraCapacity)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
flib_vector_resize(flib_vector * vec,size_t newSize)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
flib_vector_append(flib_vector * vec,const void * data,size_t len)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
flib_vector_appendf(flib_vector * vec,const char * fmt,...)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
flib_vector_as_buffer(flib_vector * vec)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
flib_vector_as_constbuffer(flib_vector * vec)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
flib_vector_data(flib_vector * vec)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
flib_vector_size(flib_vector * vec)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 }
178