Newer
Older
Fabrice Bellard
committed
/*
* default memory allocator for libavutil
* Copyright (c) 2002 Fabrice Bellard
Fabrice Bellard
committed
*
* This file is part of Libav.
Diego Biurrun
committed
*
* Libav is free software; you can redistribute it and/or
Fabrice Bellard
committed
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
Diego Biurrun
committed
* version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard
committed
*
* Libav is distributed in the hope that it will be useful,
Fabrice Bellard
committed
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Fabrice Bellard
committed
*/
* default memory allocator for libavutil
#include "config.h"
#include <limits.h>
#include <string.h>
Fabrice Bellard
committed
#include <malloc.h>
#endif
#include "avutil.h"
#include "mem.h"
#ifdef MALLOC_PREFIX
#define malloc AV_JOIN(MALLOC_PREFIX, malloc)
#define memalign AV_JOIN(MALLOC_PREFIX, memalign)
#define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign)
#define realloc AV_JOIN(MALLOC_PREFIX, realloc)
#define free AV_JOIN(MALLOC_PREFIX, free)
void *malloc(size_t size);
void *memalign(size_t align, size_t size);
int posix_memalign(void **ptr, size_t align, size_t size);
void *realloc(void *ptr, size_t size);
void free(void *ptr);
#endif /* MALLOC_PREFIX */
/* You can redefine av_malloc and av_free in your project to use your
* memory allocator. You do not need to suppress this file because the
* linker will do it automatically. */
Fabrice Bellard
committed
Fabrice Bellard
committed
{
/* let's disallow possibly ambiguous cases */
Patrik Kullman
committed
ptr = NULL;
#elif HAVE_ALIGNED_MALLOC
ptr = _aligned_malloc(size, 32);
* Indeed, we should align it:
* on 4 for 386
* on 16 for 486
* on 32 for 586, PPro - K6-III
* on 64 for K7 (maybe for P3 too).
* Because L1 and L2 caches are aligned on those values.
* But I don't want to code such logic here!
Fabrice Bellard
committed
*/
/* Why 32?
* For AVX ASM. SSE / NEON needs only 16.
* Why not larger? Because I did not see a difference in benchmarks ...
/* benchmarks with P3
* memalign(64) + 1 3071, 3051, 3032
* memalign(64) + 2 3051, 3032, 3041
* memalign(64) + 4 2911, 2896, 2915
* memalign(64) + 8 2545, 2554, 2550
* memalign(64) + 16 2543, 2572, 2563
* memalign(64) + 32 2546, 2545, 2571
* memalign(64) + 64 2570, 2533, 2558
*
* BTW, malloc seems to do 8-byte alignment by default here.
Fabrice Bellard
committed
#else
ptr = malloc(size);
#endif
return ptr;
}
void *av_realloc(void *ptr, size_t size)
/* let's disallow possibly ambiguous cases */
return _aligned_realloc(ptr, size, 32);
#else
return realloc(ptr, size);
Michael Niedermayer
committed
#endif
if (!size) {
av_freep(ptr);
return 0;
}
memcpy(&val, ptr, sizeof(val));
val = av_realloc(val, size);
if (!val) {
av_freep(ptr);
return AVERROR(ENOMEM);
}
memcpy(ptr, &val, sizeof(val));
void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
{
if (!size || nmemb >= INT_MAX / size)
return NULL;
return av_realloc(ptr, nmemb * size);
}
int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
{
if (!size || nmemb >= INT_MAX / size)
return AVERROR(ENOMEM);
av_freep(ptr);
return 0;
}
memcpy(&val, ptr, sizeof(val));
val = av_realloc(val, nmemb * size);
if (!val) {
av_freep(ptr);
return AVERROR(ENOMEM);
}
memcpy(ptr, &val, sizeof(val));
Fabrice Bellard
committed
void av_free(void *ptr)
{
_aligned_free(ptr);
Michael Niedermayer
committed
#else
Michael Niedermayer
committed
#endif
Fabrice Bellard
committed
}
void av_freep(void *arg)
{
void *val;
memcpy(&val, arg, sizeof(val));
memcpy(arg, &(void *){ NULL }, sizeof(val));
av_free(val);
void *ptr = av_malloc(size);
if (ptr)
memset(ptr, 0, size);
return ptr;
}
char *av_strdup(const char *s)
{
ptr = av_realloc(NULL, len);
char *av_strndup(const char *s, size_t len)
{
char *ret = NULL, *end;
if (!s)
return NULL;
end = memchr(s, 0, len);
if (end)
len = end - s;
ret = av_realloc(NULL, len + 1);
if (!ret)
return NULL;
memcpy(ret, s, len);
ret[len] = 0;
return ret;
}
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
static void fill16(uint8_t *dst, int len)
{
uint32_t v = AV_RN16(dst - 2);
v |= v << 16;
while (len >= 4) {
AV_WN32(dst, v);
dst += 4;
len -= 4;
}
while (len--) {
*dst = dst[-2];
dst++;
}
}
static void fill24(uint8_t *dst, int len)
{
#if HAVE_BIGENDIAN
uint32_t v = AV_RB24(dst - 3);
uint32_t a = v << 8 | v >> 16;
uint32_t b = v << 16 | v >> 8;
uint32_t c = v << 24 | v;
#else
uint32_t v = AV_RL24(dst - 3);
uint32_t a = v | v << 24;
uint32_t b = v >> 8 | v << 16;
uint32_t c = v >> 16 | v << 8;
#endif
while (len >= 12) {
AV_WN32(dst, a);
AV_WN32(dst + 4, b);
AV_WN32(dst + 8, c);
dst += 12;
len -= 12;
}
if (len >= 4) {
AV_WN32(dst, a);
dst += 4;
len -= 4;
}
if (len >= 4) {
AV_WN32(dst, b);
dst += 4;
len -= 4;
}
while (len--) {
*dst = dst[-3];
dst++;
}
}
static void fill32(uint8_t *dst, int len)
{
uint32_t v = AV_RN32(dst - 4);
while (len >= 4) {
AV_WN32(dst, v);
dst += 4;
len -= 4;
}
while (len--) {
*dst = dst[-4];
dst++;
}
}
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
{
const uint8_t *src = &dst[-back];
if (!back)
return;
if (back == 1) {
memset(dst, *src, cnt);
} else if (back == 2) {
fill16(dst, cnt);
} else if (back == 3) {
fill24(dst, cnt);
} else if (back == 4) {
fill32(dst, cnt);
int blocklen = back;
while (cnt > blocklen) {
memcpy(dst, src, blocklen);
dst += blocklen;
cnt -= blocklen;
blocklen <<= 1;
}
memcpy(dst, src, cnt);
return;
}
if (cnt >= 8) {
AV_COPY32U(dst, src);
AV_COPY32U(dst + 4, src + 4);
src += 8;
dst += 8;
cnt -= 8;
}
if (cnt >= 4) {
AV_COPY32U(dst, src);
src += 4;
dst += 4;
cnt -= 4;
}
if (cnt >= 2) {
AV_COPY16U(dst, src);
src += 2;
dst += 2;
cnt -= 2;
if (cnt)
*dst = *src;
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
{
if (min_size < *size)
return ptr;
min_size = FFMAX(17 * min_size / 16 + 32, min_size);
ptr = av_realloc(ptr, min_size);
/* we could set this to the unmodified min_size but this is safer
* if the user lost the ptr and uses NULL now
*/
if (!ptr)
min_size = 0;
*size = min_size;
return ptr;
}
void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
{
void **p = ptr;
if (min_size < *size)
return;
min_size = FFMAX(17 * min_size / 16 + 32, min_size);
av_free(*p);
*p = av_malloc(min_size);
if (!*p)
min_size = 0;
*size = min_size;
}