#include "chrono/chrono.h"
#include "fix.h"

void fix_benchmarks() {
  hc_time_t t;
  const int n = 100000;
  t = hc_now();
  double dv = 0;
  for (int i = 0; i < n; i++) {
    dv += 0.001;
  }
  hc_time_print(&t, "double: ");
  t = hc_now();
  hc_fix_t fv = hc_fix(3, 0);
  hc_fix_t fd = hc_fix(3, 1);
  for (int i = 0; i < n; i++) {
    fv = hc_fix_add(fv, fd);
  }
  hc_time_print(&t, "fix: ");
}

#include "chrono/chrono.h"
#include "dsl.h"

void dsl_benchmarks() {
  hc_time_t t;
  const int n = 100000;

  char buf[32];
  t = hc_now();

  for (int i = 0; i < n; i++) {
    sprintf(buf, "abc %s def", "ghi");
  }

  hc_time_print(&t, "sprintf: ");

  struct hc_dsl dsl;
  hc_dsl_init(&dsl, &hc_malloc_default);
  hc_defer(hc_dsl_deinit(&dsl));
  struct hc_memory_stream out;
  hc_memory_stream_init(&out, &hc_malloc_default);
  hc_defer(hc_stream_deinit(&out.stream));
  dsl.out = &out.stream;
  hc_dsl_set_string(&dsl, "foo", "ghi");
  hc_dsl_eval(&dsl, "abc $(print foo) def");

  t = hc_now();

  for (int i = 0; i < n; i++) {
    hc_vector_clear(&out.data);
    hc_vm_eval(&dsl.vm, 0, -1);
  }

  hc_time_print(&t, "dsl: ");
}

#include <stdlib.h>

#include "chrono/chrono.h"
#include "malloc2.h"

#define N 1000
#define MAX_SIZE 64
#define GET_SIZE() ((rand() % MAX_SIZE) + 1)

static void run_malloc() {
  int *ps[N];
  hc_time_t t = hc_now();

  for (int i = 0; i < N; i++) {
    ps[i] = malloc(GET_SIZE());
  }

  for (int i = 0; i < N; i++) {
    free(ps[i]);
  }

  hc_time_print(&t, "malloc: ");
}

static void run_bump() {
  struct hc_bump_alloc a;
  hc_bump_alloc_init(&a, &hc_malloc_default, N * MAX_SIZE);
  hc_time_t t = hc_now();

  for (int i = 0; i < N; i++) {
    hc_acquire(&a.malloc, GET_SIZE());
  }

  hc_bump_alloc_deinit(&a);
  hc_time_print(&t, "bump: ");
}

static void run_slab() {
  struct hc_slab_alloc a;
  hc_slab_alloc_init(&a, &hc_malloc_default, N);
  hc_time_t t = hc_now();

  for (int i = 0; i < N; i++) {
    hc_acquire(&a.malloc, GET_SIZE());
  }

  hc_slab_alloc_deinit(&a);
  hc_time_print(&t, "slab: ");
}

void malloc2_benchmarks() {
  const int s = time(NULL);

  srand(s);
  run_malloc();

  srand(s);
  run_bump();

  srand(s);
  run_slab();
}

#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>

#include "chrono.h"
#include "error/error.h"
#include "stream1/stream1.h"

hc_time_t hc_now() {
  hc_time_t t;

  if (!timespec_get(&t.value, TIME_UTC)) {
    hc_throw("Failed getting time: %d", errno);
  }

  return t;
}

hc_time_t hc_time(int year,
		  int month,
		  int day,
		  int hour,
		  int minute,
		  int second) {
  struct tm t = {0};
  t.tm_year = year - 1900;
  t.tm_mon = month - 1;
  t.tm_mday = day;
  t.tm_hour = hour;
  t.tm_min = minute;
  t.tm_sec = second;

  hc_time_t result = {0};
  result.value.tv_sec = timegm(&t);
  return result;
}

uint64_t hc_time_ns(const hc_time_t *t) {
  const struct timespec now = hc_now().value;

  return
    (now.tv_sec - t->value.tv_sec) * 1000000000 +
    (now.tv_nsec - t->value.tv_nsec);
}

void hc_time_print(const hc_time_t *t, const char *m) {
  printf("%s%" PRIu64 "ns\n", m, hc_time_ns(t));
}

char *hc_time_sprintf(const hc_time_t *t, const char *spec) {
  struct tm tm;
  gmtime_r(&(t->value.tv_sec), &tm);
  size_t len = 8;
  char *result = malloc(len);

  for (;;) {
    const size_t n = strftime(result, len, spec, &tm);

    if (n) {
      result[n] = 0;
      break;
    }

    len *= 2;
    free(result);
    result = malloc(len);
  }

  return result;
}

void hc_time_printf(const hc_time_t *t,
		    const char *spec,
		    struct hc_stream *out) {
  char *s = hc_time_sprintf(t, "%Y-%m-%dT%H:%M:%S");
  hc_puts(out, s);
  free(s);
}

uint64_t hc_sleep(uint64_t ns) {
  struct timespec t = {0};
  t.tv_nsec = ns;

  switch (nanosleep(&t, &t)) {
  case 0:
    break;
  case EINTR:
    return t.tv_nsec;
  default:
    hc_throw("Failed sleeping: %d", errno);
  }

  return 0;
}

#include <dlfcn.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "dynamic.h"
#include "error/error.h"
#include "malloc1/malloc1.h"
#include "vector/vector.h"

struct hc_proc *_hc_proc_init(struct hc_proc *p, char *cmd[]) {
  int fds[2];

  if (pipe(fds) == -1) {
    hc_throw("Failed creating pipe: %d", errno);
  }

  pid_t child_pid = fork();

  switch (child_pid) {
  case 0: {
    if (close(fds[1]) == -1) {
      hc_throw("Failed closing pipe writer: %d", errno);
    }

    if (dup2(fds[0], 0) == -1) {
      hc_throw("Failed rebinding stdin: %d", errno);
    }

    char *const env[] = {"PATH=/bin:/sbin", NULL};

    if (execve(cmd[0], cmd, env) == -1) {
      hc_throw("Failed to execve '%s': %d", cmd[0], errno);
    }
  }
  case -1:
    hc_throw("Failed forking process: %d", errno);
  default:
    if (close(fds[0]) == -1) {
      hc_throw("Failed closing pipe reader: %d", errno);
    }

    p->pid = child_pid;
    p->in = fds[1];
    break;
  }

  return p;
}

static void close_in(struct hc_proc *p) {
  if (p->in != -1 && close(p->in) == -1) {
    hc_throw("Failed closing stdin: %d", errno);
  }
}

void hc_proc_wait(struct hc_proc *p) {
  close_in(p);

  if (waitpid(p->pid, NULL, 0) == -1) {
    hc_throw("Failed waiting for child process to exit: %d", errno);
  }
}

void hc_proc_deinit(struct hc_proc *p) {
  close_in(p);
}

static void free_cmd(char **in) {
  for (char **s = in; *s; s++) {
    free(*s);
  }
}

void _hc_compile(const char *code,
		 const char *out,
		 const struct hc_compile_opts opts) {
  hc_array(const char *, pre,
	   opts.cc, "-shared", "-fpic", "-o", out, "-xc");

  int n = pre_n + 2;
  for (int i = 0; opts.cflags[i]; i++, n++);
  char *cmd[n];
  int i = 0;

  for (; i < pre_n; i++) {
    cmd[i] = strdup(pre_a[i]);
  }

  for (; i <  n - 2; i++) {
    cmd[i] = strdup(opts.cflags[i - pre_n]);
  }

  cmd[i++] = strdup("-");
  cmd[i] = NULL;
  hc_defer(free_cmd(cmd));

  struct hc_proc child;
  _hc_proc_init(&child, cmd);
  hc_defer(hc_proc_deinit(&child));
  FILE *in = fdopen(child.in, "w");

  if (!in) {
    hc_throw("Failed opening stdin stream: %d", errno);
  }

  child.in = -1;
  hc_defer(hc_proc_wait(&child));
  hc_defer(fclose(in));

  if (fputs(code, in) == EOF) {
    hc_throw("Failed writing code: %d", errno);
  }
}

struct hc_dlib *hc_dlib_init(struct hc_dlib *lib, const char *path) {
  lib->handle = dlopen(path, RTLD_NOW);

  if (!lib->handle) {
    hc_throw("Error opening dynamic library '%s': %s", path, dlerror());
  }

  return lib;
}

struct hc_dlib *hc_dlib_deinit(struct hc_dlib *lib) {
  if (dlclose(lib->handle) != 0) {
    hc_throw("Failed closing dynamic library: ", dlerror());
  }

  return lib;
}

void *hc_dlib_find(const struct hc_dlib *lib, const char *s) {
  dlerror();
  void *v = dlsym(lib->handle, s);
  char *e = dlerror();

  if (e) {
    hc_throw("Symbol '%s' not found: %s", e);
  }

  return v;
}

