contributed by < cyrong
>
避免列出完整程式碼,你應該事先拆解並分析。
已經將完整程式碼換成測驗題網址
補完程式碼
(d)
(b) 32 - __builtin_clz(n) - 1
(a) 16
(d) mask[(uint8_t) byte / 8] & 1 << (uint8_t) byte % 8
(c) mask[(uint8_t) byte / 8] |= 1 << (uint8_t) byte % 8
xs
資料結構
和 fbstring 一樣的想法
filler
用於放置最多 15 個字元space_left
存放 15 - length ,當 length 最大來到 15 時存放的值會是 0 也就是 0x0 ,此時後 2 個 bits is_ptr
和 is_large_string
也都會是 0 , 再後 2 個 bits 未使用也會是 0 ,因此 15 個字元後接的是 0x00 也就是 \0
,這樣一來可以就用來表示 15 個字元is_ptr
如果字串被分配在 heap 就會是 1,否則為 0is_large_string
判斷字串是否過大,也就是長度有沒有超過 LARGE_STRING_LEN
flag2
flag3
未使用ptr
字串指標,若是字傳為 large string , ptr 的前 4 bytes 會用於作 reference countsize
表示字串 siz,通過設定 MAX_STR_LENBI_BITS
最大可至 254 - 1capacity
用來表示字串在 heap 的使用量,使用 6 個 bit 就可以覆蓋上面設定的字串大小一開使用的 xs_tmp
使用 _Static_assert
判斷字串會不會太大,不過 _Static_assert
不能放進 expression 中,因此使用一種 trick 把它放進 struct 中,struct 不能沒有成員因此多加一個 dummy 成員
檢查結束後跳到 x_new
先初始化一個空的 xs
,xs_literal_empty
使用的技巧是 designated initializers
是小字串的話就這樣放在 stack
長度若超過 16 (字串 + \0
) 就分配 heap
xs_allocate_data
分成 Medium 和 Large string ,如果是 Large 的話,結構中的 ptr
前 4 個 bytes 會是用於作 reference count ,所以在 Large 的 malloc
中會需要多分配 4 bytes
xs_trim
中間遇到 xs_cow_lazy_copy
此段程式實作的是 CoW ,降低 refcnt
1 並新分配記憶體給 x
因為原本 x
在做的是 reference ,所以要新分配記憶體給它
若是原本不是在做 reference 則回傳 false,因為沒有必要
回到 xs_trim
,程式中用 mask
紀錄 trim_set
中的資料,紀錄方式為字元的前 5 bits 作為 mask
index 後 3 bits 作為 mask[index]
的值,再用 mask
跟 dataptr
頭尾進行對比,找到要消除的對象 index
並設定 dataptr
與 slen
紀錄中間要保留的字串對 orig
進行修改
xs_concat
這段程式實做 xs
的連接,若是加上 prefix
和 suffix
後會超出原本的 capacity
則新創建一個 xs
此時會需要用到 xs_grow
xs_grow
這裡程式實作讓 input x
,可以根據 len
進行 size 增長,實作完後 x
分配的空間會增加
若是 x
原本是短字串,將其轉成中長字串,再將原字串內容複製進去
在原程式中 13 行 x->is_ptr = true
的設定會讓下面的 if 判斷一直是 true,因此進行修改
回到 xs_concat
作完 xs_grow
後,複製 prefix
, data
, suffix
進去 tmp
,將原先字串內容釋放,換上 tmp
若是要考慮 CoW,則要先判斷要複製的字串是否需要 reference ,也就是判斷是不是 Large String
先清除 dest
原資料,接著判斷 src
是否為 large string
是就作 reference
否就新創一個新的非 large string