Created
August 4, 2021 11:07
-
-
Save AliceLR/59260685a5ced32564fa9adb59966618 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
#if 0 | |
[ -z "$PREFIX" ] && [ "$MSYSTEM" = "MINGW64" ] && { PREFIX=/mingw64; TARGET=filematch64; } | |
[ -z "$PREFIX" ] && [ "$MSYSTEM" = "MINGW32" ] && { PREFIX=/mingw32; TARGET=filematch32; } | |
[ -z "$PREFIX" ] && { PREFIX=/usr; } | |
[ -z "$TARGET" ] && { TARGET=filematch; } | |
echo "PREFIX=$PREFIX" | |
echo "TARGET=$TARGET" | |
g++ -O3 -Wall -Wextra -I"$PREFIX/include" filematch.cpp -o"$TARGET" -L"$PREFIX/lib" -lz | |
exit 0 | |
#endif | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <chrono> | |
enum world_file_id | |
{ | |
FILE_ID_NONE = 0x0000, | |
FILE_ID_WORLD_INFO = 0x0001, // properties file | |
FILE_ID_WORLD_GLOBAL_ROBOT = 0x0004, // properties file | |
FILE_ID_WORLD_SFX = 0x0007, // data, NUM_SFX * SFX_SIZE | |
FILE_ID_WORLD_CHARS = 0x0008, // data, 3584*15 | |
FILE_ID_WORLD_PAL = 0x0009, // data, SMZX_PAL_SIZE * 3 | |
FILE_ID_WORLD_PAL_INDEX = 0x000A, // data, 1024 | |
FILE_ID_WORLD_VCO = 0x000C, // data | |
FILE_ID_WORLD_VCH = 0x000D, // data | |
FILE_ID_WORLD_PAL_INTENSITY = 0x000E, // data, SMZX_PAL_SIZE * 1 | |
FILE_ID_WORLD_SPRITES = 0x0080, // properties file | |
FILE_ID_WORLD_COUNTERS = 0x0081, // counter format, use stream | |
FILE_ID_WORLD_STRINGS = 0x0082, // string format, use stream | |
FILE_ID_BOARD_INFO = 0x0100, // properties file (board_id) | |
FILE_ID_BOARD_BID = 0x0101, // data | |
FILE_ID_BOARD_BPR = 0x0102, // data | |
FILE_ID_BOARD_BCO = 0x0103, // data | |
FILE_ID_BOARD_UID = 0x0104, // data | |
FILE_ID_BOARD_UPR = 0x0105, // data | |
FILE_ID_BOARD_UCO = 0x0106, // data | |
FILE_ID_BOARD_OCH = 0x0107, // data | |
FILE_ID_BOARD_OCO = 0x0108, // data | |
FILE_ID_ROBOT = 0x1000, // prop. file (board_id + robot_id) | |
FILE_ID_SCROLL = 0x2000, // prop. file (board_id + robot_id) | |
FILE_ID_SENSOR = 0x3000 // prop. file (board_id + robot_id) | |
}; | |
#define FILE_ID_MATCH(str) ((sizeof(str)-1 == len) && !strcasecmp(str, next)) | |
#define FILE_ID_VALUE(...) FILE_ID_8(__VA_ARGS__,'\0','\0','\0','\0','\0','\0','\0','\0') | |
#define FILE_ID_8(a,b,c,d,e,f,g,h,...) \ | |
(((uint64_t)a << 0) | \ | |
((uint64_t)b << 8) | \ | |
((uint64_t)c << 16) | \ | |
((uint64_t)d << 24) | \ | |
((uint64_t)e << 32) | \ | |
((uint64_t)f << 40) | \ | |
((uint64_t)g << 48) | \ | |
((uint64_t)h << 56)) | |
/** | |
* Since only ASCII values are ever valid IDs, double bit 6 to bit 5 as a | |
* cheap and tacky tolower replacement. | |
*/ | |
#define FILE_ID_VALUE_TOLOWER(...) (FILE_ID_VALUE(__VA_ARGS__) | \ | |
((FILE_ID_VALUE(__VA_ARGS__) & (uint64_t)0x4040404040404040) >> 1)) | |
static inline uint64_t world_file_id_value(const char *filename, size_t len) | |
{ | |
const char *f = filename; | |
switch(len) | |
{ | |
case 1: return FILE_ID_VALUE_TOLOWER(f[0]); | |
case 2: return FILE_ID_VALUE_TOLOWER(f[0],f[1]); | |
case 3: return FILE_ID_VALUE_TOLOWER(f[0],f[1],f[2]); | |
case 4: return FILE_ID_VALUE_TOLOWER(f[0],f[1],f[2],f[3]); | |
case 5: return FILE_ID_VALUE_TOLOWER(f[0],f[1],f[2],f[3],f[4]); | |
case 6: return FILE_ID_VALUE_TOLOWER(f[0],f[1],f[2],f[3],f[4],f[5]); | |
case 7: return FILE_ID_VALUE_TOLOWER(f[0],f[1],f[2],f[3],f[4],f[5],f[6]); | |
// Currently no valid world format filenames with >=8 chars. | |
} | |
return 0; | |
} | |
static inline void file_id_board_uint64(const char *next, size_t len, | |
unsigned int *_file_id, unsigned int *_board_id, unsigned int *_robot_id) | |
{ | |
unsigned int robot_id = 0; | |
char temp[3] = { 0 }; | |
if(len < 3 || len > 7) | |
return; | |
temp[0] = next[1]; | |
temp[1] = next[2]; | |
*_board_id = strtoul(temp, NULL, 16); | |
next += 3; | |
len -= 3; | |
if(next[0]) | |
{ | |
if(next[0] == 'r') | |
{ | |
robot_id = strtoul(next+1, NULL, 16); | |
if(robot_id != 0) | |
{ | |
*_file_id = FILE_ID_ROBOT; | |
} | |
*_robot_id = robot_id; | |
} | |
else | |
if(next[0] == 's') | |
{ | |
if(next[1] == 'c') | |
{ | |
robot_id = strtoul(next+2, NULL, 16); | |
if(robot_id != 0) | |
{ | |
*_file_id = FILE_ID_SCROLL; | |
} | |
} | |
else | |
if(next[1] == 'e') | |
{ | |
robot_id = strtoul(next+2, NULL, 16); | |
if(robot_id != 0) | |
{ | |
*_file_id = FILE_ID_SENSOR; | |
} | |
} | |
*_robot_id = robot_id; | |
} | |
else | |
switch(world_file_id_value(next, len)) | |
{ | |
case FILE_ID_VALUE('b','i','d'): | |
*_file_id = FILE_ID_BOARD_BID; | |
break; | |
case FILE_ID_VALUE('b','p','r'): | |
*_file_id = FILE_ID_BOARD_BPR; | |
break; | |
case FILE_ID_VALUE('b','c','o'): | |
*_file_id = FILE_ID_BOARD_BCO; | |
break; | |
case FILE_ID_VALUE('u','i','d'): | |
*_file_id = FILE_ID_BOARD_UID; | |
break; | |
case FILE_ID_VALUE('u','p','r'): | |
*_file_id = FILE_ID_BOARD_UPR; | |
break; | |
case FILE_ID_VALUE('u','c','o'): | |
*_file_id = FILE_ID_BOARD_UCO; | |
break; | |
case FILE_ID_VALUE('o','c','h'): | |
*_file_id = FILE_ID_BOARD_OCH; | |
break; | |
case FILE_ID_VALUE('o','c','o'): | |
*_file_id = FILE_ID_BOARD_OCO; | |
break; | |
} | |
} | |
else | |
{ | |
*_file_id = FILE_ID_BOARD_INFO; | |
} | |
} | |
static uint32_t file_id_uint64(const char *filename, size_t len) | |
{ | |
const char *next = filename; | |
unsigned int file_id = FILE_ID_NONE; | |
unsigned int board_id; | |
unsigned int robot_id; | |
if(next[0] == 'b') | |
{ | |
file_id_board_uint64(next, len, &file_id, &board_id, &robot_id); | |
} | |
else | |
switch(world_file_id_value(next, len)) | |
{ | |
case FILE_ID_VALUE('w','o','r','l','d'): | |
file_id = FILE_ID_WORLD_INFO; | |
break; | |
case FILE_ID_VALUE('g','r'): | |
file_id = FILE_ID_WORLD_GLOBAL_ROBOT; | |
break; | |
case FILE_ID_VALUE('s','f','x'): | |
file_id = FILE_ID_WORLD_SFX; | |
break; | |
case FILE_ID_VALUE('c','h','a','r','s'): | |
file_id = FILE_ID_WORLD_CHARS; | |
break; | |
case FILE_ID_VALUE('p','a','l'): | |
file_id = FILE_ID_WORLD_PAL; | |
break; | |
case FILE_ID_VALUE('p','a','l','i','d','x'): | |
file_id = FILE_ID_WORLD_PAL_INDEX; | |
break; | |
case FILE_ID_VALUE('p','a','l','i','n','t'): | |
file_id = FILE_ID_WORLD_PAL_INTENSITY; | |
break; | |
case FILE_ID_VALUE('v','c','o'): | |
file_id = FILE_ID_WORLD_VCO; | |
break; | |
case FILE_ID_VALUE('v','c','h'): | |
file_id = FILE_ID_WORLD_VCH; | |
break; | |
case FILE_ID_VALUE('s','p','r'): | |
file_id = FILE_ID_WORLD_SPRITES; | |
break; | |
case FILE_ID_VALUE('c','o','u','n','t','e','r'): | |
file_id = FILE_ID_WORLD_COUNTERS; | |
break; | |
case FILE_ID_VALUE('s','t','r','i','n','g'): | |
file_id = FILE_ID_WORLD_STRINGS; | |
break; | |
} | |
return file_id; | |
} | |
static inline void file_id_board_cmp(const char *next, size_t len, | |
unsigned int *_file_id, unsigned int *_board_id, unsigned int *_robot_id) | |
{ | |
unsigned int robot_id = 0; | |
char temp[3] = { 0 }; | |
if(len < 3 || len > 7) | |
return; | |
temp[0] = next[1]; | |
temp[1] = next[2]; | |
*_board_id = strtoul(temp, NULL, 16); | |
next += 3; | |
len -= 3; | |
if(next[0]) | |
{ | |
if(next[0] == 'r') | |
{ | |
robot_id = strtoul(next+1, NULL, 16); | |
if(robot_id != 0) | |
{ | |
*_file_id = FILE_ID_ROBOT; | |
} | |
*_robot_id = robot_id; | |
} | |
else | |
if(next[0] == 's') | |
{ | |
if(next[1] == 'c') | |
{ | |
robot_id = strtoul(next+2, NULL, 16); | |
if(robot_id != 0) | |
{ | |
*_file_id = FILE_ID_SCROLL; | |
} | |
} | |
else | |
if(next[1] == 'e') | |
{ | |
robot_id = strtoul(next+2, NULL, 16); | |
if(robot_id != 0) | |
{ | |
*_file_id = FILE_ID_SENSOR; | |
} | |
} | |
*_robot_id = robot_id; | |
} | |
else | |
if(FILE_ID_MATCH("bid")) | |
{ | |
*_file_id = FILE_ID_BOARD_BID; | |
} | |
else | |
if(FILE_ID_MATCH("bpr")) | |
{ | |
*_file_id = FILE_ID_BOARD_BPR; | |
} | |
else | |
if(FILE_ID_MATCH("bco")) | |
{ | |
*_file_id = FILE_ID_BOARD_BCO; | |
} | |
else | |
if(FILE_ID_MATCH("uid")) | |
{ | |
*_file_id = FILE_ID_BOARD_UID; | |
} | |
else | |
if(FILE_ID_MATCH("upr")) | |
{ | |
*_file_id = FILE_ID_BOARD_UPR; | |
} | |
else | |
if(FILE_ID_MATCH("uco")) | |
{ | |
*_file_id = FILE_ID_BOARD_UCO; | |
} | |
else | |
if(FILE_ID_MATCH("och")) | |
{ | |
*_file_id = FILE_ID_BOARD_OCH; | |
} | |
else | |
if(FILE_ID_MATCH("oco")) | |
{ | |
*_file_id = FILE_ID_BOARD_OCO; | |
} | |
} | |
else | |
{ | |
*_file_id = FILE_ID_BOARD_INFO; | |
} | |
} | |
static uint32_t file_id_cmp(const char *filename, size_t len) | |
{ | |
const char *next = filename; | |
unsigned int file_id = FILE_ID_NONE; | |
unsigned int board_id; | |
unsigned int robot_id; | |
if(next[0] == 'b') | |
{ | |
file_id_board_cmp(next, len, &file_id, &board_id, &robot_id); | |
} | |
else | |
if(FILE_ID_MATCH("world")) | |
{ | |
file_id = FILE_ID_WORLD_INFO; | |
} | |
else | |
if(FILE_ID_MATCH("gr")) | |
{ | |
file_id = FILE_ID_WORLD_GLOBAL_ROBOT; | |
} | |
else | |
if(FILE_ID_MATCH("sfx")) | |
{ | |
file_id = FILE_ID_WORLD_SFX; | |
} | |
else | |
if(FILE_ID_MATCH("chars")) | |
{ | |
file_id = FILE_ID_WORLD_CHARS; | |
} | |
else | |
if(FILE_ID_MATCH("pal")) | |
{ | |
file_id = FILE_ID_WORLD_PAL; | |
} | |
else | |
if(FILE_ID_MATCH("palidx")) | |
{ | |
file_id = FILE_ID_WORLD_PAL_INDEX; | |
} | |
else | |
if(FILE_ID_MATCH("palint")) | |
{ | |
file_id = FILE_ID_WORLD_PAL_INTENSITY; | |
} | |
else | |
if(FILE_ID_MATCH("vco")) | |
{ | |
file_id = FILE_ID_WORLD_VCO; | |
} | |
else | |
if(FILE_ID_MATCH("vch")) | |
{ | |
file_id = FILE_ID_WORLD_VCH; | |
} | |
else | |
if(FILE_ID_MATCH("spr")) | |
{ | |
file_id = FILE_ID_WORLD_SPRITES; | |
} | |
else | |
if(FILE_ID_MATCH("counter")) | |
{ | |
file_id = FILE_ID_WORLD_COUNTERS; | |
} | |
else | |
if(FILE_ID_MATCH("string")) | |
{ | |
file_id = FILE_ID_WORLD_STRINGS; | |
} | |
return file_id; | |
} | |
struct file_id_data | |
{ | |
const char *filename; | |
enum world_file_id expected; | |
}; | |
static const struct file_id_data data[] = | |
{ | |
// Valid cases. | |
{ "world", FILE_ID_WORLD_INFO }, | |
{ "WORLD", FILE_ID_WORLD_INFO }, | |
{ "World", FILE_ID_WORLD_INFO }, | |
{ "gr", FILE_ID_WORLD_GLOBAL_ROBOT }, | |
{ "sfx", FILE_ID_WORLD_SFX }, | |
{ "chars", FILE_ID_WORLD_CHARS }, | |
{ "pal", FILE_ID_WORLD_PAL }, | |
{ "palidx", FILE_ID_WORLD_PAL_INDEX }, | |
{ "vco", FILE_ID_WORLD_VCO }, | |
{ "vch", FILE_ID_WORLD_VCH }, | |
{ "palint", FILE_ID_WORLD_PAL_INTENSITY }, | |
{ "spr", FILE_ID_WORLD_SPRITES }, | |
{ "counter", FILE_ID_WORLD_COUNTERS }, | |
{ "string", FILE_ID_WORLD_STRINGS }, | |
{ "b00", FILE_ID_BOARD_INFO }, | |
{ "b01bid", FILE_ID_BOARD_BID }, | |
{ "bFFbpr", FILE_ID_BOARD_BPR }, | |
{ "b7Abco", FILE_ID_BOARD_BCO }, | |
{ "b12uid", FILE_ID_BOARD_UID }, | |
{ "b99upr", FILE_ID_BOARD_UPR }, | |
{ "bEEuco", FILE_ID_BOARD_UCO }, | |
{ "bADoch", FILE_ID_BOARD_OCH }, | |
{ "bBBoco", FILE_ID_BOARD_OCO }, | |
{ "b59r01", FILE_ID_ROBOT }, | |
{ "b0FscFF", FILE_ID_SCROLL }, | |
{ "bF0seFF", FILE_ID_SENSOR }, | |
// Not valid cases. | |
{ "", FILE_ID_NONE }, | |
{ "worlddd", FILE_ID_NONE }, | |
{ "puddle", FILE_ID_NONE }, | |
{ "a", FILE_ID_NONE }, | |
{ "bb", FILE_ID_NONE }, | |
{ "ccc", FILE_ID_NONE }, | |
{ "dddd", FILE_ID_NONE }, | |
{ "eeeee", FILE_ID_NONE }, | |
{ "ffffff", FILE_ID_NONE }, | |
{ "ggggggg", FILE_ID_NONE }, | |
{ "hhhhhhhh",FILE_ID_NONE }, | |
{ "bFFbi", FILE_ID_NONE }, | |
{ "countr", FILE_ID_NONE }, | |
{ "bFFse001",FILE_ID_NONE }, | |
{ "b00r\x11",FILE_ID_NONE }, | |
}; | |
static constexpr size_t REPEAT_TIMES = 1000000; | |
template<uint32_t (*TESTFUNC)(const char *, size_t)> | |
__attribute__((noinline)) | |
static void do_test(const char *TESTNAME) | |
{ | |
auto start_time = std::chrono::steady_clock::now(); | |
for(size_t i = 0; i < REPEAT_TIMES; i++) | |
{ | |
for(const file_id_data &d : data) | |
{ | |
uint32_t result = TESTFUNC(d.filename, strlen(d.filename)); | |
if(result != d.expected) | |
{ | |
printf("ERROR: test for '%s' expects %u, got %u\n", d.filename, d.expected, result); | |
exit(1); | |
} | |
} | |
} | |
auto end_time = std::chrono::steady_clock::now(); | |
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time); | |
printf("%-8.8s : %.3fms\n", TESTNAME, duration.count() / 1000.0); | |
fflush(stdout); | |
} | |
int main() | |
{ | |
do_test<file_id_cmp>("strcmp"); | |
do_test<file_id_uint64>("uint64"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment