1
0
mirror of https://github.com/stedolan/jq.git synced 2024-05-11 05:55:39 +00:00
Files
stedolan-jq/c/forkable_stack.h

117 lines
3.0 KiB
C
Raw Normal View History

2012-08-16 01:00:30 +01:00
#include <stdlib.h>
#include <stddef.h>
#include <assert.h>
2012-08-20 15:53:20 +01:00
#include <string.h>
2012-08-16 01:00:30 +01:00
struct forkable_stack_header {
int next;
};
#define FORKABLE_STACK_HEADER struct forkable_stack_header fk_header_
struct forkable_stack {
2012-08-20 15:53:20 +01:00
// Stack grows down from stk+length
2012-08-16 01:00:30 +01:00
char* stk;
// stk+length is just past end of allocated area
2012-08-20 15:53:20 +01:00
// stk = malloc(length)
2012-08-16 01:00:30 +01:00
int length;
2012-08-20 15:53:20 +01:00
// stk+pos is header of top object, or stk+length if empty
2012-08-16 01:00:30 +01:00
int pos;
2012-08-20 15:53:20 +01:00
// everything after-or-including stk+savedlimit must be preserved
2012-08-16 01:00:30 +01:00
int savedlimit;
};
static void forkable_stack_check(struct forkable_stack* s) {
assert(s->stk);
assert(s->length > 0);
assert(s->pos >= 0 && s->pos <= s->length);
assert(s->savedlimit >= 0 && s->savedlimit <= s->length);
}
static int forkable_stack_empty(struct forkable_stack* s) {
2012-08-20 15:53:20 +01:00
return s->pos == s->length;
2012-08-16 01:00:30 +01:00
}
static void forkable_stack_init(struct forkable_stack* s, size_t sz) {
s->stk = malloc(sz);
s->length = sz;
2012-08-20 15:53:20 +01:00
s->pos = s->length;
s->savedlimit = s->length;
2012-08-16 01:00:30 +01:00
forkable_stack_check(s);
}
static void* forkable_stack_push(struct forkable_stack* s, size_t size) {
forkable_stack_check(s);
2012-08-20 15:53:20 +01:00
int curr = s->pos < s->savedlimit ? s->pos : s->savedlimit;
if (curr - size < 0) {
assert(0);
int oldlen = s->length;
s->length = (size + oldlen + 1024) * 2;
2012-08-16 01:00:30 +01:00
s->stk = realloc(s->stk, s->length);
2012-08-20 15:53:20 +01:00
int shift = s->length - oldlen;
memmove(s->stk + shift, s->stk, oldlen);
s->pos += shift;
s->savedlimit += shift;
curr += shift;
2012-08-16 01:00:30 +01:00
}
2012-08-20 15:53:20 +01:00
void* ret = (void*)(s->stk + curr - size);
2012-08-16 01:00:30 +01:00
((struct forkable_stack_header*)ret)->next = s->pos;
2012-08-20 15:53:20 +01:00
s->pos = curr - size;
forkable_stack_check(s);
2012-08-16 01:00:30 +01:00
return ret;
}
static void* forkable_stack_peek(struct forkable_stack* s, size_t size) {
assert(!forkable_stack_empty(s));
2012-08-20 15:53:20 +01:00
forkable_stack_check(s);
return (void*)(s->stk + s->pos);
2012-08-16 01:00:30 +01:00
}
static void* forkable_stack_peek_next(struct forkable_stack* s, void* top, size_t size) {
2012-08-20 15:53:20 +01:00
forkable_stack_check(s);
2012-08-16 01:00:30 +01:00
struct forkable_stack_header* elem = top;
2012-08-20 15:53:20 +01:00
return (void*)(s->stk + elem->next);
2012-08-16 01:00:30 +01:00
}
static void forkable_stack_pop(struct forkable_stack* s, size_t size) {
2012-08-20 15:53:20 +01:00
forkable_stack_check(s);
2012-08-16 01:00:30 +01:00
struct forkable_stack_header* elem = forkable_stack_peek(s, size);
s->pos = elem->next;
}
2012-08-20 15:53:20 +01:00
2012-08-16 01:00:30 +01:00
struct forkable_stack_state {
int prevpos, prevlimit;
};
static void forkable_stack_save(struct forkable_stack* s, struct forkable_stack_state* state) {
2012-08-20 15:53:20 +01:00
forkable_stack_check(s);
2012-08-16 01:00:30 +01:00
state->prevpos = s->pos;
state->prevlimit = s->savedlimit;
2012-08-20 15:53:20 +01:00
if (s->pos < s->savedlimit) s->savedlimit = s->pos;
2012-08-16 01:00:30 +01:00
}
static void forkable_stack_switch(struct forkable_stack* s, struct forkable_stack_state* state) {
2012-08-20 15:53:20 +01:00
forkable_stack_check(s);
2012-08-16 01:00:30 +01:00
int curr_pos = s->pos;
s->pos = state->prevpos;
state->prevpos = curr_pos;
int curr_limit = s->savedlimit;
2012-08-20 15:53:20 +01:00
if (curr_pos < curr_limit) s->savedlimit = curr_pos;
2012-08-16 01:00:30 +01:00
state->prevlimit = curr_limit;
2012-08-20 15:53:20 +01:00
forkable_stack_check(s);
2012-08-16 01:00:30 +01:00
}
static void forkable_stack_restore(struct forkable_stack* s, struct forkable_stack_state* state) {
2012-08-20 15:53:20 +01:00
forkable_stack_check(s);
2012-08-16 01:00:30 +01:00
s->pos = state->prevpos;
s->savedlimit = state->prevlimit;
2012-08-20 15:53:20 +01:00
forkable_stack_check(s);
2012-08-16 01:00:30 +01:00
}