char *hc_vsprintf(const char *format, va_list args) {
  va_list tmp_args;
  va_copy(tmp_args, args);
  int len = vsnprintf(NULL, 0, format, tmp_args);
  va_end(tmp_args);

  if (len < 0) {
    hc_throw("Formatting '%s' failed: %d", format, errno);
  }

  len++;
  char *out = malloc(len);
  vsnprintf(out, len, format, args);
  return out;
}

#include <assert.h>
#include <stdio.h>
#include "vector.h"

void vector_tests() {
  struct hc_vector v;
  hc_vector_init(&v, &hc_malloc_default, sizeof(int));
  const int n = 100;

  for (int i = 0; i < n; i++) {
    *(int *)hc_vector_push(&v) = i;
  }

  {
    int i = 0;

    hc_vector_do(&v, it) {
      assert(*(int *)it == i++);
    }
  }

  assert(v.length == n);

  for (int i = 0; i < n; i++) {
    assert(*(int *)hc_vector_get(&v, i) == i);
  }

  assert(*(int *)hc_vector_pop(&v) == n-1);
  assert(*(int *)hc_vector_peek(&v) == n-2);
  assert(v.length == n-1);

  for (int i = 0; i < n-1; i++) {
    assert(*(int *)hc_vector_get(&v, i) == i);
  }

  assert(hc_vector_delete(&v, 0, 1));
  assert(v.length == n-2);

  for (int i = 1; i < n-1; i++) {
    assert(*(int *)hc_vector_get(&v, i-1) == i);
  }

  (*(int *)hc_vector_insert(&v, 0, 1) = 0);
  assert(v.length == n-1);

  for (int i = 0; i < n-1; i++) {
    assert(*(int *)hc_vector_get(&v, i) == i);
  }

  hc_vector_clear(&v);
  assert(v.length == 0);

  hc_vector_deinit(&v);
}

#include <assert.h>
#include <inttypes.h>

#include "fix.h"
#include "macro/macro.h"
#include "stream1/stream1.h"

uint32_t hc_scale(const uint8_t exp) {
  static const uint32_t scale[HC_FIX_MAX_EXP+1] = {
    1,
    10,
    100,
    1000,
    10000,
    100000,
    1000000,
    10000000};

  assert(exp <= HC_FIX_MAX_EXP);
  return scale[exp];
}

hc_fix_t hc_fix(const uint8_t exp, const int64_t val) {
  return (hc_fix_t)hc_bitmask(exp, HC_FIX_EXP) +
    (hc_fix_t)(((val < 0) ? 1 : 0) << HC_FIX_EXP) +
    (hc_fix_t)(hc_abs(val) << HC_FIX_HDR);
}

uint8_t hc_fix_exp(const hc_fix_t x) {
  return hc_bitmask(x, HC_FIX_EXP);
}

int64_t hc_fix_val(const hc_fix_t x) {
  const int64_t v = x >> HC_FIX_HDR;
  return ((x >> HC_FIX_EXP) & 1) ? -v : v;
}

int64_t hc_fix_int(const hc_fix_t x) {
  return hc_fix_val(x) / hc_scale(hc_fix_exp(x));
}

int64_t hc_fix_frac(const hc_fix_t x) {
  const int64_t xv = hc_fix_val(x);
  const uint32_t xs = hc_scale(hc_fix_exp(x));
  return xv - (xv / xs) * xs;
}

double hc_fix_double(const hc_fix_t x) {
  return hc_fix_val(x) / (double)hc_scale(hc_fix_exp(x));
}

hc_fix_t hc_fix_add(const hc_fix_t x, const hc_fix_t y) {
  const uint8_t xe = hc_fix_exp(x);
  const uint8_t ye = hc_fix_exp(y);

  if (xe == ye) {
    return hc_fix(xe, hc_fix_val(x) + hc_fix_val(y));
  }

  return hc_fix(xe, hc_fix_val(x) +
		hc_fix_val(y) * hc_scale(xe) / hc_scale(ye));
}

hc_fix_t hc_fix_sub(const hc_fix_t x, const hc_fix_t y) {
  const uint8_t xe = hc_fix_exp(x);
  const uint8_t ye = hc_fix_exp(y);

  if (xe == ye) {
    return hc_fix(xe, hc_fix_val(x) - hc_fix_val(y));
  }

  return hc_fix(xe, hc_fix_val(x) -
		hc_fix_val(y) * hc_scale(xe) / hc_scale(ye));
}

hc_fix_t hc_fix_mul(const hc_fix_t x, const hc_fix_t y) {
  return hc_fix(hc_fix_exp(x), hc_fix_val(x) *
		hc_fix_val(y) / hc_scale(hc_fix_exp(y)));
}

hc_fix_t hc_fix_div(const hc_fix_t x, const hc_fix_t y) {
  return hc_fix(hc_fix_exp(x), hc_fix_val(x) /
		hc_fix_val(y) / hc_scale(hc_fix_exp(y)));
}

void hc_fix_print(const hc_fix_t v, struct hc_stream *out) {
  hc_printf(out,
	    "%" PRId64 ".%" PRId64,
	    hc_fix_int(v),
	    hc_fix_frac(v));
}

#include <assert.h>
#include <stdio.h>
#include "set.h"

struct map_item {
  int k, v;
};

static enum hc_order cmp(const void *x, const void *y) {
  return hc_cmp(*(const int *)x, *(const int *)y);
}

static const void *key(const void *x) {
  return &((const struct map_item *)x)->k;
}

void set_tests() {
  int n = 10;
  struct hc_set s;
  hc_set_init(&s, &hc_malloc_default, sizeof(struct map_item), cmp);
  s.key = key;

  for (int i = 0; i < n; i++) {
    struct map_item *it = hc_set_add(&s, &i, false);
    *it = (struct map_item){.k = i, .v = i};
  }

  assert(hc_set_length(&s) == n);

  for (int i = 0; i < n; i++) {
    struct map_item *it = hc_set_find(&s, &i);
    assert(it);
    assert(it->k == i);
    assert(it->v == i);
  }

  hc_set_clear(&s);
  assert(hc_set_length(&s) == 0);
  hc_set_deinit(&s);
}

#include <assert.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

#include "error/error.h"
#include "macro/macro.h"
#include "malloc1/malloc1.h"
#include "slog.h"

__thread struct hc_slog *_hc_slog = NULL;

struct hc_slog *hc_slog() {
  if (_hc_slog != NULL) {
    return _hc_slog;
  }

  static __thread bool init = true;
  static __thread struct hc_slog_stream s;

  if (init) {
    hc_slog_stream_init(&s, hc_stdout());
    init = false;
  }

  return &s.slog;
}

static void field_deinit(struct hc_slog_field *f) {
  free(f->name);
  hc_value_deinit(&f->value);
}

static void slog_write(struct hc_slog *s,
		       const size_t n,
		       struct hc_slog_field *fields[]) {
  assert(s->write);
  s->write(s, n, fields);
}

void __hc_slog_write(struct hc_slog *s,
		     const size_t n,
		     struct hc_slog_field *fields[]) {
  slog_write(s, n, fields);

  for(size_t i = 0; i < n; i++) {
    struct hc_slog_field *f = fields[i];
    field_deinit(f);
    free(f);
  }
}

void _hc_slog_deinit(struct hc_slog *s) {
  if (s->deinit) {
    s->deinit(s);
  }
}

static struct hc_value *field_init(struct hc_slog_field *f,
				   const char *name,
				   const struct hc_type *type) {
  f->name = strdup(name);
  hc_value_init(&f->value, type);
  return &f->value;
}

struct hc_slog_field *hc_slog_bool(const char *name, const bool value) {
  struct hc_slog_field *f = malloc(sizeof(struct hc_slog_field));
  field_init(f, name, &HC_BOOL)->as_bool = value;
  return f;
}

struct hc_slog_field *hc_slog_int(const char *name, const int value) {
  struct hc_slog_field *f = malloc(sizeof(struct hc_slog_field));
  field_init(f, name, &HC_INT)->as_int = value;
  return f;
}

struct hc_slog_field *hc_slog_string(const char *name, const char *value) {
  struct hc_slog_field *f = malloc(sizeof(struct hc_slog_field));
  field_init(f, name, &HC_STRING)->as_string = strdup(value);
  return f;
}

struct hc_slog_field *hc_slog_time(const char *name, const hc_time_t value) {
  struct hc_slog_field *f = malloc(sizeof(struct hc_slog_field));
  field_init(f, name, &HC_TIME)->as_time = value;
  return f;
}

void stream_deinit(struct hc_slog *s) {
  struct hc_slog_stream *ss = hc_baseof(s, struct hc_slog_stream, slog);
  if (ss->opts.close_out) { hc_stream_deinit(ss->out); }
}

static void field_write(struct hc_slog_field *f, struct hc_stream *out) {
  hc_puts(out, f->name);
  hc_putc(out, '=');
  hc_value_write(&f->value, out);
}

static void stream_write(struct hc_slog *s,
			 const size_t n,
			 struct hc_slog_field *fields[]) {
  struct hc_slog_stream *ss = hc_baseof(s, struct hc_slog_stream, slog);

  for(size_t i = 0; i < n; i++) {
    struct hc_slog_field *f = fields[i];
    if (i) { hc_puts(ss->out, ", "); }
    field_write(f, ss->out);
  }

  hc_putc(ss->out, '\n');
}

struct hc_slog_stream *_hc_slog_stream_init(struct hc_slog_stream *s,
					    struct hc_stream *out,
					    const struct hc_slog_stream_opts opts) {
  s->slog.deinit = stream_deinit;
  s->slog.write = stream_write;
  s->out = out;
  s->opts = opts;
  return s;
}

static void context_deinit(struct hc_slog *s) {
  struct hc_slog_context *sc = hc_baseof(s, struct hc_slog_context, slog);

  for (size_t i = 0; i < sc->length; i++) {
    struct hc_slog_field *f = sc->fields[i];
    field_deinit(f);
    free(f);
  }

  free(sc->fields);
}

static void context_write(struct hc_slog *s,
			  const size_t n,
			  struct hc_slog_field *fields[]) {
  struct hc_slog_context *c = hc_baseof(s, struct hc_slog_context, slog);
  struct hc_slog_field *fs[c->length + n];
  memcpy(fs, c->fields, sizeof(struct hc_slog_field *) * c->length);
  memcpy(fs + c->length, fields, sizeof(struct hc_slog_field *) * n);
  slog_write(c->parent, c->length + n, fs);
}

struct hc_slog_context *hc_slog_context_init(struct hc_slog_context *c,
					     size_t length,
					     struct hc_slog_field *fields[]) {
  c->slog.deinit = context_deinit;
  c->slog.write = context_write;
  c->parent = hc_slog();
  c->length = length;
  size_t s = sizeof(struct hc_slog_field *) * length;
  c->fields = malloc(s);
  memcpy(c->fields, fields, s);
  return c;
}

#include <assert.h>
#include "list.h"

struct list_item {
  struct hc_list ls;
  int value;
};

void list_tests() {
  struct hc_list head;
  hc_list_init(&head);

  const int n = 10;
  struct list_item items[n];

  for (int i = 0; i < n; i++) {
    items[i].value = i;
    hc_list_push_back(&head, &items[i].ls);
  }

  int i = 0;

  hc_list_do(&head, il) {
    assert(hc_baseof(il, struct list_item, ls)->value == i++);
  }
}

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "vector.h"
#include "malloc1/malloc1.h"

static void grow(struct hc_vector *v) {
  hc_vector_grow(v, v->capacity ? v->capacity*2 : 2);
}

struct hc_vector *hc_vector_init(struct hc_vector *v,
				 struct hc_malloc *malloc,
				 const size_t item_size) {
  v->malloc = malloc;
  v->item_size = item_size;
  v->capacity = 0;
  v->length = 0;
  v->start = v->end = NULL;
  return v;
}

void hc_vector_deinit(struct hc_vector *v) {
  if (v->start) { hc_release(v->malloc, v->start); }
}

void hc_vector_grow(struct hc_vector *v, const size_t capacity) {
  v->capacity = capacity;
  size_t size = v->item_size * (v->capacity+1);
  uint8_t *new_start = hc_acquire(v->malloc, size);

  if (v->start) {
    memmove(new_start, v->start, v->length * v->item_size);
    hc_release(v->malloc, v->start);
  }

  v->start = new_start;
  v->end = v->start + v->item_size*v->length;
}

void hc_vector_clear(struct hc_vector *v) {
  v->length = 0;
  v->end = v->start;
}

void *hc_vector_get(struct hc_vector *v, const size_t i) {
  return v->start ? v->start + v->item_size*i : NULL;
}

const void *hc_vector_get_const(const struct hc_vector *v, const size_t i) {
  return v->start ? v->start + v->item_size*i : NULL;
}

void *hc_vector_push(struct hc_vector *v) {
  if (v->length == v->capacity) { grow(v); }
  void *p = v->end;
  v->end += v->item_size;
  v->length++;
  return p;
}

void *hc_vector_peek(struct hc_vector *v) {
  return v->length ? v->end - v->item_size : NULL;
}

void *hc_vector_pop(struct hc_vector *v) {
  if (!v->length) { return NULL; }
  v->end -= v->item_size;
  v->length--;
  return v->end;
}

void *hc_vector_insert(struct hc_vector *v, const size_t i, const size_t n) {
  const size_t m = v->length+n;
  if (m > v->capacity) { hc_vector_grow(v, m); }
  uint8_t *const p = hc_vector_get(v, i);

  if (i < v->length) {
    memmove(p + v->item_size*n, p, (v->length - i) * v->item_size);
  }

  v->length += n;
  v->end += n*v->item_size;
  return p;
}

bool hc_vector_delete(struct hc_vector *v, const size_t i, const size_t n) {
  const size_t m = i+n;
  assert(m <= v->length);

  if (m < v->length) {
    uint8_t *const p = hc_vector_get(v, i);
    memmove(p, p + n*v->item_size, i + (v->length-n) * v->item_size);
  }

  v->length -= n;
  v->end -= n*v->item_size;
  return true;
}

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include "reflect.h"
#include "stream1/stream1.h"

struct hc_value *hc_value_init(struct hc_value *v, const struct hc_type *t) {
  v->type = t;
  return v;
}

void hc_value_deinit(struct hc_value *v) {
  if (v->type->deinit) {
    v->type->deinit(v);
  }
}

struct hc_value *hc_value_copy(struct hc_value *dst, struct hc_value *src) {
  const struct hc_type *t = src->type;

  if (t->copy) {
    dst->type = t;
    t->copy(dst, src);
  } else {
    *dst = *src;
  }

  return dst;
}

void hc_value_print(struct hc_value *v, struct hc_stream *out) {
  if (v->type->print) {
    v->type->print(v, out);
  } else {
    hc_value_write(v, out);
  }
}

void hc_value_write(struct hc_value *v, struct hc_stream *out) {
  assert(v->type->write);
  v->type->write(v, out);
}

static void bool_write(const struct hc_value *v, struct hc_stream *out) {
  hc_puts(out, v->as_bool ? "true" : "false");
}

const struct hc_type HC_BOOL = {
  .name = "Bool",
  .copy = NULL,
  .write = bool_write
};

static void fix_write(const struct hc_value *v, struct hc_stream *out) {
  hc_fix_print(v->as_fix, out);
}

const struct hc_type HC_FIX = {
  .name = "Fix",
  .copy = NULL,
  .write = fix_write
};

static void int_write(const struct hc_value *v, struct hc_stream *out) {
  hc_printf(out, "%d", v->as_int);
}

const struct hc_type HC_INT = {
  .name = "Int",
  .copy = NULL,
  .write = int_write
};

static void string_copy(struct hc_value *dst, struct hc_value *src) {
  dst->as_string = strdup(src->as_string);
}

static void string_deinit(struct hc_value *v) {
  free(v->as_string);
}

static void string_print(const struct hc_value *v, struct hc_stream *out) {
  hc_puts(out, v->as_string);
}

static void string_write(const struct hc_value *v, struct hc_stream *out) {
  hc_putc(out, '"');
  string_print(v, out);
  hc_putc(out, '"');
}

const struct hc_type HC_STRING = {
  .name = "String",
  .copy = string_copy,
  .deinit = string_deinit,
  .print = string_print,
  .write = string_write
};

static void time_write(const struct hc_value *v, struct hc_stream *out) {
  hc_time_printf(&v->as_time, HC_TIME_FORMAT, out);
}

const struct hc_type HC_TIME = {
  .name = "Time",
  .copy = NULL,
  .write = time_write
};

#include <assert.h>
#include <string.h>

#include "slog.h"
#include "malloc1/malloc1.h"

void slog_tests() {
  struct hc_memory_stream out;
  hc_memory_stream_init(&out, &hc_malloc_default);

  struct hc_slog_stream s;
  hc_slog_stream_init(&s, &out.stream, .close_out=true);

  hc_slog_do(&s) {
    hc_slog_context_do(hc_slog_string("string", "abc")) {
      hc_time_t t = hc_time(2025, 4, 13, 1, 40, 0);

      hc_slog_write(hc_slog_bool("bool", true),
		    hc_slog_int("int", 42),
		    hc_slog_time("time", t));
    }
  }

  assert(strcmp("string=\"abc\", "
		"bool=true, "
		"int=42, "
		"time=2025-04-13T01:40:00\n",
		hc_memory_stream_string(&out)) == 0);

  hc_slog_deinit(&s);
}

#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#include "dsl.h"
#include "error/error.h"
#include "list/list.h"

enum hc_order hc_strcmp(const char *x, const char *y) {
  const int result = strcmp(x, y);
  if (!result) { return HC_EQ; }
  return (result < 0) ? HC_LT : HC_GT;
}

char *hc_upcase(char *s) {
  while (*s) {
    *s = toupper(*s);
    s++;
  }

  return s;
}

static void lib_print(struct hc_vm *vm, struct hc_sloc sloc) {
  struct hc_value *v = hc_vm_pop(vm);
  struct hc_dsl *dsl = hc_baseof(vm, struct hc_dsl, vm);
  hc_value_print(v, dsl->out);
  hc_value_deinit(v);
}

static void lib_upcase(struct hc_vm *vm, struct hc_sloc sloc) {
  struct hc_value *v = hc_vm_peek(vm);

  if (v->type != &HC_STRING) {
    hc_throw("Error in %s: Expected string (%s)",
	     hc_sloc_string(&sloc), v->type->name);
  }

  hc_upcase(v->as_string);
}

struct env_item {
  char *key;
  struct hc_value value;
};

static enum hc_order env_cmp(const void *x, const void *y) {
  return hc_strcmp(*(const char **)x, *(const char **)y);
}

static const void *env_key(const void *x) {
  return &((const struct env_item *)x)->key;
}

void hc_dsl_init(struct hc_dsl *dsl, struct hc_malloc *malloc) {
  hc_set_init(&dsl->env, malloc, sizeof(struct env_item), env_cmp);
  dsl->env.key = env_key;
  dsl->out = hc_stdout();

  hc_vm_init(&dsl->vm, &hc_malloc_default);
  hc_dsl_set_fun(dsl, "print", lib_print);
  hc_dsl_set_fun(dsl, "upcase", lib_upcase);
}

static void deinit_env(struct hc_set *env) {
  hc_vector_do(&env->items, _it) {
    struct env_item *it = _it;
    free(it->key);
    hc_value_deinit(&it->value);
  }

  hc_set_deinit(env);
}

void hc_dsl_deinit(struct hc_dsl *dsl) {
  deinit_env(&dsl->env);
  hc_vm_deinit(&dsl->vm);
}

struct hc_value *hc_dsl_getenv(struct hc_dsl *dsl, const char *key) {
  struct env_item *it = hc_set_find(&dsl->env, &key);
  return it ? &it->value : NULL;
}

struct hc_value *hc_dsl_setenv(struct hc_dsl *dsl,
			       const char *key,
			       const struct hc_type *type) {
  struct env_item *it = hc_set_add(&dsl->env, &key, false);
  it->key = strdup(key);
  hc_value_init(&it->value, type);
  return &it->value;
}

void hc_dsl_set_fun(struct hc_dsl *dsl, const char *key, hc_vm_fun_t val) {
  hc_dsl_setenv(dsl, key, &HC_VM_FUN)->as_other = val;
}

void hc_dsl_set_string(struct hc_dsl *dsl, const char *key, const char *val) {
  hc_dsl_setenv(dsl, key, &HC_STRING)->as_string = strdup(val);
}

void hc_dsl_eval(struct hc_dsl *dsl, const char *in) {
  struct hc_list forms;
  hc_list_init(&forms);
  hc_defer(hc_forms_free(&forms));
  struct hc_sloc sloc = hc_sloc("eval", 0, 0);
  while (hc_read_next(&in, &forms, &sloc));
  const size_t pc = dsl->vm.code.length;
  hc_forms_emit(&forms, dsl);
  hc_vm_eval(&dsl->vm, pc, -1);
}

void hc_form_init(struct hc_form *f,
		  const struct hc_form_type *t,
		  const struct hc_sloc sloc,
		  struct hc_list *owner) {
  f->type = t;
  f->sloc = sloc;

  if (owner) {
    hc_list_push_back(owner, &f->owner);
  } else {
    hc_list_init(&f->owner);
  }
}

void hc_form_emit(struct hc_form *f, struct hc_dsl *dsl) {
  assert(f->type->emit);
  f->type->emit(f, dsl);
}

void hc_form_print(struct hc_form *f, struct hc_stream *out) {
  assert(f->type->print);
  f->type->print(f, out);
}

struct hc_value *hc_form_value(const struct hc_form *f, struct hc_dsl *dsl) {
  return f->type->value ? f->type->value(f, dsl) : NULL;
}

void hc_form_free(struct hc_form *f) {
  hc_list_delete(&f->owner);
  assert(f->type->free);
  f->type->free(f);
}

static void call_emit(struct hc_form *_f, struct hc_dsl *dsl) {
  struct hc_call *f = hc_baseof(_f, struct hc_call, form);
  struct hc_value *t = hc_form_value(f->target, dsl);

  if (!t) {
    hc_throw("Error in %s: Missing call target",
	     hc_sloc_string(&_f->sloc));
  }

  if (t->type != &HC_VM_FUN) {
    hc_throw("Error in %s: '%s' isn't callable",
	     hc_sloc_string(&_f->sloc),
	     t->type->name);
  }

  hc_list_do(&f->args, a) {
    hc_form_emit(hc_baseof(a, struct hc_form, owner), dsl);
  }

  hc_vm_emit(&dsl->vm,
	     &HC_CALL,
	     &(struct hc_call_op){
	       .target = t->as_other,
	       .sloc = _f->sloc
	     });
}

static void call_print(const struct hc_form *_f, struct hc_stream *out) {
  struct hc_call *f = hc_baseof(_f, struct hc_call, form);
  hc_putc(out, '(');
  hc_form_print(f->target, out);

  hc_list_do(&f->args, i) {
    hc_putc(out, ' ');
    hc_form_print(hc_baseof(i, struct hc_form, owner), out);
  }

  hc_putc(out, ')');
}

static void call_free(struct hc_form *_f) {
  struct hc_call *f = hc_baseof(_f, struct hc_call, form);
  hc_form_free(f->target);

  hc_list_do(&f->args, i) {
    hc_form_free(hc_baseof(i, struct hc_form, owner));
  }

  free(f);
}

const struct hc_form_type HC_CALL_FORM = {
  .emit = call_emit,
  .print = call_print,
  .value = NULL,
  .free = call_free
};

void hc_call_init(struct hc_call *f,
		  const struct hc_sloc sloc,
		  struct hc_list *owner,
		  struct hc_form *target) {
  hc_form_init(&f->form, &HC_CALL_FORM, sloc, owner);
  f->target = target;
  hc_list_init(&f->args);
}

static void id_emit(struct hc_form *_f, struct hc_dsl *dsl) {
  struct hc_id *f = hc_baseof(_f, struct hc_id, form);
  struct hc_value *v = hc_dsl_getenv(dsl, f->name);

  if (!v) {
    hc_throw("Error in %s: Unknown identifier '%s'",
	     hc_sloc_string(&_f->sloc), f->name);
  }

  struct hc_push_op op;
  hc_value_copy(&op.value, v);
  hc_vm_emit(&dsl->vm, &HC_PUSH, &op);
}

static void id_print(const struct hc_form *_f, struct hc_stream *out) {
  struct hc_id *f = hc_baseof(_f, struct hc_id, form);
  hc_puts(out, f->name);
}

static struct hc_value *id_value(const struct hc_form *_f,
				 struct hc_dsl *dsl) {
  struct hc_id *f = hc_baseof(_f, struct hc_id, form);
  return hc_dsl_getenv(dsl, f->name);
}

static void id_free(struct hc_form *_f) {
  struct hc_id *f = hc_baseof(_f, struct hc_id, form);
  free(f->name);
  free(f);
}

const struct hc_form_type HC_ID_FORM = {
  .emit = id_emit,
  .print = id_print,
  .value = id_value,
  .free = id_free
};

void hc_id_init(struct hc_id *f,
		const struct hc_sloc sloc,
		struct hc_list *owner,
		const char *name) {
  hc_form_init(&f->form, &HC_ID_FORM, sloc, owner);
  f->name = strdup(name);
}

static void literal_emit(struct hc_form *_f, struct hc_dsl *dsl) {
  struct hc_literal *f = hc_baseof(_f, struct hc_literal, form);
  struct hc_push_op op;
  hc_value_copy(&op.value, &f->value);
  hc_vm_emit(&dsl->vm, &HC_PUSH, &op);
}

static void literal_print(const struct hc_form *_f, struct hc_stream *out) {
  struct hc_literal *f = hc_baseof(_f, struct hc_literal, form);
  hc_value_write(&f->value, out);
}

static struct hc_value *literal_value(const struct hc_form *_f,
				      struct hc_dsl *dsl) {
  struct hc_literal *f = hc_baseof(_f, struct hc_literal, form);
  return &f->value;
}

static void literal_free(struct hc_form *_f) {
  struct hc_literal *f = hc_baseof(_f, struct hc_literal, form);
  hc_value_deinit(&f->value);
  free(f);
}

const struct hc_form_type HC_LITERAL = {
  .emit = literal_emit,
  .print = literal_print,
  .value = literal_value,
  .free = literal_free,
};

void hc_literal_init(struct hc_literal *f,
		     const struct hc_sloc sloc,
		     struct hc_list *owner) {
  hc_form_init(&f->form, &HC_LITERAL, sloc, owner);
}

void hc_skip_ws(const char **in, struct hc_sloc *sloc) {
  for (;; (*in)++) {
    switch (**in) {
    case ' ':
    case '\t':
      sloc->col++;
      break;
    case '\n':
      sloc->row++;
      sloc->col = 0;
      break;
    default:
      return;
    }
  }
}

