view src/ploki/venus.c @ 12292:d51f2100210c draft

<kspalaiologos> `` cat <<<"asmbf && bfi output.b" > /hackenv/ibin/asmbf
author HackEso <hackeso@esolangs.org>
date Thu, 02 Jan 2020 15:38:21 +0000
parents ac0403686959
children
line wrap: on
line source

#include "Str.h"
#include "hash.h"
#include "op.h"
#include "venus.h"
#include "xmalloc.h"
#include "zz.h"

#include <stddef.h>
#include <stdio.h>
#include <string.h>

enum {MAGIC = 23};

struct sorted {
	size_t size, length;
	struct op **array;
};

static size_t hash(const void *p, size_t seed) {
	return St_hash(p, seed);
}

static int compar(const void *a, const void *b) {
	return St_cmp(a, b);
}

static void delk(void *k) {
	St_clear(k);
	xfree(k);
}

static void delv(void *v) {
	xfree(((struct sorted *)v)->array);
	xfree(v);
}

void ve_init(struct venus *v) {
	h_init(&v->table, hash, compar, delk, delv);
}

void ve_end(struct venus *v) {
	h_end(&v->table);
}

void ve_enter(struct venus *v, const String *s, struct op *o) {
	struct sorted *x;
	void *tmp;
	size_t a, z;

	if (h_get(&v->table, s, &tmp) == H_NOENT) {
		String *label;
		x = xmalloc(1, sizeof *x);
		x->array = xmalloc(x->size = MAGIC, sizeof *x->array);
		x->array[0] = o;
		x->length = 1;
		label = xmalloc(1, sizeof *label);
		St_init(label);
		St_cpy(label, s);
		h_put(&v->table, label, x, 1);
		return;
	}
	x = tmp;

	for (a = 0, z = x->length; a < z; ) {
		if (x->array[(a + z) / 2]->line < o->line) {
			a = (a + z) / 2 + 1u;
		} else if (x->array[(a + z) / 2]->line > o->line) {
			z = (a + z) / 2;
		} else {
			NOTREACHED;
		}
	}

	if (x->length >= x->size) {
		x->array = xrealloc(x->array, x->size *= 2);
	}
	memmove(x->array + a + 1u, x->array + a, x->length - a);
	x->array[a] = o;
	x->length++;
}

struct op *ve_findnext(struct venus *v, const String *s, size_t line) {
	struct sorted *x;
	void *tmp;
	size_t a, z;

	if (h_get(&v->table, s, &tmp) == H_NOENT) {
		return NULL;
	}
	x = tmp;

	for (a = 0, z = x->length; a < z; ) {
		if (x->array[(a + z) / 2]->line < line) {
			a = (a + z) / 2 + 1u;
		} else if (x->array[(a + z) / 2]->line > line) {
			z = (a + z) / 2;
		} else {
			a = (a + z) / 2 + 1u;
			break;
		}
	}

	return x->array[a % x->length];
}

struct op *ve_findprev(struct venus *v, const String *s, size_t line) {
	struct sorted *x;
	void *tmp;
	size_t a, z;

	if (h_get(&v->table, s, &tmp) == H_NOENT) {
		return NULL;
	}
	x = tmp;

	for (a = 0, z = x->length; a < z; ) {
		if (x->array[(a + z) / 2]->line < line) {
			a = (a + z) / 2 + 1u;
		} else if (x->array[(a + z) / 2]->line > line) {
			z = (a + z) / 2;
		} else {
			a = (a + z) / 2;
			break;
		}
	}
	a += x->length - 1u;
	return x->array[a % x->length];
}

const String *ve_label(struct venus *v, const struct op *op) {
	void *key, *value;

	h_reset(&v->table);
	while (h_nextkv(&v->table, &key, &value) == H_OK) {
		const struct sorted *x = value;
		size_t i;

		for (i = 0; i < x->length; ++i) {
			if (x->array[i] == op) {
				return key;
			}
		}
	}

	return NULL;
}