contributed by < Holycung
>
2020q3 Homework3 (dict) 題目
test_common.c
有兩種模式 CPY 和 REF 根據輸入的參數決定。
if (!strcmp(argv[1], "CPY") || (argc > 2 && !strcmp(argv[2], "CPY"))) {
CPYmask = 0;
REF = DEL;
printf("CPY mechanism\n");
} else
printf("REF mechanism\n");
如果是 REF 模式了話,會配置一個 memory pool 到 Top。
if (CPYmask) { // Only allacte pool in REF mechanism
pool = malloc(poolsize);
if (!pool) {
fprintf(stderr, "Failed to allocate memory pool.\n");
return 1;
}
Top = pool;
}
再來會去開起檔案 cities.txt
。
#define IN_FILE "cities.txt"
FILE *fp = fopen(IN_FILE, "r");
第 74 行會先初始化 bloom filter 結構。
bloom_t bloom = bloom_create(TableSize);
第 77 行這邊是用 fgets
讀取檔案並進行 parse,把逗號跟 newline parse 掉,然後透過 tst_ins
加入到 tst,bloom_add
加入到 bloom filter。
char buf[WORDMAX];
while (fgets(buf, WORDMAX, fp)) {
int offset = 0;
for (int i = 0, j = 0; buf[i + offset]; i++) {
Top[i] =
(buf[i + j] == ',' || buf[i + j] == '\n') ? '\0' : buf[i + j];
j += (buf[i + j] == ',');
}
while (*Top) {
if (!tst_ins(&root, Top, REF)) { /* fail to insert */
fprintf(stderr, "error: memory exhausted, tst_insert.\n");
fclose(fp);
return 1;
}
bloom_add(bloom, Top);
idx++;
int len = strlen(Top);
offset += len + 1;
Top += len + 1;
}
Top -= offset & ~CPYmask;
memset(Top, '\0', WORDMAX);
}
tst.c
ternary search tree node.
typedef struct tst_node {
char key; /* char key for node (null for node with string) */
unsigned refcnt; /* refcnt tracks occurrence of word (for delete) */
struct tst_node *lokid; /* ternary low child pointer */
struct tst_node *eqkid; /* ternary equal child pointer */
struct tst_node *hikid; /* ternary high child pointer */
} tst_node;
tst_ins
把 s
insert 到 tst 當中。
第 221 行可以看到,如果是 cpy mode 每次都會用 strdup
複製字串到新的空間 eqdata
存起來。如果是 ref mode 則是把 s
的地址直接存起來。
void *tst_ins(tst_node **root, const char *s, const int cpy)
{
const char *p = s;
tst_node *curr, **pcurr;
if (!root || !s)
return NULL; /* validate parameters */
if (strlen(s) + 1 > STKMAX / 2) /* limit length to 1/2 STKMAX */
return NULL; /* 128 char word length is plenty */
pcurr = root;
while ((curr = *pcurr)) {
if (*p == 0 && curr->key == 0) {
curr->refcnt++;
return (void *) curr->eqkid;
}
pcurr = next_node(pcurr, &p);
}
/* if not duplicate, insert remaining chars into tree rooted at curr */
for (;;) {
/* allocate memory for node, and fill. use calloc (or include
* string.h and initialize w/memset) to avoid valgrind warning
* "Conditional jump or move depends on uninitialised value(s)"
*/
if (!(*pcurr = calloc(1, sizeof **pcurr))) {
fprintf(stderr, "error: tst_insert(), memory exhausted.\n");
return NULL;
}
curr = *pcurr;
curr->key = *p;
curr->refcnt = 1;
curr->lokid = curr->hikid = curr->eqkid = NULL;
/* Place nodes until end of the string, at end of stign allocate
* space for data, copy data as final eqkid, and return.
*/
if (*p++ == 0) {
if (cpy) { /* allocate storage for 's' */
const char *eqdata = strdup(s);
if (!eqdata)
return NULL;
curr->eqkid = (tst_node *) eqdata;
return (void *) eqdata;
} else { /* save pointer to 's' (allocated elsewhere) */
curr->eqkid = (tst_node *) s;
return (void *) s;
}
}
pcurr = &(curr->eqkid);
}
}
bloom.c
bloom_create
用來初始化大小為 TableSize
的 bloom_filter。
#define TableSize 5000000 /* size of bloom filter */
struct bloom_filter {
struct bloom_hash *func;
void *bits;
size_t size;
};
這邊選用 calloc
因為要確保 memory content 都被設為 0,然後可以看到這邊是從 byte-level 改成 bit-level 節省空間。最後再用 bloom_add_hash
把兩個 hash function djb2
、jenkins
加入結構當中。
bloom_t bloom_create(size_t size)
{
bloom_t res = calloc(1, sizeof(struct bloom_filter));
res->size = size;
res->bits = calloc((size + 7) >> 3, 1);
bloom_add_hash(res, djb2);
bloom_add_hash(res, jenkins);
return res;
}
bloom_add
將傳進來的 item 進行 hash function,並更新 bits
陣列。
void bloom_add(bloom_t filter, const void *item)
{
struct bloom_hash *h = filter->func;
uint8_t *bits = filter->bits;
while (h) {
unsigned int hash = h->func(item);
hash %= filter->size;
bits[hash >> 3] |= 0x80 >> (hash & 7);
h = h->next;
}
}
bloom_test
測試給定的 item 是否存在,如果 hash 過後的位元都是 1 就代表存在。
bool bloom_test(bloom_t filter, const void *item)
{
struct bloom_hash *h = filter->func;
uint8_t *bits = filter->bits;
while (h) {
unsigned int hash = h->func(item);
hash %= filter->size;
if (!(bits[hash >> 3] & (0x80 >> (hash & 7)))) {
return false;
}
h = h->next;
}
return true;
}
contributed by < Holychung > 2020q3 Homework5 (render) 題目 Outline [TOC] 背景知識 在開始 trace code 之前可以先閱讀 Casting Wolf3D-style Rays with an FPGA and Arduino,當中有提到要撰寫一個 ray casting engine 有兩個方法,其中一個比較直接明瞭的是 Lode's Computer Graphics Tutorial,強烈建議先讀完這篇。 我在讀這篇的時候順便做了點筆記,因為篇幅太長就記錄到 研讀筆記: Raycasting。
Jan 6, 2021source Introduction Raycasting 是一個算繪的技巧,在 2D 呈現 3D 的視野。在電腦運算不夠快的時候是沒辦法跑 3D 引擎,這時候 raycasting 就是一個好辦法。 Raycasting 速度非常的快,因為只需要計算完螢幕上每個垂直的線就好,使用這個方法著名的遊戲 Wolfenstein 3D (德軍總部3D)。 The Basic Idea 基本的 raycasting 觀念是地圖是一個 2D 網狀方格,每一個方格都是 0 (= no wall) 或是正數 (= wall with a certain color or texture)。
Jan 5, 2021source 全文主要是翻譯原文,並記錄自己的閱讀。 Introduction 在這篇文章中我們的目的是建構一個指向 Shape 物件的指標陣列,每一個 Shape 指向物件 Circle、Square、Goat 等不同物件,皆以純 C 實現。 Airticle 先建立三個結構。
Jan 4, 2021antirez/linenoise linenoise 這個 function 是整個程式主要的 API,一開始會檢查是否是 tty,然後在看終端機是否有支援,有支援了話就會呼叫 linenoiseRaw。 char *linenoise(const char *prompt) { char buf[LINENOISE_MAX_LINE]; int count; if (!isatty(STDIN_FILENO)) {
Jan 4, 2021or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up