nstr: Make cloning zero-copy

This commit is contained in:
anna 2021-07-22 14:15:25 +02:00
parent d504786bc7
commit cf4bd2ea5b
Signed by: fef
GPG key ID: EC22E476DC2D3D84
5 changed files with 42 additions and 18 deletions

View file

@ -109,7 +109,7 @@ nstr_t *u2nstr(u64 u, int radix, error *err);
* @param err: Error pointer
* @returns The duplicated string, unless an error occurred
*/
nstr_t *nstrdup(const nstr_t *s, error *err);
nstr_t *nstrdup(nstr_t *s, error *err);
/**
* Repeat a string `n` times and return the new string.
@ -123,7 +123,7 @@ nstr_t *nstrdup(const nstr_t *s, error *err);
* @param err: Error pointer
* @returns A new string with the repeated content, unless an error occurred
*/
nstr_t *nstrmul(const nstr_t *s, usize n, error *err);
nstr_t *nstrmul(nstr_t *s, usize n, error *err);
/**
* Create a string considting of `n` repetitions of `c`.
@ -205,6 +205,9 @@ nstr_t *leftpad(const nstr_t *s, usize length, nchar fill, error *err);
*__pos != '\0' && (err) != nil && (err)->_number + 1 < 2; \
__pos += utf8_to_nchr(cursor, __pos, err))
/** Internal callback for nref */
void _neo_nstr_destroy(nstr_t *s);
/*
* This file is part of libneo.
* Copyright (c) 2021 Fefie <owo@fef.moe>.

View file

@ -80,7 +80,12 @@ struct _neo_nstr {
NREF_FIELD;
/* physical size in bytes, including the four NUL terminators */
usize _size;
char *_data;
/**
* If this string was cloned or converted from a buffer, this points to
* the original structure's refcounter. Otherwise, it is nil.
*/
nref_t *_borrow;
const char *_data;
};
typedef struct _neo_nstr nstr_t;

View file

@ -14,12 +14,14 @@
#include "neo/_types.h"
#include "neo/utf.h"
static void nstr_destroy(nstr_t *str)
void _neo_nstr_destroy(nstr_t *str)
{
if (str->_borrow != nil)
_neo_nput(str->_borrow);
nfree(str);
}
static nstr_t *nstr_unsafe(const char *restrict s, usize size_without_nul, error *err)
static nstr_t *nstr_unsafe(const char *s, usize size_without_nul, error *err)
{
usize len = utf8_ncheck(s, size_without_nul, err);
catch(err) {
@ -49,16 +51,16 @@ static nstr_t *nstr_unsafe(const char *restrict s, usize size_without_nul, error
* stored immediately after the string itself. This also saves us an
* additional memory allocation.
*/
str->_data = (char *)str + sizeof(*str);
str->_len = len;
str->_size = size_without_nul + 4;
nref_init(str, nstr_destroy);
char *data = (char *)str + sizeof(*str);
memcpy(data, s, size_without_nul);
for (unsigned int i = 0; i < 4; i++)
data[size_without_nul + i] = '\0';
memcpy(str->_data, s, size_without_nul);
str->_data[size_without_nul] = '\0';
str->_data[size_without_nul + 1] = '\0';
str->_data[size_without_nul + 2] = '\0';
str->_data[size_without_nul + 3] = '\0';
str->_data = data;
str->_len = len;
str->_borrow = nil;
str->_size = size_without_nul + 4;
nref_init(str, _neo_nstr_destroy);
return str;
}
@ -97,7 +99,7 @@ nchar nchrat(const nstr_t *s, usize index, error *err)
return '\0';
}
char *ptr = s->_data;
const char *ptr = s->_data;
while (index != 0)
index -= (*ptr++ & 0xc0) != 0x80;
ptr--;

View file

@ -3,17 +3,31 @@
#include <errno.h>
#include "neo/_error.h"
#include "neo/_nalloc.h"
#include "neo/_nref.h"
#include "neo/_nstr.h"
#include "neo/_types.h"
nstr_t *nstrdup(const nstr_t *s, error *err)
nstr_t *nstrdup(nstr_t *s, error *err)
{
if (s == nil) {
yeet(err, EFAULT, "String is nil");
return nil;
}
return nstr(s->_data, err);
nstr_t *copy = nalloc(sizeof(*copy), err);
catch(err) {
return nil;
}
nget(s);
copy->_len = s->_len;
copy->_size = s->_size;
copy->_borrow = &s->__neo_nref;
copy->_data = s->_data;
nref_init(copy, _neo_nstr_destroy);
return copy;
}
/*

View file

@ -11,7 +11,7 @@
#include "neo/_types.h"
#include "neo/utf.h"
nstr_t *nstrmul(const nstr_t *s, usize n, error *err)
nstr_t *nstrmul(nstr_t *s, usize n, error *err)
{
if (s == nil) {
yeet(err, EFAULT, "String is nil");