# 2021q1 Homework2 (quiz2)
contributed by < `mahavishnuj` >
## 測驗一 include/linux/list.h 解讀與實作
### `struct` 的初始化與 ?
```cpp
struct list_head {
struct list_head *prev, *next;
};
/**
* LIST_HEAD - Declare list head and initialize it
* @head: name of the new object
*/
#define LIST_HEAD(head) struct list_head head = {&(head), &(head)}
/**
* INIT_LIST_HEAD() - Initialize empty list head
* @head: pointer to list head
*/
static inline void INIT_LIST_HEAD(struct list_head *head)
{
head->next = head; head->prev = head;
}
/**
```
除了上述的的內容可以看出 `struct` 本身是一個是一個 Doubly-linked list 裡面含了兩個 `Pointer`
:::warning
注意 doubly-linked list 連字號的擺放位置。
:notes: jserv
:::
``` graphviz
digraph struct {
rankdir=LR
node[shape=record]
head [label="{<prev>prev|<head>head|<next>next}"]
}
```
一開始新增第一個 `node` 之後把 `head->next` 跟 `head->prev` 都指向自己
``` graphviz
digraph struct {
rankdir=LR
node[shape=record]
head [label="{<prev>prev|<head>head|<next>next}"]
head:next:e -> head:prev:w[arrowhead=arrow]
}
```
### add_tail
這邊有個 `add_tail` 的部分就是在 `head` 的後面加入新的節點
```c=
static inline void list_add_tail(struct list_head *node, struct list_head *head)
{
struct list_head *prev = head->prev;
prev->next = node;
node->next = head;
node->prev = prev;
head->prev = node;
}
/**
* list_del() - Remove a list node from the list
* @node: pointer to the node
*/
static inline void list_del(struct list_head *node)
{
struct list_head *next = node->next, *prev = node->prev;
next->prev = prev; prev->next = next;
}
/**
```
先新增一個一個 `Pointer` `Prev` 指向原本的點, `node` 就是即將新增的點
``` graphviz
digraph structs {
rankdir=LR
node[shape=plaintext]
prev [label="prev"]
node[shape=record]
head [label="{<prev>prev|<listnode>head|<next>next}"]
tail [label="{<prev>prev|<listnode>node|<next>next}"]
head:next:n -> head:n
head:prev:s -> head:s
prev-> head
}
```
把 `prev` 所指的點的 `next` 這個指標指向新的點
``` graphviz
digraph structs {
rankdir=LR
node[shape=plaintext]
prev [label="prev"]
node[shape=record]
head [label="{<prev>prev|<listnode>head|<next>next}"]
tail [label="{<prev>prev|<listnode>node|<next>next}"]
head:next:s -> tail:s
head:prev:s -> head:s
prev-> head
}
```
再把 `tail` 的 `next` 指標指到 `Prev` 所指向的位置
``` graphviz
digraph structs {
rankdir=LR
node[shape=plaintext]
prev [label="prev"]
node[shape=record]
head [label="{<prev>prev|<listnode>head|<next>next}"]
tail [label="{<prev>prev|<listnode>node|<next>next}"]
head:next:s -> tail:s
tail:next:n -> head:n
head:prev:s -> head:s
prev-> head
}
```
再把 `tail` 的 `prev` 指標也指到 `Prev` 所指向的位置
``` graphviz
digraph structs {
rankdir=LR
node[shape=plaintext]
prev [label="prev"]
node[shape=record]
head [label="{<prev>prev|<listnode>head|<next>next}"]
tail [label="{<prev>prev|<listnode>node|<next>next}"]
head:next:s -> tail:s
tail:next:n -> head:n
tail:prev:s -> head:s
head:prev:s -> head:s
prev-> head
}
```
完整結束後的結構長這樣,指標都是指向都是指向該節點的位置
``` graphviz
digraph structs {
rankdir=LR
node[shape=plaintext]
prev [label="prev"]
node[shape=record]
head [label="{<prev>prev|<listnode>head|<next>next}"]
tail [label="{<prev>prev|<listnode>node|<next>next}"]
head:next:s -> tail:prev:s
tail:next:s -> head:prev:s
tail:prev:n -> head:next:n
head:prev:n -> tail:next:n
prev-> head
}
```
### del_tail():
先新增兩個指標 `next` 跟 `prev` 分別指向 `node 的 next` 與 `node 的 prev`
``` graphviz
digraph structs {
rankdir=LR
node[shape=plaintext]
prev [label="prev"]
next [label="next"]
node[shape=record]
head [label="{<prev>prev|<listnode>head|<next>next}"]
tail [label="{<prev>prev|<listnode>node|<next>next}"]
head:next:s -> tail:prev:s
tail:next:s -> head:prev:s
tail:prev:n -> head:next:n
head:prev:n -> tail:next:n
prev-> head
next-> head
}
```
再分別把 `next 的 prev 指標指到 prev 的位置`
``` graphviz
digraph structs {
rankdir=LR
node[shape=plaintext]
prev [label="prev"]
next [label="next"]
node[shape=record]
head [label="{<prev>prev|<listnode>head|<next>next}"]
tail [label="{<prev>prev|<listnode>node|<next>next}"]
head:next:s -> tail:prev:s
tail:next:s -> head:prev:s
tail:prev:n -> head:next:n
head:prev:n -> head
prev-> head
next-> head
}
```
最後把 `prev 的 next 指標指到` next的位置
``` graphviz
digraph structs {
rankdir=LR
node[shape=plaintext]
prev [label="prev"]
next [label="next"]
node[shape=record]
head [label="{<prev>prev|<listnode>head|<next>next}"]
tail [label="{<prev>prev|<listnode>node|<next>next}"]
head:next:n -> head:prev:n
prev-> head
next-> head
}
```
### list_empty() and list_is_singular
顧名思義一個是檢查是否為空的 `list` 另一個則是檢查是否為單一 `node`
```c=
static inline int list_empty(const struct list_head *head)
{
return (head->next == head);
}
/**
* list_is_singular() - Check if list head has exactly one node attached
* @head: pointer to the head of the list
*/
static inline int list_is_singular(const struct list_head *head)
{
return (!list_empty(head) && head->prev == head->next);
}
```
### list_splice_tail
這裡的部分是哪兩條 `linked-list` 串接起來但需要注意的是從 `list->next開始串接`
```c=
static inline void list_splice_tail(struct list_head *list,
struct list_head *head)
{
struct list_head *head_last = head->prev;
struct list_head *list_first = list->next, *list_last = list->prev;
if (list_empty(list))
return;
head->prev = list_last;
list_last->next = head;
list_first->prev = head_last;
head_last->next = list_first;
}
```
### list_cut_position
```c=
static inline void list_cut_position(struct list_head *head_to,
struct list_head *head_from,
struct list_head *node)
{
struct list_head *head_from_first = head_from->next;
if (list_empty(head_from))
return;
if (head_from == node) {
INIT_LIST_HEAD(head_to);
return;
}
head_from->next = node->next;
head_from->next->prev = head_from;
head_to->prev = node;
node->next = head_to;
head_to->next = head_from_first;
head_to->next->prev = head_to;
}
```
假設一開始為三個點的狀態下,先新增一個 `Pointer : head_from_first` 指向 `head_from` 的 `next`
``` graphviz
digraph structs {
rankdir=LR
node[shape=plaintext]
dummy [label="head_from_first"]
node[shape=record]
head [label="{<prev>prev|<listnode>head_to|<next>next}"]
first [label="{<prev>prev|<listnode>head_from|<next>next}"]
cutnode [label="{<prev>prev|<listnode>node|<next>next}"]
head:next:s -> first:prev:s
first:next:s -> cutnode:prev:s
cutnode:next:e ->head:s
dummy-> cutnode
}
```
接著開始操作`head_from` 的 `next` 所指向 `node->next` 還有 `head_from->next->prev` 指向 `head_from`
``` graphviz
digraph structs {
rankdir=LR
node[shape=plaintext]
dummy [label="head_from_first"]
node[shape=record]
head [label="{<prev>prev|<listnode>head_to|<next>next}"]
first [label="{<prev>prev|<listnode>head_from|<next>next}"]
cutnode [label="{<prev>prev|<listnode>node|<next>next}"]
head:next:s -> first:prev:s
head:prev:w -> first:e
first:next:n -> head:prev:n
cutnode:next:e ->head:s
cutnode:prev:e ->head:s
dummy-> cutnode
}
```
最後調整
``` graphviz
digraph structs {
rankdir=LR
node[shape=plaintext]
dummy [label="head_from_first"]
node[shape=record]
head [label="{<prev>prev|<listnode>head_to|<next>next}"]
first [label="{<prev>prev|<listnode>head_from|<next>next}"]
cutnode [label="{<prev>prev|<listnode>node|<next>next}"]
head:next:s -> cutnode:prev:s
head:prev:w -> cutnode:e
first:next:n -> head:prev:n
cutnode:next:n ->cutnode:n
dummy-> cutnode
}
```
### MergeSort() 實作
COND1 = ?
(c) fast->next == list
COND2 = ?
(b) fast->next->next == list
MMM = ?
(e) &get_middle(&q->list)->list
TTT = ?
(a) slow
## 測驗 `2`
- 考慮函式 func 接受一個 16 位元無號整數 N,並回傳小於或等於 N 的 power-of-2
```c=
uint16_t func(uint16_t N) {
/* change all right side bits to 1 */
N |= N >> 1;
N |= N >> X;
N |= N >> Y;
N |= N >> Z;
return (N + 1) >> 1;
}
```
從 `f(21) = 16` 的結果來推斷,最後在 `return` 之前結果會是 `1111` 加上一之後變成 `10000` 之後在經過 `bitwise` 運算變成 `1000` 以十六位無號數來說以最糟糕的情況大概是只有最高位元是一,並且要在四次的運算把所有 `bit` 變成 `1`
```c=
N = 1000 0000 0000 0000
//N |= N >> 1;
N = 1100 0000 0000 0000
//N |= N >> 2;
N = 1111 0000 0000 0000
//N |= N >> 4;
N = 1111 1111 0000 0000
//N |= N >> 8;
N = 1111 1111 1111 1111
```
## 測驗 `3`
### bitcpy 實驗與相關議題
```c=
#include <stdint.h>
void bitcpy(void *_dest, /* Address of the buffer to write to */
size_t _write, /* Bit offset to start writing to */
const void *_src, /* Address of the buffer to read from */
size_t _read, /* Bit offset to start reading from */
size_t count)
{
size_t read_lhs = _read & 7;
size_t read_rhs = 8 - read_lhs;
const uint8_t *source = (const uint8_t *) _src + (_read / 8);
size_t write_lhs = _write & 7;
size_t write_rhs = 8 - write_lhs;
uint8_t *dest = (uint8_t *) _dest + (_write / 8);
static const uint8_t read_mask[] = {
0x00, /* == 0 00000000b */
0x80, /* == 1 10000000b */
0xC0, /* == 2 11000000b */
0xE0, /* == 3 11100000b */
0xF0, /* == 4 11110000b */
0xF8, /* == 5 11111000b */
0xFC, /* == 6 11111100b */
0xFE, /* == 7 11111110b */
0xFF /* == 8 11111111b */
};
static const uint8_t write_mask[] = {
0xFF, /* == 0 11111111b */
0x7F, /* == 1 01111111b */
0x3F, /* == 2 00111111b */
0x1F, /* == 3 00011111b */
0x0F, /* == 4 00001111b */
0x07, /* == 5 00000111b */
0x03, /* == 6 00000011b */
0x01, /* == 7 00000001b */
0x00 /* == 8 00000000b */
};
while (count > 0) {
uint8_t data = *source++;
size_t bitsize = (count > 8) ? 8 : count;
if (read_lhs > 0) {
data <<= read_lhs;
if (bitsize > read_rhs)
data |= (*source >> read_rhs);
}
if (bitsize < 8)
data &= read_mask[bitsize];
uint8_t original = *dest;
uint8_t mask = read_mask[write_lhs];
if (bitsize > write_rhs) {
/* Cross multiple bytes */
*dest++ = (original & mask) | (data >> write_lhs);
original = *dest & write_mask[bitsize - write_rhs];
*dest = original | (data << write_rhs);
} else {
// Since write_lhs + bitsize is never >= 8, no out-of-bound access.
mask |= write_mask[write_lhs + bitsize];
*dest++ = (original & mask) | (data >> write_lhs);
}
count -= bitsize;
}
}
```
一個 `byte` 有 8 個 `bits` , 假設 `_read = 0 ` 的話, `read_lhs = 0` 再來 `read_rhs = 8` 因此 `lsh` 跟 `rhs` 分別表示了要寫或讀的範圍的 `offset'
```c=
size_t read_lhs = _read & 7;
size_t read_rhs = 8 - read_lhs;
```
## 測驗 `4`
- TO DO