project_files/frontlib/util/buffer.c
branchhedgeroid
changeset 7857 2bc61f8841a1
parent 7316 f7b49b2c5d84
child 10017 de822cd3df3a
equal deleted inserted replaced
7855:ddcdedd3330b 7857:2bc61f8841a1
       
     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 }