rewrite GC

This commit is contained in:
yoyo 2024-09-04 12:20:58 +09:00
parent 275c03f518
commit 8c3a666975
9 changed files with 228 additions and 312 deletions

46
bltin.c
View File

@ -1,28 +1,28 @@
#include "dat.h" #include "dat.h"
#include "fn.h" #include "fn.h"
Object Nil = (Object){.type=OSYMBOL, .sym="nil"}; Object Nil = (Object){.type=OSYMBOL, .beg="nil"};
Object Minus= (Object){.type=OBLTIN, .sym="-"}; Object Minus= (Object){.type=OBLTIN, .beg="-"};
Object Plus = (Object){.type=OBLTIN, .sym="+"}; Object Plus = (Object){.type=OBLTIN, .beg="+"};
Object Mul = (Object){.type=OBLTIN, .sym="*"}; Object Mul = (Object){.type=OBLTIN, .beg="*"};
Object Div = (Object){.type=OBLTIN, .sym="/"}; Object Div = (Object){.type=OBLTIN, .beg="/"};
Object Mod = (Object){.type=OBLTIN, .sym="%"}; Object Mod = (Object){.type=OBLTIN, .beg="%"};
Object Ge = (Object){.type=OBLTIN, .sym= ">="}; Object Ge = (Object){.type=OBLTIN, .beg= ">="};
Object Le = (Object){.type=OBLTIN, .sym= "<="}; Object Le = (Object){.type=OBLTIN, .beg= "<="};
Object Lt = (Object){.type=OBLTIN, .sym= "<"}; Object Lt = (Object){.type=OBLTIN, .beg= "<"};
Object Gt = (Object){.type=OBLTIN, .sym= ">"}; Object Gt = (Object){.type=OBLTIN, .beg= ">"};
Object Ne = (Object){.type=OBLTIN, .sym= "!="}; Object Ne = (Object){.type=OBLTIN, .beg= "!="};
Object Eq = (Object){.type=OBLTIN, .sym= "=="}; Object Eq = (Object){.type=OBLTIN, .beg= "=="};
Object Lambda= (Object){.type=OBLTIN, .sym="lambda"}; Object Lambda= (Object){.type=OBLTIN, .beg="lambda"};
Object Car = (Object){.type=OBLTIN, .sym="car"}; Object Car = (Object){.type=OBLTIN, .beg="car"};
Object Cdr = (Object){.type=OBLTIN, .sym="cdr"}; Object Cdr = (Object){.type=OBLTIN, .beg="cdr"};
Object Quote= (Object){.type=OBLTIN, .sym="'"}; Object Quote= (Object){.type=OBLTIN, .beg="'"};
Object Cons = (Object){.type=OBLTIN, .sym="cons"}; Object Cons = (Object){.type=OBLTIN, .beg="cons"};
Object Define= (Object){.type=OBLTIN, .sym="define"}; Object Define= (Object){.type=OBLTIN, .beg="define"};
Object Setq = (Object){.type=OBLTIN, .sym="setq"}; Object Setq = (Object){.type=OBLTIN, .beg="setq"};
Object If = (Object){.type=OBLTIN, .sym="if"}; Object If = (Object){.type=OBLTIN, .beg="if"};
extern Object* fnplus(Object *, Object *); extern Object* fnplus(Object *, Object *);
extern Object* fnmul(Object *, Object *); extern Object* fnmul(Object *, Object *);
@ -50,7 +50,7 @@ bltinlookup(Object *obj)
{ {
static struct static struct
{ {
Object *sym; Object *beg;
Bltinfn fn; Bltinfn fn;
}bltins[] = { }bltins[] = {
{&Lambda , fnlambda}, {&Lambda , fnlambda},
@ -75,8 +75,8 @@ bltinlookup(Object *obj)
{0}, {0},
}; };
for(int i = 0; bltins[i].sym; ++i){ for(int i = 0; bltins[i].beg; ++i){
if(obj == bltins[i].sym) if(obj == bltins[i].beg)
return bltins[i].fn; return bltins[i].fn;
} }
return 0; return 0;

48
dat.h
View File

@ -1,19 +1,17 @@
#include <stdint.h> typedef struct GC GC;
typedef uintptr_t u64;
typedef struct Object Object; typedef struct Object Object;
typedef Object* (*Bltinfn)(Object *env, Object *args); typedef Object* (*Bltinfn)(Object *env, Object *args);
enum OType enum OType
{ {
OERROR, ONONE,
OCELL,
OSYMBOL,
OIDENT,
OINT,
OSTRING,
OLAMBDA,
OBLTIN, OBLTIN,
OSYMBOL,
OCELL,
OIDENT,
OSTRING,
OINT,
OLAMBDA,
OFUNC, OFUNC,
OENV, OENV,
}; };
@ -22,7 +20,6 @@ struct Object
{ {
enum OType type; /* type */ enum OType type; /* type */
int flag; /* flag */ int flag; /* flag */
Object *next; /* for gc */
Object *forward; Object *forward;
union{ union{
/* int */ /* int */
@ -32,8 +29,7 @@ struct Object
Object *car; Object *car;
Object *cdr; Object *cdr;
}; };
/* string & ident */ /* string & ident & symbol */
char *sym;
struct{ struct{
char *beg; char *beg;
char *ptr; char *ptr;
@ -54,32 +50,6 @@ struct Object
}; };
}; };
/*
*0 ~ 64 : for object
*64 ~ 100 : for string
*/
typedef struct
{
int running;
void *memory;
u64 cap;
u64 using;
u64 top;
/* objects */
struct{
Object *objs;
Object *freed;
u64 ob;
u64 oe;
u64 op;
};
/* string */
struct{
u64 sb;
u64 se;
};
}GC;
extern GC *gc; extern GC *gc;
extern Object Nil; extern Object Nil;
extern Object Minus; extern Object Minus;

2
eval.c
View File

@ -144,7 +144,7 @@ plusstr(Object *env, Object *p)
for(;p!=&Nil; p=p->cdr){ for(;p!=&Nil; p=p->cdr){
if(p->car->type != OSTRING) if(p->car->type != OSTRING)
error("+ take only number"); error("+ take only number");
strputs(str, p->car->beg); str = strputs(str, p->car);
} }
return str; return str;
} }

