*
* Copyright (C) 2019 and up by Alexander Pevzner (pzz@apevzner.com)
* See LICENSE for license terms and conditions
*
* Memory allocation and strings
*/
#include "airscan.h"
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
* MEM_CAP_BLOCK is reached, then it grows linearly,
* reminding a multiple of whole MEM_CAP_BLOCKs
*/
#define MEM_CAP_BLOCK 65536
* control record
*/
typedef struct {
uint32_t len, cap;
} mem_head;
*/
#define mem_check_oom(p,must) \
do{ \
if ((p) == NULL && must) { \
log_panic(NULL, "Out of memory"); \
__builtin_unreachable(); \
} \
} while(0)
*/
void
mem_trunc (void *p)
{
((mem_head*) p)[-1].len = 0;
}
*/
void
mem_free (void *p)
{
if (p != NULL) {
free(((mem_head*) p) - 1);
}
}
*/
size_t
mem_len_bytes (const void *p)
{
return p ? ((mem_head*) p)[-1].len : 0;
}
*/
size_t
mem_cap_bytes (const void *p)
{
return p ? ((mem_head*) p)[-1].cap : 0;
}
*/
static inline int
mem_alloc_size(size_t len, size_t extra, size_t elsize)
{
size_t sz = sizeof(mem_head) + elsize * (len + extra);
if (sz < MEM_CAP_BLOCK) {
sz --;
sz |= sz >> 1;
sz |= sz >> 2;
sz |= sz >> 4;
sz |= sz >> 8;
sz |= sz >> 16;
sz ++;
} else {
sz += MEM_CAP_BLOCK - 1;
sz &= ~(MEM_CAP_BLOCK - 1);
}
return sz;
}
*/
void*
__mem_alloc (size_t len, size_t extra, size_t elsize, bool must)
{
size_t sz = mem_alloc_size(len, extra, elsize);
mem_head *h = calloc(sz, 1);
if (h == NULL) {
mem_check_oom(h, must);
return NULL;
}
h->len = len * elsize;
h->cap = sz - (sizeof(mem_head));
return h + 1;
}
* Allocated or resizes memory block
*/
void*
__mem_resize (void *p, size_t len, size_t extra, size_t elsize, bool must)
{
size_t sz;
mem_head *h;
if (p == NULL) {
return __mem_alloc(len, extra, elsize, must);
}
h = ((mem_head*) p) - 1;
sz = mem_alloc_size(len, extra, elsize);
if (h->cap + sizeof(mem_head) < sz) {
h = realloc(h, sz);
if (h == NULL) {
mem_check_oom(h, must);
return NULL;
}
}
len *= elsize;
if (len > h->len) {
memset((char*) (h + 1) + h->len, 0, len - h->len);
}
h->len = len;
h->cap = sz - (sizeof(mem_head));
return h + 1;
}
* Shrinks memory block
*/
void
__mem_shrink (void *p, size_t len, size_t elsize)
{
mem_head *h = ((mem_head*) p) - 1;
len *= elsize;
log_assert(NULL, len <= h->len);
h->len = len;
}
*/
char*
str_dup_tolower (const char *s1)
{
char *s = str_dup(s1);
size_t i;
for (i = 0; s[i]; i ++) {
s[i] = safe_tolower(s[i]);
}
return s;
}
*/
char*
str_printf (const char *format, ...)
{
va_list ap;
char *s;
va_start(ap, format);
s = str_append_vprintf(NULL, format, ap);
va_end(ap);
return s;
}
*/
char*
str_vprintf (const char *format, va_list ap)
{
return str_append_vprintf(NULL, format, ap);
}
*
* `s' must be previously created by some of str_XXX functions,
* `s' will be consumed and the new pointer will be returned
*/
char*
str_append_printf (char *s, const char *format, ...)
{
va_list ap;
va_start(ap, format);
s = str_append_vprintf(s, format, ap);
va_end(ap);
return s;
}
*/
char*
str_append_vprintf (char *s, const char *format, va_list ap)
{
char buf[4096];
size_t len, oldlen;
va_list ap2;
va_copy(ap2, ap);
len = vsnprintf(buf, sizeof(buf), format, ap2);
va_end(ap2);
if (len < sizeof(buf)) {
return str_append_mem(s, buf, len);
}
oldlen = mem_len(s);
s = mem_resize(s, oldlen + len, 1);
va_copy(ap2, ap);
vsnprintf(s + oldlen, len + 1, format, ap2);
va_end(ap2);
return s;
}
* The returned pointer must be eventually freed by mem_free
*/
char*
str_concat (const char *s, ...)
{
va_list ap;
char *ret = str_dup(s);
va_start(ap, s);
while ((s = va_arg(ap, const char*)) != NULL) {
ret = str_append(ret, s);
}
va_end(ap);
return ret;
}
*/
bool
str_has_prefix (const char *s, const char *prefix)
{
size_t l1 = strlen(s);
size_t l2 = strlen(prefix);
return l1 >= l2 && !memcmp(s, prefix, l2);
}
*/
bool
str_has_suffix (const char *s, const char *suffix)
{
size_t l1 = strlen(s);
size_t l2 = strlen(suffix);
return l1 >= l2 && !memcmp(s + (l1 - l2), suffix, l2);
}
* This function modifies string in place, and returns pointer
* to original string, for convenience
*/
char*
str_trim (char *s)
{
size_t len = strlen(s), skip;
while (len > 0 && safe_isspace(s[len - 1])) {
len --;
}
for (skip = 0; skip < len && safe_isspace(s[skip]); skip ++) {
;
}
len -= skip;
if (len != 0 && skip != 0) {
memmove(s, s + skip, len);
}
s[len] = '\0';
return s;
}
*/