Deleted the platform module and rewrote the arena allocator
This commit is contained in:
parent
886793a950
commit
682f83da16
|
@ -1,3 +1,4 @@
|
||||||
# libRR
|
# libRR: Library for Redundancy Reduction
|
||||||
|
|
||||||
|
A simple C library which implements basic yet time-consuming functionality once.
|
||||||
|
|
||||||
Redundancy Reduction Library
|
|
|
@ -1 +1 @@
|
||||||
core/exports/
|
core/exports
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
#ifndef RR_ALLOC_H
|
||||||
|
#define RR_ALLOC_H
|
||||||
|
|
||||||
|
#include <librr/types.h>
|
||||||
|
|
||||||
|
typedef struct rr_arena rr_arena_s;
|
||||||
|
|
||||||
|
struct rr_arena
|
||||||
|
{
|
||||||
|
usz_t capacity;
|
||||||
|
usz_t usage;
|
||||||
|
void *allocation;
|
||||||
|
rr_arena_s *continuation;
|
||||||
|
bool_t allow_continuation;
|
||||||
|
};
|
||||||
|
|
||||||
|
rr_arena_s * rr_new_fixed_arena(usz_t capacity);
|
||||||
|
rr_arena_s * rr_new_dynamic_arena(usz_t capacity);
|
||||||
|
void rr_delete_arena(rr_arena_s *arena);
|
||||||
|
void * rr_aalloc(rr_arena_s *arena, usz_t amount);
|
||||||
|
|
||||||
|
#endif // RR_ALLOC_H
|
|
@ -1,59 +0,0 @@
|
||||||
|
|
||||||
#ifndef RR_GENERIC_ALLOCATOR_H
|
|
||||||
#define RR_GENERIC_ALLOCATOR_H
|
|
||||||
|
|
||||||
#include <librr/types.h>
|
|
||||||
|
|
||||||
typedef struct rr_generic_allocator rr_generic_allocator_s;
|
|
||||||
typedef struct rr_generic_pool rr_generic_pool_s;
|
|
||||||
typedef struct rr_generic_arena rr_generic_arena_s;
|
|
||||||
|
|
||||||
typedef rr_generic_arena_s (*rr_create_arena_fn) (usz_t capacity);
|
|
||||||
typedef rr_generic_pool_s (*rr_create_pool_fn) (usz_t item_size, usz_t num_items);
|
|
||||||
|
|
||||||
struct rr_generic_allocator
|
|
||||||
{
|
|
||||||
void * (*fn_alloc) (rr_generic_allocator_s *allocator, usz_t num_bytes);
|
|
||||||
void (*fn_free) (rr_generic_allocator_s *allocator, void *block);
|
|
||||||
void (*fn_destruct) (rr_generic_allocator_s *allocator);
|
|
||||||
void *specifics;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rr_generic_pool
|
|
||||||
{
|
|
||||||
void * (*fn_alloc) (rr_generic_pool_s *pool);
|
|
||||||
void (*fn_free) (rr_generic_pool_s *pool, void *block);
|
|
||||||
void (*fn_destruct) (rr_generic_pool_s *pool);
|
|
||||||
void *specifics;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rr_generic_arena
|
|
||||||
{
|
|
||||||
void * (*fn_alloc) (rr_generic_arena_s *arena, usz_t num_bytes);
|
|
||||||
void (*fn_destruct) (rr_generic_arena_s *arena);
|
|
||||||
void *specifics;
|
|
||||||
};
|
|
||||||
|
|
||||||
void * rr_alloc(rr_generic_allocator_s *allocator, usz_t size);
|
|
||||||
void rr_free(rr_generic_allocator_s *allocator, void *allocation);
|
|
||||||
|
|
||||||
void * rr_arena_alloc(rr_generic_arena_s *arena, usz_t size);
|
|
||||||
|
|
||||||
void * rr_pool_alloc(rr_generic_pool_s *pool);
|
|
||||||
void rr_pool_free(rr_generic_pool_s *pool, void *allocation);
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef __RR_AVOID_STDLIB
|
|
||||||
rr_generic_allocator_s rr_provide_stdlib_allocator();
|
|
||||||
#endif // __RR_AVOID_STDLIB
|
|
||||||
|
|
||||||
rr_generic_arena_s rr_provide_arena(rr_generic_allocator_s *allocator, usz_t len_allocation);
|
|
||||||
rr_generic_pool_s rr_provide_dynamic_pool(rr_generic_allocator_s *allocator, usz_t item_size, usz_t capacity);
|
|
||||||
rr_generic_pool_s rr_provide_static_pool(rr_generic_allocator_s *allocator, usz_t item_size, usz_t capacity);
|
|
||||||
|
|
||||||
rr_generic_arena_s rr_provide_arena_from_malloc(usz_t len_allocation);
|
|
||||||
rr_generic_pool_s rr_provide_dynamic_pool_from_malloc(usz_t item_size, usz_t capacity);
|
|
||||||
rr_generic_pool_s rr_provide_static_pool_from_malloc(usz_t item_size, usz_t capacity);
|
|
||||||
|
|
||||||
#endif // RR_GENERIC_ALLOCATOR_H
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
|
|
||||||
#ifndef RR_FS_QUICK_H
|
|
||||||
#define RR_FS_QUICK_H
|
|
||||||
|
|
||||||
#include <librr/types.h>
|
|
||||||
|
|
||||||
usz_t rr_get_file_length(const char *path);
|
|
||||||
void * rr_load_whole_file(const char *path);
|
|
||||||
|
|
||||||
#endif // RR_FS_QUICK_H
|
|
|
@ -1,24 +0,0 @@
|
||||||
|
|
||||||
#ifndef RR_ARENA_ALLOCATOR_H
|
|
||||||
#define RR_ARENA_ALLOCATOR_H
|
|
||||||
|
|
||||||
#include <librr/types.h>
|
|
||||||
#include <librr/alloc/generic.h>
|
|
||||||
|
|
||||||
typedef struct rr_arena rr_arena_s;
|
|
||||||
|
|
||||||
struct rr_arena
|
|
||||||
{
|
|
||||||
usz_t capacity;
|
|
||||||
usz_t offset;
|
|
||||||
char *allocation;
|
|
||||||
rr_generic_allocator_s *allocator;
|
|
||||||
};
|
|
||||||
|
|
||||||
rr_generic_arena_s rr_new_arena(rr_generic_allocator_s *allocator, usz_t capacity);
|
|
||||||
void rr_destruct_arena(rr_generic_arena_s *generic_arena);
|
|
||||||
|
|
||||||
void * rr_arena_alloc(rr_generic_arena_s *generic_arena, usz_t length);
|
|
||||||
char * rr_arena_clone_string(rr_generic_arena_s *generic_arena, const char *string);
|
|
||||||
|
|
||||||
#endif // RR_ARENA_ALLOCATOR_H
|
|
|
@ -1,32 +0,0 @@
|
||||||
|
|
||||||
#ifndef RR_POOL_PROVIDER_H
|
|
||||||
#define RR_POOL_PROVIDER_H
|
|
||||||
|
|
||||||
#include <librr/types.h>
|
|
||||||
#include <librr/alloc/generic.h>
|
|
||||||
|
|
||||||
typedef struct rr_pool_unit_header rr_pool_unit_header_s;
|
|
||||||
typedef struct rr_pool rr_pool_s;
|
|
||||||
|
|
||||||
struct rr_pool_unit_header
|
|
||||||
{
|
|
||||||
rr_pool_unit_header_s *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rr_pool
|
|
||||||
{
|
|
||||||
usz_t capacity;
|
|
||||||
usz_t item_size;
|
|
||||||
rr_pool_unit_header_s *first_free;
|
|
||||||
void *allocation;
|
|
||||||
rr_generic_allocator_s *allocator;
|
|
||||||
};
|
|
||||||
|
|
||||||
rr_generic_pool_s rr_new_dynamic_pool(rr_generic_allocator_s *allocator, usz_t unit_size, usz_t capacity);
|
|
||||||
rr_generic_pool_s rr_new_static_pool(rr_generic_allocator_s *allocator, usz_t unit_size, usz_t capacity);
|
|
||||||
void rr_destruct_pool(rr_generic_pool_s *pool);
|
|
||||||
|
|
||||||
void * rr_pool_alloc_slot(rr_generic_pool_s *pool);
|
|
||||||
void rr_pool_free_slot(rr_generic_pool_s *pool, void *block);
|
|
||||||
|
|
||||||
#endif // RR_POOL_PROVIDER_H
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include <librr/alloc.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
rr_arena_s * rr_new_fixed_arena(usz_t capacity)
|
||||||
|
{
|
||||||
|
usz_t allocation_size =
|
||||||
|
(sizeof(rr_arena_s))
|
||||||
|
+ (capacity + (32 - capacity % 32) // Round up to the next 32 for the allocation block's padding
|
||||||
|
);
|
||||||
|
rr_arena_s *arena = malloc(allocation_size);
|
||||||
|
|
||||||
|
arena->allocation = arena + (sizeof(rr_arena_s) + (32 - sizeof(rr_arena_s) % 32));
|
||||||
|
arena->capacity = capacity;
|
||||||
|
arena->usage = 0;
|
||||||
|
arena->continuation = NULL;
|
||||||
|
arena->allow_continuation = FALSE;
|
||||||
|
return arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
rr_arena_s * rr_new_dynamic_arena(usz_t capacity)
|
||||||
|
{
|
||||||
|
usz_t allocation_size =
|
||||||
|
(sizeof(rr_arena_s))
|
||||||
|
+ (capacity + (32 - capacity % 32) // Round up to the next 32 for the allocation block's padding
|
||||||
|
);
|
||||||
|
rr_arena_s *arena = malloc(allocation_size);
|
||||||
|
|
||||||
|
arena->allocation = arena + (sizeof(rr_arena_s) + (32 - sizeof(rr_arena_s) % 32));
|
||||||
|
arena->capacity = capacity;
|
||||||
|
arena->usage = 0;
|
||||||
|
arena->continuation = NULL;
|
||||||
|
arena->allow_continuation = TRUE;
|
||||||
|
return arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rr_delete_arena(rr_arena_s *arena)
|
||||||
|
{
|
||||||
|
free(arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * rr_aalloc(rr_arena_s *arena, usz_t amount)
|
||||||
|
{
|
||||||
|
if((arena->usage + amount) >= arena->capacity)
|
||||||
|
{
|
||||||
|
if(!arena->allow_continuation)
|
||||||
|
return NULL;
|
||||||
|
if(arena->continuation == NULL)
|
||||||
|
arena->continuation = rr_new_dynamic_arena(arena->capacity * 2);
|
||||||
|
|
||||||
|
rr_aalloc(arena->continuation, amount);
|
||||||
|
}
|
||||||
|
void *allocation = &arena->continuation[amount];
|
||||||
|
arena->usage += amount;
|
||||||
|
return allocation;
|
||||||
|
}
|
|
@ -1,52 +0,0 @@
|
||||||
#include <alloc/arena.h>
|
|
||||||
#include <librr/strutil.h>
|
|
||||||
#include <librr/memory.h>
|
|
||||||
|
|
||||||
rr_generic_arena_s rr_new_arena(rr_generic_allocator_s *allocator, usz_t capacity)
|
|
||||||
{
|
|
||||||
rr_arena_s *specifics = rr_alloc(allocator, sizeof(rr_arena_s) + capacity);
|
|
||||||
specifics->capacity = capacity;
|
|
||||||
specifics->offset = 0;
|
|
||||||
// The arena allocation is right after the head structure.
|
|
||||||
specifics->allocation = (void *) (specifics + sizeof(rr_arena_s));
|
|
||||||
specifics->allocator = allocator;
|
|
||||||
|
|
||||||
rr_generic_arena_s arena;
|
|
||||||
arena.fn_alloc = &rr_arena_alloc;
|
|
||||||
arena.fn_destruct = &rr_destruct_arena;
|
|
||||||
arena.specifics = specifics;
|
|
||||||
|
|
||||||
return arena;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rr_destruct_arena(rr_generic_arena_s *generic_arena)
|
|
||||||
{
|
|
||||||
rr_arena_s *arena = generic_arena->specifics;
|
|
||||||
rr_free(arena->allocator, generic_arena->specifics);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void * rr_arena_alloc(rr_generic_arena_s *generic_arena, usz_t length)
|
|
||||||
{
|
|
||||||
rr_arena_s *arena = generic_arena->specifics;
|
|
||||||
|
|
||||||
if((arena->offset + length) > arena->capacity)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
void *block = &arena->allocation[arena->offset];
|
|
||||||
arena->offset += length;
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
char * rr_arena_clone_string(rr_generic_arena_s *generic_arena, const char *string)
|
|
||||||
{
|
|
||||||
usz_t len_string = rr_measure_string(string);
|
|
||||||
char *cloned_string = rr_arena_alloc(generic_arena, len_string+1);
|
|
||||||
if(cloned_string == NULL)
|
|
||||||
return NULL;
|
|
||||||
rr_memcopy(cloned_string, string, len_string);
|
|
||||||
cloned_string[len_string] = 0x00;
|
|
||||||
|
|
||||||
return cloned_string;
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
#include <librr/alloc/generic.h>
|
|
||||||
#include <librr/memory.h>
|
|
||||||
#include <alloc/pool.h>
|
|
||||||
|
|
||||||
void rr_initialize_pool_allocation(rr_pool_s *pool)
|
|
||||||
{
|
|
||||||
usz_t slot_size = sizeof(rr_pool_unit_header_s) + pool->item_size;
|
|
||||||
slot_size = (slot_size + (32 - slot_size % 32));
|
|
||||||
|
|
||||||
usz_t slot_index = 0;
|
|
||||||
while(slot_index < pool->capacity)
|
|
||||||
{
|
|
||||||
rr_pool_unit_header_s *current_header = pool->allocation + (slot_index * slot_size);
|
|
||||||
current_header->next = current_header + slot_size;
|
|
||||||
++slot_index;
|
|
||||||
}
|
|
||||||
rr_pool_unit_header_s *last_header = pool->allocation + ((pool->capacity - 1) * slot_size);
|
|
||||||
last_header->next = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
rr_generic_pool_s rr_new_dynamic_pool(rr_generic_allocator_s *allocator, usz_t item_size, usz_t capacity)
|
|
||||||
{
|
|
||||||
// Size of (header + item) rounded up to 32
|
|
||||||
usz_t slot_size = sizeof(rr_pool_unit_header_s) + item_size;
|
|
||||||
slot_size = (slot_size + (32 - slot_size % 32));
|
|
||||||
|
|
||||||
rr_pool_s pool;
|
|
||||||
pool.allocator = allocator;
|
|
||||||
pool.allocation = rr_alloc(allocator, slot_size * capacity);
|
|
||||||
pool.item_size = item_size;
|
|
||||||
pool.capacity = capacity;
|
|
||||||
pool.first_free = pool.allocation;
|
|
||||||
rr_initialize_pool_allocation(&pool);
|
|
||||||
|
|
||||||
rr_generic_pool_s generic_pool;
|
|
||||||
generic_pool.fn_alloc = &rr_pool_alloc_slot;
|
|
||||||
generic_pool.fn_free = &rr_pool_free_slot;
|
|
||||||
generic_pool.fn_destruct = &rr_destruct_pool;
|
|
||||||
return generic_pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
rr_generic_pool_s rr_new_static_pool(rr_generic_allocator_s *allocator, usz_t item_size, usz_t capacity)
|
|
||||||
{
|
|
||||||
// Size of (header + item) rounded up to 32
|
|
||||||
usz_t slot_size = sizeof(rr_pool_unit_header_s) + item_size;
|
|
||||||
slot_size = (slot_size + (32 - slot_size % 32));
|
|
||||||
|
|
||||||
rr_pool_s pool;
|
|
||||||
pool.allocator = allocator;
|
|
||||||
pool.allocation = rr_alloc(allocator, slot_size * capacity);
|
|
||||||
pool.item_size = item_size;
|
|
||||||
pool.capacity = capacity;
|
|
||||||
pool.first_free = pool.allocation;
|
|
||||||
rr_initialize_pool_allocation(&pool);
|
|
||||||
|
|
||||||
rr_generic_pool_s generic_pool;
|
|
||||||
generic_pool.fn_alloc = &rr_pool_alloc_slot;
|
|
||||||
generic_pool.fn_free = &rr_pool_free_slot;
|
|
||||||
generic_pool.fn_destruct = &rr_destruct_pool;
|
|
||||||
return generic_pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rr_destruct_pool(rr_generic_pool_s *generic_pool)
|
|
||||||
{
|
|
||||||
rr_pool_s *specifics = generic_pool->specifics;
|
|
||||||
rr_free(specifics->allocator, specifics->allocation);
|
|
||||||
rr_free(specifics->allocator, specifics);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void * rr_pool_alloc_slot(rr_generic_pool_s *generic_pool)
|
|
||||||
{
|
|
||||||
rr_pool_s *specifics = generic_pool->specifics;
|
|
||||||
rr_pool_unit_header_s *header = specifics->first_free;
|
|
||||||
specifics->first_free = header->next;
|
|
||||||
void *item = header + sizeof(rr_pool_unit_header_s);
|
|
||||||
rr_memset(item, specifics->item_size, 0x00);
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rr_pool_free_slot(rr_generic_pool_s *generic_pool, void *block)
|
|
||||||
{
|
|
||||||
rr_pool_s *specifics = generic_pool->specifics;
|
|
||||||
rr_pool_unit_header_s *header = block - sizeof(rr_pool_unit_header_s);
|
|
||||||
header->next = specifics->first_free;
|
|
||||||
specifics->first_free = header;
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
#include <librr/alloc/generic.h>
|
|
||||||
#include <alloc/pool.h>
|
|
||||||
#include <alloc/arena.h>
|
|
||||||
|
|
||||||
#ifndef __RR_BAREMETAL
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/// @brief An allocator for the sole purpose of preventing warnings because of an unused
|
|
||||||
/// parameter in the standard allocator proxying functions.
|
|
||||||
rr_generic_allocator_s *rr_last_used_proxy_allocator;
|
|
||||||
|
|
||||||
void * rr_proxy_malloc(rr_generic_allocator_s *allocator, usz_t num_bytes)
|
|
||||||
{
|
|
||||||
rr_last_used_proxy_allocator = allocator;
|
|
||||||
return malloc(num_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rr_proxy_free(rr_generic_allocator_s *allocator, void *block)
|
|
||||||
{
|
|
||||||
rr_last_used_proxy_allocator = allocator;
|
|
||||||
free(block);
|
|
||||||
}
|
|
||||||
|
|
||||||
rr_generic_allocator_s rr_provide_stdlib_allocator()
|
|
||||||
{
|
|
||||||
rr_generic_allocator_s allocator;
|
|
||||||
allocator.fn_alloc = &rr_proxy_malloc;
|
|
||||||
allocator.fn_free = &rr_proxy_free;
|
|
||||||
allocator.specifics = NULL;
|
|
||||||
allocator.fn_destruct = NULL;
|
|
||||||
return allocator;
|
|
||||||
}
|
|
||||||
#endif // __RR_BAREMETAL
|
|
||||||
|
|
||||||
rr_generic_arena_s rr_provide_arena(rr_generic_allocator_s *allocator, usz_t len_allocation)
|
|
||||||
{
|
|
||||||
return rr_new_arena(allocator, len_allocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
rr_generic_pool_s rr_provide_dynamic_pool(rr_generic_allocator_s *allocator, usz_t item_size, usz_t capacity)
|
|
||||||
{
|
|
||||||
return rr_new_dynamic_pool(allocator, item_size, capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
rr_generic_pool_s rr_provide_static_pool(rr_generic_allocator_s *allocator, usz_t item_size, usz_t capacity)
|
|
||||||
{
|
|
||||||
return rr_new_dynamic_pool(allocator, item_size, capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
rr_generic_arena_s rr_provide_arena_from_malloc(usz_t len_allocation)
|
|
||||||
{
|
|
||||||
rr_generic_allocator_s allocator = rr_provide_stdlib_allocator();
|
|
||||||
return rr_new_arena(&allocator, len_allocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
rr_generic_pool_s rr_provide_dynamic_pool_from_malloc(usz_t item_size, usz_t capacity)
|
|
||||||
{
|
|
||||||
rr_generic_allocator_s allocator = rr_provide_stdlib_allocator();
|
|
||||||
return rr_new_dynamic_pool(&allocator, item_size, capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
rr_generic_pool_s rr_provide_static_pool_from_malloc(usz_t item_size, usz_t capacity)
|
|
||||||
{
|
|
||||||
rr_generic_allocator_s allocator = rr_provide_stdlib_allocator();
|
|
||||||
return rr_new_static_pool(&allocator, item_size, capacity);
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
#include <librr/alloc/generic.h>
|
|
||||||
|
|
||||||
void * rr_alloc(rr_generic_allocator_s *allocator, usz_t size)
|
|
||||||
{
|
|
||||||
return allocator->fn_alloc(allocator, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rr_free(rr_generic_allocator_s *allocator, void *allocation)
|
|
||||||
{
|
|
||||||
return allocator->fn_free(allocator, allocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void * rr_arena_alloc(rr_generic_arena_s *arena, usz_t size)
|
|
||||||
{
|
|
||||||
return arena->fn_alloc(arena, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void * rr_pool_alloc(rr_generic_pool_s *pool)
|
|
||||||
{
|
|
||||||
return pool->fn_alloc(pool);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rr_pool_free(rr_generic_pool_s *pool, void *allocation)
|
|
||||||
{
|
|
||||||
return pool->fn_free(pool, allocation);
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
#include <librr/fs/quick.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
usz_t rr_get_file_length(const char *path)
|
|
||||||
{
|
|
||||||
FILE *file = fopen(path, "rb");
|
|
||||||
if(file == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fseek(file, 0, SEEK_END);
|
|
||||||
usz_t length = ftell(file);
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void * rr_load_whole_file(const char *path)
|
|
||||||
{
|
|
||||||
FILE *file = fopen(path, "rb");
|
|
||||||
if(file == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
fseek(file, 0, SEEK_END);
|
|
||||||
usz_t length = ftell(file);
|
|
||||||
fseek(file, 0, SEEK_SET);
|
|
||||||
|
|
||||||
char *data = malloc(length+1);
|
|
||||||
usz_t read_length = fread(data, length, 1, file);
|
|
||||||
if(read_length < length)
|
|
||||||
data = realloc(data, read_length);
|
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
Loading…
Reference in New Issue