added garbage collector draft

This commit is contained in:
Francesco Cozzuto
2021-12-06 00:12:02 +01:00
parent 60b871be55
commit dbcf50c71b
21 changed files with 389 additions and 48 deletions
+10
View File
@@ -0,0 +1,10 @@
i = 0;
n = 10000000;
while i < n:
{
1 + 1 * 1;
i = i + 1;
print('\r', 100.0 * i / n, '% ');
}
+2
View File
@@ -237,6 +237,8 @@ int main(int argc, char **argv)
Object *result = run(runtime, (Error*) &error, exe, 0, NULL, NULL, 0);
// NOTE: The `builtins` pointer is invalidated now.
if(result == NULL)
{
fprintf(stderr, "RUNTIME ERROR: %s.\n", error.base.message);
+1 -1
View File
@@ -21,7 +21,7 @@ typedef struct {
Runtime *runtime;
} BuiltinsMapOjbect;
static const Type t_builtins_map = {
static TypeObject t_builtins_map = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "builtins map",
.size = sizeof(BuiltinsMapOjbect),
+1 -1
View File
@@ -32,7 +32,7 @@ typedef struct {
Runtime *runtime;
} NetworkBuiltinsMapOjbect;
static const Type t_builtins_map = {
static TypeObject t_builtins_map = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "network builtins map",
.size = sizeof(NetworkBuiltinsMapOjbect),
+169 -1
View File
@@ -17,8 +17,17 @@ struct OflowAlloc {
struct xHeap {
int size;
int used;
int total;
void *body;
OflowAlloc *oflow;
_Bool collecting;
_Bool collection_failed;
void *old_body;
int old_used;
int old_total;
OflowAlloc *old_oflow;
Error *error;
};
Heap *Heap_New(int size)
@@ -31,10 +40,12 @@ Heap *Heap_New(int size)
if(heap == NULL)
return NULL;
heap->total = 0;
heap->size = size;
heap->used = 0;
heap->body = malloc(size);
heap->oflow = 0;
heap->collecting = 0;
if(heap->body == NULL)
{
@@ -67,7 +78,12 @@ void Heap_Free(Heap *heap)
free(heap);
}
void *Heap_Malloc(Heap *heap, const Type *type, Error *err)
float Heap_GetUsagePercentage(Heap *heap)
{
return 100.0 * heap->total / heap->size;
}
void *Heap_Malloc(Heap *heap, TypeObject *type, Error *err)
{
void *addr = Heap_RawMalloc(heap, type->size, err);
@@ -107,14 +123,20 @@ void *Heap_RawMalloc(Heap *heap, int size, Error *err)
heap->oflow = oflow;
addr = oflow->body;
heap->total += size;
}
else
{
int prev_used = heap->used;
if(heap->used & 7)
heap->used = (heap->used & ~7) + 8;
addr = heap->body + heap->used;
heap->used += size;
heap->total += heap->used - prev_used;
}
assert(((intptr_t) addr) % 8 == 0);
@@ -125,3 +147,149 @@ void *Heap_RawMalloc(Heap *heap, int size, Error *err)
return addr;
}
_Bool Heap_StartCollection(Heap *heap, Error *error)
{
assert(heap->collecting == 0);
void *new_body = malloc(heap->size);
if(new_body == NULL)
{
Error_Report(error, 1, "No memory");
return 0;
}
heap->old_body = heap->body;
heap->old_used = heap->used;
heap->old_total = heap->total;
heap->old_oflow = heap->oflow;
heap->total = 0;
heap->body = new_body;
heap->used = 0;
heap->oflow = NULL;
heap->collecting = 1;
heap->collection_failed = 0;
heap->error = error;
return 1;
}
_Bool Heap_StopCollection(Heap *heap)
{
assert(heap->collecting == 1);
if(heap->collection_failed)
{
free(heap->old_body);
return 0;
}
/* Call destructors here */
while(heap->old_oflow)
{
OflowAlloc *prev = heap->old_oflow->prev;
free(heap->old_oflow);
heap->old_oflow = prev;
}
free(heap->old_body);
heap->collecting = 0;
return 1;
}
void Heap_CollectExtension(void **referer, int size, Heap *heap)
{
assert(referer != NULL);
assert(heap->collecting);
void *old_location = *referer;
if(heap->collection_failed || old_location == NULL)
return;
void *new_location = Heap_RawMalloc(heap, size, heap->error);
if(new_location == NULL)
{
heap->collection_failed = 1;
return;
}
memcpy(new_location, old_location, size);
*referer = new_location;
}
void Heap_CollectReference(Object **referer, Heap *heap)
{
assert(referer != NULL);
assert(heap->collecting);
Object *old_location = *referer;
if(heap->collection_failed || old_location == NULL)
return;
Object *new_location;
if(old_location->flags & Object_STATIC)
// The object doesn't need to be moved
// since it was statically allocated.
new_location = old_location;
else if(old_location->flags & Object_MOVED)
// The object was already moved.
new_location = ((MovedObject*) old_location)->new_location;
else
{
// This object wasn't moved to
// the new heap yet.
// Get some information.
TypeObject *type = old_location->type;
int size = type->size;
// Copy the object to a new location.
{
new_location = Heap_RawMalloc(heap, size, heap->error);
if(new_location == NULL)
{
heap->collection_failed = 1;
return;
}
memcpy(new_location, old_location, size);
}
// Set the old location as moved and
// leave the reference to the new
// location.
{
old_location->flags |= Object_MOVED;
assert((int) sizeof(MovedObject) <= size);
((MovedObject*) old_location)->new_location = new_location;
}
}
// Update the referer
*referer = new_location;
// Collect the reference to the type.
if((Object*) new_location->type != new_location)
Heap_CollectReference((Object**) &new_location->type, heap);
// Collect all of the references to
// extensions allocate using the GC'd
// heap.
Object_WalkExtensions(new_location, Heap_CollectExtension, heap);
// Now collect all of the children.
Object_WalkReferences(new_location, Heap_CollectReference, heap);
}
+1 -1
View File
@@ -5,7 +5,7 @@
static _Bool to_bool(Object *obj, Error *err);
static void print(Object *obj, FILE *fp);
static const Type t_bool = {
static TypeObject t_bool = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "bool",
.size = sizeof (Object),
+1 -1
View File
@@ -20,7 +20,7 @@ static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error
static int count(Object *self);
static void print(Object *obj, FILE *fp);
static const Type t_buffer = {
static TypeObject t_buffer = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "buffer",
.size = sizeof (BufferObject),
+11 -1
View File
@@ -9,13 +9,15 @@ struct ClosureObject {
Object *vars;
};
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp);
static Object *select(Object *self, Object *key, Heap *heap, Error *err);
static const Type t_closure = {
static TypeObject t_closure = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "closure",
.size = sizeof(ClosureObject),
.select = select,
.walk = walk,
};
Object *Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *error)
@@ -55,3 +57,11 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *err)
return selected;
}
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp)
{
ClosureObject *closure = (ClosureObject*) self;
callback((Object**) &closure->prev, userp);
callback(&closure->vars, userp);
}
+1 -1
View File
@@ -9,7 +9,7 @@ typedef struct {
double val;
} FloatObject;
static const Type t_float = {
static TypeObject t_float = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "float",
.size = sizeof (FloatObject),
+1 -1
View File
@@ -11,7 +11,7 @@ typedef struct {
long long int val;
} IntObject;
static const Type t_int = {
static TypeObject t_int = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "int",
.size = sizeof (IntObject),
+20 -1
View File
@@ -12,8 +12,10 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *err);
static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *err);
static int count(Object *self);
static void print(Object *obj, FILE *fp);
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp);
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp);
static const Type t_list = {
static TypeObject t_list = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "list",
.size = sizeof (ListObject),
@@ -21,6 +23,8 @@ static const Type t_list = {
.insert = insert,
.count = count,
.print = print,
.walk = walk,
.walkexts = walkexts,
};
static inline int calc_capacity(int mapper_size)
@@ -53,6 +57,21 @@ Object *Object_NewList(int capacity, Heap *heap, Error *error)
return (Object*) obj;
}
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp)
{
ListObject *list = (ListObject*) self;
for(int i = 0; i < list->count; i += 1)
callback(&list->vals[i], userp);
}
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp)
{
ListObject *list = (ListObject*) self;
callback((void**) &list->vals, sizeof(Object) * list->capacity, userp);
}
static Object *select(Object *self, Object *key, Heap *heap, Error *error)
{
assert(self != NULL);
+25 -1
View File
@@ -14,8 +14,10 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *err);
static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *err);
static int count(Object *self);
static void print(Object *self, FILE *fp);
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp);
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp);
static const Type t_map = {
static TypeObject t_map = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "map",
.size = sizeof (MapObject),
@@ -23,6 +25,8 @@ static const Type t_map = {
.insert = insert,
.count = count,
.print = print,
.walk = walk,
.walkexts = walkexts,
};
static inline int calc_capacity(int mapper_size)
@@ -68,6 +72,26 @@ Object *Object_NewMap(int num, Heap *heap, Error *error)
return (Object*) obj;
}
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp)
{
MapObject *map = (MapObject*) self;
for(int i = 0; i < map->count; i += 1)
{
callback(&map->keys[i], userp);
callback(&map->vals[i], userp);
}
}
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp)
{
MapObject *map = (MapObject*) self;
callback((void**) &map->mapper, sizeof(int) * map->mapper_size, userp);
callback((void**) &map->keys, sizeof(Object) * calc_capacity(map->mapper_size), userp);
callback((void**) &map->vals, sizeof(Object) * calc_capacity(map->mapper_size), userp);
}
static Object *select(Object *self, Object *key, Heap *heap, Error *error)
{
assert(self != NULL);
+1 -1
View File
@@ -5,7 +5,7 @@
static _Bool op_eql(Object *self, Object *other);
static void print(Object *obj, FILE *fp);
static const Type t_none = {
static TypeObject t_none = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "none",
.size = sizeof (Object),
+10 -1
View File
@@ -16,8 +16,9 @@ static Object *copy(Object *self, Heap *heap, Error *err);
static void print(Object *obj, FILE *fp);
static char *to_string(Object *self, int *size, Heap *heap, Error *err);
static _Bool op_eql(Object *self, Object *other);
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp);
static const Type t_string = {
static TypeObject t_string = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "string",
.atomic = ATMTP_STRING,
@@ -28,6 +29,7 @@ static const Type t_string = {
.print = print,
.to_string = to_string,
.op_eql = op_eql,
.walkexts = walkexts,
};
static char *to_string(Object *self, int *size, Heap *heap, Error *err)
@@ -128,3 +130,10 @@ static void print(Object *obj, FILE *fp)
fprintf(fp, "%.*s", str->size, str->body);
}
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp)
{
StringObject *str = (StringObject*) self;
callback((void**) &str->body, str->size+1, userp);
}
+32 -20
View File
@@ -2,17 +2,17 @@
#include "../utils/defs.h"
#include "objects.h"
const Type t_type = {
TypeObject t_type = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "type",
.size = sizeof (Type),
.size = sizeof (TypeObject),
};
const char *Object_GetName(const Object *obj)
{
assert(obj != NULL);
const Type *type = Object_GetType(obj);
const TypeObject *type = Object_GetType(obj);
assert(type);
const char *name = type->name;
@@ -21,7 +21,7 @@ const char *Object_GetName(const Object *obj)
return name;
}
const Type *Object_GetType(const Object *obj)
const TypeObject *Object_GetType(const Object *obj)
{
assert(obj != NULL);
assert(obj->type != NULL);
@@ -33,7 +33,7 @@ unsigned int Object_GetSize(const Object *obj, Error *err)
assert(err != NULL);
assert(obj != NULL);
const Type *type = Object_GetType(obj);
const TypeObject *type = Object_GetType(obj);
assert(type);
return type->size;
@@ -44,7 +44,7 @@ unsigned int Object_GetDeepSize(const Object *obj, Error *err)
assert(err != NULL);
assert(obj != NULL);
const Type *type = Object_GetType(obj);
const TypeObject *type = Object_GetType(obj);
assert(type);
if(type->deepsize == NULL)
@@ -60,7 +60,7 @@ int Object_Hash(Object *obj, Error *err)
{
assert(obj != NULL);
const Type *type = Object_GetType(obj);
const TypeObject *type = Object_GetType(obj);
assert(type != NULL);
if(type->hash == NULL)
@@ -77,7 +77,7 @@ Object *Object_Copy(Object *obj, Heap *heap, Error *err)
assert(err != NULL);
assert(obj != NULL);
const Type *type = Object_GetType(obj);
const TypeObject *type = Object_GetType(obj);
assert(type != NULL);
if(type->copy == NULL)
@@ -94,7 +94,7 @@ Object *Object_Call(Object *obj, Object **argv, unsigned int argc, Heap *heap, E
assert(err);
assert(obj);
const Type *type = Object_GetType(obj);
const TypeObject *type = Object_GetType(obj);
assert(type);
if(type->call == NULL)
@@ -110,7 +110,7 @@ void Object_Print(Object *obj, FILE *fp)
{
assert(obj != NULL);
const Type *type = Object_GetType(obj);
const TypeObject *type = Object_GetType(obj);
assert(type);
if(type->print == NULL)
@@ -125,7 +125,7 @@ Object *Object_Select(Object *coll, Object *key, Heap *heap, Error *err)
assert(key);
assert(coll);
const Type *type = Object_GetType(coll);
const TypeObject *type = Object_GetType(coll);
assert(type);
if(type->select == NULL)
@@ -143,7 +143,7 @@ Object *Object_Delete(Object *coll, Object *key, Heap *heap, Error *err)
assert(key);
assert(coll);
const Type *type = Object_GetType(coll);
const TypeObject *type = Object_GetType(coll);
assert(type);
if(type->delete == NULL)
@@ -161,7 +161,7 @@ _Bool Object_Insert(Object *coll, Object *key, Object *val, Heap *heap, Error *e
assert(key);
assert(coll);
const Type *type = Object_GetType(coll);
const TypeObject *type = Object_GetType(coll);
assert(type);
if(type->insert == NULL)
@@ -178,7 +178,7 @@ int Object_Count(Object *coll, Error *err)
assert(err);
assert(coll);
const Type *type = Object_GetType(coll);
const TypeObject *type = Object_GetType(coll);
assert(type);
if(type->count == NULL)
@@ -195,7 +195,7 @@ Object *Object_Next(Object *iter, Heap *heap, Error *err)
assert(err);
assert(iter);
const Type *type = Object_GetType(iter);
const TypeObject *type = Object_GetType(iter);
assert(type);
if(type->next == NULL)
@@ -212,7 +212,7 @@ Object *Object_Prev(Object *iter, Heap *heap, Error *err)
assert(err);
assert(iter);
const Type *type = Object_GetType(iter);
const TypeObject *type = Object_GetType(iter);
assert(type);
if(type->prev == NULL)
@@ -263,7 +263,7 @@ long long int Object_ToInt(Object *obj, Error *err)
return 0;
}
const Type *type = Object_GetType(obj);
const TypeObject *type = Object_GetType(obj);
assert(type);
if(type->to_int == NULL)
@@ -286,7 +286,7 @@ _Bool Object_ToBool(Object *obj, Error *err)
return 0;
}
const Type *type = Object_GetType(obj);
const TypeObject *type = Object_GetType(obj);
assert(type);
if(type->to_bool == NULL)
@@ -309,7 +309,7 @@ double Object_ToFloat(Object *obj, Error *err)
return 0;
}
const Type *type = Object_GetType(obj);
const TypeObject *type = Object_GetType(obj);
assert(type);
if(type->to_float == NULL)
@@ -332,7 +332,7 @@ const char *Object_ToString(Object *obj, int *size, Heap *heap, Error *err)
return NULL;
}
const Type *type = Object_GetType(obj);
const TypeObject *type = Object_GetType(obj);
assert(type);
if(type->to_string == NULL)
@@ -361,3 +361,15 @@ _Bool Object_Compare(Object *obj1, Object *obj2, Error *error)
return obj1->type->op_eql(obj1, obj2);
}
void Object_WalkReferences(Object *parent, void (*callback)(Object **referer, void *userp), void *userp)
{
if(parent->type->walk != NULL)
parent->type->walk(parent, callback, userp);
}
void Object_WalkExtensions(Object *parent, void (*callback)(void **referer, unsigned int size, void *userp), void *userp)
{
if(parent->type->walkexts != NULL)
parent->type->walkexts(parent, callback, userp);
}
+23 -7
View File
@@ -4,15 +4,20 @@
#include <stdio.h>
#include "../utils/error.h"
typedef struct Type Type;
typedef struct TypeObject TypeObject;
typedef struct Object Object;
typedef struct xHeap Heap;
struct Object {
const Type *type;
TypeObject *type;
unsigned int flags;
};
typedef struct {
Object base;
Object *new_location;
} MovedObject;
typedef enum {
ATMTP_NOTATOMIC = 0,
ATMTP_INT,
@@ -21,7 +26,7 @@ typedef enum {
ATMTP_STRING,
} AtomicType;
struct Type {
struct TypeObject {
Object base;
@@ -57,18 +62,27 @@ struct Type {
};
_Bool (*op_eql)(Object *self, Object *other);
// All.
void (*walk) (Object *self, void (*callback)(Object **referer, void *userp), void *userp);
void (*walkexts)(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp);
};
enum {
Object_STATIC = 1,
Object_MOVED = 2,
};
Heap* Heap_New(int size);
void Heap_Free(Heap *heap);
void* Heap_Malloc (Heap *heap, const Type *type, Error *err);
void* Heap_RawMalloc(Heap *heap, int size, Error *err);
void* Heap_Malloc (Heap *heap, TypeObject *type, Error *err);
void* Heap_RawMalloc(Heap *heap, int size, Error *err);
_Bool Heap_StartCollection(Heap *heap, Error *error);
_Bool Heap_StopCollection(Heap *heap);
void Heap_CollectReference(Object **referer, Heap *heap);
float Heap_GetUsagePercentage(Heap *heap);
const Type* Object_GetType(const Object *obj);
const TypeObject* Object_GetType(const Object *obj);
const char* Object_GetName(const Object *obj);
unsigned int Object_GetSize(const Object *obj, Error *err);
unsigned int Object_GetDeepSize(const Object *obj, Error *err);
@@ -83,6 +97,8 @@ _Bool Object_Insert(Object *coll, Object *key, Object *val, Heap *heap, Error
int Object_Count (Object *coll, Error *err);
Object* Object_Next (Object *iter, Heap *heap, Error *err);
Object* Object_Prev (Object *iter, Heap *heap, Error *err);
void Object_WalkReferences(Object *parent, void (*callback)(Object **referer, void *userp), void *userp);
void Object_WalkExtensions(Object *parent, void (*callback)(void **referer, unsigned int size, void *userp), void *userp);
Object* Object_NewMap(int num, Heap *heap, Error *error);
Object* Object_NewList(int capacity, Heap *heap, Error *error);
@@ -108,5 +124,5 @@ const char *Object_ToString(Object *obj, int *size, Heap *heap, Error *err);
_Bool Object_Compare(Object *obj1, Object *obj2, Error *error);
extern const Type t_type;
extern TypeObject t_type;
#endif
+9 -1
View File
@@ -13,14 +13,22 @@ typedef struct {
} FunctionObject;
static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error);
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp);
static const Type t_func = {
static TypeObject t_func = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "function",
.size = sizeof (FunctionObject),
.call = call,
.walk = walk,
};
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp)
{
FunctionObject *func = (FunctionObject*) self;
callback(&func->closure, userp);
}
static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error)
{
assert(self != NULL);
+1 -1
View File
@@ -13,7 +13,7 @@ typedef struct {
static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error);
static const Type t_nfunc = {
static TypeObject t_nfunc = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "native function",
.size = sizeof (NativeFunctionObject),
+48 -6
View File
@@ -1032,6 +1032,33 @@ static _Bool step(Runtime *runtime, Error *error)
return 1;
}
static _Bool collect(Runtime *runtime, Error *error)
{
Frame *frame = runtime->frame;
if(!Heap_StartCollection(runtime->heap, error))
return 0;
Heap_CollectReference(&runtime->builtins, runtime->heap);
while(frame)
{
Heap_CollectReference(&frame->locals, runtime->heap);
Heap_CollectReference(&frame->closure, runtime->heap);
frame = frame->prev;
}
for(unsigned int i = 0; i < Stack_Size(runtime->stack); i += 1)
{
Object **ref = (Object**) Stack_TopRef(runtime->stack, -i);
assert(ref != NULL);
Heap_CollectReference(ref, runtime->heap);
}
return Heap_StopCollection(runtime->heap);
}
Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc)
{
assert(runtime != NULL);
@@ -1086,14 +1113,29 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *
Error_Report(error, 0, "Forced abortion");
else
while(step(runtime, error))
if(!runtime->callback_addr(runtime, runtime->callback_userp))
{
Error_Report(error, 0, "Forced abortion");
break;
}
{
if(!runtime->callback_addr(runtime, runtime->callback_userp))
{
Error_Report(error, 0, "Forced abortion");
break;
}
//printf("%2.2f%% percent.\n", Heap_GetUsagePercentage(runtime->heap));
if(Heap_GetUsagePercentage(runtime->heap) > 100)
if(!collect(runtime, error))
break;
}
}
else
while(step(runtime, error));
while(step(runtime, error))
{
if(Heap_GetUsagePercentage(runtime->heap) > 100)
if(!collect(runtime, error))
break;
//printf("%2.2f%% percent.\n", Heap_GetUsagePercentage(runtime->heap));
}
// This is what the function will return.
Object *result = NULL;
+20
View File
@@ -54,6 +54,26 @@ void *Stack_Top(Stack *s, int n)
return s->body[s->used + n - 1];
}
void **Stack_TopRef(Stack *s, int n)
{
assert(n <= 0);
if(Stack_IsReadOnlyCopy(s))
return NULL;
// Remove readonly bit.
s = unmark(s);
if(s->used == 0)
return NULL;
if((int) s->used + n - 1 < 0)
return NULL;
return &s->body[s->used + n - 1];
}
_Bool Stack_Pop(Stack *s, unsigned int n)
{
if(Stack_IsReadOnlyCopy(s))
+1
View File
@@ -8,6 +8,7 @@ _Bool Stack_Push(Stack *s, void *item);
void Stack_Free(Stack *s);
unsigned int Stack_Size(Stack *s);
Stack *Stack_Copy(Stack *s, _Bool readonly);
void **Stack_TopRef(Stack *s, int n);
unsigned int Stack_Capacity(Stack *s);
_Bool Stack_IsReadOnlyCopy(Stack *s);
#endif