void hc_read_call(const char **in,
		  struct hc_list *out,
		  struct hc_sloc *sloc) {
  struct hc_sloc floc = *sloc;

  if (**in != '(') {
    hc_throw("Error in %s: Invalid call syntax",
	     hc_sloc_string(sloc));
  }

  (*in)++;
  sloc->col++;
  hc_skip_ws(in, sloc);

  if (!hc_read_expr(in, out, sloc)) {
    hc_throw("Error in %s: Missing call target",
	     hc_sloc_string(sloc));
  }

  struct hc_form *t = hc_baseof(hc_list_pop_back(out),
				struct hc_form,
				owner);

  struct hc_call *f = malloc(sizeof(struct hc_call));
  hc_list_init(&t->owner);
  hc_call_init(f, floc, out, t);

  for (bool done = false; !done;) {
    hc_skip_ws(in, sloc);

    switch (**in) {
    case 0:
      hc_form_free(&f->form);

      hc_throw("Error in %s: Open call form",
	       hc_sloc_string(sloc));
    case ')':
      (*in)++;
      sloc->col++;
      done = true;
      continue;
    default:
      break;
    }

    if (!hc_read_expr(in, &f->args, sloc)) {
      hc_form_free(&f->form);

      hc_throw("Error in %s: Invalid call syntax",
	       hc_sloc_string(sloc));
    }
  }
}

bool hc_read_expr(const char **in,
		  struct hc_list *out,
		  struct hc_sloc *sloc) {
  const char c = **in;

  switch (c) {
  case '(':
    hc_read_call(in, out, sloc);
    return true;
  default:
    if (isalpha(c)) {
      hc_read_id(in, out, sloc);
      return true;
    }

    break;
  }

  return false;
}

void hc_read_id(const char **in,
		struct hc_list *out,
		struct hc_sloc *sloc) {
  struct hc_sloc floc = *sloc;
  struct hc_memory_stream buf;
  hc_memory_stream_init(&buf, &hc_malloc_default);
  hc_defer(hc_stream_deinit(&buf.stream));
  char c = 0;

  while ((c = **in)) {
    if (isspace(c) || c == '(' || c == ')') {
      break;
    }

    hc_putc(&buf.stream, c);
    sloc->col++;
    (*in)++;
  }

  struct hc_id *f = malloc(sizeof(struct hc_id));
  hc_id_init(f, floc, out, hc_memory_stream_string(&buf));
}

bool hc_read_next(const char **in,
		  struct hc_list *out,
		  struct hc_sloc *sloc) {
  if (**in == '$') {
    (*in)++;
    hc_read_call(in, out, sloc);
    return true;
  }

  return hc_read_text(in, out, sloc);
}

bool hc_read_text(const char **in,
		  struct hc_list *out,
		  struct hc_sloc *sloc) {
  struct hc_sloc floc = *sloc;
  const char *start = *in;

  while (**in && **in != '$') {
    if (**in == '\n') {
      sloc->row++;
    } else {
      sloc->col++;
    }

    (*in)++;
  }

  size_t n = *in - start;

  if (n) {
    struct hc_value v;
    hc_value_init(&v, &HC_STRING)->as_string = strndup(start, n);
    struct hc_literal *vf = malloc(sizeof(struct hc_literal));
    hc_literal_init(vf, floc, out);
    vf->value = v;
    struct hc_id *t = malloc(sizeof(struct hc_literal));
    hc_id_init(t, floc, NULL, "print");
    struct hc_call *c = malloc(sizeof(struct hc_call));
    hc_call_init(c, floc, out, &t->form);
    return true;
  }

  return false;
}

void hc_forms_free(struct hc_list *in) {
  hc_list_do(in, i) {
    hc_form_free(hc_baseof(i, struct hc_form, owner));
  }
}

void hc_forms_emit(struct hc_list *in, struct hc_dsl *dsl) {
  hc_list_do(in, i) {
    hc_form_emit(hc_baseof(i, struct hc_form, owner), dsl);
  }
}

#include <assert.h>

#include "vm.h"
#include "malloc1/malloc1.h"

static void emit_tests() {
  struct hc_vm vm;
  hc_vm_init(&vm, &hc_malloc_default);
  hc_defer(hc_vm_deinit(&vm));
  struct hc_push_op op;
  hc_value_init(&op.value, &HC_FIX)->as_fix = hc_fix(0, 42);
  hc_vm_emit(&vm, &HC_PUSH, &op);
  hc_vm_eval(&vm, 0, -1);
  assert(vm.stack.length == 1);
  assert(hc_vm_pop(&vm)->as_fix == op.value.as_fix);
}

void vm_tests() {
  emit_tests();
}

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "dynamic/dynamic.h"
#include "error/error.h"
#include "malloc1/malloc1.h"
#include "macro/macro.h"
#include "stream1.h"

size_t hc_read(struct hc_stream *s, uint8_t *data, const size_t n) {
  assert(s->read);
  return s->read(s, data, n);
}

size_t hc_write(struct hc_stream *s, const uint8_t *data, const size_t n) {
  assert(s->write);
  return s->write(s, data, n);
}

char hc_getc(struct hc_stream *s) {
  char c = 0;
  return hc_read(s, (uint8_t *)&c, 1) ? c : 0;
}

char *hc_gets(struct hc_stream *s, struct hc_malloc *malloc) {
  struct hc_vector out;
  hc_vector_init(&out, malloc, 1);

  for (;;) {
    char c = hc_getc(s);

    if (c == EOF) {
      break;
    }

    *(char *)hc_vector_push(&out) = c;

    if (c == '\n') {
      break;
    }
  }

  *(char *)hc_vector_push(&out) = 0;
  return (char *)out.start;
}

size_t hc_putc(struct hc_stream *s, const char data) {
  const uint8_t d[2] = {data, 0};
  return hc_write(s, d, 1);
}

size_t hc_puts(struct hc_stream *s, const char *data) {
  return hc_write(s, (const uint8_t *)data, strlen(data));
}

size_t hc_vprintf(struct hc_stream *s,
		  const char *spec,
		  va_list args) {
  char *data = hc_vsprintf(spec, args);
  hc_defer(free(data));
  return hc_write(s, (uint8_t *)data, strlen(data));
}

size_t hc_printf(struct hc_stream *s, const char *spec, ...) {
  va_list args;
  va_start(args, spec);
  hc_defer(va_end(args));
  return hc_vprintf(s, spec, args);
}

void hc_stream_deinit(struct hc_stream *s) {
  assert(s->deinit);
  s->deinit(s);
}

size_t file_read(struct hc_stream *s, uint8_t *data, const size_t n) {
  struct hc_file_stream *fs = hc_baseof(s, struct hc_file_stream, stream);
  assert(fs->file);
  return fread(data, n, 1, fs->file);
}

size_t file_write(struct hc_stream *s, const uint8_t *data, const size_t n) {
  struct hc_file_stream *fs = hc_baseof(s, struct hc_file_stream, stream);
  assert(fs->file);
  return fwrite(data, n, 1, fs->file);
}

void file_deinit(struct hc_stream *s) {
  struct hc_file_stream *fs = hc_baseof(s, struct hc_file_stream, stream);

  if (fs->opts.close_file) {
    assert(fs->file);

    if (fclose(fs->file) == EOF) {
      hc_throw("Failed closing file");
    }

    fs->file = NULL;
  }
}

struct hc_file_stream *_hc_file_stream_init(struct hc_file_stream *s,
					    FILE *file,
					    const struct hc_file_stream_opts opts) {
  s->stream = (struct hc_stream){
    .read   = file_read,
    .write  = file_write,
    .deinit = file_deinit,
  };

  s->file = file;
  s->opts = opts;
  return s;
};

struct hc_stream *hc_stdout() {
  static __thread bool init = true;
  static __thread struct hc_file_stream s;

  if (init) {
    hc_file_stream_init(&s, stdout);
    init = false;
  }

  return &s.stream;
}

size_t memory_read(struct hc_stream *s, uint8_t *data, size_t n) {
  struct hc_memory_stream *ms = hc_baseof(s, struct hc_memory_stream, stream);

  if (ms->rpos + n > ms->data.length) {
    n = ms->data.length - ms->rpos;
  }

  memcpy(data, ms->data.start + ms->rpos, n);
  ms->rpos += n;
  return n;
}

size_t memory_write(struct hc_stream *s,
		    const uint8_t *data,
		    const size_t n) {
  struct hc_memory_stream *ms = hc_baseof(s, struct hc_memory_stream, stream);
  uint8_t *const dst = hc_vector_insert(&ms->data, ms->data.length, n);
  memcpy(dst, data, n);
  return n;
}

void memory_deinit(struct hc_stream *s) {
  struct hc_memory_stream *ms = hc_baseof(s, struct hc_memory_stream, stream);
  hc_vector_deinit(&ms->data);
}

struct hc_memory_stream *hc_memory_stream_init(struct hc_memory_stream *s,
					       struct hc_malloc *malloc) {
  s->stream = (struct hc_stream){
    .read   = memory_read,
    .write  = memory_write,
    .deinit = memory_deinit,
  };

  hc_vector_init(&s->data, malloc, 1);
  s->rpos = 0;
  return s;
}

const char *hc_memory_stream_string(struct hc_memory_stream *s) {
  if (!s->data.length || (*(s->data.end-1))) {
    *(uint8_t *)hc_vector_push(&s->data) = 0;
  }

  return (const char *)s->data.start;
}

