Генератор функций с хешами
Dec. 8th, 2022 05:44 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Закинул код на гитхаб. Помимо старого hashtest добавил еще hashgen, который может генерировать по заданной таблице команд заголовочный файл и исходник, принимающий пользовательскую строку на вход, вычисляющий хеш команды (первое слово) и запускающий соответствующую функцию. Можно проверить это при помощи test.c.
Проверять на словаре с 43000 словами, конечно, можно, но код получается дюже длинный (за 41мс оно мне сгенерило исходник размером в 8МБ - 300тыс строк - и заголовочник на 2.5МБ). Поэтому для примера беру компактный словарик:
и запускаю time ./hashgen -Fd testdic. Через 2мс получаю заголовочный файл:
и исходник:
Остается лишь заполнить содержимое пустых функций. Можно собрать тест и проверить:
Проверять на словаре с 43000 словами, конечно, можно, но код получается дюже длинный (за 41мс оно мне сгенерило исходник размером в 8МБ - 300тыс строк - и заголовочник на 2.5МБ). Поэтому для примера беру компактный словарик:
hello
world
what
put
change
set
clear
reset
get
out
in
и запускаю time ./hashgen -Fd testdic. Через 2мс получаю заголовочный файл:
int parsecmd(char *cmdwargs);
#define CMD_CHANGE (3110904043)
#define CMD_CLEAR (2063720716)
#define CMD_GET (2963126085)
#define CMD_HELLO (3433426201)
#define CMD_IN (89558876)
#define CMD_OUT (2963261277)
#define CMD_PUT (2963277918)
#define CMD_RESET (1907803304)
#define CMD_SET (2963325777)
#define CMD_WHAT (25570233)
#define CMD_WORLD (3313868845)
и исходник:
#include <stdint.h>
#include <stddef.h>
#include "hash.h"
#ifndef _U_
#define _U_ __attribute__((__unused__))
#endif
#ifndef TRUE_INLINE
#define TRUE_INLINE __attribute__((always_inline)) static inline
#endif
TRUE_INLINE int fn_change(_U_ uint32_t hash, _U_ char *args){ // change (3110904043)
return 1;
}
TRUE_INLINE int fn_clear(_U_ uint32_t hash, _U_ char *args){ // clear (2063720716)
return 1;
}
TRUE_INLINE int fn_get(_U_ uint32_t hash, _U_ char *args){ // get (2963126085)
return 1;
}
TRUE_INLINE int fn_hello(_U_ uint32_t hash, _U_ char *args){ // hello (3433426201)
return 1;
}
TRUE_INLINE int fn_in(_U_ uint32_t hash, _U_ char *args){ // in (89558876)
return 1;
}
TRUE_INLINE int fn_out(_U_ uint32_t hash, _U_ char *args){ // out (2963261277)
return 1;
}
TRUE_INLINE int fn_put(_U_ uint32_t hash, _U_ char *args){ // put (2963277918)
return 1;
}
TRUE_INLINE int fn_reset(_U_ uint32_t hash, _U_ char *args){ // reset (1907803304)
return 1;
}
TRUE_INLINE int fn_set(_U_ uint32_t hash, _U_ char *args){ // set (2963325777)
return 1;
}
TRUE_INLINE int fn_what(_U_ uint32_t hash, _U_ char *args){ // what (25570233)
return 1;
}
TRUE_INLINE int fn_world(_U_ uint32_t hash, _U_ char *args){ // world (3313868845)
return 1;
}
static uint32_t hashf(const char *str){
uint32_t hash = 5381;
uint32_t c;
while((c = (uint32_t)*str++))
hash = ((hash << 7) + hash) + c;
return hash;
}
int parsecmd(char *cmdwargs){
if(!cmdwargs || !*cmdwargs) return 0;
char cmd[32];
int i = 0;
char *args = cmdwargs;
while(*args && *args < 33) ++args;
if(!args || !*args) return 0;
while(*args > 33 && i < 31){
cmd[i++] = *args++;
}
cmd[i] = 0;
if(i == 31) args = NULL;
if(args){
while(*args && *args < 33) ++args;
if(!*args) args = NULL;
}
uint32_t h = hashf(cmd);
switch(h){
case CMD_CHANGE:
return fn_change(h, args);
break;
case CMD_CLEAR:
return fn_clear(h, args);
break;
case CMD_GET:
return fn_get(h, args);
break;
case CMD_HELLO:
return fn_hello(h, args);
break;
case CMD_IN:
return fn_in(h, args);
break;
case CMD_OUT:
return fn_out(h, args);
break;
case CMD_PUT:
return fn_put(h, args);
break;
case CMD_RESET:
return fn_reset(h, args);
break;
case CMD_SET:
return fn_set(h, args);
break;
case CMD_WHAT:
return fn_what(h, args);
break;
case CMD_WORLD:
return fn_world(h, args);
break;
default: return 0;
}
return 0;
}
Остается лишь заполнить содержимое пустых функций. Можно собрать тест и проверить:
gcc test.c hash.c -o test ./test "hell1o clear ass asdlf" hell1o clear ass asdlf not found ./test "hello clear ass asdlf" All OK