mirror of
https://github.com/kmod-project/kmod.git
synced 2026-01-26 15:39:08 +00:00
If strbuf is used (depmod, modprobe -c) then strbuf_reserve_extra is performance critical. This reduces amount of instructions for modprobe -c by around 10 %, the total instruction count for depmod by 1 % (majority is within reading module files). Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org> Link: https://github.com/kmod-project/kmod/pull/296 Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
123 lines
2.0 KiB
C
123 lines
2.0 KiB
C
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
/*
|
|
* Copyright (C) 2011-2013 ProFUSION embedded systems
|
|
* Copyright (C) 2014 Intel Corporation. All rights reserved.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/param.h>
|
|
|
|
#include "util.h"
|
|
#include "strbuf.h"
|
|
|
|
#define BUF_STEP 128
|
|
|
|
static bool buf_realloc(struct strbuf *buf, size_t sz)
|
|
{
|
|
void *tmp = realloc(buf->heap ? buf->bytes : NULL, sz);
|
|
|
|
if (sz > 0) {
|
|
if (tmp == NULL)
|
|
return false;
|
|
|
|
if (!buf->heap)
|
|
memcpy(tmp, buf->bytes, MIN(buf->size, sz));
|
|
}
|
|
|
|
buf->heap = true;
|
|
buf->bytes = tmp;
|
|
buf->size = sz;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool strbuf_reserve_extra(struct strbuf *buf, size_t n)
|
|
{
|
|
if (n < buf->size - buf->used)
|
|
return true;
|
|
|
|
if (uaddsz_overflow(buf->used, n, &n) || n >= SIZE_MAX - BUF_STEP)
|
|
return false;
|
|
|
|
if (++n % BUF_STEP)
|
|
n = ((n / BUF_STEP) + 1) * BUF_STEP;
|
|
|
|
return buf_realloc(buf, n);
|
|
}
|
|
|
|
void strbuf_init(struct strbuf *buf)
|
|
{
|
|
buf->bytes = NULL;
|
|
buf->size = 0;
|
|
buf->used = 0;
|
|
buf->heap = true;
|
|
}
|
|
|
|
void strbuf_release(struct strbuf *buf)
|
|
{
|
|
if (buf->heap)
|
|
free(buf->bytes);
|
|
}
|
|
|
|
const char *strbuf_str(struct strbuf *buf)
|
|
{
|
|
if (!buf->used)
|
|
return "";
|
|
|
|
if (buf->bytes[buf->used - 1])
|
|
buf->bytes[buf->used] = '\0';
|
|
return buf->bytes;
|
|
}
|
|
|
|
bool strbuf_pushchar(struct strbuf *buf, char ch)
|
|
{
|
|
if (!strbuf_reserve_extra(buf, 1))
|
|
return false;
|
|
buf->bytes[buf->used] = ch;
|
|
buf->used++;
|
|
return true;
|
|
}
|
|
|
|
size_t strbuf_pushmem(struct strbuf *buf, const char *src, size_t sz)
|
|
{
|
|
assert(src != NULL);
|
|
assert(buf != NULL);
|
|
|
|
if (sz == 0)
|
|
return 0;
|
|
|
|
if (!strbuf_reserve_extra(buf, sz))
|
|
return 0;
|
|
|
|
memcpy(buf->bytes + buf->used, src, sz);
|
|
buf->used += sz;
|
|
|
|
return sz;
|
|
}
|
|
|
|
void strbuf_popchar(struct strbuf *buf)
|
|
{
|
|
assert(buf->used > 0);
|
|
buf->used--;
|
|
}
|
|
|
|
void strbuf_popchars(struct strbuf *buf, size_t n)
|
|
{
|
|
assert(buf->used >= n);
|
|
buf->used -= n;
|
|
}
|
|
|
|
void strbuf_shrink_to(struct strbuf *buf, size_t sz)
|
|
{
|
|
assert(buf->used >= sz);
|
|
buf->used = sz;
|
|
}
|
|
|
|
void strbuf_clear(struct strbuf *buf)
|
|
{
|
|
buf->used = 0;
|
|
}
|