# 2021q1 Homework3 (quiz3)
contributed by < `mahavishnuj` >
:::danger
注意作業規範:登記在作業區的網址,應為「瀏覽模式」的發表網址。唯有掌握細節,才能挑戰龐大無比的 Linux 核心。
:notes: jserv
:::
## 測驗 `1`
#### OFF = ?
- `(d) 4`
在 `xs_allocate_data` 裡面我們看到說明說 `The extra 4 bytes are used to store the reference count` 我們已知 `ptr` 是指向 `char` 的指標,位移量在這裡是一個 `byte` 的大小,但是要保留四個 `byte` 情況下所以要一次移動四個單位
```cpp
static void xs_allocate_data(xs *x, size_t len, bool reallocate)
{
/* Medium string */
if (len < LARGE_STRING_LEN) {
x->ptr = reallocate ? realloc(x->ptr, (size_t) 1 << x->capacity)
: malloc((size_t) 1 << x->capacity);
return;
}
/* Large string */
x->is_large_string = 1;
/* The extra 4 bytes are used to store the reference count */
x->ptr = reallocate ? realloc(x->ptr, (size_t)(1 << x->capacity) + 4)
: malloc((size_t)(1 << x->capacity) + 4);
xs_set_refcnt(x, 1);
}
```
#### `LLL = ?`
- `(b) 32 - __builtin_clz(n) - 1`
說明提到是取 `lowerbound` 所以在扣掉第一個遇到 `1` 的地方之後還要在扣掉 `1` , 以 $log_{2}3$ = 1.584... 取下底則等於 `1` 以`32 bits` 來表示 `3 = 0000 0000 0000 0000 0000 0000 0000 0011` , `__builtin_clz(3) = 30` , `32-30 = 2` ,若是要取上高斯則沒問題,但我們是要取下高斯所以必須再減一。
```cpp
/* lowerbound (floor log2) */
static inline int ilog2(uint32_t n) { return LLL; }
```
#### `NNN = ?`
- `(a) 16`
`NNN` 用來判斷字串的長度,是否是大字串,因此用大於 `16` 來比較
```cpp
xs *xs_new(xs *x, const void *p)
{
*x = xs_literal_empty();
size_t len = strlen(p) + 1;
if (len > NNN) {
x->capacity = ilog2(len) + 1;
x->size = len - 1;
x->is_ptr = true;
xs_allocate_data(x, x->size, 0);
memcpy(xs_data(x), p, len);
} else {
memcpy(x->data, p, len);
x->space_left = 15 - (len - 1);
}
return x;
}
```
#### `SSS = ?`
- `(c) mask[(uint8_t) byte / 8] |= 1 << (uint8_t) byte % 8`
在範例中的程式碼 `xs_trim(&string, "\n ")` 透過 `xc_trim` 把字串中的的空白跟 `\n` 給去除,得到結果為 `[foobarbar] : 9 ` ,我們仔細看 `trim` 如何實作
```cpp
xs string = *xs_tmp(" foobarbar \n\n");
xs_trim(&string, "\n ");
printf("[%s] : %2zu\n", xs_data(&string), xs_size(&string));
xs prefix = *xs_tmp("((("), suffix = *xs_tmp(")))");
xs_concat(&string, &prefix, &suffix);
printf("[%s] : %2zu\n", xs_data(&string), xs_size(&string));
```
傳入的除了我們即將修改的 `x` 之外還有要去除的參考值 `trimset` 且內容為 `char` ,每個 `char` 大小為一個 `byte` 即八個 `bits` 再看了同學的解說之後更暸解查表與建表的過程。
:::danger
避免說「看了同學的解說」,只要參照他人成果,都該清楚標註來源。將心比心,你會希望自己的心血被他人一筆帶過嗎?
既然你啟發自他人,那詳讀後應該會有更多想法,寫出來。
「傳入的除了我們即將修改的 `x` 之外還有要去除的參考值 `trimset` 且內容為 `char`」這句話不通順,請改進你的漢語表達!
:notes: jserv
:::
```cpp
#define set_bit(byte) (mask[(uint8_t) byte / 8] |= 1 << (uint8_t) byte % 8)
```
因為一個字元是以一個 `byte` 來儲存,以字元 'A' 來表示, A 的 `ASCII` 碼是 0x41 以八個位元來表示就是 `0100 0001` 因此 `/8` 又可以當作向右做 `bitwise` `>>3` 因此變成 `0000 1000` 以十進位表示就是 8 , `mask[8] |= 1 << (0100 0001)%8` , 跟 `8` 取餘數又可以表示成跟 `& 7` ,餘下的結果 `mask[8] |= 1 << 1` , `mask` 每一個元素又是 `8` 個 `bit` ,運算完後成 `mask[8] = 0000 0010`
:::warning
TODO: 研讀 C 語言規格書,找出關於 `char` 型態實際佔用空間的描述,是否總是 1 byte 呢?
:notes: jserv
:::
#### `CCC = ?`
- `(d) mask[(uint8_t) byte / 8] & 1 << (uint8_t) byte % 8`
```cpp
define check_bit(byte) (CCC)
for (i = 0; i < slen; i++)
if (!check_bit(dataptr[i]))
break;
for (; slen > 0; slen--)
if (!check_bit(dataptr[slen - 1]))
break;
```
`check_bit` 由於先前已經用 `set_bit` 來建立一個表,之後透過 `check_bit` 的方式來進行查表, 再以 `A` 作為例子,會得到 `mask[8] |= 1 << 1` 得到 `True` , 如此的查詢速度可以達到常數時間。
```cpp
#define check_bit(byte) (mask[(uint8_t) byte / 8] & 1 << (uint8_t) byte % 8)
```
```cpp
xs *xs_trim(xs *x, const char *trimset)
{
if (!trimset[0])
return x;
char *dataptr = xs_data(x), *orig = dataptr;
if (xs_cow_lazy_copy(x, &dataptr))
orig = dataptr;
/* similar to strspn/strpbrk but it operates on binary data */
uint8_t mask[32] = {0};
#define check_bit(byte) (CCC)
#define set_bit(byte) (SSS)
size_t i, slen = xs_size(x), trimlen = strlen(trimset);
for (i = 0; i < trimlen; i++)
set_bit(trimset[i]);
for (i = 0; i < slen; i++)
if (!check_bit(dataptr[i]))
break;
for (; slen > 0; slen--)
if (!check_bit(dataptr[slen - 1]))
break;
dataptr += i;
slen -= i;
/* reserved space as a buffer on the heap.
* Do not reallocate immediately. Instead, reuse it as possible.
* Do not shrink to in place if < 16 bytes.
*/
memmove(orig, dataptr, slen);
/* do not dirty memory unless it is needed */
if (orig[slen])
orig[slen] = 0;
if (xs_is_ptr(x))
x->size = slen;
else
x->space_left = 15 - slen;
return x;
#undef check_bit
#undef set_bit
}
```
---
## COW and experiment
- to-do