Files
git/reftable/basics.c
Patrick Steinhardt 81eddda540 reftable/basics: provide new reftable_buf interface
Implement a new `reftable_buf` interface that will replace Git's own
`strbuf` interface. This is done due to three reasons:

  - The `strbuf` interfaces do not handle memory allocation failures and
    instead causes us to die. This is okay in the context of Git, but is
    not in the context of the reftable library, which is supposed to be
    usable by third-party applications.

  - The `strbuf` interface is quite deeply tied into Git, which makes it
    hard to use the reftable library as a standalone library. Any
    dependent would have to carefully extract the relevant parts of it
    to make things work, which is not all that sensible.

  - The `strbuf` interface does not use the pluggable allocators that
    can be set up via `reftable_set_alloc()`.

So we have good reasons to use our own type, and the implementation is
rather trivial. Implement our own type. Conversion of the reftable
library will be handled in subsequent commits.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2024-10-17 16:59:55 -04:00

285 lines
5.1 KiB
C

/*
Copyright 2020 Google LLC
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/
#define REFTABLE_ALLOW_BANNED_ALLOCATORS
#include "basics.h"
#include "reftable-basics.h"
#include "reftable-error.h"
static void *(*reftable_malloc_ptr)(size_t sz);
static void *(*reftable_realloc_ptr)(void *, size_t);
static void (*reftable_free_ptr)(void *);
void *reftable_malloc(size_t sz)
{
if (reftable_malloc_ptr)
return (*reftable_malloc_ptr)(sz);
return malloc(sz);
}
void *reftable_realloc(void *p, size_t sz)
{
if (reftable_realloc_ptr)
return (*reftable_realloc_ptr)(p, sz);
return realloc(p, sz);
}
void reftable_free(void *p)
{
if (reftable_free_ptr)
reftable_free_ptr(p);
else
free(p);
}
void *reftable_calloc(size_t nelem, size_t elsize)
{
void *p;
if (nelem && elsize > SIZE_MAX / nelem)
return NULL;
p = reftable_malloc(nelem * elsize);
if (!p)
return NULL;
memset(p, 0, nelem * elsize);
return p;
}
char *reftable_strdup(const char *str)
{
size_t len = strlen(str);
char *result = reftable_malloc(len + 1);
if (!result)
return NULL;
memcpy(result, str, len + 1);
return result;
}
void reftable_set_alloc(void *(*malloc)(size_t),
void *(*realloc)(void *, size_t), void (*free)(void *))
{
reftable_malloc_ptr = malloc;
reftable_realloc_ptr = realloc;
reftable_free_ptr = free;
}
void reftable_buf_init(struct reftable_buf *buf)
{
struct reftable_buf empty = REFTABLE_BUF_INIT;
*buf = empty;
}
void reftable_buf_release(struct reftable_buf *buf)
{
reftable_free(buf->buf);
reftable_buf_init(buf);
}
void reftable_buf_reset(struct reftable_buf *buf)
{
if (buf->alloc) {
buf->len = 0;
buf->buf[0] = '\0';
}
}
int reftable_buf_setlen(struct reftable_buf *buf, size_t len)
{
if (len > buf->len)
return -1;
if (len == buf->len)
return 0;
buf->buf[len] = '\0';
buf->len = len;
return 0;
}
int reftable_buf_cmp(const struct reftable_buf *a, const struct reftable_buf *b)
{
size_t len = a->len < b->len ? a->len : b->len;
if (len) {
int cmp = memcmp(a->buf, b->buf, len);
if (cmp)
return cmp;
}
return a->len < b->len ? -1 : a->len != b->len;
}
int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len)
{
size_t newlen = buf->len + len;
if (newlen + 1 > buf->alloc) {
char *reallocated = buf->buf;
REFTABLE_ALLOC_GROW(reallocated, newlen + 1, buf->alloc);
if (!reallocated)
return REFTABLE_OUT_OF_MEMORY_ERROR;
buf->buf = reallocated;
}
memcpy(buf->buf + buf->len, data, len);
buf->buf[newlen] = '\0';
buf->len = newlen;
return 0;
}
int reftable_buf_addstr(struct reftable_buf *buf, const char *s)
{
return reftable_buf_add(buf, s, strlen(s));
}
char *reftable_buf_detach(struct reftable_buf *buf)
{
char *result = buf->buf;
reftable_buf_init(buf);
return result;
}
void put_be24(uint8_t *out, uint32_t i)
{
out[0] = (uint8_t)((i >> 16) & 0xff);
out[1] = (uint8_t)((i >> 8) & 0xff);
out[2] = (uint8_t)(i & 0xff);
}
uint32_t get_be24(uint8_t *in)
{
return (uint32_t)(in[0]) << 16 | (uint32_t)(in[1]) << 8 |
(uint32_t)(in[2]);
}
void put_be16(uint8_t *out, uint16_t i)
{
out[0] = (uint8_t)((i >> 8) & 0xff);
out[1] = (uint8_t)(i & 0xff);
}
size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args)
{
size_t lo = 0;
size_t hi = sz;
/* Invariants:
*
* (hi == sz) || f(hi) == true
* (lo == 0 && f(0) == true) || fi(lo) == false
*/
while (hi - lo > 1) {
size_t mid = lo + (hi - lo) / 2;
int ret = f(mid, args);
if (ret < 0)
return sz;
if (ret > 0)
hi = mid;
else
lo = mid;
}
if (lo)
return hi;
return f(0, args) ? 0 : 1;
}
void free_names(char **a)
{
char **p;
if (!a) {
return;
}
for (p = a; *p; p++) {
reftable_free(*p);
}
reftable_free(a);
}
size_t names_length(const char **names)
{
const char **p = names;
while (*p)
p++;
return p - names;
}
char **parse_names(char *buf, int size)
{
char **names = NULL;
size_t names_cap = 0;
size_t names_len = 0;
char *p = buf;
char *end = buf + size;
while (p < end) {
char *next = strchr(p, '\n');
if (next && next < end) {
*next = 0;
} else {
next = end;
}
if (p < next) {
char **names_grown = names;
REFTABLE_ALLOC_GROW(names_grown, names_len + 1, names_cap);
if (!names_grown)
goto err;
names = names_grown;
names[names_len] = reftable_strdup(p);
if (!names[names_len++])
goto err;
}
p = next + 1;
}
REFTABLE_REALLOC_ARRAY(names, names_len + 1);
names[names_len] = NULL;
return names;
err:
for (size_t i = 0; i < names_len; i++)
reftable_free(names[i]);
reftable_free(names);
return NULL;
}
int names_equal(const char **a, const char **b)
{
size_t i = 0;
for (; a[i] && b[i]; i++)
if (strcmp(a[i], b[i]))
return 0;
return a[i] == b[i];
}
int common_prefix_size(struct strbuf *a, struct strbuf *b)
{
int p = 0;
for (; p < a->len && p < b->len; p++) {
if (a->buf[p] != b->buf[p])
break;
}
return p;
}
int hash_size(uint32_t id)
{
switch (id) {
case 0:
case GIT_SHA1_FORMAT_ID:
return GIT_SHA1_RAWSZ;
case GIT_SHA256_FORMAT_ID:
return GIT_SHA256_RAWSZ;
}
abort();
}