#include <stdlib.h>
#include "set.h"

struct hc_set *hc_set_init(struct hc_set *s,
			   struct hc_malloc *malloc,
			   const size_t item_size,
			   hc_cmp_t cmp) {
  hc_vector_init(&s->items, malloc, item_size);
  s->cmp = cmp;
  s->key = NULL;
  return s;
}

void hc_set_deinit(struct hc_set *s) {
  hc_vector_deinit(&s->items);
}

size_t hc_set_index(const struct hc_set *s, const void *key, bool *ok) {
  size_t min = 0, max = s->items.length;

  while (min < max) {
    const size_t i = (min+max)/2;
    const void *v = hc_vector_get_const(&s->items, i);
    const void *k = s->key ? s->key(v) : v;

    switch (s->cmp(key, k)) {
    case HC_LT:
      max = i;
      break;
    case HC_GT:
      min = i+1;
      break;
    default:
      if (ok) {
	*ok = true;
      }

      return i;
    }
  }

  return min;
}

size_t hc_set_length(const struct hc_set *s) {
  return s->items.length;
}

void *hc_set_find(struct hc_set *s, const void *key) {
  bool ok = false;
  const size_t i = hc_set_index(s, key, &ok);
  return ok ? hc_vector_get(&s->items, i) : NULL;
}

void *hc_set_add(struct hc_set *s, const void *key, const bool force) {
  bool ok = false;
  const size_t i = hc_set_index(s, key, &ok);

  if (ok && !force) {
    return NULL;
  }

  return hc_vector_insert(&s->items, i, 1);
}

void hc_set_clear(struct hc_set *s) {
  hc_vector_clear(&s->items);
}

#include <stddef.h>
#include <stdlib.h>
#include "task.h"

struct hc_task *hc_task_init(struct hc_task *t,
			     struct hc_task_list *tl,
			     hc_task_body body) {
  t->body = body;
  t->state = 0;
  t->done = false;
  hc_list_push_back(&tl->tasks, &t->list);
  return t;
}

struct hc_task_list *hc_task_list_init(struct hc_task_list *tl) {
  hc_list_init(&tl->tasks);
  return tl;
}

void hc_task_list_run(const struct hc_task_list *tl) {
  bool all_done = false;

  while (!all_done) {
    all_done = true;

    hc_list_do(&tl->tasks, i) {
      struct hc_task *t = hc_baseof(i, struct hc_task, list);

      if (!t->done) {
	t->body(t);
	all_done = false;
      }
    }
  }
}

#include "error/error.h"

#include "dsl/benchmarks.c"
#include "fix/benchmarks.c"
#include "malloc2/benchmarks.c"

int main() {
  fix_benchmarks();
  malloc2_benchmarks();
  dsl_benchmarks();

  hc_errors_deinit();
  return 0;
}

#include <assert.h>
#include "malloc1.h"

void malloc1_tests() {
  assert(hc_align(0, 4) == 0);
  assert(hc_align(1, 4) == 4);
  assert(hc_align(3, 4) == 4);
  assert(hc_align(4, 4) == 4);
  assert(hc_align(5, 4) == 8);

  const int s = 1024;
  struct hc_bump_alloc a;
  hc_bump_alloc_init(&a, &hc_malloc_default, s);
  hc_defer(hc_bump_alloc_deinit(&a));
  assert(a.size == s);
  assert(a.offset == 0);

  int *ip = hc_acquire(&a.malloc, sizeof(int));
  *ip = 42;

  long *lp = hc_acquire(&a.malloc, sizeof(long));
  *lp = 42L;

  assert(a.offset >= sizeof(int) + sizeof(long));
  bool caught = false;

  void on_catch(struct hc_error *e) {
    assert(hc_streq(e->message, HC_NO_MEMORY) == 0);
    caught = true;
  }

  hc_catch(on_catch) {
    hc_acquire(&a.malloc, s);
    assert(false);
  }

  assert(caught);
}

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "error.h"
#include "malloc1/malloc1.h"
#include "vector/vector.h"

__thread struct hc_error *hc_error = NULL;

static struct hc_vector *handlers() {
  static bool init = true;
  static __thread struct hc_vector handlers;

  if (init) {
    hc_vector_init(&handlers, &hc_malloc_default, sizeof(jmp_buf));
    init = false;
  }

  return &handlers;
}

void hc_catch_push(jmp_buf h) {
  memcpy((jmp_buf *)hc_vector_push(handlers()), h, sizeof(jmp_buf));
}

void hc_catch_pop() {
  hc_vector_pop(handlers());
}

void hc_errors_deinit() {
  hc_vector_deinit(handlers());
}

void _hc_throw(struct hc_error *e) {
  struct hc_vector *hs = handlers();

  if (!hs->length) {
    fputs(e->message, stderr);
    hc_error_free(e);
    abort();
  }

  jmp_buf t;
  memcpy(t, *(jmp_buf *)hc_vector_pop(hs), sizeof(jmp_buf));
  hc_error = e;
  longjmp(t, 1);
}

struct hc_error *hc_error_new(const char *message, ...) {
  va_list args;
  va_start(args, message);

  va_list tmp_args;
  va_copy(tmp_args, args);
  int len = vsnprintf(NULL, 0, message, tmp_args);
  va_end(tmp_args);

  if (len < 0) {
    vfprintf(stderr, message, args);
    abort();
  }

  len++;
  struct hc_error *e = malloc(sizeof(struct hc_error));
  e->message = malloc(len);
  vsnprintf(e->message, len, message, args);
  va_end(args);
  return e;
}

void hc_error_free(struct hc_error *e) {
  free(e->message);
  free(e);
}

bool hc_streq(const char *l, const char *r) {
  for (; *l && *l == *r; l++, r++);
  return *l == *r;
}

#include <stdlib.h>
#include <stdio.h>
#include "error/error.h"
#include "macro/macro.h"
#include "malloc2.h"

/* Memo */

struct memo {
  size_t size;
  uint8_t data[];
};

static void *memo_acquire(struct hc_malloc *a, size_t size) {
  struct hc_memo_alloc *ma = hc_baseof(a, struct hc_memo_alloc, malloc);

  if (hc_set_length(&ma->memo)) {
    bool ok = false;
    size_t i = hc_set_index(&ma->memo, &size, &ok);

    if (ok) {
      struct hc_vector *is = &ma->memo.items;
      struct memo *m = *(struct memo **)hc_vector_get(is, i);
      hc_vector_delete(is, i, 1);
      return m->data;
    }
  }

  struct memo *m = hc_acquire(ma->source, sizeof(struct memo) + size);
  m->size = size;
  return m->data;
}

static void memo_release(struct hc_malloc *a, void *p) {
  struct hc_memo_alloc *ma = hc_baseof(a, struct hc_memo_alloc, malloc);
  struct memo *m = hc_baseof(p, struct memo, data);
  *(struct memo **)hc_set_add(&ma->memo, &m->size, true) = m;
}

static enum hc_order memo_cmp(const void *l, const void *r) {
  return hc_cmp(*(size_t *)l, *(size_t *)r);
}

static const void *memo_key(const void *p) {
  struct memo *m = *(struct memo **)p;
  return &m->size;
}

struct hc_memo_alloc *hc_memo_alloc_init(struct hc_memo_alloc *a,
					 struct hc_malloc *source) {
  a->malloc.acquire = memo_acquire;
  a->malloc.release = memo_release;
  a->source = source;
  hc_set_init(&a->memo, &hc_malloc_default, sizeof(struct memo *), memo_cmp);
  a->memo.key = memo_key;
  return a;
}

void hc_memo_alloc_deinit(struct hc_memo_alloc *a) {
  hc_vector_do(&a->memo.items, _m) {
    struct memo *m = *(struct memo **)_m;
    hc_release(a->source, m);
  }

  hc_set_deinit(&a->memo);
}

/* Slab */

struct slab {
  struct hc_list slabs;
  uint8_t *next;
  uint8_t memory[];
};

static struct slab *add_slab(struct hc_slab_alloc *a, const size_t size) {
  struct slab *s = hc_acquire(a->source, sizeof(struct slab) + size);
  hc_list_push_front(&a->slabs, &s->slabs);
  s->next = s->memory;
  return s;
}

static struct slab *get_slab(struct hc_slab_alloc *a, const size_t size) {
  if (size > a->slab_size) {
    return add_slab(a, size);
  }

  struct slab *result = NULL;

  hc_list_do(&a->slabs, sl) {
    struct slab *s = hc_baseof(sl, struct slab, slabs);
    uint8_t *p = hc_align(s->next, size);

    if (p + size > s->memory + a->slab_size) {
      break;
    }

    result = s;
  }

  return result ? result : add_slab(a, a->slab_size);
}

static void *slab_acquire(struct hc_malloc *a, const size_t size) {
  struct hc_slab_alloc *sa = hc_baseof(a, struct hc_slab_alloc, malloc);
  struct slab *s = get_slab(sa, size);
  uint8_t *p = hc_align(s->next, size);
  s->next = p + size;

  while (s->slabs.next != &s->slabs) {
    struct slab *ns = hc_baseof(s->slabs.next, struct slab, slabs);

    if (ns->next - ns->memory > s->next - s->memory) {
      hc_list_shift_back(&s->slabs);
    } else {
      break;
    }
  }

  return p;
}

