/*
* Tiny String Library
*/
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#if 0
# define __atomic_fetch_add __sync_fetch_and_add
#elif 1
size_t __atomic_fetch_add(volatile size_t *x, size_t n) {
size_t i;
i = *x;
*x += n;
return i;
}
#endif
typedef union { void *p; size_t n; } ptradr_t;
struct string_s {
int refcnt;
size_t capacity, length;
struct string_s *prev, *next;
char *data;
};
typedef struct string_s *string_t;
struct string_s *g_str_head = (struct string_s *)0;
struct string_s *g_str_tail = (struct string_s *)0;
struct string_s *g_strar_head = (struct string_s *)0;
struct string_s *g_strar_tail = (struct string_s *)0;
void *memory(void *p, size_t n) {
return !p&&n ? malloc(n) : p&&n ? realloc(p, n) : p&&!n ? (free(p), (void *)0) : (void *)0;
}
string_t newstring(const char *src) {
string_t str;
size_t l;
src = src ? src : "";
l = strlen(src) + 1;
if (!(str = (string_t)memory((void *)0, sizeof(*str))))
return (string_t)0;
str->capacity = (l - l%64) + 64;
if (!(str->data = (char *)memory((void *)0, str->capacity))) {
memory((void *)str, 0);
return (string_t)0;
}
str->refcnt = 1;
str->length = l - 1;
str->next = (struct string_s *)0;
if ((str->prev = g_str_tail) != (struct string_s *)0)
g_str_tail->next = str;
else
g_str_head = str;
memcpy((void *)str->data, (const void *)src, l);
return str;
}
string_t deletestring(string_t str) {
if (!str)
return (string_t)0;
if (str->prev)
str->prev->next = str->next;
if (str->next)
str->next->prev = str->prev;
if (g_str_head==str)
g_str_head = str->next;
if (g_str_tail==str)
g_str_tail = str->prev;
if (g_strar_head==str)
g_strar_head = str->next;
if (g_strar_tail==str)
g_strar_tail = str->prev;
str->refcnt = 0;
str->capacity = 0;
str->length = 0;
str->data = (char *)memory((void *)str->data, 0);
return (string_t)memory((void *)str, 0);
}
void setstring(string_t dst, const char *src) {
size_t l;
if (!dst || !src)
return;
src = src ? src : "";
l = strlen(src) + 1;
if (l > dst->capacity) {
dst->capacity = (l - l%64) + 64; /*round up to next boundary*/
dst->data = (char *)memory((void *)dst->data, dst->capacity);
}
dst->length = l - 1;
memcpy((void *)dst->data, (const void *)src, l);
}
size_t stringcapacity(string_t str) {
return str ? str->capacity : 0;
}
size_t stringlength(string_t str) {
return str ? str->length : 0;
}
void retainstring(string_t str) {
if (!str)
return;
str->refcnt++;
}
string_t releasestring(string_t str) {
if (str)
if (--str->refcnt<=0)
return deletestring(str);
return (string_t)0;
}
char *stringdata(string_t str) {
return str ? str->data : (char *)0;
}
const char *cstring(string_t str) {
return str ? (const char *)str->data : "";
}
string_t copycstring(const char *cstr) {
return newstring(cstr);
}
string_t copystring(string_t str) {
return newstring(cstring(str));
}
bool appendcstring(string_t str, const char *cstr) {
size_t l, n;
if (!str)
return newstring(cstr);
if (!(l = strlen(cstr ? cstr : "")))
return false;
if (str->length + l + 1 > str->capacity) {
n = str->length + l + 1;
str->capacity = (n - n%64) + 64;
str->data = (char *)memory((void *)str->data, str->capacity);
if (!str->data)
return false;
}
memcpy(&str->data[str->length], (const void *)cstr, l + 1);
str->length += l;
return true;
}
bool appendstring(string_t dst, string_t src) {
return appendcstring(dst, cstring(src));
}
string_t vformat(const char *f, va_list v) {
#define L 0x1000
#define N 128
static char buf[L*N];
static size_t i = 0;
size_t I;
I = __atomic_fetch_add(&i, 1) % N;
vsnprintf(&buf[I*L], L-1, f, v);
buf[I*L + L - 1] = 0;
return newstring(&buf[I*L]);
#undef N
#undef L
}
string_t format(const char *f, ...) {
string_t s;
va_list v;
va_start(v, f);
s = vformat(f, v);
va_end(v);
return s;
}
const char *removestring(string_t str) {
if (!str)
return "";
if (str->prev)
str->prev->next = str->next;
if (str->next)
str->next->prev = str->prev;
if (g_str_head==str)
g_str_head = str->next;
if (g_str_tail==str)
g_str_tail = str->prev;
str->next = (string_t)0;
if ((str->prev = g_strar_tail) != (struct string_s *)0)
g_strar_tail->next = str;
else
g_strar_head = str;
g_strar_tail = str;
str->refcnt = 0;
return str->data ? (const char *)str->data : "";
}
void deleteremovedstrings() {
string_t str, next;
for(str=g_strar_head; str; str=next) {
next = str->next;
deletestring(str);
}
}
void deleteallstrings() {
deleteremovedstrings();
while(g_str_head)
deletestring(g_str_head);
}
int main() {
string_t str;
atexit(deleteallstrings);
str = newstring("Hello, world!");
printf("%s", removestring(format("%s\n", removestring(str))));
return 0;
}