79650816

Date: 2025-06-03 07:46:20
Score: 0.5
Natty:
Report link

So after some thinking i came up with this system. it's not exactly idiomatic form pov of C programming, but it does exactly what i want and seems to work well with limited number of arguments (0-7 arguments, 0-1 return value). Key insights:

limitations:

below is the prototype i've ended up with for now:


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

// type system. for now only numeric types, 
// but can be extended to arrays, strings & custom types
typedef union TPun TPun;
typedef struct Obj Obj;
union TPun{ // for type punning
  uintptr_t Any; void* P; Obj (*Fn)(Obj *arg7);
  uint8_t U8; uint16_t U16; uint32_t U32; uint64_t U64;
  int8_t I8; int16_t I16; int32_t I32; int64_t I64;
  float F32; double F64;
};
struct Obj {uint16_t T; TPun V;};

typedef enum {
  T_Unit = 0, T_Any=1, T_P = 2, T_Fn=3,
  T_U8=4, T_U16=5, T_U32=6, T_U64=7,
  T_I8=8, T_I16=9, T_I32=10, T_I64=11,
  T_F32=12, T_F64=13,
} TBase;

const char * TBaseNames[14] = {
  "Unit", "Any", "Ptr", "Fn", 
  "U8", "U16", "U32", "U64",
  "I8", "I16", "I32", "I64",
  "F32", "F64",
};
// dispatch system
typedef struct {uint16_t retT; uint16_t aT[7]; void* fn;} Method7; 
typedef struct {uint16_t len; uint16_t cap; Method7*methods;} Dispatch7;
// Dispatch is a dynamic array of signatures + pointers
int find_method7(Dispatch7 *disp, uint16_t sig[8]){
  for (int i=0; i<(int) disp->len; i++) {
    Method7*m = &disp->methods[i];
    uint16_t* msig = (uint16_t*) m;
    int sig_match = 1;
    for (int a = 0; a<8; a++) {
      sig_match &= (sig[a] == T_Any) | (msig[a] == T_Any) | (msig[a] == sig[a]);
      // any type is expected | returns untyped | types match 
    }
    if (sig_match) {return i;}
  }
  return -1;
}

int put_method7(Dispatch7 *disp, Method7*meth){
  int i = find_method7(disp, (uint16_t*) meth);
  if (i != -1) { // substitute
    disp->methods[i] = *meth;
    return i;
  } else { // append
    if ((disp->cap-disp->len)==0) {// realloc
      uint32_t newcap;
      if (disp->cap == 0) newcap=1;
      else if (disp->cap==1) newcap=4;
      else newcap=disp->cap+4;
      disp->methods = reallocarray(disp->methods, disp->cap+4, sizeof(Method7));
      assert(disp->methods && "don't forget to buy some RAM");
      disp->cap = newcap;
    } // append
    i = disp->len;
    disp->len++;
    disp->methods[i] = *meth;
    return i;
  }
}
int call7(Dispatch7*disp, Obj args[8]){
  uint16_t sig[8];
  for (int i=0; i<8; i++) {sig[i] = args[i].T;}
  int i = find_method7(disp, sig);
  if (i == -1) return 1;
  TPun fn; fn.Fn = disp->methods[i].fn;
  args[0] = fn.Fn(&args[1]);
  return 0;
}
void clear_args7(Obj args[8]){
  for (int i = 0; i<8; i++){
    args[i].T = T_Unit;//0
    args[i].V.Any = 0;
  }
  args[0].T = T_Any; // by default no expectation of return type, 
  // if particular type should be matched, it must be set explicitly
}

// example functions
Obj f_int(Obj *args){
  printf("int x = %ld\n", args[0].V.I64);
  return ((Obj) {T_Unit,{.Any=0}});
}
Obj int_f_int(Obj *args){
  printf("int x = %ld ; return int x = %ld \n", args[0].V.I64, args[0].V.I64+5);
  return (Obj) {T_I64,{.I64=args[0].V.I64+5}}; // to test returns
}
Obj f_float(Obj *args) {
  printf("float x = %f\n", args[0].V.F32);
  return (Obj) {T_Unit,{.Any=0}};
}
Obj f_int_float(Obj *args) {
  printf("int x = %ld ; float y = %f\n", args[0].V.I64, args[1].V.F32);
  return (Obj) {T_Unit,{.Any=0}};
}


Method7 ms[4] = {
    {0, T_I64, 0,0,0,0,0,0, f_int},
    {T_I64, T_I64, 0,0,0,0,0,0, int_f_int},
    {0, T_F32, 0,0,0,0,0,0, f_float},
    {0, T_I64, T_F32, 0,0,0,0,0, f_int_float},
  };
Dispatch7 f = {4, 4, ms};
int main(){
  Obj args[8];
  clear_args7(args);
  args[1] = (Obj) {T_I64,{.I64=5}}; 
  call7(&f, args); // int x = 5
  assert((args[0].T == T_Unit) && "void_f_int should be called");
  clear_args7(args);
  args[0].T = T_I64;
  args[1] = (Obj) {T_I64,{.I64=5}}; 
  call7(&f, args); // int x = 5
  assert((args[0].T == T_I64) && "inf_f_int should be called"); 
  assert((args[0].V.I64 == 10) && "int_f_int should return 10"); 
  clear_args7(args);
  args[1] = (Obj) {T_F32,{.F32=6.5}}; 
  call7(&f, args); // float y = 6.50000
  clear_args7(args);
  args[1] = (Obj) {T_I64, {.I64=7}};
  args[2] = (Obj) {T_F32,{.F32=8.5}};
  call7(&f, args); // int x = 7 ; float y = 8.50000
  clear_args7(args);
  args[1] = (Obj) {T_F32,{.F32=9.5}};
  args[2] = (Obj) {T_I64, {.I64=10}};
  int i = call7(&f, args); 
  assert((i != 0) && "should fail");
}
Reasons:
  • RegEx Blacklisted phrase (1): i want
  • Long answer (-1):
  • Has code block (-0.5):
  • Self-answer (0.5):
  • Low reputation (0.5):
Posted by: Daniil Zuev