-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathtinystring.c
More file actions
80 lines (64 loc) · 2.32 KB
/
tinystring.c
File metadata and controls
80 lines (64 loc) · 2.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// C string library
// - rlyeh, public domain
// temporary strings api (stack)
char* strtmp(const char *fmt, ...);
int stristmp(const char *s);
// allocated strings api (heap)
#define strnew(fmt, ...) strdup(strtmp(fmt,__VA_ARGS__))
#define strdel(s) ((stristmp(s) ? (void)0 : free(s)), (s)=0)
// implementation --------------------------------------------------------------
#if defined _MSC_VER && !defined __thread
#define __thread __declspec(thread)
#endif
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
int stristmp(const char *s) { // is_va()
return (1&(uintptr_t)s) && s[-1] == 0;
}
char* strtmp(const char *fmt, ...) { // va()
va_list vl;
va_start(vl, fmt);
int sz = vsnprintf( 0, 0, fmt, vl ) + 1;
va_end(vl);
int reqlen = sz + 1; // 1 for even padding
char* ptr;
enum { STACK_ALLOC = 16384 };
if( reqlen < STACK_ALLOC ) { // fit stack?
static __thread char buf[STACK_ALLOC+1];
static __thread int cur = 1, len = STACK_ALLOC;
ptr = buf + ((cur+reqlen) > len ? cur = 1 : (cur += reqlen) - reqlen);
} else { // else use heap (@fixme: single memleak per invoking thread)
static __thread char *buf = 0;
static __thread int cur = 1, len = -STACK_ALLOC;
if( reqlen >= len ) buf = realloc(buf, len = abs(len) * 1.75 + reqlen);
ptr = buf + ((cur+reqlen) > len ? cur = 1 : (cur += reqlen) - reqlen);
}
ptr += !(1&(uintptr_t)ptr); // align to even address only when already odd
ptr[-1] = 0; // add header
assert(stristmp(ptr));
va_start(vl,fmt);
vsnprintf( ptr, sz, fmt, vl );
va_end(vl);
return (char *)ptr;
}
/*
int main() {
// creation
char *x = strtmp("hello %d", 123); puts(x);
char *y = strnew("hello %d", 123); puts(y);
assert(strcmp(x,y)==0);
// destruction
// strdel(x); assert(x == 0); // optional free, since x is a temporary string (strtmp)
strdel(y); assert(y == 0); // required free, since y was explicitly allocated (with strnew)
// test concat
char *z = strtmp("%d",6); z = strtmp("%s%s%s",z,z,z); assert( 0 == strcmp(z,"666") );
// test memory is never exhausted
for(int i = 0; i < 10000; ++i) assert(strtmp("hello %d",123));
// test asserts are enabled
assert(~puts("Ok"));
}
*/