static void slab_release(struct hc_malloc *a, void *p) {
  // Do nothing
}

struct hc_slab_alloc *hc_slab_alloc_init(struct hc_slab_alloc *a,
					 struct hc_malloc *source,
					 const size_t slab_size) {
  a->malloc.acquire = slab_acquire;
  a->malloc.release = slab_release;
  a->source = source;
  hc_list_init(&a->slabs);
  a->slab_size = slab_size;
  return a;
}

void hc_slab_alloc_deinit(struct hc_slab_alloc *a) {
  hc_list_do(&a->slabs, _s) {
    struct slab *s = hc_baseof(_s, struct slab, slabs);
    hc_release(a->source, s);
  }
}

#include <assert.h>
#include <math.h>
#include <stdalign.h>
#include <stdlib.h>
#include <string.h>

#include "error/error.h"
#include "macro/macro.h"
#include "vm.h"

struct hc_sloc hc_sloc(const char *source, const int row, const int col) {
  struct hc_sloc s = {.source = {0}, .row = row, .col = col};
  assert(strlen(source) < sizeof(s.source));
  strcpy(s.source, source);
  return s;
}

const char *hc_sloc_string(struct hc_sloc *sloc) {
  snprintf(sloc->out, sizeof(sloc->out), "'%s'; row %d, column %d",
	  sloc->source, sloc->row, sloc->col);
  return sloc->out;
}

void hc_vm_init(struct hc_vm *vm, struct hc_malloc *malloc) {
  hc_vector_init(&vm->stack, malloc, sizeof(struct hc_value));
  hc_vector_init(&vm->ops, malloc, sizeof(const struct hc_op *));
  hc_vector_init(&vm->code, malloc, sizeof(hc_op_eval_t));
}

static size_t op_items(const struct hc_op *op,
		       uint8_t *p,
		       struct hc_vm *vm) {
  const size_t s = op->size + hc_align(p, op->align) - p;
  return ceil(s / (double)vm->code.item_size);
}

static void deinit_stack(struct hc_vm *vm) {
  hc_vector_do(&vm->stack, v) {
    hc_value_deinit(v);
  }

  hc_vector_deinit(&vm->stack);
}

static void deinit_ops(struct hc_vm *vm) {
  uint8_t *p = vm->code.start;

  hc_vector_do(&vm->ops, _op) {
    const struct hc_op *op = *(const struct hc_op **)_op;
    p += sizeof(hc_op_eval_t);

    if (op->deinit) {
      op->deinit(hc_align(p, op->align));
    }

    p += op_items(op, p, vm) * vm->code.item_size;
  }

  hc_vector_deinit(&vm->ops);
}

void hc_vm_deinit(struct hc_vm *vm) {
  deinit_stack(vm);
  deinit_ops(vm);
  hc_vector_deinit(&vm->code);
}

struct hc_value *hc_vm_push(struct hc_vm *vm) {
  return hc_vector_push(&vm->stack);
}

struct hc_value *hc_vm_peek(struct hc_vm *vm) {
  return hc_vector_peek(&vm->stack);
}

struct hc_value *hc_vm_pop(struct hc_vm *vm) {
  return hc_vector_pop(&vm->stack);
}

size_t hc_vm_emit(struct hc_vm *vm,
		  const struct hc_op *op,
		  const void *data) {
  *(const struct hc_op **)hc_vector_push(&vm->ops) = op;
  const size_t pc = vm->code.length;
  *(hc_op_eval_t *)hc_vector_push(&vm->code) = op->eval;

  uint8_t *const p = hc_vector_insert(&vm->code,
				      vm->code.length,
				      op_items(op, vm->code.end, vm));

  memcpy(hc_align(p, op->align), data, op->size);
  return pc;
}

void hc_vm_eval(struct hc_vm *vm,
		const size_t start_pc,
		const size_t end_pc) {
  const uint8_t *const ep = (end_pc == -1)
    ? vm->code.end
    : hc_vector_get(&vm->code, end_pc);

  for (uint8_t *p = hc_vector_get(&vm->code, start_pc);
       p != ep;
       p = (*(hc_op_eval_t *)p)(vm, p + vm->code.item_size));
}

static void fun_print(const struct hc_value *v, struct hc_stream *out) {
  hc_printf(out, "%p", v->as_other);
}

const struct hc_type HC_VM_FUN = {
  .name = "VM/Fun",
  .copy = NULL,
  .print = fun_print
};

static uint8_t *call_eval(struct hc_vm *vm, uint8_t *data) {
  struct hc_call_op *op = (void *)hc_align(data, alignof(struct hc_call_op));
  op->target(vm, op->sloc);
  return (uint8_t *)op + sizeof(struct hc_call_op);
}

const struct hc_op HC_CALL = (struct hc_op){
  .name = "call",
  .align = alignof(struct hc_call_op),
  .size = sizeof(struct hc_call_op),
  .eval = call_eval,
  .deinit = NULL
};

static void push_deinit(uint8_t *data) {
  struct hc_push_op *op = (void *)data;
  hc_value_deinit(&op->value);
}

static uint8_t *push_eval(struct hc_vm *vm, uint8_t *data) {
  struct hc_push_op *op = (void *)hc_align(data, alignof(struct hc_push_op));
  hc_value_copy(hc_vm_push(vm), &op->value);
  return (uint8_t *)op + sizeof(struct hc_push_op);
}

const struct hc_op HC_PUSH = (struct hc_op){
  .name = "push",
  .align = alignof(struct hc_push_op),
  .size = sizeof(struct hc_push_op),
  .eval = push_eval,
  .deinit = push_deinit
};

#include <assert.h>
#include "macro.h"

void macro_tests() {
  int hc_id(foo, bar) = 42;
  assert(foobar == 42);

  assert(hc_min(7, 42) == 7);
  assert(hc_max(7.0, 42.0) == 42.0);

  {
    int foo = 0;

    {
      hc_defer(assert(foo++ == 1));
      hc_defer(assert(foo++ == 0));
    }

    assert(foo == 2);
  }
}

#include <assert.h>
#include <stdio.h>
#include "task.h"

struct my_task {
  struct hc_task task;
  int *value;
};

static void producer(struct hc_task *task) {
  int *value = hc_baseof(task, struct my_task, task)->value;

  switch (task->state) {
  case 0:
    assert(*value == 0);
    (*value)++;
    hc_task_yield(task);
    assert(*value == 2);
    (*value)++;
  }

  task->done = true;
}

static void consumer(struct hc_task *task) {
  int *value = hc_baseof(task, struct my_task, task)->value;

  switch (task->state) {
  case 0:
    assert(*value == 1);
    (*value)++;
    hc_task_yield(task);
    assert(*value == 3);
    (*value)++;
  }

  task->done = true;
}

void task_tests() {
  struct hc_task_list tl;
  hc_task_list_init(&tl);

  int value = 0;

  struct my_task pt = {.value = &value};
  hc_task_init(&pt.task, &tl, &producer);

  struct my_task ct = {.value = &value};
  hc_task_init(&ct.task, &tl, &consumer);

  hc_task_list_run(&tl);
  assert(value == 4);
}

#include "error/error.h"

#include "chrono/tests.c"
#include "dsl/tests.c"
#include "dynamic/tests.c"
#include "error/tests.c"
#include "fix/tests.c"
#include "list/tests.c"
#include "macro/tests.c"
#include "malloc1/tests.c"
#include "malloc2/tests.c"
#include "reflect/tests.c"
#include "set/tests.c"
#include "slog/tests.c"
#include "stream1/tests.c"
#include "task/tests.c"
#include "vector/tests.c"
#include "vm/tests.c"

int main() {
  chrono_tests();
  dsl_tests();
  dynamic_tests();
  error_tests();
  fix_tests();
  list_tests();
  macro_tests();
  malloc1_tests();
  malloc2_tests();
  reflect_tests();
  set_tests();
  slog_tests();
  stream1_tests();
  task_tests();
  vector_tests();
  vm_tests();

  hc_errors_deinit();
  return 0;
}

#include "macro.h"

size_t hc_alignof(size_t size) {
  const size_t max = _Alignof(max_align_t);
  if (size >= max) { return max; }
  size_t v = 1;
  for (size_t nv = 1; nv <= size; v = nv, nv = v << 1);
  return v;
}

#include <assert.h>
#include "malloc2.h"

static void memo_tests() {
  struct hc_memo_alloc a;
  hc_memo_alloc_init(&a, &hc_malloc_default);

  int *ip1 = hc_acquire(&a.malloc, sizeof(int));

  long *lp = hc_acquire(&a.malloc, sizeof(long));
  assert((int *)lp != ip1);
  *lp = 42;

  hc_release(&a.malloc, ip1);
  int *ip2 = hc_acquire(&a.malloc, sizeof(int));
  assert(ip2 == ip1);
  *ip2 = 42;

  int *ip3 = hc_acquire(&a.malloc, sizeof(int));
  assert(ip3 != ip1);
  *ip3 = 42;

  hc_release(&a.malloc, lp);
  hc_release(&a.malloc, ip2);
  hc_release(&a.malloc, ip3);

  hc_memo_alloc_deinit(&a);
}

static void slab_tests() {
  struct hc_slab_alloc a;
  hc_slab_alloc_init(&a, &hc_malloc_default, 2 * sizeof(int));
  assert(a.slab_size == 2 * sizeof(int));

  const int *p1 = hc_acquire(&a.malloc, sizeof(int));
  const int *p2 = hc_acquire(&a.malloc, sizeof(int));
  assert(p2 == p1 + 1);

  const int *p3 = hc_acquire(&a.malloc, sizeof(int));
  assert(p3 > p2 + 1);

  const int *p4 = hc_acquire(&a.malloc, 10 * sizeof(int));
  assert(p4 > p3 + 1);

  hc_slab_alloc_deinit(&a);
}

void malloc2_tests() {
  memo_tests();
  slab_tests();
}

#include <stdlib.h>
#include <stdio.h>
#include "error/error.h"
#include "macro/macro.h"
#include "malloc1.h"

static void *default_acquire(struct hc_malloc *m, size_t size) {
  return malloc(size);
}

static void default_release(struct hc_malloc *m, void *p) {
  free(p);
}

struct hc_malloc hc_malloc_default = {.acquire = default_acquire,
				      .release = default_release};

__thread struct hc_malloc *hc_mallocp = NULL;

/* Bump */

static void *bump_acquire(struct hc_malloc *a, size_t size) {
  if (size <= 0) {
    hc_throw(HC_INVALID_SIZE);
  }

  struct hc_bump_alloc *ba = hc_baseof(a, struct hc_bump_alloc, malloc);

  if (ba->size - ba->offset < size) {
    hc_throw(HC_NO_MEMORY);
  }

  uint8_t *p = ba->memory + ba->offset;
  uint8_t *pa = hc_align(p, size);
  ba->offset = ba->offset + pa - p + size;
  return pa;
}

static void bump_release(struct hc_malloc *a, void *p) {
  //Do nothing
}

void hc_bump_alloc_init(struct hc_bump_alloc *a,
			struct hc_malloc *source,
			size_t size) {
  a->malloc.acquire = bump_acquire;
  a->malloc.release = bump_release;
  a->source = source;
  a->size = size;
  a->offset = 0;
  a->memory = hc_acquire(source, size);
}

void hc_bump_alloc_deinit(struct hc_bump_alloc *a) {
  hc_release(a->source, a->memory);
}

#include <assert.h>
#include <string.h>
#include "dsl.h"

static void read_call_tests() {
  struct hc_sloc sloc = hc_sloc("read_call_tests", 0, 0);

  struct hc_list out;
  hc_list_init(&out);
  hc_defer(hc_forms_free(&out));

  const char *s = "( foo bar )";
  const char *in = s;
  assert(hc_read_expr(&in, &out, &sloc));

  struct hc_form *f = hc_baseof(out.next, struct hc_form, owner);
  assert(f->type == &HC_CALL_FORM);
}

static void read_id_tests() {
  struct hc_sloc sloc = hc_sloc("read_id_tests", 0, 0);

  struct hc_list out;
  hc_list_init(&out);
  hc_defer(hc_forms_free(&out));

  const char *s = "foo";
  const char *in = s;
  assert(hc_read_expr(&in, &out, &sloc));

  struct hc_form *f = hc_baseof(out.next, struct hc_form, owner);
  assert(f->type == &HC_ID_FORM);
}

static void eval_tests() {
  struct hc_dsl dsl;
  hc_dsl_init(&dsl, &hc_malloc_default);
  hc_defer(hc_dsl_deinit(&dsl));
  struct hc_memory_stream out;
  hc_memory_stream_init(&out, &hc_malloc_default);
  hc_defer(hc_stream_deinit(&out.stream));
  dsl.out = &out.stream;
  hc_dsl_set_string(&dsl, "foo", "ghi");
  hc_dsl_eval(&dsl, "abc $(print (upcase foo)) def");
  assert(strcmp("abc GHI def", hc_memory_stream_string(&out)) == 0);
}

void dsl_tests() {
  read_id_tests();
  read_call_tests();
  eval_tests();
}

#include <assert.h>
#include "dynamic.h"

void dynamic_tests() {
  const char *out = "/var/tmp/libtest.so";

  hc_compile("#include <stdio.h>\n"
	     "int test() { return 42; }",
	     out,
	     .cflags = (const char *[]){"-Wall",
					"-fsanitize=undefined",
					NULL});

  struct hc_dlib lib;
  hc_dlib_init(&lib, out);
  hc_defer(hc_dlib_deinit(&lib));
  int (*fn)() = hc_dlib_find(&lib, "test");
  assert(fn() == 42);
}

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "error.h"

void error_tests() {
  void on_catch(struct hc_error *e) {
    assert(hc_streq("E123", e->message) == 0);
  }

  hc_catch(on_catch) {
    hc_throw("E123 Going %s", "Down!");
  }
}

#include <assert.h>
#include "reflect.h"

void reflect_tests() {
  struct hc_value v;
  hc_value_init(&v, &HC_STRING)->as_string = strdup("foo");
  hc_defer(hc_value_deinit(&v));
  struct hc_value c;
  hc_value_copy(&c, &v);
  hc_defer(hc_value_deinit(&c));
  assert(strcmp(c.as_string, v.as_string) == 0);
}

#include <assert.h>
#include <string.h>
#include "stream1.h"

void stream1_tests() {
  struct hc_memory_stream s;
  hc_memory_stream_init(&s, &hc_malloc_default);
  hc_defer(hc_stream_deinit(&s.stream));
  hc_printf(&s.stream, "%s%d", "foo", 42);
  assert(strcmp("foo42", hc_memory_stream_string(&s)) == 0);
}

#include <stddef.h>
#include "list.h"

void hc_list_init(struct hc_list *l) {
  l->prev = l->next = l;
}

bool hc_list_nil(const struct hc_list *l) {
  return l->prev == l && l->next == l;
}

struct hc_list *hc_list_delete(struct hc_list *l) {
  l->prev->next = l->next;
  l->next->prev = l->prev;
  return l;
}

void hc_list_push_front(struct hc_list *l, struct hc_list *it) {
  hc_list_push_back(l->next, it);
}

struct hc_list *hc_list_pop_front(struct hc_list *l) {
  struct hc_list *it = l->next;
  return (it == l) ? NULL : hc_list_delete(it);
}

struct hc_list *hc_list_peek_front(struct hc_list *l) {
  struct hc_list *it = l->next;
  return (it == l) ? NULL : it;
}

void hc_list_push_back(struct hc_list *l, struct hc_list *it) {
  it->prev = l->prev;
  l->prev->next = it;
  it->next = l;
  l->prev = it;
}

struct hc_list *hc_list_pop_back(struct hc_list *l) {
  struct hc_list *it = l->prev;
  return (it == l) ? NULL : hc_list_delete(it);
}

struct hc_list *hc_list_peek_back(struct hc_list *l) {
  struct hc_list *it = l->prev;
  return (it == l) ? NULL : it;
}

void hc_list_shift_back(struct hc_list *l) {
  l->next->prev = l->prev;
  l->prev->next = l->next;
  l->prev = l->next;
  l->next = l->next->next;
  l->prev->next = l;
  l->next->prev = l;
}

This code segment functions to: Benchmark and compare the execution time of arithmetic operations performed using two different numerical representations by iterating through a large set of calculations for each type while measuring processing duration.

```c
[TASK_BEGIN]
void fix_benchmarks() {
    const int ITERATIONS = 1000000;
    chrono_t timer;

    // Benchmark fixed-point multiplication
    chrono_start(&timer);
    for(int i = 0; i < ITERATIONS; i++) {
        fix_mul(0x10000, 0x10000);  // Q16.16 format 1.0 * 1.0
    }
    double mul_time = chrono_elapsed_us(&timer) / ITERATIONS;

    // Benchmark fixed-point division
    chrono_start(&timer);
    for(int i = 0; i < ITERATIONS; i++) {
        fix_div(0x10000, 0x10000);  // Q16.16 format 1.0 / 1.0
    }
    double div_time = chrono_elapsed_us(&timer) / ITERATIONS;

    printf("Fixed-point multiplication: %.3fus/op\n", mul_time);
    printf("Fixed-point division: %.3fus/op\n", div_time);
}
[TASK_END]
```

void fix_benchmarks() {
    const int ITERATIONS = 1000000;
    chrono_t timer;
    chrono_start(&timer);
    for(int i = 0; i < ITERATIONS; i++) {
        fix_mul(0x10000, 0x10000);
    }
    double mul_time = chrono_elapsed_us(&timer) / ITERATIONS;
    chrono_start(&timer);
    for(int i = 0; i < ITERATIONS; i++) {
        fix_div(0x10000, 0x10000);
    }
    double div_time = chrono_elapsed_us(&timer) / ITERATIONS;
    printf("Fixed-point multiplication: %.3fus/op\n", mul_time);
    printf("Fixed-point division: %.3fus/op\n", div_time);
}