10
fn.h
View File

@ -16,16 +16,16 @@ Object* newstr(GC *,int);
Object* newfn(GC *,Object *env, Object *params, Object *body); Object* newfn(GC *,Object *env, Object *params, Object *body);
/* gc.c */ /* gc.c */
Object* newobj(GC *,enum OType);
void* gcalloc(GC *,int);
void* gcralloc(GC *, void*, int);
GC* newgc(void *top, int cap); GC* newgc(void *top, int cap);
void gcrun(GC *); void gcrun(GC *);
void* gcalloc(GC *gc, int sz);
void printgc(char *, GC *);
/* str.c */ /* str.c */
void strputc(Object*, int); Object* strputc(Object*, int);
void strputs(Object*, char*); Object* strputs(Object*, Object*);
int strequal(Object*, Object*); int strequal(Object*, Object*);
void strinit(Object *s, Object *str);
/* error.c */ /* error.c */
void panic(char *fmt, ...); void panic(char *fmt, ...);

340
gc.c
View File

@ -4,50 +4,75 @@
#include <setjmp.h> #include <setjmp.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <assert.h>
#include <stdint.h>
struct GC
{
int running;
int cap;
int using;
uintptr_t *top;
uintptr_t *beg;
uintptr_t *end;
};
enum enum
{ {
USING = 1 << 1, USING = 1 << 1,
FORWARD = 1 << 2, FORWARD = 1 << 2,
OFFSET = sizeof(int), PTR = sizeof(void*),
}; };
static Object*
findobj(GC *gc, uintptr_t *stk)
{
if(gc->beg <= stk && stk < gc->end)
for(uintptr_t *p = gc->beg; p < stk;){
if(*p){
if(p <= stk && stk < p + *p) return (Object*)&p[1];
else p += *p;
}else{
p++;
}
}
return 0;
}
Object* Object*
cloneobj(GC *dst, GC *src, Object *obj) cloneobj(GC *dst, GC *src, Object *obj)
{ {
if(obj == 0) if(obj->type==OBLTIN||obj->type==OSYMBOL) return obj;
return 0; if(obj->flag&FORWARD) return obj->forward;
if(obj->type==OBLTIN||obj->type==OSYMBOL)
return obj; Object *p;
if(obj->flag&FORWARD)
return obj->forward;
Object *p = newobj(dst, obj->type);
obj->flag |= FORWARD; obj->flag |= FORWARD;
obj->forward = p;
switch(obj->type){ switch(obj->type){
default: panic("unreachable"); default: panic("unreachable");
case OINT: case OINT:
p->num = obj->num; obj->forward = p = newint(dst, obj->num);
break; break;
case OSTRING: case OSTRING:
case OIDENT:{ obj->forward = p = newstr(dst, obj->end - obj->beg);
int len = obj->ptr - obj->beg; strinit(p, obj);
p->beg = gcalloc(dst, len + 1); break;
p->end = p->ptr = p->beg + len; case OIDENT:
memcpy(p->beg, obj->beg, len + 1); obj->forward = p = newsymbol(dst, obj->beg, obj->ptr - obj->beg);
break; break;
}
case OCELL: case OCELL:
obj->forward = p = newcons(dst, &Nil, &Nil);
p->car = cloneobj(dst, src, obj->car); p->car = cloneobj(dst, src, obj->car);
p->cdr = cloneobj(dst, src, obj->cdr); p->cdr = cloneobj(dst, src, obj->cdr);
break; break;
case OENV: case OENV:
obj->forward = p = newenv(dst, &Nil, &Nil, &Nil);
p->name = cloneobj(dst, src, obj->name); p->name = cloneobj(dst, src, obj->name);
p->vars = cloneobj(dst, src, obj->vars); p->vars = cloneobj(dst, src, obj->vars);
p->up = cloneobj(dst, src, obj->up); p->up = cloneobj(dst, src, obj->up);
break; break;
case OFUNC: case OFUNC:
obj->forward = p = newfn(dst, &Nil, &Nil, &Nil);
p->params = cloneobj(dst, src, obj->params); p->params = cloneobj(dst, src, obj->params);
p->body = cloneobj(dst, src, obj->body); p->body = cloneobj(dst, src, obj->body);
p->env = cloneobj(dst, src, obj->env); p->env = cloneobj(dst, src, obj->env);
@ -56,138 +81,45 @@ cloneobj(GC *dst, GC *src, Object *obj)
return p; return p;
} }
Object*
moveobj(Object *p)
{
if(p == 0 || p->type == 0)
return 0;
switch(p->type){
default:
return p->forward;
case OBLTIN:
case OSYMBOL:
return p;
}
}
void void
forwardstack(u64 bot, GC *dst, GC *src) gcraise(GC *src)
{ {
u64 pos, diff, *stk; jmp_buf reg;
Object *moved, *org; uintptr_t _ = 0;
for(; bot < src->top; bot += sizeof(bot)){ if(src->running) return;
stk = (u64*)(void**)bot; if(setjmp(reg) == 1) return;
if(src->ob <= *stk && *stk < src->oe){
diff = (*stk - src->ob) % sizeof(Object); GC *dst = newgc(src->top, src->cap * 2);
org = (Object*)(*stk - diff); src->running = dst->running = 1;
if((moved = moveobj(org)) == 0) for(uintptr_t *p = src->beg; p < src->end;)
continue; if(*p){
diff = (u64)org - *stk; cloneobj(dst, src, (Object*)&p[1]);
pos = (u64)moved + diff; p += *p;
memcpy(stk, &pos, sizeof(pos)); }else{
p++;
} }
else if(src->sb <= *stk && *stk < src->se) for(uintptr_t *bot = &_; bot < src->top; bot++){
for(org = src->objs; org; org = org->next){ Object *p = findobj(src, (uintptr_t*)*bot);
if(org->type == OSTRING || org->type == OIDENT){ if(p){
u64 beg = (u64)org->beg - OFFSET; uintptr_t diff = (uintptr_t)p - *bot;
u64 end = beg + *(int*)beg; uintptr_t pos = (uintptr_t)p->forward + diff;
if(beg <= *stk && *stk < end){ memcpy(bot, &pos, PTR);
moved = moveobj(org);
diff = (*stk - beg);
pos = (u64)moved->beg - OFFSET + diff;
memcpy(stk, &pos, sizeof(pos));
break;
}
}
} }
} }
}
void free((void*)src->beg);
gccompact(int cap, GC *src) dst->running = 0;
{
void *_ = 0;
u64 bot = (u64)&_;
GC *dst = newgc((void*)src->top, cap);
dst->running = 1;
for(Object *p=src->objs; p; p=p->next)
cloneobj(dst, src, p);
forwardstack(bot, dst, src);
free(src->memory);
*src = *dst; *src = *dst;
free(dst); free(dst);
} longjmp(reg, 1);
void
gcfree(GC *gc, void *src)
{
int *p = (int*)src - 1;
int sz = *p;
memset(p, 0, sz);
gc->using -= sz;
}
void
freeobj(GC *gc, Object *p)
{
gc->using -= sizeof(Object);
p->next = 0;
switch(p->type){
default:
break;
case OSTRING:
case OIDENT:
gcfree(gc, p->beg);
break;
}
memset(p, 0, sizeof(Object));
if(gc->freed == 0)
gc->freed = p;
else{
p->next = gc->freed;
gc->freed = p;
}
}
void*
gcalloc(GC *gc, int sz)
{
sz += OFFSET;
if(sz % OFFSET) sz = sz + OFFSET - (sz % OFFSET);
for(u64 i = gc->sb; i < gc->se;){
u64 j = i;
for(;j - i < sz; j += OFFSET){
if(*(int*)(j) != 0)
break;
}
if(j - i == sz){
gc->using += sz;
*(int*)i = sz;
i += OFFSET;
return (void*)i;
}
i = j + *(int*)(j);
}
panic("gccalloc : Not impl yet raise");
return 0;
}
void*
gcralloc(GC *gc, void *src, int sz)
{
void *dst = gcalloc(gc, sz);
int osz = ((int*)src)[-1];
memcpy(dst, src, osz);
gcfree(gc, src);
return dst;
} }
void void
mark(GC *gc, Object *obj) mark(GC *gc, Object *obj)
{ {
if(obj == 0 || obj->flag&USING || if(obj->flag&USING||obj->type==ONONE||obj->type==OSYMBOL||obj->type==OBLTIN)
obj->type == 0|| obj->type==OBLTIN ||obj->type==OSYMBOL)
return; return;
obj->flag = USING; obj->flag = USING;
switch(obj->type){ switch(obj->type){
default:break; default:break;
@ -211,91 +143,93 @@ mark(GC *gc, Object *obj)
void void
gcsweep(GC *gc) gcsweep(GC *gc)
{ {
Object *last = 0; for(uintptr_t *p = gc->beg; p < gc->end;)
for(Object *p = gc->objs; p;){ if(*p){
if(p->type == 0|| p->type==OBLTIN ||p->type==OSYMBOL) Object *obj = (Object*)&p[1];
return; if(obj->flag & USING){
if(p->flag&USING){ obj->flag = 0;
p->flag &= ~(USING); p += p[0];
last = p;
p = p->next;
}else{
Object *tmp = p;
if(last == 0){
gc->objs = p->next;
}else{ }else{
last->next = p->next; uintptr_t sz = *p;
memset(p, 0, sz*PTR);
gc->using -= sz*PTR;
p += sz;
} }
p = p->next; }else{
freeobj(gc, tmp); p++;
} }
}
} }
void void
gcmark(GC *gc) gcmark(GC *gc)
{ {
u64 _ = 0, stk, diff; uintptr_t _ = 0;
u64 bot = (u64)&_; for(uintptr_t *bot = &_; bot < gc->top; bot++){
Object *obj; Object *obj = findobj(gc, (uintptr_t*)*bot);
for(; bot < gc->top; bot += sizeof(bot)){ if(obj)
stk = (u64)*(void**)bot;
if(gc->ob <= stk && stk <= gc->oe){
diff = (stk - gc->ob) % sizeof(Object);
obj = (Object*)(stk - diff);
mark(gc, obj); mark(gc, obj);
}
else if(gc->sb <= stk && stk <= gc->se)
for(Object *obj = gc->objs; obj; obj = obj->next)
if(obj->type == OSTRING || obj->type == OIDENT){
u64 beg = (u64)obj->beg - OFFSET;
u64 end = beg + *(int*)beg;
if(beg <= stk && stk < end){
mark(gc, obj);
break;
}
}
} }
} }
void void
gcrun(GC *src) gcrun(GC *gc)
{ {
if(src->running) if(gc->running)
return; return;
printf("BEFORE=> cap:%10ld using:%10ld remain:%10ld\n", src->cap, src->using, src->cap - src->using); printgc("gc-beg", gc);
src->running = 1; gc->running = 1;
jmp_buf reg; jmp_buf reg;
if(setjmp(reg)==1){ if(setjmp(reg)==1){
printf("AFTER => cap:%10ld using:%10ld remain:%10ld\n", src->cap, src->using, src->cap - src->using); gc->running = 0;
src->running = 0; printgc("gc-end", gc);
return; return;
} }
gcmark(src); gcmark(gc);
gcsweep(src); gcsweep(gc);
if(src->using >= src->cap * 0.5){
gccompact(src->cap * 2, src);
}
longjmp(reg, 1); longjmp(reg, 1);
} }
Object* static void*
newobj(GC *gc, enum OType type) alloc(GC *gc, int sz)
{ {
gcrun(gc); sz /= PTR;
gc->using += sizeof(Object); for(uintptr_t *p = gc->beg; p < gc->end - sz;){
Object *r = 0; int i = 0;
if(gc->freed){ for(; p[i] == 0 && i < sz; ++i)
r = gc->freed; ;
gc->freed = gc->freed->next; if(i == sz){
}else{ *p = sz;
r = (Object*)gc->op; gc->using += sz*PTR;
gc->op += sizeof(Object); return p+1;
}
if(p[i]) p = &p[i] + p[i];
else p = &p[i] + 1;
} }
r->type = type; return 0;
if(gc->objs) }
r->next = gc->objs;
return gc->objs = r; void*
gcalloc(GC *gc, int sz)
{
sz += PTR;
if(sz%PTR) sz = sz + PTR - sz % PTR;
if(gc->using + sz > gc->cap * 0.64) gcrun(gc);
void *p = alloc(gc, sz);
if(p)
return p;
gcraise(gc);
p = alloc(gc, sz);
if(p)
return p;
panic("newobj:can't alloc %d byte", sz);
return 0;
}
void
printgc(char *prefix, GC *gc)
{
printf("%*s=> cap:%10d using:%10d remain:%10d\n", 10, prefix, gc->cap, gc->using, gc->cap - gc->using);
} }
GC* GC*
@ -304,16 +238,10 @@ newgc(void *top, int cap)
GC *gc = calloc(1, sizeof(GC)); GC *gc = calloc(1, sizeof(GC));
if(gc == 0) if(gc == 0)
panic("can't alloc %d byte\n", sizeof(GC)); panic("can't alloc %d byte\n", sizeof(GC));
gc->top = (u64)top;
if((gc->memory = calloc(1, cap)) == 0)
panic("can't alloc %d byte\n", cap);
gc->cap = cap; gc->cap = cap;
gc->using = 0; gc->top = top;
if((gc->beg = calloc(1, cap)) == 0)
gc->op = gc->ob = (u64)gc->memory; panic("can't alloc %d byte\n", cap);
gc->oe = gc->op + (float)cap * 0.75; gc->end = gc->beg + cap/PTR;
gc->sb = (u64)gc->memory + (float)cap * 0.75;
gc->se = (u64)gc->memory + cap;
return gc; return gc;
} }

5
main.c
View File

@ -32,7 +32,7 @@ SExprint(Object *obj)
break; break;
case OBLTIN: case OBLTIN:
case OSYMBOL: case OSYMBOL:
printf("%s", obj->sym); printf("%s", obj->beg);
break; break;
case OENV: case OENV:
printf("<env>"); printf("<env>");
@ -71,6 +71,7 @@ loop(void)
while(1){ while(1){
Object *res = nextexpr(); Object *res = nextexpr();
res = eval(env, res); res = eval(env, res);
printgc("status", gc);
printf("=============res===========\n"); printf("=============res===========\n");
printexpr(res); printexpr(res);
printf("=============env===========\n"); printf("=============env===========\n");
@ -82,6 +83,6 @@ loop(void)
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
gc = newgc(&argc, 4000); gc = newgc(&argc, 500);
loop(); loop();
} }

31
obj.c
View File

@ -3,10 +3,18 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
static Object*
newobj(GC *gc, enum OType type, int sz)
{
Object *obj = gcalloc(gc, sizeof(Object) + sz);
obj->type = type;
return obj;
}
Object* Object*
newint(GC *gc, long val) newint(GC *gc, long val)
{ {
Object *obj = newobj(gc, OINT); Object *obj = newobj(gc, OINT, 0);
obj->num = val; obj->num = val;
return obj; return obj;
} }
@ -14,7 +22,7 @@ newint(GC *gc, long val)
Object* Object*
newcons(GC *gc, Object *car, Object *cdr) newcons(GC *gc, Object *car, Object *cdr)
{ {
Object *obj = newobj(gc, OCELL); Object *obj = newobj(gc, OCELL, 0);
obj->car = car; obj->car = car;
obj->cdr = cdr; obj->cdr = cdr;
return obj; return obj;
@ -23,7 +31,7 @@ newcons(GC *gc, Object *car, Object *cdr)
Object* Object*
newenv(GC *gc, Object* name, Object *vars, Object *up) newenv(GC *gc, Object* name, Object *vars, Object *up)
{ {
Object *obj = newobj(gc, OENV); Object *obj = newobj(gc, OENV, 0);
obj->name = name; obj->name = name;
obj->up = up; obj->up = up;
obj->vars = vars; obj->vars = vars;
@ -40,7 +48,7 @@ newacons(GC *gc, Object *x, Object *y, Object *z)
Object* Object*
newfn(GC *gc, Object *env, Object *params, Object *body) newfn(GC *gc, Object *env, Object *params, Object *body)
{ {
Object *fn = newobj(gc, OFUNC); Object *fn = newobj(gc, OFUNC, 0);
fn->params = params; fn->params = params;
fn->body = body; fn->body = body;
fn->env = env; fn->env = env;
@ -57,21 +65,22 @@ newsymbol(GC *gc, char *str, int len)
}; };
for(int i = 0; i < sizeof(syms)/sizeof(syms[0]); ++i){ for(int i = 0; i < sizeof(syms)/sizeof(syms[0]); ++i){
Object *c = syms[i]; Object *c = syms[i];
if(strlen(c->sym)==len && memcmp(c->sym, str, len) == 0) if(strlen(c->beg)==len && memcmp(c->beg, str, len) == 0)
return c; return c;
} }
Object *obj = newobj(gc, OIDENT); Object *obj = newobj(gc, OIDENT, len + 1);
obj->beg = gcalloc(gc, len + 1); obj->ptr = obj->beg = (char*)&obj[1];
obj->end = obj->ptr = obj->beg + len; obj->end = obj->beg + len;
memcpy(obj->beg, str, len+1); memcpy(obj->beg, str, len + 1);
obj->ptr += len;
return obj; return obj;
} }
Object* Object*
newstr(GC *gc, int len) newstr(GC *gc, int len)
{ {
Object *obj = newobj(gc, OSTRING); Object *obj = newobj(gc, OSTRING, len + 1);
obj->ptr = obj->beg = gcalloc(gc, len + 1); obj->ptr = obj->beg = (char*)&obj[1];
obj->end = obj->beg + len; obj->end = obj->beg + len;
return obj; return obj;
} }

View File

@ -88,7 +88,7 @@ string(void)
{ {
Object *str = newstr(gc, 16); Object *str = newstr(gc, 16);
while(lookup() != '\"'){ while(lookup() != '\"'){
strputc(str, get()); str = strputc(str, get());
} }
expect('\"'); expect('\"');
return str; return str;

50
str.c
View File

@ -3,33 +3,41 @@
#include <string.h> #include <string.h>
void void
strraise(Object *s, int ns) strinit(Object *s, Object *p)
{ {
int pos = s->ptr - s->beg; for(char *c = p->beg ; c < p->ptr;)
char *ptr = gcralloc(gc, s->beg, ns + 1); *s->ptr++ = *c++;
s->beg = ptr;
s->ptr = s->beg + pos;
s->end = s->beg + ns;
}
void
strputc(Object *s, int c)
{
if(s->ptr >= s->end)
strraise(s, (s->end - s->beg) * 2);
*s->ptr++ = c;
*s->ptr = 0; *s->ptr = 0;
} }
void Object*
strputs(Object *s, char *ptr) strraise(Object *s, int ns)
{ {
int l = strlen(ptr); Object *dst = newstr(gc, ns + 1);
if(s->ptr + l >= s->end) strinit(dst, s);
strraise(s, s->end - s->beg + l); return dst;
memcpy(s->ptr, ptr, l); }
Object*
strputc(Object *s, int c)
{
if(s->ptr + 1 >= s->end)
s = strraise(s, (s->end - s->beg) * 2);
*s->ptr++ = c;
*s->ptr = 0;
return s;
}
Object*
strputs(Object *s, Object *ptr)
{
int l = ptr->ptr - ptr->beg;
if(s->ptr + l>= s->end)
s = strraise(s, s->end - s->beg + l);
memcpy(s->ptr, ptr->beg, l);
s->ptr += l; s->ptr += l;
s->ptr[0] = 0; *s->ptr = 0;
return s;
} }
int int