mirror of
https://github.com/neovim/neovim.git
synced 2024-12-28 14:31:13 -07:00
27a7a4d384
assert() is compiled out for release builds, but we don't want to continue running in these impossible situations. This also resolves the "implicit fallthrough" warnings for the asserts in switch cases.
102 lines
2.3 KiB
C
102 lines
2.3 KiB
C
#include <stdlib.h>
|
|
#include <assert.h>
|
|
|
|
#include "nvim/lib/ringbuf.h"
|
|
|
|
enum { RB_SIZE = 1024 };
|
|
|
|
typedef struct {
|
|
void *ptr;
|
|
size_t size;
|
|
} AllocRecord;
|
|
|
|
RINGBUF_TYPEDEF(AllocRecords, AllocRecord)
|
|
RINGBUF_INIT(AllocRecords, arecs, AllocRecord, RINGBUF_DUMMY_FREE)
|
|
RINGBUF_STATIC(static, AllocRecords, AllocRecord, arecs, RB_SIZE)
|
|
|
|
size_t allocated_memory = 0;
|
|
size_t ever_allocated_memory = 0;
|
|
|
|
size_t allocated_memory_limit = SIZE_MAX;
|
|
|
|
void *xmalloc(const size_t size)
|
|
{
|
|
void *ret = malloc(size);
|
|
allocated_memory += size;
|
|
ever_allocated_memory += size;
|
|
assert(allocated_memory <= allocated_memory_limit);
|
|
assert(arecs_rb_length(&arecs) < RB_SIZE);
|
|
arecs_rb_push(&arecs, (AllocRecord) {
|
|
.ptr = ret,
|
|
.size = size,
|
|
});
|
|
return ret;
|
|
}
|
|
|
|
void xfree(void *const p)
|
|
{
|
|
if (p == NULL) {
|
|
return;
|
|
}
|
|
RINGBUF_FORALL(&arecs, AllocRecord, arec) {
|
|
if (arec->ptr == p) {
|
|
allocated_memory -= arec->size;
|
|
arecs_rb_remove(&arecs, arecs_rb_find_idx(&arecs, arec));
|
|
return;
|
|
}
|
|
}
|
|
abort();
|
|
}
|
|
|
|
void *xrealloc(void *const p, size_t new_size)
|
|
{
|
|
void *ret = realloc(p, new_size);
|
|
RINGBUF_FORALL(&arecs, AllocRecord, arec) {
|
|
if (arec->ptr == p) {
|
|
allocated_memory -= arec->size;
|
|
allocated_memory += new_size;
|
|
if (new_size > arec->size) {
|
|
ever_allocated_memory += (new_size - arec->size);
|
|
}
|
|
arec->ptr = ret;
|
|
arec->size = new_size;
|
|
return ret;
|
|
}
|
|
}
|
|
abort();
|
|
return (void *)(intptr_t)1;
|
|
}
|
|
|
|
char *xstrdup(const char *str)
|
|
FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
|
|
FUNC_ATTR_NONNULL_ALL
|
|
{
|
|
return xmemdupz(str, strlen(str));
|
|
}
|
|
|
|
void *xmallocz(size_t size)
|
|
FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
|
|
{
|
|
size_t total_size = size + 1;
|
|
assert(total_size > size);
|
|
|
|
void *ret = xmalloc(total_size);
|
|
((char *)ret)[size] = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
char *xstpcpy(char *restrict dst, const char *restrict src)
|
|
FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
|
{
|
|
const size_t len = strlen(src);
|
|
return (char *)memcpy(dst, src, len + 1) + len;
|
|
}
|
|
|
|
void *xmemdupz(const void *data, size_t len)
|
|
FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
|
|
FUNC_ATTR_NONNULL_ALL
|
|
{
|
|
return memcpy(xmallocz(len), data, len);
|
|
}
|