Last active
March 1, 2023 18:56
-
-
Save AlexCeleste/ad2db35940a77d7dc8575cf9744402f9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// basic array mapper | |
// we can use it with mis-typed arguments | |
typedef void (* Mutate) (void *, void *); | |
typedef void * (* Step) (void *); | |
void addOneInt (void * in, void * out) { *(int *)out = *(int *)in + 1; } | |
void addOneFloat (void * in, void * out) { *(float *)out = *(float *)in + 1.0f; } | |
void * step_float (void * p) { return (float *)p + 1; } | |
void * step_int (void * p) { return (int *)p + 1; } | |
int ia[10]; | |
float fa[10]; | |
void map (void * array_in, void * array_out, int size, Mutate mut, Step step) { | |
void * in = array_in; | |
void * out = array_out; | |
for (int i = 0; i < size; ++ i, in = step (in), out = step (out)) { | |
mut (in, out); | |
} | |
} | |
void incrArrays (void) { | |
map (ia, ia, 10, addOneInt, step_int); | |
map (fa, fa, 10, addOneFloat, step_float); | |
// oh no: this also compiles, because of void* | |
map (fa, fa, 10, addOneInt, step_float); | |
map (ia, fa, 10, addOneInt, step_float); | |
map (ia, fa, 10, addOneInt, step_float); | |
map (ia, ia, 10, addOneInt, step_float); | |
map (fa, fa, 10, addOneInt, step_int); | |
map (ia, ia, 10, addOneFloat, step_int); | |
map (ia, fa, 10, addOneFloat, step_int); | |
map (ia, ia, 10, addOneFloat, step_int); | |
map (ia, ia, 10, addOneFloat, step_int); | |
map (ia, ia, 10, addOneFloat, step_float); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// basic array mapper but with a "step pack" to slightly simplify step fn generation | |
typedef void (* Mutate) (void const *, void *); | |
void addOneInt (void const * in, void * out) { *(int *)out = *(int const *)in + 1; } | |
void addOneFloat (void const * in, void * out) { *(float *)out = *(float const *)in + 1.0f; } | |
typedef struct Step { | |
void * (*m_func) (void * p); | |
void const * (*c_func) (void const * p); | |
} Step; | |
#define genStepFuncName(Type, Qual) step_##Type##_##Qual | |
#define genStepFunc(Type, Qual) static inline void Qual * genStepFuncName (Type, Qual) (void Qual * p) { return (Type Qual *)p + 1; } | |
#define genStepFuncs(Type) \ | |
genStepFunc(Type, ) \ | |
genStepFunc(Type, const) \ | |
static struct Step const step_##Type = { genStepFuncName (Type, ), genStepFuncName (Type, const) } | |
genStepFuncs(int); | |
genStepFuncs(float); | |
int ia[10]; | |
float fa[10]; | |
void map (void const * array_in, void * array_out, int size, Mutate mut, Step step) { | |
void const * in = array_in; | |
void * out = array_out; | |
for (int i = 0; i < size; ++ i, in = step.c_func (in), out = step.m_func (out)) { | |
mut (in, out); | |
} | |
} | |
void incrArrays (void) { | |
map (ia, ia, 10, addOneInt, step_int); | |
map (fa, fa, 10, addOneFloat, step_float); | |
// oh no: this also compiles, because of void* | |
map (fa, fa, 10, addOneInt, step_float); | |
map (ia, fa, 10, addOneInt, step_float); | |
map (ia, fa, 10, addOneInt, step_float); | |
map (ia, ia, 10, addOneInt, step_float); | |
map (fa, fa, 10, addOneInt, step_int); | |
map (ia, ia, 10, addOneFloat, step_int); | |
map (ia, fa, 10, addOneFloat, step_int); | |
map (ia, ia, 10, addOneFloat, step_int); | |
map (ia, ia, 10, addOneFloat, step_int); | |
map (ia, ia, 10, addOneFloat, step_float); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// basic array mapper | |
// enhanced with type checking despite accepting arrays of any type - checks | |
// that the operand kind of the mapped function matches the array element type | |
// i.e. map :: ([T], T -> T) -> [T] | |
typedef void (* Mutate) (void *, void *); | |
typedef void * (* Step) (void *); | |
void addOneInt (void * in, void * out) { *(int *)out = *(int *)in + 1; } | |
void addOneFloat (void * in, void * out) { *(float *)out = *(float *)in + 1.0f; } | |
void * step_float (void * p) { return (float *)p + 1; } | |
void * step_int (void * p) { return (int *)p + 1; } | |
int ia[10]; | |
float fa[10]; | |
void map_impl (void * array_in, void * array_out, int size, Mutate mut, Step step) { | |
void * in = array_in; | |
void * out = array_out; | |
for (int i = 0; i < size; ++ i, in = step (in), out = step (out)) { | |
mut (in, out); | |
} | |
} | |
#define FunctionDescriptor(Type, Func) union { Func func; Type T; } | |
#define same_type(A, B) _Generic(1 ? (A) : (B) \ | |
, void *: 0 \ | |
, void const *: 0 \ | |
, void volatile *: 0 \ | |
, void const volatile *: 0 \ | |
, default: 1) | |
#define check_same_type(A, B) _Static_assert (same_type (A, B), "types must match"); | |
#define check_array_size | |
#define map(in, out, size, mut, step) do { \ | |
check_same_type ((in), (out)); \ | |
\ | |
check_same_type ((in), &(mut).T); \ | |
check_same_type ((in), &(step).T); \ | |
\ | |
map_impl ((in), (out), (size), (mut).func, (step).func); \ | |
} while (0) | |
typedef FunctionDescriptor (int, Mutate) MutInt; | |
typedef FunctionDescriptor (int, Step) StepInt; | |
typedef FunctionDescriptor (float, Mutate) MutFloat; | |
typedef FunctionDescriptor (float, Step) StepFloat; | |
MutInt addOneInt_g; | |
StepInt stepInt_g; | |
MutFloat addOneFloat_g; | |
StepFloat stepFloat_g; | |
void incrArrays (void) { | |
map (ia, ia, 10, addOneInt_g, stepInt_g); | |
map (fa, fa, 10, addOneFloat_g, stepFloat_g); | |
// no longer compile! | |
// map (fa, fa, 10, addOneInt, step_float); | |
// map (ia, fa, 10, addOneInt, step_float); | |
// map (ia, fa, 10, addOneInt, step_float); | |
// map (ia, ia, 10, addOneInt, step_float); | |
// map (fa, fa, 10, addOneInt, step_int); | |
// map (ia, ia, 10, addOneFloat, step_int); | |
// map (ia, fa, 10, addOneFloat, step_int); | |
// map (ia, ia, 10, addOneFloat, step_int); | |
// map (ia, ia, 10, addOneFloat, step_int); | |
// map (ia, ia, 10, addOneFloat, step_float); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// basic array mapper | |
// enhanced with type checking despite accepting arrays of any type - checks | |
// that the operand kind of the mapped function matches the array element type | |
// i.e. map :: ([T], T -> T) -> [T] | |
// also simplified with step packs, because argument type descriptor pattern | |
// doesn't actually care about the type of the callable! So we can apply generic | |
// type descriptor info to any type, including a function pack or container! | |
typedef void (* Mutate) (void const *, void *); | |
void addOneInt (void const * in, void * out) { *(int *)out = *(int const *)in + 1; } | |
void addOneFloat (void const * in, void * out) { *(float *)out = *(float const *)in + 1.0f; } | |
typedef struct Step { | |
void * (*m_func) (void * p); | |
void const * (*c_func) (void const * p); | |
} Step; | |
#define genStepFuncName(Type, Qual) step_##Type##_##Qual | |
#define genStepFunc(Type, Qual) static inline void Qual * genStepFuncName (Type, Qual) (void Qual * p) { return (Type Qual *)p + 1; } | |
#define genStepFuncs(Type) \ | |
genStepFunc(Type, ) \ | |
genStepFunc(Type, const) \ | |
static struct Step const step_##Type = { genStepFuncName (Type, ), genStepFuncName (Type, const) } | |
genStepFuncs(int); | |
genStepFuncs(float); | |
int ia[10]; | |
float fa[10]; | |
void map_impl (void const * array_in, void * array_out, int size, Mutate mut, Step step) { | |
void const * in = array_in; | |
void * out = array_out; | |
for (int i = 0; i < size; ++ i, in = step.c_func (in), out = step.m_func (out)) { | |
mut (in, out); | |
} | |
} | |
#define FunctionDescriptor(Type, Func) union { Func func; Type T; } | |
#define same_type(A, B) _Generic(1 ? (A) : (B) \ | |
, void *: 0 \ | |
, void const *: 0 \ | |
, void volatile *: 0 \ | |
, void const volatile *: 0 \ | |
, default: 1) | |
#define check_same_type(A, B) _Static_assert (same_type (A, B), "types must match"); | |
#define check_array_size | |
#define map(in, out, size, mut, step) do { \ | |
check_same_type ((in), (out)); \ | |
\ | |
check_same_type ((in), &(mut).T); \ | |
check_same_type ((in), &(step).T); \ | |
\ | |
map_impl ((in), (out), (size), (mut).func, (step).func); \ | |
} while (0) | |
typedef FunctionDescriptor (int, Mutate) MutInt; | |
typedef FunctionDescriptor (int, Step) StepInt; | |
typedef FunctionDescriptor (float, Mutate) MutFloat; | |
typedef FunctionDescriptor (float, Step) StepFloat; | |
MutInt addOneInt_g; | |
StepInt stepInt_g; | |
MutFloat addOneFloat_g; | |
StepFloat stepFloat_g; | |
void incrArrays (void) { | |
map (ia, ia, 10, addOneInt_g, stepInt_g); | |
map (fa, fa, 10, addOneFloat_g, stepFloat_g); | |
// no longer compile! | |
// map (fa, fa, 10, addOneInt, step_float); | |
// map (ia, fa, 10, addOneInt, step_float); | |
// map (ia, fa, 10, addOneInt, step_float); | |
// map (ia, ia, 10, addOneInt, step_float); | |
// map (fa, fa, 10, addOneInt, step_int); | |
// map (ia, ia, 10, addOneFloat, step_int); | |
// map (ia, fa, 10, addOneFloat, step_int); | |
// map (ia, ia, 10, addOneFloat, step_int); | |
// map (ia, ia, 10, addOneFloat, step_int); | |
// map (ia, ia, 10, addOneFloat, step_float); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment