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