c
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
a.out
|
||||
*.plist
|
||||
*.o
|
||||
*.exe
|
||||
core
|
12
adj_matrix.c
12
adj_matrix.c
@@ -1,12 +0,0 @@
|
||||
#include "common.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char buf[512];
|
||||
char *dest;
|
||||
|
||||
while (( dest = slowgraph_next_edge(stdin, buf, slowgraph_lenof(buf), 0) )) {
|
||||
printf("%s -> %s\n", buf, dest);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
201
common.h
201
common.h
@@ -1,201 +0,0 @@
|
||||
#ifndef SLOWGRAPH_COMMON_H
|
||||
#define SLOWGRAPH_COMMON_H
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define slowgraph_lenof(x) (sizeof((x)) / sizeof(*(x)))
|
||||
|
||||
static unsigned
|
||||
slowgraph_hash(char const *buf) {
|
||||
unsigned res = 5381;
|
||||
for (; *buf; buf++) {
|
||||
res = (res << 5) + res + *buf;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
slowgraph_hashn(void const *bufp, int len) {
|
||||
char const* buf = (char const *) bufp;
|
||||
unsigned res = 5381;
|
||||
for (; buf != buf + len; buf ++) {
|
||||
res = (res << 5) + res + *buf;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static char *
|
||||
slowgraph_next_edge(
|
||||
FILE* inp,
|
||||
char* buf, int bufn,
|
||||
void (*opt_attr_clbk)(char* node, char* key, char* val))
|
||||
{
|
||||
int c;
|
||||
char *n, *k, *v, *retv = 0;
|
||||
|
||||
c = fgetc(inp);
|
||||
|
||||
for (;;) {
|
||||
if (c == EOF) {
|
||||
retv = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (; isspace(c); c = fgetc(inp))
|
||||
;
|
||||
|
||||
if (c == '#') {
|
||||
c = fgetc(inp);
|
||||
if (c == '#' && opt_attr_clbk && buf == fgets(buf, bufn, inp)) {
|
||||
n = strtok(buf+1, " \r\n");
|
||||
k = strtok(0, " \r\n");
|
||||
v = strtok(0, " \r\n");
|
||||
opt_attr_clbk(n, k, v);
|
||||
} else {
|
||||
for (; c != EOF && c != '\n'; c = fgetc(inp))
|
||||
;
|
||||
c = fgetc(inp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for (k = buf; c != EOF && !isspace(c); k ++) {
|
||||
*k = c;
|
||||
c = fgetc(inp);
|
||||
}
|
||||
|
||||
*k++=0;
|
||||
|
||||
for (; isspace(c); c = fgetc(inp))
|
||||
;
|
||||
|
||||
for (v = k; c != EOF && !isspace(c); v ++) {
|
||||
*v = c;
|
||||
c = fgetc(inp);
|
||||
}
|
||||
*v = 0;
|
||||
|
||||
retv = k;
|
||||
break;
|
||||
}
|
||||
|
||||
ungetc(c, inp);
|
||||
return retv;
|
||||
}
|
||||
|
||||
typedef struct SlowGraph SlowGraph;
|
||||
typedef struct SlowGraphNode SlowGraphNode;
|
||||
typedef struct SlowGraphEdge SlowGraphEdge;
|
||||
typedef struct SlowGraphAttr SlowGraphAttr;
|
||||
|
||||
struct SlowGraphAttr {
|
||||
SlowGraphAttr* next;
|
||||
unsigned hash;
|
||||
char *key, *val;
|
||||
};
|
||||
|
||||
static char*
|
||||
SlowGraphAttr_find(SlowGraphAttr* a, unsigned hash) {
|
||||
for (; a; a = a->next)
|
||||
if (a->hash == hash)
|
||||
return a->val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct SlowGraphNode {
|
||||
SlowGraphNode *next;
|
||||
|
||||
unsigned name_hash;
|
||||
char *name;
|
||||
SlowGraphAttr* attr;
|
||||
SlowGraphEdge* children;
|
||||
|
||||
unsigned gc_used : 1;
|
||||
};
|
||||
|
||||
struct SlowGraphEdge {
|
||||
SlowGraphEdge *next;
|
||||
unsigned cost;
|
||||
unsigned aig_inv : 1;
|
||||
unsigned user_attr;
|
||||
|
||||
SlowGraphNode *node;
|
||||
};
|
||||
|
||||
struct SlowGraph {
|
||||
SlowGraphNode *first;
|
||||
};
|
||||
|
||||
// Step 1: call SlowGraph_markAllUnused(graph)
|
||||
//
|
||||
// Step 2: manually mark input nodes as used
|
||||
//
|
||||
// Step 3: call SlowGraph_gcUnused(graph) // only deletes nodes not used by manually marked used nodes
|
||||
static void
|
||||
SlowGraph_markAllUnused(SlowGraph *graph) {
|
||||
SlowGraphNode *n;
|
||||
for (n = graph->first; n; n = n->next)
|
||||
n->gc_used = 0;
|
||||
}
|
||||
|
||||
// Step 1: call SlowGraph_markAllUnused(graph)
|
||||
//
|
||||
// Step 2: manually mark input nodes as used
|
||||
//
|
||||
// Step 3: call SlowGraph_gcUnused(graph) // only deletes nodes not used by manually marked used nodes
|
||||
static void
|
||||
SlowGraph_gcUnused(SlowGraph *graph) {
|
||||
int changed = 0;
|
||||
SlowGraphNode *n, *o, **prev;
|
||||
SlowGraphEdge *e, *oe;
|
||||
SlowGraphAttr *a, *oa;
|
||||
|
||||
do {
|
||||
for (n = graph->first; n; n = n->next) {
|
||||
if (n->gc_used) {
|
||||
for (e = n->children; e; e = e->next) {
|
||||
if (!e->node->gc_used) {
|
||||
e->node->gc_used = 1;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (changed);
|
||||
|
||||
prev = &graph->first;
|
||||
for (n = graph->first; n; ) {
|
||||
if (n->gc_used) {
|
||||
prev = &n->next;
|
||||
n = n->next;
|
||||
} else {
|
||||
o = n;
|
||||
n = n->next;
|
||||
*prev = n;
|
||||
|
||||
for (e = o->children; e; ) {
|
||||
oe = e;
|
||||
e = e->next;
|
||||
free(oe);
|
||||
}
|
||||
|
||||
for (a = o->attr; a; ) {
|
||||
oa = a;
|
||||
a = a->next;
|
||||
|
||||
free(a->key);
|
||||
free(a->val);
|
||||
free(a);
|
||||
}
|
||||
|
||||
free(o->name);
|
||||
free(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
60
lint.sh
Executable file
60
lint.sh
Executable file
@@ -0,0 +1,60 @@
|
||||
set -e
|
||||
|
||||
run () {
|
||||
set -e
|
||||
echo "# $@"
|
||||
$@
|
||||
}
|
||||
|
||||
echo "# ==== clang NATIVE ===="
|
||||
for f in */std*.c; do
|
||||
for std in c89 c90 c99 c11 c17 c23 gnu89 gnu99 gnu11 gnu17 gnu23 c2y gnu2y; do
|
||||
run clang $f -Wall -Wextra -Wpedantic -Werror -Wno-extra-semi -std=$std --analyze -O0 -o /dev/null
|
||||
done
|
||||
done
|
||||
|
||||
echo
|
||||
echo "# ==== clang rv32 FREESTANDING ===="
|
||||
for f in */nostd*.c; do
|
||||
for std in c89 c90 c99 c11 c17 c23 gnu89 gnu99 gnu11 gnu17 gnu23 c2y gnu2y; do
|
||||
run clang $f -Wall -Wextra -Wpedantic -Werror -Wno-extra-semi -std=$std --analyze -O0 -target riscv32-unknown-freestanding -nostdlib -o /dev/null
|
||||
done
|
||||
done
|
||||
|
||||
echo
|
||||
echo "# ==== clang wasm32 FREESTANDING ===="
|
||||
for f in */nostd*.c; do
|
||||
for std in c89 c90 c99 c11 c17 c23 gnu89 gnu99 gnu11 gnu17 gnu23 c2y gnu2y; do
|
||||
run clang $f -Wall -Wextra -Wpedantic -Werror -Wno-extra-semi -std=$std --analyze -O0 -target wasm32-unknown-freestanding -nostdlib -o /dev/null
|
||||
done
|
||||
done
|
||||
|
||||
echo
|
||||
echo "# ==== clang++ NATIVE ===="
|
||||
for f in */std*.cxx; do
|
||||
for std in c++03 c++98 gnu++98 c++11 gnu++11 c++14 c++17 gnu++17 c++20 gnu++20 c++23 gnu++23 c++2c gnu++2c; do
|
||||
run clang++ $f -Wall -Wextra -Wpedantic -Werror -Wno-extra-semi -std=$std --analyze -O0 -o /dev/null
|
||||
done
|
||||
done
|
||||
|
||||
echo
|
||||
echo "# ==== g++ NATIVE ===="
|
||||
for f in */std*.cxx; do
|
||||
for std in c++03 c++98 gnu++98 c++11 gnu++11 c++14 c++17 gnu++17 c++20 gnu++20 c++23 gnu++23 c++2c gnu++2c; do
|
||||
run g++ $f -Wall -Wextra -Wpedantic -Werror -std=$std -fanalyzer -O0 -o /dev/null
|
||||
done
|
||||
done
|
||||
|
||||
echo
|
||||
echo "# ==== gcc NATIVE ===="
|
||||
for f in */std*.c; do
|
||||
for std in c89 c90 c99 c11 c17 c23 gnu89 gnu99 gnu11 gnu17 gnu23; do
|
||||
run gcc $f -Wall -Wextra -Wpedantic -Werror -std=$std -fanalyzer -O0 -o /dev/null
|
||||
done
|
||||
done
|
||||
|
||||
echo
|
||||
echo "# ==== tcc NATIVE ===="
|
||||
for f in */std*.c; do
|
||||
run tcc $f -Wall -Werror -o /dev/null
|
||||
done
|
247
slowarr.h
Normal file
247
slowarr.h
Normal file
@@ -0,0 +1,247 @@
|
||||
#ifndef SLOWARR_H_
|
||||
#define SLOWARR_H_
|
||||
|
||||
#ifndef SLOWARR_NAMESPACE
|
||||
#define SLOWARR_NAMESPACE(X) SLOWARR__##X
|
||||
#define SLOWARR_CXXT SlowArr
|
||||
#endif
|
||||
|
||||
#ifndef SLOWARR_FUNC
|
||||
#define SLOWARR_FUNC /**/
|
||||
#endif
|
||||
|
||||
#ifndef SLOWARR_ASSERT_USER_ERROR
|
||||
#include <assert.h>
|
||||
#define SLOWARR_ASSERT_USER_ERROR(expr) assert(expr)
|
||||
#endif
|
||||
|
||||
#ifndef SLOWARR_MEMZERO
|
||||
#include <string.h>
|
||||
#define SLOWARR_MEMZERO(ptr, len) memset(ptr, 0, len)
|
||||
#endif
|
||||
|
||||
#ifndef SLOWARR_MEMMOVE
|
||||
#include <string.h>
|
||||
#define SLOWARR_MEMMOVE(dst, src, len) memmove(dst, src, len)
|
||||
#endif
|
||||
|
||||
#ifdef SLOW_DEFINE_ACCESS
|
||||
#ifndef SLOW_DEFINE_ACCESS__DONE
|
||||
#define T(B, T) B##__##T
|
||||
#define F(B, T, f) B##__##T##__##f
|
||||
#define SLOW_DEFINE_ACCESS__DONE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SLOWARR_SZT
|
||||
#include <stddef.h>
|
||||
#define SLOWARR_SZT size_t
|
||||
#endif
|
||||
|
||||
#ifndef SLOWARR_REALLOC
|
||||
#include <stdlib.h>
|
||||
#define SLOWARR_REALLOC(ptr, old, news) realloc(ptr, news)
|
||||
#define SLOWARR_FREE(ptr, size) free(ptr)
|
||||
#endif
|
||||
|
||||
#ifndef SLOWARR_GROWTH_RATE
|
||||
/** returns len * 1.5 */
|
||||
#define SLOWARR_GROWTH_RATE(T, len) (((len) >> 1) + (len))
|
||||
#endif
|
||||
|
||||
#ifndef SLOWARR_CAP_FOR_FIRST_ELEM
|
||||
#define SLOWARR_CAP_FOR_FIRST_ELEM(T) (4) /* TODO: could do better */
|
||||
#endif
|
||||
|
||||
/* TODO */
|
||||
#define SLOWARR_MANGLE(T) SLOWARR_NAMESPACE(T)
|
||||
#define SLOWARR_MANGLE_F(T, F) SLOWARR_NAMESPACE(T##__##F)
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define SLOWARR_BEGINC extern "C" {
|
||||
#define SLOWARR_ENDC }
|
||||
#else
|
||||
#define SLOWARR_BEGINC /**/
|
||||
#define SLOWARR_ENDC /**/
|
||||
#endif
|
||||
|
||||
#ifndef SLOWARR_ON_MALLOC_FAIL
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define SLOWARR_ON_MALLOC_FAIL(nb) \
|
||||
do { \
|
||||
fprintf(stderr, "\nmemory allocation of %lu bytes failed!\n", \
|
||||
(unsigned long)nb); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define SLOWARR__BORROWED (1 << 0) /** disable reallocation / freeing */
|
||||
#define SLOWARR__ZEROIZE (1 << 1) /** for cryptography */
|
||||
|
||||
#ifdef __cplusplus
|
||||
template <typename T> struct SLOWARR_CXXT {};
|
||||
|
||||
#define SLOWARR_CXX_HEADER(T) \
|
||||
template <> struct SLOWARR_CXXT<T> { \
|
||||
SLOWARR_MANGLE(T) arr; \
|
||||
\
|
||||
T *begin() { return arr.data; } \
|
||||
T *cbegin() const { return arr.data; } \
|
||||
T *cend() const { return arr.data + arr.len; } \
|
||||
T *end() { return cend(); } \
|
||||
SLOWARR_SZT length() const { return arr.len; } \
|
||||
};
|
||||
#else
|
||||
#define SLOWARR_CXX_HEADER(T) /**/
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
static void SLOWARR___REQUIRE_SEMI(void) {}
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#define SLOWARR_REQUIRE_SEMI static void SLOWARR___REQUIRE_SEMI(void)
|
||||
|
||||
#define SLOWARR_Header(T) \
|
||||
SLOWARR_BEGINC \
|
||||
/** usage: T(Arr,int) myarr = {0}; */ \
|
||||
typedef struct { \
|
||||
SLOWARR_SZT cap, len; \
|
||||
T *data; \
|
||||
unsigned char attr; \
|
||||
} SLOWARR_MANGLE(T); \
|
||||
SLOWARR_ENDC \
|
||||
\
|
||||
SLOWARR_CXX_HEADER(T) \
|
||||
SLOWARR_BEGINC \
|
||||
\
|
||||
/** result can not be reallocated */ \
|
||||
SLOWARR_FUNC SLOWARR_MANGLE(T) \
|
||||
SLOWARR_MANGLE_F(T, borrow)(T * data, SLOWARR_SZT sz); \
|
||||
\
|
||||
/** usage: G(Arr,int,unsafeClear)(&arr) \
|
||||
* this is marked unsafe, because it assumes that the elements don't need \
|
||||
* to be destroyed each */ \
|
||||
SLOWARR_FUNC void SLOWARR_MANGLE_F(T, unsafeClear)(SLOWARR_MANGLE(T) * arr); \
|
||||
\
|
||||
/** resize to smallest cap required to hold current elems */ \
|
||||
SLOWARR_FUNC void SLOWARR_MANGLE_F(T, shrink)(SLOWARR_MANGLE(T) * arr); \
|
||||
\
|
||||
SLOWARR_FUNC void SLOWARR_MANGLE_F(T, reserveTotal)(SLOWARR_MANGLE(T) * arr, \
|
||||
SLOWARR_SZT num); \
|
||||
\
|
||||
SLOWARR_FUNC T *SLOWARR_MANGLE_F(T, pushRef)(SLOWARR_MANGLE(T) * arr); \
|
||||
\
|
||||
SLOWARR_FUNC void SLOWARR_MANGLE_F(T, push)(SLOWARR_MANGLE(T) * arr, T val); \
|
||||
\
|
||||
/** fails if oob */ \
|
||||
SLOWARR_FUNC void SLOWARR_MANGLE_F(T, remove)(SLOWARR_MANGLE(T) * arr, \
|
||||
T * out, SLOWARR_SZT i); \
|
||||
\
|
||||
SLOWARR_FUNC T SLOWARR_MANGLE_F(T, pop)(SLOWARR_MANGLE(T) * arr); \
|
||||
\
|
||||
SLOWARR_ENDC \
|
||||
SLOWARR_REQUIRE_SEMI
|
||||
|
||||
/** call this only once in your program. call SLOWARR_Header(T) first */
|
||||
#define SLOWARR_Impl(T) \
|
||||
SLOWARR_BEGINC \
|
||||
\
|
||||
/** result can not be reallocated */ \
|
||||
SLOWARR_FUNC SLOWARR_MANGLE(T) \
|
||||
SLOWARR_MANGLE_F(T, borrow)(T * data, SLOWARR_SZT sz) { \
|
||||
SLOWARR_MANGLE(T) arr; \
|
||||
arr.data = data; \
|
||||
arr.cap = sz; \
|
||||
arr.len = sz; \
|
||||
arr.attr = SLOWARR__BORROWED; \
|
||||
return arr; \
|
||||
} \
|
||||
\
|
||||
SLOWARR_FUNC void SLOWARR_MANGLE_F(T, \
|
||||
unsafeClear)(SLOWARR_MANGLE(T) * arr) { \
|
||||
if (arr->data) \
|
||||
SLOWARR_FREE(arr->data, arr->cap); \
|
||||
arr->data = (T *)(void *)0; \
|
||||
arr->cap = 0; \
|
||||
arr->len = 0; \
|
||||
/* don't change attrs */ \
|
||||
} \
|
||||
\
|
||||
/* TODO: could make this align the cap num for better perf */ \
|
||||
SLOWARR_FUNC void SLOWARR_MANGLE_F(T, shrink)(SLOWARR_MANGLE(T) * arr) { \
|
||||
if (arr->attr & SLOWARR__BORROWED) \
|
||||
return; \
|
||||
\
|
||||
if (arr->len == arr->cap) \
|
||||
return; \
|
||||
if (arr->attr & SLOWARR__ZEROIZE) \
|
||||
SLOWARR_MEMZERO(arr->data + arr->len, \
|
||||
(arr->cap - arr->len) * sizeof(T)); \
|
||||
arr->data = (T *)SLOWARR_REALLOC(arr->data, arr->cap * sizeof(T), \
|
||||
arr->len * sizeof(T)); \
|
||||
arr->cap = arr->len; \
|
||||
} \
|
||||
\
|
||||
SLOWARR_FUNC void SLOWARR_MANGLE_F(T, reserveTotal)(SLOWARR_MANGLE(T) * arr, \
|
||||
SLOWARR_SZT num) { \
|
||||
\
|
||||
void *n; \
|
||||
if (num <= arr->cap) \
|
||||
return; \
|
||||
SLOWARR_ASSERT_USER_ERROR(!(arr->attr & SLOWARR__BORROWED)); \
|
||||
n = SLOWARR_REALLOC(arr->data, sizeof(T) * arr->cap, sizeof(T) * num); \
|
||||
if (!n) { \
|
||||
if (arr->attr & SLOWARR__ZEROIZE) \
|
||||
SLOWARR_MEMZERO(arr->data, arr->cap * sizeof(T)); \
|
||||
SLOWARR_FREE(arr->data, arr->cap * sizeof(T)); \
|
||||
SLOWARR_ON_MALLOC_FAIL(sizeof(T) * num); \
|
||||
} \
|
||||
arr->data = (T *)n; \
|
||||
arr->cap = num; \
|
||||
} \
|
||||
\
|
||||
SLOWARR_FUNC T *SLOWARR_MANGLE_F(T, pushRef)(SLOWARR_MANGLE(T) * arr) { \
|
||||
if (arr->cap == 0) { \
|
||||
SLOWARR_MANGLE_F(T, reserveTotal)(arr, SLOWARR_CAP_FOR_FIRST_ELEM(T)); \
|
||||
} else if (arr->len + 1 > arr->cap) { \
|
||||
SLOWARR_MANGLE_F(T, reserveTotal)(arr, \
|
||||
SLOWARR_GROWTH_RATE(T, arr->len)); \
|
||||
} \
|
||||
return &arr->data[arr->len++]; \
|
||||
} \
|
||||
\
|
||||
SLOWARR_FUNC void SLOWARR_MANGLE_F(T, push)(SLOWARR_MANGLE(T) * arr, \
|
||||
T val) { \
|
||||
*SLOWARR_MANGLE_F(T, pushRef)(arr) = val; \
|
||||
} \
|
||||
\
|
||||
SLOWARR_FUNC void SLOWARR_MANGLE_F(T, remove)(SLOWARR_MANGLE(T) * arr, \
|
||||
T * out, SLOWARR_SZT i) { \
|
||||
SLOWARR_SZT too_much; \
|
||||
SLOWARR_ASSERT_USER_ERROR(i < arr->len); \
|
||||
*out = arr->data[i]; \
|
||||
SLOWARR_MEMMOVE(&arr->data[i], &arr->data[i + 1], \
|
||||
sizeof(T) * (arr->len - (i + 1))); \
|
||||
arr->len -= 1; \
|
||||
too_much = arr->cap - arr->len; \
|
||||
if (too_much > SLOWARR_GROWTH_RATE(T, arr->len)) { \
|
||||
SLOWARR_MANGLE_F(T, shrink)(arr); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
SLOWARR_FUNC T SLOWARR_MANGLE_F(T, pop)(SLOWARR_MANGLE(T) * arr) { \
|
||||
T temp; \
|
||||
SLOWARR_MANGLE_F(T, remove)(arr, &temp, arr->len - 1); \
|
||||
return temp; \
|
||||
} \
|
||||
\
|
||||
SLOWARR_ENDC \
|
||||
SLOWARR_REQUIRE_SEMI
|
||||
|
||||
#endif
|
39
slowarr/nostd1.c
Normal file
39
slowarr/nostd1.c
Normal file
@@ -0,0 +1,39 @@
|
||||
void c_memzero(void *ptrin, unsigned len) {
|
||||
char *ptr = ptrin;
|
||||
for (; len;) {
|
||||
*ptr = 0;
|
||||
len -= 1;
|
||||
ptr += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void c_memmove(void *destp, void *srcp, unsigned len) {
|
||||
char *dest = destp;
|
||||
char *src = srcp;
|
||||
for (; len;) {
|
||||
*dest = *src;
|
||||
len -= 1;
|
||||
src += 1;
|
||||
dest += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define SLOWARR_ASSERT_USER_ERROR(expr) /**/
|
||||
#define SLOWARR_MEMZERO(ptr, len) c_memzero(ptr, len)
|
||||
#define SLOWARR_MEMMOVE(dest, src, ln) c_memmove(dest, src, ln)
|
||||
#define SLOWARR_SZT unsigned long
|
||||
#define SLOWARR_REALLOC(ptr, old, news) ((void *)0)
|
||||
#define SLOWARR_FREE(ptr, size) /**/
|
||||
#define SLOWARR_ON_MALLOC_FAIL(x) /**/
|
||||
#define SLOW_DEFINE_ACCESS
|
||||
#include "../slowarr.h"
|
||||
|
||||
typedef char const *cstr;
|
||||
SLOWARR_Header(cstr);
|
||||
SLOWARR_Impl(cstr);
|
||||
|
||||
int main(int argc, char const **argv) {
|
||||
T(SLOWARR, cstr) arr = F(SLOWARR, cstr, borrow)(argv, argc);
|
||||
(void)arr;
|
||||
return 0;
|
||||
}
|
12
slowarr/std1.c
Normal file
12
slowarr/std1.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#define SLOW_DEFINE_ACCESS
|
||||
#include "../slowarr.h"
|
||||
|
||||
typedef char const *cstr;
|
||||
SLOWARR_Header(cstr);
|
||||
SLOWARR_Impl(cstr);
|
||||
|
||||
int main(int argc, char const **argv) {
|
||||
T(SLOWARR, cstr) arr = F(SLOWARR, cstr, borrow)(argv, argc);
|
||||
(void)arr;
|
||||
return 0;
|
||||
}
|
16
slowarr/std1.cxx
Normal file
16
slowarr/std1.cxx
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <vector>
|
||||
#define SLOW_DEFINE_ACCESS
|
||||
#include "../slowarr.h"
|
||||
|
||||
typedef char const *cstr;
|
||||
SLOWARR_Header(cstr);
|
||||
SLOWARR_Impl(cstr);
|
||||
|
||||
int main(int argc, char const **argv) {
|
||||
T(SLOWARR, cstr) arr = F(SLOWARR, cstr, borrow)(argv, argc);
|
||||
SlowArr<cstr> arrx = {arr};
|
||||
(void)arr;
|
||||
(void)arrx;
|
||||
std::vector<cstr> vec(arrx.begin(), arrx.end());
|
||||
(void)vec;
|
||||
}
|
367
slowgraph.h
Normal file
367
slowgraph.h
Normal file
@@ -0,0 +1,367 @@
|
||||
/* define SLOWGRAPH_IMPL */
|
||||
|
||||
#ifndef SLOWGRAPH_COMMON_H
|
||||
#define SLOWGRAPH_COMMON_H
|
||||
|
||||
#ifndef SLOWGRAPH_FUNC
|
||||
#define SLOWGRAPH_FUNC /**/
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SLOWGRAPH_LENOF(x) (sizeof((x)) / sizeof(*(x)))
|
||||
|
||||
typedef struct SlowGraph SlowGraph;
|
||||
typedef struct SlowGraphNode SlowGraphNode;
|
||||
typedef struct SlowGraphEdge SlowGraphEdge;
|
||||
typedef struct SlowGraphAttr SlowGraphAttr;
|
||||
|
||||
struct SlowGraphAttr {
|
||||
SlowGraphAttr *next;
|
||||
unsigned hash;
|
||||
char *key, *val;
|
||||
};
|
||||
|
||||
struct SlowGraphNode {
|
||||
SlowGraphNode *next;
|
||||
|
||||
unsigned name_hash;
|
||||
char *name;
|
||||
SlowGraphAttr *attr;
|
||||
SlowGraphEdge *children;
|
||||
|
||||
unsigned gc_used : 1;
|
||||
};
|
||||
|
||||
struct SlowGraphEdge {
|
||||
SlowGraphEdge *next;
|
||||
SlowGraphAttr *attr;
|
||||
|
||||
SlowGraphNode *node;
|
||||
};
|
||||
|
||||
struct SlowGraph {
|
||||
SlowGraphNode *first;
|
||||
};
|
||||
|
||||
SLOWGRAPH_FUNC void SlowGraphAttr_free(SlowGraphAttr *attrs);
|
||||
|
||||
SLOWGRAPH_FUNC unsigned slowgraph_hash(char const *buf);
|
||||
|
||||
SLOWGRAPH_FUNC unsigned slowgraph_hashn(void const *bufp, int len);
|
||||
|
||||
SLOWGRAPH_FUNC char *
|
||||
slowgraph_next_edge(FILE *inp, char *buf, int bufn,
|
||||
void (*opt_attr_clbk)(char *node, char *key, char *val),
|
||||
void (*opt_last_edge_attr_clbk)(char *key, char *val));
|
||||
|
||||
SLOWGRAPH_FUNC SlowGraphAttr *SlowGraphAttr_find(SlowGraphAttr *a,
|
||||
unsigned hash);
|
||||
|
||||
/*
|
||||
Step 1: call SlowGraph_markAllUnused(graph)
|
||||
|
||||
Step 2: manually mark input nodes as used
|
||||
|
||||
Step 3: call SlowGraph_gcUnused(graph) // only deletes nodes not used by
|
||||
manually marked used nodes
|
||||
*/
|
||||
SLOWGRAPH_FUNC void SlowGraph_markAllUnused(SlowGraph *graph);
|
||||
SLOWGRAPH_FUNC void SlowGraph_gcUnused(SlowGraph *graph);
|
||||
|
||||
SLOWGRAPH_FUNC SlowGraphNode *SlowGraph_find(SlowGraph *g, unsigned name_hash);
|
||||
|
||||
SLOWGRAPH_FUNC SlowGraphEdge *SlowGraphNode_findConnection(SlowGraphNode *from,
|
||||
SlowGraphNode *to);
|
||||
|
||||
/* if edge from->to already exists, return it instead */
|
||||
SLOWGRAPH_FUNC SlowGraphEdge *SlowGraphNode_connect(SlowGraphNode *from,
|
||||
SlowGraphNode *to);
|
||||
|
||||
SLOWGRAPH_FUNC SlowGraphNode *SlowGraph_getOrCreate(SlowGraph *g,
|
||||
char const *name);
|
||||
|
||||
SLOWGRAPH_FUNC void slowgraph_setAttr(SlowGraphAttr **list, char const *key,
|
||||
char const *val);
|
||||
|
||||
/* returns 1 on failure */
|
||||
SLOWGRAPH_FUNC int SlowGraph_readDGTXT(SlowGraph *g, FILE *f);
|
||||
|
||||
#ifdef SLOWGRAPH_IMPL
|
||||
SLOWGRAPH_FUNC void SlowGraphAttr_free(SlowGraphAttr *attrs) {
|
||||
SlowGraphAttr *to_free;
|
||||
for (; attrs;) {
|
||||
to_free = attrs;
|
||||
attrs = attrs->next;
|
||||
free(to_free->key);
|
||||
free(to_free->val);
|
||||
free(to_free);
|
||||
}
|
||||
}
|
||||
|
||||
SLOWGRAPH_FUNC unsigned slowgraph_hash(char const *buf) {
|
||||
unsigned res = 5381;
|
||||
for (; *buf; buf++) {
|
||||
res = (res << 5) + res + *buf;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
SLOWGRAPH_FUNC unsigned slowgraph_hashn(void const *bufp, int len) {
|
||||
char const *buf = (char const *)bufp;
|
||||
unsigned res = 5381;
|
||||
for (; buf != ((char const *)bufp) + len; buf++) {
|
||||
res = (res << 5) + res + *buf;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
SLOWGRAPH_FUNC char *
|
||||
slowgraph_next_edge(FILE *inp, char *buf, int bufn,
|
||||
void (*opt_attr_clbk)(char *node, char *key, char *val),
|
||||
void (*opt_last_edge_attr_clbk)(char *key, char *val)) {
|
||||
int c;
|
||||
char *n, *k, *v, *retv = 0;
|
||||
|
||||
c = fgetc(inp);
|
||||
|
||||
for (;;) {
|
||||
if (c == EOF) {
|
||||
retv = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (; isspace(c); c = fgetc(inp))
|
||||
;
|
||||
|
||||
if (c == '#') {
|
||||
c = fgetc(inp);
|
||||
if (c == '#' && opt_attr_clbk && buf == fgets(buf, bufn, inp)) {
|
||||
n = strtok(buf + 1, " \r\n");
|
||||
k = strtok(0, " \r\n");
|
||||
v = strtok(0, " \r\n");
|
||||
opt_attr_clbk(n, k, v);
|
||||
} else if (c == ':' && opt_last_edge_attr_clbk &&
|
||||
buf == fgets(buf, bufn, inp)) {
|
||||
k = strtok(buf + 1, " \r\n");
|
||||
v = strtok(0, " \r\n");
|
||||
opt_last_edge_attr_clbk(k, v);
|
||||
} else {
|
||||
for (; c != EOF && c != '\n'; c = fgetc(inp))
|
||||
;
|
||||
c = fgetc(inp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for (k = buf; c != EOF && !isspace(c); k++) {
|
||||
*k = c;
|
||||
c = fgetc(inp);
|
||||
}
|
||||
|
||||
if (k == buf)
|
||||
continue;
|
||||
|
||||
*k++ = 0;
|
||||
|
||||
for (; isspace(c); c = fgetc(inp))
|
||||
;
|
||||
|
||||
for (v = k; c != EOF && !isspace(c); v++) {
|
||||
*v = c;
|
||||
c = fgetc(inp);
|
||||
}
|
||||
*v = 0;
|
||||
|
||||
if (v == k)
|
||||
continue;
|
||||
|
||||
retv = k;
|
||||
break;
|
||||
}
|
||||
|
||||
ungetc(c, inp);
|
||||
return retv;
|
||||
}
|
||||
|
||||
SLOWGRAPH_FUNC SlowGraphAttr *SlowGraphAttr_find(SlowGraphAttr *a,
|
||||
unsigned hash) {
|
||||
for (; a; a = a->next)
|
||||
if (a->hash == hash)
|
||||
return a;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SLOWGRAPH_FUNC void SlowGraph_markAllUnused(SlowGraph *graph) {
|
||||
SlowGraphNode *n;
|
||||
for (n = graph->first; n; n = n->next)
|
||||
n->gc_used = 0;
|
||||
}
|
||||
|
||||
SLOWGRAPH_FUNC void SlowGraph_gcUnused(SlowGraph *graph) {
|
||||
int changed = 0;
|
||||
SlowGraphNode *n, *o, **prev;
|
||||
SlowGraphEdge *e, *oe;
|
||||
|
||||
do {
|
||||
for (n = graph->first; n; n = n->next) {
|
||||
if (n->gc_used) {
|
||||
for (e = n->children; e; e = e->next) {
|
||||
if (!e->node->gc_used) {
|
||||
e->node->gc_used = 1;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (changed);
|
||||
|
||||
prev = &graph->first;
|
||||
for (n = graph->first; n;) {
|
||||
if (n->gc_used) {
|
||||
prev = &n->next;
|
||||
n = n->next;
|
||||
} else {
|
||||
o = n;
|
||||
n = n->next;
|
||||
*prev = n;
|
||||
|
||||
for (e = o->children; e;) {
|
||||
oe = e;
|
||||
e = e->next;
|
||||
SlowGraphAttr_free(oe->attr);
|
||||
free(oe);
|
||||
}
|
||||
|
||||
SlowGraphAttr_free(o->attr);
|
||||
free(o->name);
|
||||
free(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SLOWGRAPH_FUNC SlowGraphNode *SlowGraph_find(SlowGraph *g, unsigned name_hash) {
|
||||
SlowGraphNode *n;
|
||||
for (n = g->first; n; n = n->next)
|
||||
if (n->name_hash == name_hash)
|
||||
return n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SLOWGRAPH_FUNC SlowGraphEdge *SlowGraphNode_findConnection(SlowGraphNode *from,
|
||||
SlowGraphNode *to) {
|
||||
SlowGraphEdge *e;
|
||||
for (e = from->children; e; e = e->next)
|
||||
if (e->node == to)
|
||||
return e;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SLOWGRAPH_FUNC SlowGraphEdge *SlowGraphNode_connect(SlowGraphNode *from,
|
||||
SlowGraphNode *to) {
|
||||
SlowGraphEdge *e = SlowGraphNode_findConnection(from, to);
|
||||
if (e)
|
||||
return e;
|
||||
e = (SlowGraphEdge *)calloc(1, sizeof(SlowGraphEdge));
|
||||
if (!e)
|
||||
return 0;
|
||||
e->node = to;
|
||||
e->next = from->children;
|
||||
from->children = e;
|
||||
return e;
|
||||
}
|
||||
|
||||
SLOWGRAPH_FUNC SlowGraphNode *SlowGraph_getOrCreate(SlowGraph *g,
|
||||
char const *name) {
|
||||
unsigned hash, strln;
|
||||
SlowGraphNode *n;
|
||||
|
||||
strln = strlen(name);
|
||||
hash = slowgraph_hashn(name, strln);
|
||||
if ((n = SlowGraph_find(g, hash)))
|
||||
return n;
|
||||
n = (SlowGraphNode *)calloc(1, sizeof(SlowGraphNode));
|
||||
if (!n)
|
||||
return 0;
|
||||
n->name = (char *)calloc(strln + 1, sizeof(char));
|
||||
if (!n->name) {
|
||||
free(n);
|
||||
return 0;
|
||||
}
|
||||
strcpy(n->name, name);
|
||||
n->name_hash = hash;
|
||||
n->next = g->first;
|
||||
g->first = n;
|
||||
return n;
|
||||
}
|
||||
|
||||
SLOWGRAPH_FUNC void slowgraph_setAttr(SlowGraphAttr **list, char const *key,
|
||||
char const *val) {
|
||||
/* TODO: malloc fail handking */
|
||||
unsigned keylen = strlen(key);
|
||||
unsigned vallen = strlen(val);
|
||||
unsigned hash = slowgraph_hashn(key, keylen);
|
||||
SlowGraphAttr *a = SlowGraphAttr_find(*list, hash);
|
||||
if (a) {
|
||||
free(a->val);
|
||||
} else {
|
||||
a = (SlowGraphAttr *)calloc(1, sizeof(SlowGraphAttr));
|
||||
a->next = *list;
|
||||
*list = a;
|
||||
|
||||
a->hash = hash;
|
||||
a->key = (char *)calloc(keylen + 1, sizeof(char));
|
||||
strcpy(a->key, key);
|
||||
}
|
||||
|
||||
a->val = (char *)calloc(vallen + 1, sizeof(char));
|
||||
strcpy(a->val, val);
|
||||
}
|
||||
|
||||
static SlowGraph *SlowGraph_read__graph;
|
||||
static SlowGraphEdge *SlowGraph_read__lastEdge;
|
||||
|
||||
static void SlowGraph_read__nodeAttr(char *node, char *key, char *val) {
|
||||
SlowGraphNode *n = SlowGraph_getOrCreate(SlowGraph_read__graph, node);
|
||||
if (!n)
|
||||
return;
|
||||
slowgraph_setAttr(&n->attr, key, val);
|
||||
}
|
||||
|
||||
static void SlowGraph_read__edgeAttr(char *key, char *val) {
|
||||
if (!SlowGraph_read__lastEdge)
|
||||
return;
|
||||
slowgraph_setAttr(&SlowGraph_read__lastEdge->attr, key, val);
|
||||
}
|
||||
|
||||
/* returns 1 on failure */
|
||||
SLOWGRAPH_FUNC int SlowGraph_readDGTXT(SlowGraph *g, FILE *f) {
|
||||
static char buf[512];
|
||||
char *dest;
|
||||
|
||||
SlowGraph_read__graph = g;
|
||||
SlowGraph_read__lastEdge = 0;
|
||||
|
||||
while ((dest = slowgraph_next_edge(f, buf, SLOWGRAPH_LENOF(buf),
|
||||
SlowGraph_read__nodeAttr,
|
||||
SlowGraph_read__edgeAttr))) {
|
||||
|
||||
SlowGraph_read__lastEdge = SlowGraphNode_connect(
|
||||
SlowGraph_getOrCreate(g, buf), SlowGraph_getOrCreate(g, dest));
|
||||
if (!SlowGraph_read__lastEdge)
|
||||
return 1;
|
||||
}
|
||||
|
||||
SlowGraph_read__graph = 0;
|
||||
SlowGraph_read__lastEdge = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
75
slowgraph/dgtxt.typ
Normal file
75
slowgraph/dgtxt.typ
Normal file
@@ -0,0 +1,75 @@
|
||||
= dgtxt file format
|
||||
Human readable file format for directed graphs
|
||||
|
||||
== Design goals
|
||||
- any valid input to `tsort`, not containing `#`, is always valid dgtxt.
|
||||
- removing every occureance of the RegEx `#.*?\n` should produce a valid input to `tsort` (if it doesn't contain cycles of course)
|
||||
- easy to generate
|
||||
- human readable
|
||||
- easy to parse fully
|
||||
|
||||
== Concepts
|
||||
=== Node
|
||||
Has:
|
||||
- incoming edges
|
||||
- outgoing edges
|
||||
- name
|
||||
- key-value attributes
|
||||
|
||||
=== Edge
|
||||
Has:
|
||||
- source node
|
||||
- destination node
|
||||
- key-value attributes
|
||||
|
||||
== Syntax
|
||||
Note that `{x}` means none or more times.
|
||||
|
||||
```ebnf
|
||||
ident char = anything - '\n' - '\r' - ' ' - '#';
|
||||
ident = ident char, { ident char };
|
||||
|
||||
node attribute = '##', {spaces},
|
||||
ident, {spaces}, (* referred node *)
|
||||
ident, {spaces}, (* attribute key *)
|
||||
{ not new line } (* attribute value *)
|
||||
;
|
||||
|
||||
comment = '#', { note new line };
|
||||
|
||||
edge attribute = '#:', {spaces}, ident, {spaces}, {not new line} ;
|
||||
|
||||
edge = ident, {spaces}, (* source node *)
|
||||
ident, {spaces}, (* destination node *)
|
||||
{ {spaces}, edge attribute, {spaces} }
|
||||
;
|
||||
|
||||
element = edge
|
||||
| node attribute
|
||||
| comment
|
||||
;
|
||||
|
||||
|
||||
grammar = { spaces, element, spaces };
|
||||
```
|
||||
|
||||
== Example
|
||||
```
|
||||
# comment line (ignored)
|
||||
DownloadLinux FlashDrive
|
||||
# double hashtass start node attributes:
|
||||
## DownloadLinux describtion Attrbiute key/value formats are not standardized her
|
||||
FindFlashDrive FlashDrive #: cost 200
|
||||
#: another-attr-key another attr value (until end of line)
|
||||
DownloadDriveFlashSoftware FlashDrive
|
||||
FlashDrive ShutdownWindows
|
||||
ShutdownWindows RestartPc
|
||||
RestartPc InstallLinux
|
||||
```
|
||||
|
||||
== Recommendations
|
||||
- tools should prefix attribute names with the tool names, unless they think that other tools might adopt that attribute too.
|
||||
- tools that modify graphs should preserve all attributes
|
||||
- tools should not error on unknown attributes (or invalid attribute values), as they might be valid in a different tool
|
||||
- actual comments should have a space after the `#`, for future proofing
|
||||
- node attributes be listed directly after node definitions
|
63
slowgraph/sgraph-adj.c
Normal file
63
slowgraph/sgraph-adj.c
Normal file
@@ -0,0 +1,63 @@
|
||||
#define SLOWGRAPH_IMPL
|
||||
#include "../slowgraph.h"
|
||||
|
||||
static void write_csv_field(char const *s) {
|
||||
char const *y;
|
||||
int quote = 0;
|
||||
for (y = s; *y; y++) {
|
||||
if (*y == '\n' || *y == '"') {
|
||||
quote = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (quote)
|
||||
putchar('"');
|
||||
|
||||
for (; *s; s++) {
|
||||
if (*s == '"')
|
||||
putchar('"');
|
||||
putchar(*s);
|
||||
}
|
||||
|
||||
if (quote)
|
||||
putchar('"');
|
||||
}
|
||||
|
||||
static void dump_adj_matrix_row(SlowGraph *g, SlowGraphNode *row) {
|
||||
SlowGraphNode *col;
|
||||
write_csv_field(row->name);
|
||||
printf(",");
|
||||
for (col = g->first; col; col = col->next) {
|
||||
if (SlowGraphNode_findConnection(row, col)) {
|
||||
printf("1,");
|
||||
} else {
|
||||
printf("0,");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void dump_adj_matrix(SlowGraph *g) {
|
||||
SlowGraphNode *n;
|
||||
printf(",");
|
||||
for (n = g->first; n; n = n->next) {
|
||||
if (n != g->first)
|
||||
printf(",");
|
||||
write_csv_field(n->name);
|
||||
}
|
||||
printf("\n");
|
||||
for (n = g->first; n; n = n->next) {
|
||||
dump_adj_matrix_row(g, n);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
SlowGraph graph = {0};
|
||||
|
||||
if (SlowGraph_readDGTXT(&graph, stdin))
|
||||
return 1;
|
||||
|
||||
dump_adj_matrix(&graph);
|
||||
return 0;
|
||||
}
|
23
slowurl.h
Normal file
23
slowurl.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef SLOWURL_H_
|
||||
#define SLOWURL_H_
|
||||
|
||||
#ifndef SLOWARR_H_
|
||||
Please include and configure slowarr.h first;
|
||||
#include "slowarr.h"
|
||||
#endif
|
||||
|
||||
#ifndef SLOWURL_NAMESPACE
|
||||
#define SLOWURL_NAMESPACE(X) slowurl_##X
|
||||
#endif
|
||||
|
||||
SLOWARR_Header(char);
|
||||
|
||||
typedef struct {
|
||||
|
||||
} SLOWURL_NAMESPACE();
|
||||
|
||||
#ifdef SLOWURL_IMPLEMENTATION
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user