Skip to content

Instantly share code, notes, and snippets.

@agrif
Last active May 4, 2023 04:50
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save agrif/6127126 to your computer and use it in GitHub Desktop.
Save agrif/6127126 to your computer and use it in GitHub Desktop.
a horrible, horrible, wonderful C Preprocessor hack library
#ifndef __CO_BASIC_H_INCLUDED__
#define __CO_BASIC_H_INCLUDED__
/* useful stuff, usable without the rest of Cobalt */
#include <string.h>
#define co_strcmp(a, b) strcmp(a, b)
#include <stdlib.h>
#define co_malloc(x) malloc(x)
#define co_free(x) free(x)
#define co_alloca(x) alloca(x)
#include <assert.h>
#define co_assert(test) assert(test)
#define co_runtime_assert(test) co_assert(test)
#define co_num_elements(array) (sizeof(array) / sizeof((array)[0]))
#endif /* __CO_BASIC_H_INCLUDED__ */
#ifndef __CO_BOOTSTRAP_H_INCLUDED__
#define __CO_BOOTSTRAP_H_INCLUDED__
/* things that nice C environments provide, but not all */
#ifndef bool
#define bool int
#endif
#ifndef false
#define false (0)
#endif
#ifndef true
#define true (!false)
#endif
#endif /* __CO_BOOTSTRAP_H_INCLUDED__ */
#include "co-iterate.h"
void* _co_iterate_initialize(void* obj, void* helper)
{
co_runtime_assert(obj);
co_runtime_assert(helper);
const CoIterate* iface = co_implementation(obj, CoIterate);
co_runtime_assert(iface);
co_runtime_assert(iface->initialize);
iface->initialize(obj, helper);
return helper;
}
bool co_iterate_next(void* obj, void* helper, void** out)
{
co_runtime_assert(obj);
co_runtime_assert(helper);
co_runtime_assert(out);
const CoIterate* iface = co_implementation(obj, CoIterate);
co_runtime_assert(iface);
co_runtime_assert(iface->next);
return iface->next(obj, helper, out);
}
#ifndef __CO_ITERATE_H_INCLUDED__
#define __CO_ITERATE_H_INCLUDED__
#include "co-type.h"
#include "co-basic.h"
typedef struct
{
size_t helper_size;
void (*initialize)(void*, void*);
bool (*next)(void*, void*, void**);
} CoIterate;
#define co_iterate_initialize(obj) \
_co_iterate_initialize(obj, co_alloca(co_implementation(obj, CoIterate)->helper_size))
void* _co_iterate_initialize(void* obj, void* helper);
bool co_iterate_next(void* obj, void* helper, void** out);
#define foreach(...) __foreach(__VA_ARGS__)
#define __foreach(x, haystack, astype) \
for (astype* x, *__haystack = (astype*)haystack, *__iter = (astype*)co_iterate_initialize(__haystack); co_iterate_next((void*)__haystack, (void*)__iter, (void**)&x);)
#define in ,
#define as ,
#endif /* __CO_ITERATE_H_INCLUDED__ */
#include "cobalt.h"
void* co_allocate_from_type(const CoType* type)
{
co_runtime_assert(type);
const CoNew* inew = co_type_implementation(type, CoNew);
co_runtime_assert(inew);
void* data = co_malloc(inew->size + sizeof(CoTypeTag)) + sizeof(CoTypeTag);
co_runtime_assert(data);
CoTypeTag* tag = (data - sizeof(CoTypeTag));
tag->type = type;
tag->on_heap = true;
return data;
}
void* co_new_from_type(const CoType* type)
{
const CoNew* inew = co_type_implementation(type, CoNew);
co_runtime_assert(inew);
void* data = co_allocate_from_type(type);
if (inew->construct)
inew->construct(data);
return data;
}
#include <stdio.h>
void co_deallocate(void* obj)
{
CoTypeTag* origaddr = obj - sizeof(CoTypeTag);
if (origaddr->on_heap)
co_free(origaddr);
}
void co_delete(void* obj)
{
const CoNew* inew = co_implementation(obj, CoNew);
co_runtime_assert(inew);
if (inew->deconstruct)
inew->deconstruct(obj);
co_deallocate(obj);
}
void* co_construct(void* obj)
{
const CoNew* inew = co_implementation(obj, CoNew);
co_runtime_assert(inew);
if (inew->construct)
inew->construct(obj);
return obj;
}
void co_deconstruct(void* obj)
{
const CoNew* inew = co_implementation(obj, CoNew);
co_runtime_assert(inew);
if (inew->deconstruct)
inew->deconstruct(obj);
}
#ifndef __CO_NEW_H_INCLUDED__
#define __CO_NEW_H_INCLUDED__
#include "co-type.h"
#include "co-basic.h"
typedef struct
{
size_t size;
void (*construct)(void*);
void (*deconstruct)(void*);
} CoNew;
#define co_allocate(base) \
(base*)co_allocate_from_type(((void)co_static_implementation(base, CoNew), co_static_type(base)))
#define co_new(base) \
(base*)co_new_from_type(((void)co_static_implementation(base, CoNew), co_static_type(base)))
void* co_allocate_from_type(const CoType* type);
void* co_new_from_type(const CoType* type);
void co_deallocate(void* obj);
void co_delete(void* obj);
#define co_allocatea(base) \
((base*)(memcpy(co_alloca(sizeof(CoTypeTag) + co_static_implementation(base, CoNew)->size), (CoTypeTag[]){{co_static_type(base), false}}, sizeof(CoTypeTag)) + sizeof(CoTypeTag)))
#define co_newa(base) \
((base*)co_construct(co_allocatea(base)))
#define co_allocatea_with_value(base, ...) \
((base*)memcpy(co_allocatea(base), (base[]){__VA_ARGS__}, sizeof(base)))
void* co_construct(void* obj);
void co_deconstruct(void* obj);
#endif /* __CO_NEW_H_INCLUDED__ */
#include "co-range.h"
static void co_range_construct(void* p)
{
CoRange* self = p;
self->start = 0;
self->end = 0;
}
co_implementation_define(CoRange, CoNew)
{
sizeof(CoRange),
co_range_construct,
NULL,
};
static void co_range_initialize(void* p, void* h)
{
CoRange* self = p;
int* helper = h;
*helper = self->start - 1;
}
static bool co_range_next(void* p, void* h, void** out)
{
CoRange* self = p;
int* helper = h;
*helper += 1;
if (*helper >= self->end)
return false;
*out = helper;
return true;
}
co_implementation_define(CoRange, CoIterate)
{
sizeof(int),
co_range_initialize,
co_range_next,
};
co_type_define(CoRange)
{
co_type_implements(CoRange, CoNew),
co_type_implements(CoRange, CoIterate),
co_type_end
};
#ifndef __CO_RANGE_H_INCLUDED__
#define __CO_RANGE_H_INCULDED__
#include "co-new.h"
#include "co-iterate.h"
typedef struct
{
int start;
int end;
} CoRange;
co_type_export(CoRange);
co_implementation_export(CoRange, CoNew);
co_implementation_export(CoRange, CoIterate);
#define co_range(start, end) co_allocatea_with_value(CoRange, {(start), (end)})
#endif /* __CO_RANGE_H_INCULDED__ */
#ifndef __CO_TYPE_H_INCLUDED__
#define __CO_TYPE_H_INCLUDED__
#include "co-bootstrap.h"
typedef struct
{
const char* name;
const void* value;
} CoInterfaceDef;
typedef struct
{
CoInterfaceDef* defs;
} CoType;
typedef struct
{
const CoType* type;
bool on_heap;
} CoTypeTag;
#define co_type_export(base) \
extern const CoType base##_type
#define co_implementation_export(base, iface) \
extern const iface base##_##iface##_implementation
#define co_static_implementation(base, iface) \
(&base##_##iface##_implementation)
#define co_static_type(base) \
(&base##_type)
#define co_type_define(base) \
static CoInterfaceDef base##_interfaces[]; \
const CoType base##_type = \
{ \
base##_interfaces, \
}; \
static CoInterfaceDef base##_interfaces[] =
#define co_type_implements(base, iface) \
{#iface, co_static_implementation(base, iface)}
#define co_type_end \
{NULL, NULL}
#define co_implementation_define(base, iface) \
const iface base##_##iface##_implementation =
const CoType* co_type(void* obj);
#define co_type_implementation(type, iface) \
((const iface*)co_type_implementation_with_name(type, #iface))
#define co_implementation(obj, iface) \
((const iface*)co_type_implementation_with_name(co_type(obj), #iface))
const void* co_type_implementation_with_name(const CoType* type, const char* name);
#endif /* __CO_TYPE_H_INCLUDED__ */
#include "cobalt.h"
const CoType* co_type(void* obj)
{
co_runtime_assert(obj);
CoTypeTag* tag = (obj - sizeof(CoTypeTag));
const CoType* type = tag->type;
co_runtime_assert(type);
co_runtime_assert(type->defs);
return type;
}
const void* co_type_implementation_with_name(const CoType* type, const char* name)
{
co_runtime_assert(type);
co_runtime_assert(name);
size_t i;
for (i = 0; type->defs[i].name != NULL; i++)
{
if (co_strcmp(type->defs[i].name, name) == 0)
{
co_runtime_assert(type->defs[i].value);
return type->defs[i].value;
}
}
return NULL;
}
#ifndef __COBALT_H_INCLUDED__
#define __COBALT_H_INCLUDED__
#include <stdlib.h>
#include "co-bootstrap.h"
#include "co-basic.h"
#include "co-type.h"
#include "co-new.h"
#include "co-iterate.h"
#include "co-range.h"
#endif /* __COBALT_H_INCLUDED__ */
OBJECTS = cobalt.o co-new.o co-iterate.o co-range.o test.o
TARGET = test
CFLAGS = -Wall -Werror -std=gnu99
.PHONY : all clean
all : ${TARGET}
clean :
rm -f ${TARGET} ${OBJECTS}
${TARGET} : ${OBJECTS}
#include "cobalt.h"
#include <stdio.h>
int main(int argc, char** argv)
{
foreach(x in co_range(0, 10) as int)
{
printf("iterating %i\n", *x);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment