diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..b5df79a --- /dev/null +++ b/404.html @@ -0,0 +1,778 @@ + + + + + + + + + + + + + + + + + + + V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..2d449fa --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +note.v1ceversaa.cc \ No newline at end of file diff --git a/Computer Science/Algorithm/01 Algorithm Analysis/index.html b/Computer Science/Algorithm/01 Algorithm Analysis/index.html new file mode 100644 index 0000000..e4878ce --- /dev/null +++ b/Computer Science/Algorithm/01 Algorithm Analysis/index.html @@ -0,0 +1,1235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Algorithm Analysis - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 1 Algorithm Analysis

+
+

约 4 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Algorithm/02 Linear List/index.html b/Computer Science/Algorithm/02 Linear List/index.html new file mode 100644 index 0000000..1e0a4b6 --- /dev/null +++ b/Computer Science/Algorithm/02 Linear List/index.html @@ -0,0 +1,1320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Linear List - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 2 Linear List

+
+

约 13 个字 11 行代码

+
+

2.3 其他操作

+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
ListNode *reverse(ListNode *head) {
+    ListNode *newHead = NULL;
+    ListNode *tmp, *cur = head;
+    while (head != NULL) {
+        tmp = head->next;
+        head->next = newHead;
+        newHead = head;
+        head = tmp;
+    }
+    return newHead;
+}
+
+
+
+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Algorithm/03 Trees/index.html b/Computer Science/Algorithm/03 Trees/index.html new file mode 100644 index 0000000..89d2051 --- /dev/null +++ b/Computer Science/Algorithm/03 Trees/index.html @@ -0,0 +1,2185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Trees - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Trees

+
+

约 1454 个字 239 行代码 预计阅读时间 8 分钟

+
+

Concepts and Terminology

+

Degree of a node: the number of subtrees of the node.

+

Degree of a tree: the maximum degree of all nodes.

+

Parent: a node that has subtrees.

+

Children: the roots of the subtrees of a parent.

+

Silblings: the children of the same parent.

+

Leaf/terminal node: a node that has no children.

+

Path from node A to node B: a (unique) sequence of nodes starting from A and ending at B, such that each node is a child of the previous one.

+

Length of path: the number of edges on the path.

+

Depth of a node: the length of the unique path from the root to the node.

+

Height of a node: the length of the longest path from the node to a leaf.

+

Height of a tree: the height of the root.

+

Ancestors of a node: all nodes on the path from the node up to the root.

+

Descendants of a node: all nodes in its subtrees.

+

Every tree can be transformed into a binary tree with FirstChild-NextSibling representation.

+

1 Binary Trees

+

A binary tree is a tree in which no node can have more than two children.

+

可以使用 First-Child-Next-Sibling 表示法来将任意树转换为二叉树,将 FirstChild 作为左子节点,NextSibling 作为右子节点。

+

Expression Trees: 每个节点都是一个操作符,叶子节点是操作数,可以表示算数表达式。

+

1.1 节点实现

+
1
+2
+3
+4
+5
+6
typedef struct TreeNode {
+    int val;
+    int height;     // Not necessary
+    struct TreeNode *left;
+    struct TreeNode *right;
+} TreeNode;
+
+

1.2 基本操作

+
+

Info

+

这种版本的节点的定义包括了节点的高度,但是在一般的树中,这是没有必要的,只是在AVL树中,节点高度才尤其重要.在下面的操作中就干脆省略了.

+
+
+
+
+
1
+2
+3
+4
+5
+6
+7
+8
TreeNode *newTreeNode(int val) {
+    TreeNode *node;
+    node = malloc(sizeof(TreeNode));
+    node->val = val;
+    node->left = NULL;
+    node->right = NULL;   
+    return node;
+}
+
+
+
+

这是在n1->n2中插入新节点p或者删除这个节点的操作.

+
1
+2
+3
+4
+5
+6
+7
TreeNode *p = newTreeNode(1);
+p->left = n2;
+n1->left = n1;
+
+TreeNode *del = p;
+n1->left = n2;
+free(del);
+
+
+
+
+

1.3 遍历

+

遍历时间复杂度都是\(O(n)\),迭代的空间复杂度是\(O(n)\).

+
+
+
+

层序遍历从顶部到底逐层遍历二叉树,并且按照从左到右的顺序遍历每一层的节点,从本质上来讲,层序遍历其实属于广度优先遍历/Breadth-first Traversal.我们一般借助队列来实现层序遍历.

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
int *levelOrder (TreeNode *root, int *size) {
+    int front, rear;
+    int index, *arr;
+    TreeNode *node;
+    TreeNode **queue = malloc(sizeof(TreeNode *) * MAX_SIZE);
+    front = rear = 0;
+
+    queue[rear++] = root;
+    int *arr = malloc(sizeof(int) * MAX_SIZE);
+    while (front < rear) {
+        node = queue[front++];
+        arr[index++] = node->val;
+        if (node->left != NULL){
+            queue[rear++] = node->left;
+        }
+        if (node->right != NULL){
+            queue[rear++] = node-right;
+        }
+    }
+    *size = index;
+    arr - realloc(arr, sizeof(int) * index);
+    free(queue);
+    return arr;
+}
+
+
+
+

先访问根节点,再访问子树,左子树优先于右子树.

+
1
+2
+3
+4
+5
+6
+7
+8
+9
int *arr = malloc(sizeof(int) * MAX_SIZE);
+void preOrder(TreeNode *root, int *size, int *arr) {
+    if (root == NULL)
+        return;
+    arr[(*size)++] = root->val;
+    preOrder(root->left, size, arr);
+    preOrder(root->right, size, arr);
+}
+arr = realloc(arr, sizeof(int) *(*size));
+
+
+
+

先访问子树,左子树先于右子树,再访问根节点.

+
1
+2
+3
+4
+5
+6
+7
void postOrder(TreeNode *root, int *size) {
+    if (root == NULL)
+        return;
+    postOrder(root->left, size);
+    postOrder(root->right, size);
+    arr[(*size)++] = root->val;
+}
+
+
+
+

先访问左子树,再访问根,最后访问右子树.

+
1
+2
+3
+4
+5
+6
+7
void inOrder(TreeNode *root, int *size) {
+    if (root == NULL)
+        return;
+    inOrder(root->left, size);
+    arr[(*size)++] = root->val;
+    inOrder(root->right, size);
+}
+
+
+
+

什么?你还想折磨自己?

+

你需要在循环里边手动建一个堆栈来模仿系统堆栈的行为,想想都觉得受不了,消停写你的迭代版得了。

+
+
+
+

2 Binary Search Trees

+

二叉搜索树满足以下性质:

+
    +
  • 所有的节点都有一个以整数表示的键值,且互不相同;
  • +
  • 所有节点的左节点的值都小于这个节点的值;
  • +
  • 所有节点的右节点的值都大于这个节点的值;
  • +
  • 所有节点的左右子树都是二叉搜索树;
  • +
  • 二叉搜索树的中序遍历是一个递增的序列。
  • +
+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
TreeNode *rec_find(TreeNode *root, int val) {
+    if (root == NULL)
+        return NULL;
+    if (root->val < val)
+        return find(root->right, val);
+    else if (root->val > val)
+        return find(root->left, val);
+    else
+        return root;
+}
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
TreeNode *ite_find(TreeNode *root, int val) {
+    while (root != NULL) {
+        if (root->val < val)
+            root = root->right;
+        else if (root->val > val)
+            root = root->left;
+        else
+            return root;
+    }
+    return NULL;
+}
+
+
+
+
1
+2
+3
+4
+5
+6
+7
TreeNode *ite_findMin(TreeNode *root) {
+    if (root == NULL)
+        return NULL;
+    while (root->left != NULL)
+        root = root->left;
+    return root;
+}
+
+
1
+2
+3
+4
+5
+6
+7
TreeNode *rec_findMin(TreeNode *root) {
+    if (root == NULL)
+        return NULL;
+    if (root->left == NULL)
+        return root;
+    return findMin(root->left);
+}
+
+
+
+
1
+2
+3
+4
+5
+6
+7
TreeNode *findMax(TreeNode *root) {
+    if (root == NULL)
+        return NULL;
+    while (root->right != NULL)
+        root = root->right;
+    return root;
+}
+
+
1
+2
+3
+4
+5
+6
+7
TreeNode *rec_findMax(TreeNode *root) {
+    if (root == NULL)
+        return NULL;
+    if (root->right == NULL)
+        return root;
+    return findMax(root->right);
+}
+
+
+
+
1
+2
+3
+4
+5
+6
+7
+8
+9
TreeNode *insert(TreeNode *root, int val) {
+    if (root == NULL) {
+        root = newTreeNode(val);
+    } else if (root->val < val) {
+        root->right = insert(root->right, val);
+    } else if (root->val > val) {
+        root->left = insert(root->left, val);
+    }
+}
+
+
+
+
+

3 Threaded Binary Trees

+
    +
  • 如果一个节点的左子节点为空的,那么将左指针指向中序遍历的前驱节点;
  • +
  • 如果一个节点的右子节点为空的,那么将右指针指向中序遍历的后继节点。
  • +
  • 一定有一个 Head Node,其左子节点是根,右子节点是自身;被中序遍历的第一个节点的左指针和最后一个节点的右指针共同指向。
  • +
+

4 Heap/Priority Queue

+

4.1 二叉堆

+

二叉堆首先是一个满足堆性质的完全二叉树,对于最大堆为例,所谓堆性质是:某个树的所有子树的根节点值都大于等于子节点值。同理,我们可以定义最小堆。

+

4.2 堆的实现

+

堆其实是一个完全二叉树,完全二叉树又很容易表示成数组,所以堆基于数组来实现,但是存储数组的时候很有讲究:数组的元素代表二叉树的节点值,索引代表层序遍历中节点在二叉树中的位置,所有的索引将由 1 开始,这样就可以很方便的通过索引来找到节点的父节点和子节点。数据结构如下:

+
1
+2
+3
+4
+5
+6
+7
typedef struct HeapStruct{
+    int *elements;
+    int size;
+    int capacity;
+} HeapStruct;
+
+typedef HeapStruct *Heap;
+
+

下面是获取父节点、左子节点、右子节点的函数:

+
+
+
+
1
+2
+3
int getParent(int i) {
+    return i / 2;
+}
+
+
+
+
1
+2
+3
int getLeft(int i) {
+    return 2 * i;
+}
+
+
+
+
1
+2
+3
int getRight(int i) {
+    return 2 * i + 1;
+}
+
+
+
+
+

4.2 基本操作

+

典中典:线性建堆算法,时间复杂度为 \(O(n)\)

+
1
+2
+3
+4
+5
void BuildHeap(Heap H) {
+    for (int i = H->size/2; i > 0; i--) {
+        PercolateDown(i, H);
+    }
+}
+
+
+
+
+

上滤和下滤,逻辑是先把要移动的元素存起来,然后慢慢腾位置,最后把原来的值放到合适的位置。这里的代码是最小堆的代码。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
void PercolateUp(int i, Heap H) {
+    int temp = H->data[i];
+    int index;
+    for (index = i; H->data[index/2] > temp && index > 1; index /= 2)
+        H->data[index] = H->data[index/2];      // 找父节点,然后往下移动
+    H->data[index] = temp;                      // 把原来的值放到合适的位置
+}
+
+void PercolateDown(int i, Heap H) {
+    int temp = H->data[i];
+    int parent, child = 0;
+    for (parent = i; parent * 2 <= H->size; parent = child) {
+        child = parent * 2;
+        if (child != H->size && H->data[child + 1] < H->data[child])
+            child++;                            // 找到左右子节点中较小的那个
+        if (temp > H->data[child])
+            H->data[parent] = H->data[child];
+        else break;
+    }
+    H->data[parent] = temp;
+}
+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
void Insert(int x, Heap H) {
+    int i;
+    if (H->size == H->capacity) {
+        printf("Heap is full.\n");
+        return;
+    }
+    for (i = ++H->size; H->data[i/2] > x; i /= 2) 
+        H->data[i] = H->data[i/2];
+    H->data[i] = x;
+}
+
+
+
+

只需要删除堆顶的元素,把最后的元素放到堆顶,然后下滤即可。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
int DeleteMin(Heap H) {
+    if (H->size == 0) {
+        printf("Heap is empty.\n");
+        return -1;
+    }
+    int min = H->data[1];
+    H->data[1] = H->data[H->size--];
+    PercolateDown(1, H);
+    return min;
+}
+
+
+
+
+

5 Disjoint Set

+

并查集支持两种操作:

+
    +
  • Union:合并两个集合,或者说将一棵树的根节点作为另一棵树的根节点的子节点。
  • +
  • Find:查找某个元素所在的集合,或者查询两个元素是否属于同一个集合,这要求我们找到这个节点的根节点。
  • +
+

使用数组来表示并查集,S[i] 的值表示节点 i 的父节点,一般会将父节点作为负数,其绝对值表示父节点代表的集合的大小。

+

5.1 路径压缩

+

在查找的过程中将路径上的所有节点都指向根节点,这样可以减少查找的时间复杂度与树的高度。

+
1
+2
+3
+4
+5
int Find(int x) {
+    if (S[x] < 0)
+        return x;
+    return S[x] = Find(S[x]);
+}
+
+

或者一种更简单的方法:

+
1
+2
+3
int Find(int x) {
+    return S[x] < 0 ? x : S[x] = Find(S[x]);
+}
+
+

以循环实现:

+
1
+2
+3
+4
+5
+6
+7
int Find(int x) {
+    int root;
+    for (root = x; S[root] >= 0; root = S[root]) ;       // Find the root
+    for (int trail = x; trail != root; trail = S[trail]) // Path Compression
+        S[trail] = root;
+    return root;
+}
+
+

5.2 按大小合并

+

将节点数较小的树合并到节点数较大的树上。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
void Union(int x, int y) {
+    int root_x = Find(x);
+    int root_y = Find(y);
+    if (root_x == root_y)
+        return;
+    else if (root_x < root_y) {
+        S[root_x] += S[root_y];
+        S[root_y] = root_x;
+    } else {
+        S[root_y] += S[root_x];
+        S[root_x] = root_y;
+    }
+}
+
+

按大小压缩形成的拥有 \(N\) 个节点的树的高度不会超过 \(\log_{2}N+1\),因此进行 \(N\) 次 Union 操作和 \(M\) 次 Find 操作的时间复杂度为 \(O(N + M\log_{2}N)\)

+

5.3 按高度合并

+

按高度合并需要记录树的高度,将高度较小的树合并到高度较大的树上。

+

按高度合并不能和压缩路径一起使用。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
void Init (int n) {
+    for (int i = 0; i < n; i++) {
+        parent[i] = i;
+        rank[i] = 0;
+    }
+}
+
+void Union(int x, int y) {
+    int root1 = Find(x);
+    int root2 = Find(y);
+    if (root1 == root2) {
+        return;
+    }
+    if (rank[root1] < rank[root2]) {
+        parent[root1] = root2;
+    } else {
+        parent[root2] = root1;
+        if (rank[root1] == rank[root2]) {
+            rank[root1]++;
+        }
+    }
+}
+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Algorithm/04 Graph/index.html b/Computer Science/Algorithm/04 Graph/index.html new file mode 100644 index 0000000..c18e339 --- /dev/null +++ b/Computer Science/Algorithm/04 Graph/index.html @@ -0,0 +1,1866 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Graph - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Chapter 4 Graph

+
+

约 1135 个字 178 行代码 预计阅读时间 6 分钟

+
+

1 基本概念

+
    +
  • 有限可空的边集 \(E\) 和有限非空的点集 \(V\) 组成图 \(G=\{V, E\}\)
  • +
  • 无向图/Undirected Graph:边没有方向,也就是 \((u, v) = (v, u)\)
  • +
  • 有向图/Directed Graph:边有方向,也就是 \((u, v) \neq (v, u)\)
      +
    • Tip:数据结构基础中不考虑自环/Self Loop和多重边/Multigraph;
    • +
    +
  • +
  • 完全图/Complete Graph:任意两个点之间都有边;
  • +
  • 无向图中 \(v_i\)\(v_j\) 被称为连通的,当且仅当 \(G\) 中存在一条从 \(v_i\)\(v_j\) 的路径;
  • +
  • 无向图 \(G\) 被称为连通图,当且仅当 \(G\) 中任意两个节点都是连通的;
  • +
  • 无向图的联通成分是指无向图的极大连通子图;
  • +
  • 有向图中 \(v_i\)\(v_j\) 被称为强连通的,当且仅当 \(G\) 中存在一条从 \(v_i\)\(v_j\) 的路径和一条从 \(v_j\)\(v_i\) 的路径;
  • +
  • 有向图 \(G\) 被称为强连通图,当且仅当 \(G\) 中任意两个节点都是强连通的。有向图的强连通成分是指有向图的极大强连通子图;
  • +
  • 有向图 \(G\) 被称为弱连通图,当且仅当 \(G\) 的基础图(去掉所有边的方向)是连通图;
  • +
+

2 图的表示

+
    +
  • +

    邻接矩阵/Adjacency Matrix +

    1
    +2
    +3
    #define MaxVertexNum 100
    +int G[MaxVertexNum][MaxVertexNum];
    +// 1 for connected, 0 for unconnected
    +

    +
  • +
  • +

    邻接表/Adjacency List +

     1
    + 2
    + 3
    + 4
    + 5
    + 6
    + 7
    + 8
    + 9
    +10
    +11
    +12
    +13
    +14
    +15
    typedef struct ArcNode {
    +    int adjvex;           // 顶点下标
    +    int weight;
    +    struct ArcNode *next;
    +} ArcNode;                // 边表结点 
    +
    +typedef struct VNode {    // 顶点表结点
    +    VertexData data;
    +    ArcNode *first;       // 指向第一个邻接点
    +} VNode, AdjList[MaxVertexNum];
    +
    +typedef struct {
    +    AdjList vertices;     // 邻接表,存储图中所有顶点
    +    int vexnum, arcnum;
    +} ALGraph;
    +

    +
  • +
+

3 图的建立

+
    +
  • 邻接矩阵 +
    1
    +2
    +3
    +4
    +5
    +6
    +7
    +8
    +9
    void BuildGraph(ALGraph *G) {
    +    int ne, nv;
    +    scanf("%d %d", &nv, &ne);
    +    int u, v, w;
    +    for(int i = 0; i < ne; i++) {
    +        scanf("%d %d %d", &u, &v, &w);
    +        G->G[V][W] = G->G[W][V] = w;
    +    }
    +}
    +
  • +
  • 邻接表 +
    void BuildGraph(ALGraph *G)
    +
  • +
+

4 拓扑排序

+
    +
  • AOV网/Activity On Vertex Network;有向图,其顶点代表活动,边代表活动之间的先后顺序关系;
  • +
  • 如果存在一条从 \(v_i\)\(v_j\) 的路径,则 \(v_i\) 称为 \(v_j\) 的前驱/predecessor,\(v_j\) 称为 \(v_i\) 的后继/successor;
  • +
  • 如果存在一条边 \((v_i, v_j)\),则 \(v_i\)\(v_j\) 的直接/Immediate 前驱,\(v_j\)\(v_i\) 的直接后继;
  • +
  • 拓扑排序/Topological Order 是一个图的点集的线性序列,满足:
      +
    • 对于任意的点 \(v_i\)\(v_j\),如果 \(v_i\)\(v_j\)的前驱,在序列中 \(v_i\) 出现在 \(v_j\) 之前;
    • +
    • Tip:拓扑排序不唯一;
    • +
    +
  • +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
void TopologicalSort(ALGraph G) {
+    Queue Q = CreateQueue(NumVertex(G));
+    int cnt;
+    Vertex V, W;
+    for(int i = 0; i < NumVertex(G); i++)
+        if(Indegree[i] == 0) Enqueue(i, Q);
+    while(!IsEmpty(Q)) {
+        V = Dequeue(Q);
+        TopNum[V] = ++cnt;
+        for(each W adjacent to V)
+            if(--Indegree[W] == 0) Enqueue(W, Q);
+    }
+    if(cnt != NumVertex(G)) Error("Graph has a cycle");
+    free(Q);
+}
+
+

5 BFS 和 DFS

+

广度优先搜索/Breadth First Search:从一个点出发,依次访问其邻接点,再访问邻接点的邻接点,以此类推,直到所有点都被访问过;

+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
#define MaxN 100
+int G[MaxN][MaxN];
+int pre[MaxN];
+int visited[MaxN];
+
+void BFS(int src, int dst) {
+    int queue[MaxN] = {0};
+    int front = 0, rear = 0;
+    queue[rear++] = src;
+    visited[src] = 1;
+    while (front < rear) {
+        int v = queue[front++];
+        for (int w = 0; w < MaxN; w++) {
+            if (G[v][w] && !visited[w]) {
+                queue[rear++] = w;
+                visited[w] = 1;
+                pre[w] = v;
+                if (w == dst) {
+                    return;
+                }
+            }
+        }
+    }
+}
+
+
+
+

时间复杂度:\(O(V+E)\)(若不使用队列硬遍历则\(T=O(V^2)\)

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
define MAXN 100
+int visited[MAXN];
+int prev[MAXN];
+
+void BFS(ALGraph G, int src, int dst) {
+    int queue[MAXN] = {0};
+    int front = 0, rear = 0;
+    queue[rear++] = src;
+    visited[src] = 1;
+    while(front < rear) {
+        int v = queue[front++];
+        for(ArcNode *arc = G->vertices[v].first; arc != NULL; arc = arc->next) {
+            int w = arc->adjvex;
+            if(!visited[w]) {
+                prev[w] = v;
+                iqueue[rear++] = w;
+                visited[w] = 1;
+                if(w == dst) return;
+            }
+        }
+    }
+}
+
+
+
+
+

深度优先搜索/Depth First Search:从一个点出发,访问其邻接点,再访问邻接点的邻接点,以此类推,直到所有点都被访问过,再回溯到上一个点,继续访问其他邻接点;

+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
#define MaxN 100
+int G[MaxN][MaxN];
+int pre[MaxN];
+int visited[MaxN];
+
+void DFS(int v, int dst) {
+    visited[v] = 1;
+    for (int w = 0; w < MaxN; w++) {
+        if (G[v][w] && !visited[w]) {
+            pre[w] = v;
+            DFS(w, dst);
+            if (w == dst) {
+                return;
+            }
+        }
+    }
+}
+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
#define MaxN 100
+int visited[MaxN];
+int pre[MaxN];
+
+void DFS(ALGraph *G, int v, int dst) {
+    visited[v] = 1;
+    for (ArcNode *arc = G->vertices[v].firstarc; arc; arc = arc->nextarc) {
+        int w = arc->adjvex;
+        if (!visited[w]) {
+            pre[w] = v;
+            DFS(G, w, dst);
+            if (w == dst) {
+                return;
+            }
+        }
+    }
+}
+
+
+
+
+

6 最短路径

+

单源最短路径/Single Source Shortest Path:从一个点到其他所有点的最短路径

+
    +
  • 无向无权图:广度优先搜索/BFS
  • +
  • 无向/有向正权图:Dijkstra 算法 +
     1
    + 2
    + 3
    + 4
    + 5
    + 6
    + 7
    + 8
    + 9
    +10
    +11
    +12
    +13
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    #define INFINITY INT_MAX
    +void Dijkstra(ALGraph G, ins src){          // 确定源点 src 到其他所有点的最短路径长度
    +    int dist[MaxN] = {0};
    +    int visited[MaxN] = {0};                // 记录是否已经访问
    +    for (int i = 0; i < G->vexnum; i++)
    +        dist[i] = INFINITY;                 // 初始化
    +    dist[src] = 0;
    +    visited[src] = 1;
    +    for (ArcNode *arc = G->vertices[src].first; arc != NULL; arc = arc->next)
    +        dist[arc->adjvex] = arc->weight;    // 更新原点的邻接点距离
    +    for (int i = 0; i < G->vexnum; i++) {   // 重复 n-1 次
    +        int min = INFINITY, v = -1;
    +        for (int j = 0; j < G->vexnum; j++) {
    +            if (!visited[j] && dist[j] < min) {
    +                min = dist[j];
    +                v = j;                      // 找到未访问的最小距离点
    +            }
    +        }
    +        if (v == -1) break;                 // 未找到则剩下所有节点都不可达
    +        visited[v] = 1;
    +        for (ArcNode *arc = G->vertices[v].first; arc != NULL; arc = arc->next) {
    +            if (!visited[arc->adjvex] && dist[v] + arc->weight < dist[arc->adjvex])
    +                dist[arc->adjvex] = dist[v] + arc->weight;
    +        }                                   // 更新其他点的距离
    +    }
    +}
    +
    + 这种实现的时间复杂度为 \(O(V^2+E)\) 原因之一是内部寻找未访问的最小距离点的步骤是纯粹的线性搜索。
  • +
+

:If the length of each edge in an undirected graph \(G(V, E)\) is increased by 1, the shortest path between any pair of nodes \(v_i\) and \(v_j\) will keep unchanged.

+
+

错!之需要考虑两条权重分别为 2->2->2 与 7 的路径,会发现原来的最短路径不再是最短路径。

+
+

7 网络流

+

最大流:给定一个正权有向图\(G\),每个边上都有一个流量 \(c\),从源点 \(s\) 到汇点 \(t\) 的最大流量。

+

求解方法:建立残差图,残差网络的边权如下,每在残差网络中寻找到一条增广路径,就更新一下残差图,知道找不到增广路径为止。

+
\[ + c_f(u, v) = \begin{cases} c(u, v) - f(u, v) & \text{if } (u, v) \in E \\ + f(v, u) & \text{if } (v, u) \in E \\ + 0 & \text{otherwise } \end{cases} +\]
+

增广路径:从源点到汇点的一条简单路径路径,流量是路径上的最短路径。

+
1
+2
+3
+4
int maxFlow(int src, int dst) {
+    int maxflow = 0;
+    return maxflow;
+}
+
+

8 最小生成树

+

最小生成树/Minimum Spanning Tree:给定一个无向连通图\(G\),每个边上都有一个权重 \(w\),找到一个树,包含这个图的所有节点并且使得所有边的权重之和最小。可以使用贪心算法!

+

Prim 算法:从一个节点开始,每次选择一个与当前生成树距离最小并且不会产生环的节点加入生成树,很适合稠密图。

+

Kruskal 算法:从所有边中选择权重最小的边,如果这条边不会产生环就加入生成树,跟适合稀疏图。

+
+
+
+

和 Dijkstra 算法很像。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
void Prim(ALGraph G, int src){
+    int dist[MaxN] = {0};
+    int visited[MaxN] = {0};                // 记录是否已经访问
+    for (int i = 0; i < G->vexnum; i++)
+        dist[i] = INFINITY;                 // 初始化
+    dist[src] = 0;
+    visited[src] = 1;
+    for (ArcNode *arc = G->vertices[src].first; arc != NULL; arc = arc->next)
+        dist[arc->adjvex] = arc->weight;    // 更新原点的邻接点距离
+    for (int i = 0; i < G->vexnum; i++) {
+        int min = INFINITY, v = -1;
+        for (int j = 0; j < G->vexnum; j++) {
+            if (!visited[j] && dist[j] < min) {
+                min = dist[j];
+                v = j;                      // 找到未访问的最小距离点
+            }
+        }
+        if (v == -1) break;                 // 未找到则剩下所有节点都不可达
+        visited[v] = 1;
+        for (ArcNode *arc = G->vertices[v].first; arc != NULL; arc = arc->next) {
+            if (!visited[arc->adjvex] && arc->weight < dist[arc->adjvex])
+                dist[arc->adjvex] = arc->weight;
+        }                                   // 更新其他点的距离
+    }
+}
+
+
+
+
+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Algorithm/05 Sorting/index.html b/Computer Science/Algorithm/05 Sorting/index.html new file mode 100644 index 0000000..21d24cb --- /dev/null +++ b/Computer Science/Algorithm/05 Sorting/index.html @@ -0,0 +1,1758 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Sorting - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + +

Chapter 5 Sorting

+
+

约 882 个字 129 行代码 预计阅读时间 5 分钟

+
+

1 Insertion Sort

+
Insertion Sort
1
+2
+3
+4
+5
+6
+7
+8
+9
void insertSort (int arr[], int len) {
+    int i, j, tmp;
+    for (i = 1; i < len; i++) {
+        tmp = arr[i];
+        for (j = i; j > 0 && arr[j - 1] > tmp; j--)
+            arr[j] = arr[j - 1];
+        arr[j] = tmp;
+    }
+}
+
+

进行 \(n-1\) 趟排序,每一趟排序(第 \(P\) 趟)都可以保证从 \(0\)\(P-1\) 的元素是有序的,然后再插入第 \(P\) 个元素。

+
    +
  • 最好情况的时间复杂度是 \(O(N)\),这时整个数列是顺序的,开场就已经排好了;
  • +
  • 最坏情况的时间复杂度是 \(O(N^2)\),这种情况下数列是逆序的。
  • +
  • 完全不需要另外一个数组,只需要临时变量,空间复杂度是 \(O(1)\)
  • +
+

2 Shell Sort

+

希尔排序是插入排序的一种改进,它的时间复杂度会随具体实现(也就是增量序列的选取)而变化。

+
Shell Sort
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
void shellSort(int arr[], int n) {
+    int i, j, tmp;
+    for (int inc = N / 2; inc > 0; inc /= 2) {  // Increment Sequence
+        for (i = inc; i < N; ++i) {             // Insertion Sort
+            tmp = arr[i];
+            for (j = i; j >= inc; j -= inc) {
+                if (tmp < arr[j - inc])
+                    arr[j] = arr[j - inc];
+                else
+                    break;
+            }
+            a[j] = tmp;
+        }
+    }
+}
+
+
    +
  • 希尔增量序列:如上面实现,\(h_t=\lfloor N/2\rfloor, h_k = \lfloor h_{k+1}/2\rfloor\)
      +
    • 最坏复杂度 \(O(N^2)\)(即只在 1-sort 时进行了排序)。
    • +
    +
  • +
  • Hibbard 增量序列:\(h_k = 2^k-1\)
      +
    • 最坏复杂度 \(O(N^{3/2})\)
    • +
    • 平均复杂度 \(O(N^{5/4})\)
    • +
    +
  • +
+

3 Heap Sort

+

堆排序使用堆结构来进行排序:

+
    +
  • 算法一:将数组中的元素依次插入到堆中(可以是 \(O(N)\) 线性建堆),然后依次从堆中取出最小元素
      +
    • 时间复杂度 \(O(N\log N)\)
    • +
    • 但是空间消耗翻倍了; +```C +void heapSort(int arr[], int n) { + BuildHeap(arr, n); // 最小堆, O(N) + int tmp = malloc(sizeof(int) * n); + for (int i = 0; i < n; ++i) + tmp[i] = DeleteMin(arr); // O(logN) + for (int i = 0; i < n; ++i) + arr[i] = tmp[i]; +}
    • +
    +
  • +
  • 算法二:
      +
    • 以线性时间建最大堆(PercolateDown);
    • +
    • 将堆顶元素与最后一个元素交换(相当于删除最大元素),然后进行 PercolateDown;
    • +
    • 依此循环,N-1 次删除后得到一个从小到大的序列。 +
      1
      +2
      +3
      +4
      +5
      +6
      +7
      +8
      void heapSort(int arr[], int n) {
      +    for (int i = n / 2; i >= 0; --i)    // Build Max Heap
      +        percolateDown(arr, i, n);
      +    for (int i = n - 1; i > 0; --i) {   // Delete Max
      +        swap(&arr[0], &arr[i]);
      +        percolateDown(arr, 0, i);
      +    }
      +}
      +
    • +
    • 平均比较次数为 \(2N\log N - O(N\log\log N)\)
    • +
    +
  • +
+

4 Merge Sort

+

归并排序的时间复杂度在任何情况下都是 \(O(N\log N)\),空间复杂度为 \(O(N)\)

+

关键的操作是合并两个有序列表变成一个有序列表,归并操作则可以递归进行,分而治之,依次合并。

+
Merge Sort
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
void mergeSort(int arr[], int n) {
+    int *tmp = malloc(sizeof(int) * n);
+    if (tmp != NULL) {
+        mergeSortHelper(arr, tmp, 0, n - 1);
+        free(tmp);
+    } else {
+        printf("No space for tmp array!\n");
+    }
+}
+
+void mergeSortHelper(int arr[], int tmp[], int left, int right) {
+    if (left < right) {
+        int center = (left + right) / 2;
+        mergeSortHelper(arr, tmp, left, center);
+        mergeSortHelper(arr, tmp, center + 1, right);
+        merge(arr, tmp, left, center + 1, right);
+    }
+}
+
+void merge(int arr[], int tmp[], int leftPos, int rightPos, int rightEnd) {
+    int leftEnd = rightPos - 1;
+    int tmpPos = leftPos
+    int numElements = rightEnd - leftPos + 1;
+    while (leftPos <= leftEnd && rightPos <= rightEnd)
+        if (arr[leftPos] <= arr[rightPos])
+            tmp[tmpPos++] = arr[leftPos++];
+        else
+            tmp[tmpPos++] = arr[rightPos++];
+    while (leftPos <= leftEnd)
+        tmp[tmpPos++] = arr[leftPos++];
+    while (rightPos <= rightEnd)
+        tmp[tmpPos++] = arr[rightPos++];
+    for (int i = 0; i < numElements; ++i, rightEnd--)
+        arr[rightEnd] = tmp[rightEnd];
+}
+
+

5 Quick Sort

+

已知的实际运行最快的排序算法:

+
    +
  • 最坏复杂度 \(O(N^2)\)
  • +
  • 最优复杂度 \(O(N\log N)\)
  • +
  • 平均复杂度 \(O(N\log N)\)
  • +
+

选择一个基准元素(枢轴 pivot),将数组分成两个子数组,左边的元素都小于等于基准元素,右边的元素都大于等于基准元素,然后对两个子数组进行快排、合并。

+
    +
  • 选取 pivot:
      +
    • 错误方法:pivot = arr[0](对于排好序的数组仍会消耗 \(O(N^2)\) 的时间);
    • +
    • 安全方法:pivot = random element in arr;
        +
      • 但随机数生成也有开销。
      • +
      +
    • +
    • 三数中值分割法:pivot = (left + center + right) / 3。
    • +
    +
  • +
  • 小数组:
      +
    • 对于小的 \(N\)\(N\leq 20\)),快速排序慢于插入排序。
    • +
    • 可以在递归到 \(N\) 较小的情况下改为插入排序。
    • +
    +
  • +
+
Quick Sort
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
void quickSort(int *arr, int len) {
+    quickSortHelper(arr, 0, len - 1);
+}
+
+void quickSortHelper(int *arr, int left, int right) {
+    if (left + cutoff < right) {                 // Cutoff for small arrays
+        int pivot = median3(arr, left, right);
+        int i = left, j = right - 1;
+        while (1) {
+            while (arr[++i] < pivot) ;
+            while (arr[--j] > pivot) ;
+            if (i < j) 
+                swap(&arr[i], &arr[j]);
+            else
+                break;
+        }
+        swap(&arr[i], &arr[right - 1]);
+        quickSortHelper(arr, left, i - 1);
+        quickSortHelper(arr, i + 1, right);
+    } else 
+        insertSort(arr + left, right - left + 1);
+}
+
+int median3(int *arr, int left, int right) {
+    int center = (left + right) / 2;
+    if (arr[left] > arr[center]) 
+        swap(&arr[left], &arr[center]);
+    if (arr[left] > arr[right])
+        swap(&arr[left], &arr[right]);
+    if (arr[center] > arr[right])
+        swap(&arr[center], &arr[right]);
+    swap(&arr[center], &arr[right - 1]);
+    return arr[right - 1];
+}
+
+void swap(int *a, int *b) {
+    int temp = *a;
+    *a = *b;
+    *b = temp;
+}
+
+

6 Bucket Sort

+

如果输入数据都小于 \(M\),则可以用一个大小为 \(M\) 的数组来记录某个值出现了多少次,这个数组称为桶(bucket):

+
    +
  • 桶初始化为 0,遍历输入数据,将每个数据对应的桶加 1
  • +
  • 最后遍历桶中的所有元素,对于 bucket[x] = y,将 x 输出 y 次
  • +
+

时间复杂度 \(O(N+M)\)

+
Bucket Sort
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
void bucketSort(int *arr, int len) {
+    int *bucket = malloc(sizeof(int) * len);
+    if (bucket != NULL) {
+        for (int i = 0; i < len; i++)   // Initialize Bucket
+            bucket[i] = 0;
+        for (int i = 0; i < len; i++)   // Counting
+            bucket[arr[i]]++;
+        for (int i = 0, j = 0; i < len; i++) {
+            while (bucket[i] > 0) {
+                arr[j++] = i;
+                bucket[i]--;
+            }
+        }
+        free(bucket);
+    } else {
+        printf("No space for bucket!\n");
+    }
+}
+
+

7 Radix Sort

+

从低位(LSD,Least Significant Digit)到高位(MSB),对每一位进行进行排序:时间复杂度为 \(O(P(N+B))\),其中 \(P\) 为轮数,\(N\) 为元素个数,\(B\) 为桶个数。

+

8 Stability

+
    +
  • 对于一个序列,如果存在两个相等的元素:
      +
    • 排序后它们的相对位置不变,则称这个排序算法是稳定的;
    • +
    • 排序后它们的相对位置发生了变化,则称这个排序算法是不稳定的。
    • +
    +
  • +
  • 稳定排序:冒泡、归并、插入、基数;
  • +
  • 不稳定排序:快排、希尔、堆排、选择。
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Algorithm/06 Hash/index.html b/Computer Science/Algorithm/06 Hash/index.html new file mode 100644 index 0000000..01f7f3b --- /dev/null +++ b/Computer Science/Algorithm/06 Hash/index.html @@ -0,0 +1,1399 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Hash - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Hashing

+
+

约 952 个字 29 行代码 预计阅读时间 4 分钟

+
+

1 Hash Table

+

哈希表/Hash Table 也被称为散列表,将关键字值映射到表中的一个位置来访问记录,以加快查找的速度,哈希表需要支持查找关键词是否在表中,查询关键词,插入关键词,删除关键词等操作。

+

哈希表通常使用一个数组来实现,哈希表的每个位置都叫做一个桶/Bucket,一个桶可以有多个槽/Slot,当多个关键字对应一个位置的时候,将不同的关键词存放在同一个位置的不同槽中。

+

哈希表的核心是哈希函数/Hash Function,我们通过哈希函数将关键字/标识符/Identifier 映射到哈希表中的一个位置/索引。

+

对于大小为 b,最多有 s 个槽的哈希表,定义 \(T\) 为哈希表关键字可能的所有不同值的个数,\(n\) 为哈希表中所有不同关键字的个数,关键字密度定义为 \(n / T\), 装载密度定义为 \(\lambda = n / (sb)\)

+

当存在 \(i_1 \neq i_2\) 但是 \(\mathrm{hash}(k_1) = \mathrm{hash}(k_2)\) 的时候,我们称发生了碰撞/Collision,当把一个新的标识符映射到一个已经满了的桶的时候,我们称发生了溢出/Overflow

+

在没有溢出的情况下,哈希表的查找时间、插入时间、删除时间都是 \(O(1)\),但是在发生溢出的情况下,哈希表的性能会下降。

+

哈希函数应该满足以下条件:

+
    +
  • 尽可能易于计算,并且减少碰撞的可能性;
  • +
  • 应该均匀分布/unbiased,即 \(P(\mathrm{hash}(k) = i) = 1 / b\),这样的哈希函数称之为均匀哈希函数/Uniform Hash Fuction
  • +
  • 对于整数的哈希,比如 \(f(x) = x\ \mathrm{ mod }\ \text{Tablesize}\),其中模应该最好选择为素数,因为这样对于随机输入,关键字的分布就会变得更加均匀。
  • +
+

2 Solving Collisions

+
    +
  • 分离链接/Sepatate Chaining:把有限大小的槽换成一个链表,将哈希映射到同一个值的所有元素都保存在这个链表之中。 +
     1
    + 2
    + 3
    + 4
    + 5
    + 6
    + 7
    + 8
    + 9
    +10
    +11
    +12
    #define ElementType int
    +typedef struct ListNode *Position;
    +typedef struct HashTable *HashTable;
    +typedef Position List;
    +struct ListNode{
    +    ElementType val;     // Key Stored
    +    Position Next;       // Next Node in List 
    +};
    +struct HashTable{
    +    int TableSize;       // Size of Hash Table
    +    List *TheLists;      // Array of Buckets
    +};
    +
  • +
  • 开放寻址/Open Addressing:使用多个哈希函数 \(\mathrm{hash}_1(x)\), \(\mathrm{hash}_2(x)\), \(\cdots\), \(\mathrm{hash}_n(x)\),与增量函数 \(f_i(x)\),其中每个哈希函数 \(\mathrm{hash}_i(x)\) 都通过主哈希函数与增量函数来计算,亦即具有 \(\mathrm{hash}_i(x) = \mathrm{hash}(x) + f_i(x)\ \mathrm{mod}\ \text{TableSize}\) 的形式,增量函数有很多种选择,因此衍生出不同的寻址方法,常见的有线性探测/Linear Probing二次探测/Quadratic Probing双重哈希/Double Hashing 等。使用开放寻址的哈希表的装载密度 \(\lambda\) 不能超过 \(0.5\),否则会导致性能下降。
  • +
  • 线性探测/Linear Probing
  • +
  • 二次探测/Quadratic Probing:亦即增量函数 \(f_i(x) = i ^ 2\)如果使用二次探测,且表的大小为指数时,那么当表至少有一半是空的时,总能插入一个新的元素
      +
    • 查找:\(f(i) = f(i-1) + i^2 - (i-1)^2 = f(i-1) + 2i - 1\); +
       1
      + 2
      + 3
      + 4
      + 5
      + 6
      + 7
      + 8
      + 9
      +10
      Position find(ElementType key, HashTable H) {
      +    Position currentPos = hash(key, H->TableSize);
      +    int collisionNum = 0;
      +    while (H->TheCells[currentPos].Info    != Empty && 
      +           H->TheCells[currentPos].Element != key) {
      +        currentPos += 2 * ++collisionNum - 1;
      +        if (currentPos >= H->TableSize) currentPos -= H->TableSize;
      +    }
      +    return currentPos;
      +}
      +
    • +
    • 插入: +
      1
      +2
      +3
      +4
      +5
      +6
      +7
      void insert(ElementType key, HashTable H) {
      +    Position pos = find(key, H);
      +    if (H->TheCells[pos].Info != Legitimate) {
      +        H->TheCells[pos].Info = Legitimate;
      +        H->TheCells[pos].Element = key;
      +    }
      +}
      +
    • +
    +
  • +
  • 双重哈希/Double Hashing:亦即增量函数 \(f_i(x) = i \cdot \mathrm{hash}'(x)\),其中 \(\mathrm{hash}'(x)\) 是另一个哈希函数。说白了就是从第一次哈希的位置开始以 \(\mathrm{hash}'(x)\) 为步长进行探测。
  • +
  • 再哈希/Rehashing:当哈希表填满一半了,或插入失败以及哈希表达到了某一个特定的装载密度时,我们需要进行再哈希。
      +
    • 建立一个两倍大的哈希表;
    • +
    • 扫描原始哈希表;
    • +
    • 利用新的哈希函数将元素映射到新的哈希值,并插入;
    • +
    • 如果有原来的哈希表有 \(N\) 个元素,则再哈希的时间复杂度为 \(O(N)\)
    • +
    +
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Algorithm/Algorithms and Data Structure/index.html b/Computer Science/Algorithm/Algorithms and Data Structure/index.html new file mode 100644 index 0000000..e3e862c --- /dev/null +++ b/Computer Science/Algorithm/Algorithms and Data Structure/index.html @@ -0,0 +1,1315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Algorithms and Data Structure - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Algorithms and Data Structure

+
+

约 102 个字

+
+
+

Abstract

+

这是我在浙江大学《数据结构基础》与《高级数据结构与算法分析》两门课上的课程笔记与延伸学习内容.

+

参考书籍:

+
    +
  • Algorithms, 4th Edition
  • +
  • 《算法导论》
  • +
  • 《数据结构与算法分析 C语言描述》
  • +
+

特别鸣谢:

+ +
+

Table of Contents

+ + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Buffer/240602/ALU.sv b/Computer Science/Buffer/240602/ALU.sv new file mode 100644 index 0000000..b34d37e --- /dev/null +++ b/Computer Science/Buffer/240602/ALU.sv @@ -0,0 +1,167 @@ +`include "core_struct.vh" +module ALU ( + input CorePack::data_t a, + input CorePack::data_t b, + input CorePack::alu_op_enum alu_op, + output CorePack::data_t res +); + + import CorePack::*; + + // fill your code + logic [31:0] tmp_ADDW; + logic [31:0] tmp_SUBW; + logic [31:0] tmp_SLLW; + logic [31:0] tmp_SRLW; + logic [31:0] tmp_SRAW; + always_comb begin + tmp_ADDW = a[31:0] + b[31:0]; + tmp_SUBW = a[31:0] - b[31:0]; + tmp_SLLW = a[31:0] << b[4:0]; + tmp_SRLW = a[31:0] >> b[4:0]; + tmp_SRAW = $signed(a[31:0]) >>> b[4:0]; + case (alu_op) + ALU_ADD: res = a + b; + ALU_SUB: res = a - b; + ALU_AND: res = a & b; + ALU_OR: res = a | b; + ALU_XOR: res = a ^ b; + ALU_SLT: res = ($signed(a) < $signed(b)) ? 1 : 0; + ALU_SLTU: res = (a < b) ? 1 : 0; + ALU_SLL: res = a << b[5:0]; + ALU_SRL: res = a >> b[5:0]; + ALU_SRA: res = $signed(a) >>> b[5:0]; + ALU_ADDW: res = {{32{tmp_ADDW[31]}}, tmp_ADDW[31:0]}; + ALU_SUBW: res = {{32{tmp_SUBW[31]}}, tmp_SUBW[31:0]}; + ALU_SLLW: res = {{32{tmp_SLLW[31]}}, tmp_SLLW[31:0]}; + ALU_SRLW: res = {{32{tmp_SRLW[31]}}, tmp_SRLW[31:0]}; + ALU_SRAW: res = {{32{tmp_SRAW[31]}}, tmp_SRAW[31:0]}; + ALU_DEFAULT: res = 0; + endcase + end + +endmodule + +/* +`ifndef __CORE_STRUCT__ +`define __CORE_STRUCT__ + +package CorePack; + + parameter xLen = 64; + parameter ADDR_WIDTH = xLen; + parameter DATA_WIDTH = xLen; + parameter MASK_WIDTH = DATA_WIDTH/8; + typedef logic [ADDR_WIDTH-1:0] addr_t; + typedef logic [DATA_WIDTH-1:0] data_t; + typedef logic [MASK_WIDTH-1:0] mask_t; + typedef logic [31:0] inst_t; + typedef logic [4:0] reg_ind_t; + + typedef enum logic [3:0] { + ALU_ADD, ALU_SUB, ALU_AND, ALU_OR, + ALU_XOR, ALU_SLT, ALU_SLTU, ALU_SLL, + ALU_SRL, ALU_SRA, ALU_ADDW, ALU_SUBW, + ALU_SLLW, ALU_SRLW, ALU_SRAW, ALU_DEFAULT + } alu_op_enum; + + typedef enum logic [2:0] { + MEM_NO, MEM_D, MEM_W, MEM_H, + MEM_B, MEM_UB, MEM_UH, MEM_UW + } mem_op_enum; + + typedef enum logic [2:0] { + CMP_NO, CMP_EQ, CMP_NE, CMP_LT, + CMP_GE, CMP_LTU, CMP_GEU, CMP7 + } cmp_op_enum; + + typedef enum logic [2:0] { + IMM0, I_IMM, S_IMM, B_IMM, + U_IMM, UJ_IMM, IMM6, IMM7 + } imm_op_enum; + + typedef enum logic [1:0] { + ASEL0, ASEL_REG, ASEL_PC, ASEL3 + } alu_asel_op_enum; + + typedef enum logic [1:0] { + BSEL0, BSEL_REG, BSEL_IMM, BSEL3 + } alu_bsel_op_enum; + + typedef enum logic [1:0] { + WB_SEL0, WB_SEL_ALU, WB_SEL_MEM, WB_SEL_PC + } wb_sel_op_enum; + + typedef logic [6:0] opcode_t; + parameter LOAD_OPCODE = 7'b0000011; + parameter IMM_OPCODE = 7'b0010011; + parameter AUIPC_OPCODE = 7'b0010111; + parameter IMMW_OPCODE = 7'b0011011; + parameter STORE_OPCODE = 7'b0100011; + parameter REG_OPCODE = 7'b0110011; + parameter LUI_OPCODE = 7'b0110111; + parameter REGW_OPCODE = 7'b0111011; + parameter BRANCH_OPCODE = 7'b1100011; + parameter JALR_OPCODE = 7'b1100111; + parameter JAL_OPCODE = 7'b1101111; + + typedef logic [2:0] funct3_t; + typedef logic [6:0] funct7_t; + parameter BEQ_FUNCT3 = 3'b000; + parameter BNE_FUNCT3 = 3'b001; + parameter BLT_FUNCT3 = 3'b100; + parameter BGE_FUNCT3 = 3'b101; + parameter BLTU_FUNCT3 = 3'b110; + parameter BGEU_FUNCT3 = 3'b111; + + parameter LB_FUNCT3 = 3'b000; + parameter LH_FUNCT3 = 3'b001; + parameter LW_FUNCT3 = 3'b010; + parameter LD_FUNCT3 = 3'b011; + parameter LBU_FUNCT3 = 3'b100; + parameter LHU_FUNCT3 = 3'b101; + parameter LWU_FUNCT3 = 3'b110; + + parameter SB_FUNCT3 = 3'b000; + parameter SH_FUNCT3 = 3'b001; + parameter SW_FUNCT3 = 3'b010; + parameter SD_FUNCT3 = 3'b011; + + parameter ADD_FUNCT3 = 3'b000; + parameter SUB_FUNCT3 = 3'b000; + parameter SLL_FUNCT3 = 3'b001; + parameter SLT_FUNCT3 = 3'b010; + parameter SLTU_FUNCT3 = 3'b011; + parameter XOR_FUNCT3 = 3'b100; + parameter SRL_FUNCT3 = 3'b101; + parameter SRA_FUNCT3 = 3'b101; + parameter OR_FUNCT3 = 3'b110; + parameter AND_FUNCT3 = 3'b111; + parameter ADDW_FUNCT3 = 3'b000; + parameter SUBW_FUNCT3 = 3'b000; + parameter SLLW_FUNCT3 = 3'b001; + parameter SRLW_FUNCT3 = 3'b101; + parameter SRAW_FUNCT3 = 3'b101; + + typedef struct{ + logic [63:0] pc; + logic [63:0] inst; + logic [63:0] rs1_id; + logic [63:0] rs1_data; + logic [63:0] rs2_id; + logic [63:0] rs2_data; + logic [63:0] alu; + logic [63:0] mem_addr; + logic [63:0] mem_we; + logic [63:0] mem_wdata; + logic [63:0] mem_rdata; + logic [63:0] rd_we; + logic [63:0] rd_id; + logic [63:0] rd_data; + logic [63:0] br_taken; + logic [63:0] npc; + } CoreInfo; + +endpackage +`endif +*/ \ No newline at end of file diff --git a/Computer Science/Buffer/240602/Cmp.sv b/Computer Science/Buffer/240602/Cmp.sv new file mode 100644 index 0000000..791a3ea --- /dev/null +++ b/Computer Science/Buffer/240602/Cmp.sv @@ -0,0 +1,25 @@ +`include"core_struct.vh" +module Cmp ( + input CorePack::data_t a, + input CorePack::data_t b, + input CorePack::cmp_op_enum cmp_op, + output cmp_res +); + + import CorePack::*; + + // fill your code + always_comb begin + case (cmp_op) + CMP_NO: cmp_res = 0; + CMP_EQ: cmp_res = (a == b) ? 1 : 0; + CMP_NE: cmp_res = (a != b) ? 1 : 0; + CMP_LT: cmp_res = ($signed(a) < $signed(b)) ? 1 : 0; + CMP_GE: cmp_res = ($signed(a) >= $signed(b)) ? 1 : 0; + CMP_LTU: cmp_res = (a < b) ? 1 : 0; + CMP_GEU: cmp_res = (a >= b) ? 1 : 0; + default: cmp_res = 0; + endcase + end + +endmodule \ No newline at end of file diff --git a/Computer Science/Buffer/240602/Controller.sv b/Computer Science/Buffer/240602/Controller.sv new file mode 100644 index 0000000..98c623b --- /dev/null +++ b/Computer Science/Buffer/240602/Controller.sv @@ -0,0 +1,195 @@ +// `include "core_struct.vh" +// module controller ( +// input CorePack::inst_t inst, +// output we_reg, +// output we_mem, +// output re_mem, +// output is_b, +// output is_j, +// output npc_sel, +// output CorePack::imm_op_enum immgen_op, +// output CorePack::alu_op_enum alu_op, +// output CorePack::cmp_op_enum cmp_op, +// output CorePack::alu_asel_op_enum alu_asel, +// output CorePack::alu_bsel_op_enum alu_bsel, +// output CorePack::wb_sel_op_enum wb_sel, +// output CorePack::mem_op_enum mem_op, +// output [4:0] memdata_width +// ); + +// import CorePack::*; + +// // fill your code +// logic [6:0] opcode; +// logic [3:0] funct3; +// logic [6:0] funct7; +// logic [4:0] rs1; +// logic [4:0] rs2; +// logic [4:0] rd; + + + +// endmodule +`include "core_struct.vh" +module controller ( + input CorePack::inst_t inst, + output we_reg, + output we_mem, + output re_mem, + output is_b, + output is_j, + output CorePack::imm_op_enum immgen_op, + output CorePack::alu_op_enum alu_op, + output CorePack::cmp_op_enum cmp_op, + output CorePack::alu_asel_op_enum alu_asel, + output CorePack::alu_bsel_op_enum alu_bsel, + output CorePack::wb_sel_op_enum wb_sel, + output CorePack::mem_op_enum mem_op, + output [4:0] memdata_width, //用于package , mask ,truncation + output npc_sel +); + + import CorePack::*; + // fill your code + opcode_t opcode = inst[6:0]; + wire inst_reg=opcode==REG_OPCODE; + wire inst_regw=opcode==REGW_OPCODE; + wire inst_load=opcode==LOAD_OPCODE; + wire inst_lui=opcode==LUI_OPCODE; + wire inst_imm=opcode==IMM_OPCODE; + wire inst_immw=opcode==IMMW_OPCODE; + wire inst_store=opcode==STORE_OPCODE; + wire inst_branch=opcode==BRANCH_OPCODE; + wire inst_jalr=opcode==JALR_OPCODE; + wire inst_jal=opcode==JAL_OPCODE; + wire inst_auipc=opcode==AUIPC_OPCODE; + + assign we_reg= inst_reg|inst_load|inst_imm|inst_lui|inst_immw|inst_regw|inst_auipc|inst_jalr|inst_jal; + assign we_mem= inst_store; + assign re_mem= inst_load; + assign is_b= inst_branch; + assign is_j= inst_jalr | inst_jal; // npc_sel can displace the is_j + assign npc_sel = inst_jalr | inst_jal; // branch is not in here but in cor.sv:branch_res + funct3_t funct3; + funct7_t funct7; + + always_comb begin + //immgen_op + funct3=inst[14:12]; + funct7=inst[31:25]; + if(inst_load | inst_imm | inst_immw | inst_jalr)begin + // if((funct3 == 3'b101) && (inst_imm || inst_immw)) immgen_op = S_IMM; // srli for func3 = 101 and inst_imm = 1 + // else immgen_op=I_IMM; + immgen_op = I_IMM; + end else if(inst_store) immgen_op=S_IMM; // although ld is I type,but it's imm is S type + else if(inst_branch) immgen_op=B_IMM; + else if(inst_lui | inst_auipc) immgen_op=U_IMM; + else if(inst_jal) immgen_op=UJ_IMM; + else immgen_op=IMM0; + //alu_op + if(inst_reg | inst_imm)begin + case(funct3) + 3'b000:begin + if(inst_imm) alu_op = ALU_ADD; //I Type 没有funct7 + else if(funct7 == 7'b0000000) alu_op=ALU_ADD; + else alu_op=ALU_SUB; + end + 3'b101:begin + if(funct7 == 7'b0000000) begin alu_op=ALU_SRL; alu_bsel = BSEL_REG; end + else alu_op=ALU_SRA; + end + SLL_FUNCT3:alu_op=ALU_SLL; + SLT_FUNCT3:alu_op=ALU_SLT; + SLTU_FUNCT3:alu_op=ALU_SLTU; + XOR_FUNCT3:alu_op=ALU_XOR; + OR_FUNCT3:alu_op=ALU_OR; + AND_FUNCT3:alu_op=ALU_AND; + endcase + end else if(inst_immw | inst_regw)begin + case(funct3) + 3'b000:begin + if (funct7 == 7'b0000000) begin + alu_op = ALU_ADDW; + end else if (funct7 == 7'b0100000) begin + alu_op = ALU_SUBW; + end else begin alu_op = ALU_ADDW; end + end + 3'b101:begin + if(funct7 == 7'b0000000) alu_op=ALU_SRLW; + else alu_op=ALU_SRAW; + end + SLL_FUNCT3:alu_op=ALU_SLLW; + default:alu_op=ALU_ADDW; + endcase + end else if(inst_auipc | inst_load | inst_store | inst_jalr | inst_jal) begin + alu_op = ALU_ADD; + end else alu_op = ALU_ADD; //defaul + //cmp_op + if(inst_branch)begin + case(funct3) + BEQ_FUNCT3:cmp_op=CMP_EQ; + BNE_FUNCT3:cmp_op=CMP_NE; + BLT_FUNCT3:cmp_op=CMP_LT; + BGE_FUNCT3:cmp_op=CMP_GE; + BLTU_FUNCT3:cmp_op=CMP_LTU; + BGEU_FUNCT3:cmp_op=CMP_GEU; + default:cmp_op=CMP_NO; + endcase + end else cmp_op=CMP_NO; + //alu_asel + if(inst_reg | inst_regw | inst_load | inst_imm | inst_immw | inst_store | inst_jalr) alu_asel = ASEL_REG; + else if(inst_auipc | inst_jal | inst_branch) alu_asel = ASEL_PC; + else alu_asel = ASEL0; + //alu_bsel + if(inst_reg | inst_regw) alu_bsel = BSEL_REG; + else if (inst_load | inst_imm | inst_immw | inst_store | inst_branch | inst_jalr | inst_jal | inst_auipc | inst_lui) alu_bsel = BSEL_IMM; + else if (inst_imm && alu_op == ALU_SRL) alu_bsel = BSEL_REG; + else alu_bsel = BSEL0; + //wb_sel + if(inst_load) wb_sel = WB_SEL_MEM; + else if(inst_imm | inst_immw | inst_reg | inst_regw | inst_auipc | inst_lui) wb_sel = WB_SEL_ALU; + else if(inst_jalr | inst_jal) wb_sel = WB_SEL_PC; + else wb_sel = WB_SEL0; //branch store + + //mem_op and memdata_width + if(inst_load | inst_store) begin + case(funct3) + 3'b000:begin + mem_op = MEM_B; + memdata_width = 1; + end + 3'b001:begin + mem_op = MEM_H; + memdata_width = 2; + end + 3'b010:begin + mem_op = MEM_W; + memdata_width = 4; + end + 3'b011:begin + mem_op = MEM_D; + memdata_width = 8; + end + 3'b100:begin + mem_op = MEM_UB; + memdata_width = 1; + end + 3'b101:begin + mem_op = MEM_UH; + memdata_width = 2; + end + 3'b110:begin + mem_op = MEM_UW; + memdata_width = 4; + end + default:begin + mem_op = MEM_NO; + memdata_width = 0; + end + endcase + end else begin + mem_op = MEM_NO; + memdata_width = 0; + end + end +endmodule \ No newline at end of file diff --git a/Computer Science/Buffer/240602/Core.sv b/Computer Science/Buffer/240602/Core.sv new file mode 100644 index 0000000..07b69c2 --- /dev/null +++ b/Computer Science/Buffer/240602/Core.sv @@ -0,0 +1,293 @@ +`include "core_struct.vh" +module Core ( + input clk, + input rst, + + Mem_ift.Master imem_ift, + Mem_ift.Master dmem_ift, + + output cosim_valid, + output CorePack::CoreInfo cosim_core_info +); + import CorePack::*; + + // fill your code + logic [63:0] next_pc; + logic [63:0] pc; + logic [31:0] inst; + logic [63:0] inst_unselected; + logic cmp_res; // assigned with br_taken to be used in PC + logic br_taken; // 1 for take the branch + + logic [63:0] alu_res; // the output of the alu_unit + logic [63:0] ro_addr; + logic [63:0] ro_rdata; + + logic we_reg; + logic we_mem; + logic re_mem; + logic npc_sel; // 1 for branch or jump instruction + logic [2 :0] immgen_op; + logic [3 :0] alu_op; + logic [2 :0] cmp_op; + logic [1 :0] alu_asel; + logic [1 :0] alu_bsel; + logic [1 :0] wb_sel; + logic [2 :0] mem_op; + logic [4 :0] memdata_width; + logic [63:0] wb_val; + + parameter pc_increment = 4; + + + // Part PC + always_comb begin + br_taken = cmp_res; + if (br_taken | npc_sel) begin + next_pc = alu_res; + end else begin + next_pc = pc + pc_increment; + end + ro_addr = pc; + end + + always @(posedge clk) begin + if (rst) begin + pc <= 64'b0; + end else begin + pc <= next_pc; + end + end + + // Part IMEM + always_comb begin + imem_ift.r_request_valid = 1; + imem_ift.r_request_bits.raddr = ro_addr; + imem_ift.r_reply_ready = 1; + imem_ift.w_request_bits.wdata = 0; + imem_ift.w_request_bits.waddr = 0; + imem_ift.w_request_bits.wmask = 0; + imem_ift.w_request_valid = 0; + imem_ift.w_reply_ready = 0; + ro_rdata = imem_ift.r_reply_bits.rdata; + inst_unselected = ro_rdata; + end + + // Part Inst Selector + always_comb begin + if (pc[2] == 1) begin + inst = inst_unselected[63:32]; + end else begin + inst = inst_unselected[31:0]; + end + end + + // Part RegFile + logic [4 :0] rs1; + logic [4 :0] rs2; + logic [4 :0] rd; + logic [63:0] read_data_1; + logic [63:0] read_data_2; + + always_comb begin + rs1 = inst[19:15]; + rs2 = inst[24:20]; + rd = inst[11:7]; + end + + RegFile regf(.clk(clk), + .rst(rst), + .we(we_reg), + .read_addr_1(rs1), + .read_addr_2(rs2), + .write_addr(rd), + .write_data(wb_val), + .read_data_1(read_data_1), + .read_data_2(read_data_2) + + ); + + // Part Imm Gen + logic [63:0] Imm; + always_comb begin + case(immgen_op) + IMM0: Imm = 64'b0; + I_IMM: Imm = {{52{inst[31]}}, inst[31:20]}; + S_IMM: Imm = {{52{inst[31]}}, inst[31:25], inst[11:7]}; + B_IMM: Imm = {{51{inst[31]}}, inst[31], inst[7], inst[30:25], inst[11:8], 1'b0}; + U_IMM: Imm = {{32{inst[31]}}, inst[31:12], 12'b0}; + UJ_IMM: Imm = {{43{inst[31]}}, inst[31], inst[19:12], inst[20], inst[30:21], 1'b0}; + default: Imm = 64'b0; + endcase + end + + // Part Branch Comparator + Cmp cmp(.a(read_data_1), + .b(read_data_2), + .cmp_op(cmp_op), + .cmp_res(cmp_res) + ); + + // ALU A Selector: ASEL0 for 0, REG for RS1, PC for PC + logic [63:0] alu_a; + always_comb begin + case(alu_asel) + ASEL0: alu_a = 64'b0; + ASEL_REG: alu_a = read_data_1; + ASEL_PC: alu_a = pc; + default: alu_a = 64'b0; + endcase + end + // ALU B Selector: BSEL0 for 0, REG for RS2, IMM for Imm + logic [63:0] alu_b; + always_comb begin + case(alu_bsel) + BSEL0: alu_b = 64'b0; + BSEL_REG: alu_b = read_data_2; + BSEL_IMM: alu_b = Imm; + default: alu_b = 64'b0; + endcase + end + // Part ALU + ALU alu_unit(.a(alu_a), + .b(alu_b), + .alu_op(alu_op), + .res(alu_res) + ); + + // Data Package with mask + logic [63:0] wdata_data; + logic [7 :0] wdata_mask; + integer location = {29'b0, alu_res[2:0]}; + integer mask_width; + + always_comb begin + mask_width = {27'b0, memdata_width[4:0]}; + mask_width = mask_width * 8; + for (integer i = 0; i < 8; i = i + 1) begin + if (i < location + mask_width / 8 && i >= location) begin + wdata_mask[i] = 1; + end else begin + wdata_mask[i] = 0; + end + end + for (integer i = 0; i < 64; i = i + 1) begin + if (i < location * 8) begin + wdata_data[i] = 0; + end else begin + wdata_data[i] = read_data_2[i - location * 8]; + end + end + end + + // Part DMEM + logic [63:0] read_data; + always_comb begin + // read_data = 0; + dmem_ift.r_request_bits.raddr = alu_res; + if (re_mem)begin + dmem_ift.r_request_valid = 1; + dmem_ift.r_reply_ready = 1; + end else begin + dmem_ift.r_request_valid = 0; + dmem_ift.r_reply_ready = 0; + end + read_data = dmem_ift.r_reply_bits.rdata; + dmem_ift.w_request_bits.waddr = alu_res; + dmem_ift.w_request_bits.wdata = wdata_data; + dmem_ift.w_request_bits.wmask = wdata_mask; + if (we_mem)begin + dmem_ift.w_request_valid = 1; + dmem_ift.w_reply_ready = 1; + end else begin + dmem_ift.w_request_valid = 0; + dmem_ift.w_reply_ready = 0; + end + end + + // Part Data Truncation + logic [63:0] trunc_data; + always_comb begin + for (integer i = 0; i < 64; i = i + 1)begin + if(i >= mask_width)begin + case(mem_op) + MEM_UW: trunc_data[i] = 0; + MEM_UH: trunc_data[i] = 0; + MEM_UB: trunc_data[i] = 0; + default: trunc_data[i] = read_data[location * 8 + mask_width - 1]; // signed extension + endcase + end else begin + trunc_data[i] = read_data[location * 8 + i]; + end + end + end + + + // Part WB + always_comb begin + case(wb_sel) + WB_SEL0: wb_val = 64'b0; + WB_SEL_ALU: wb_val = alu_res; + WB_SEL_MEM: wb_val = trunc_data; + WB_SEL_PC: wb_val = pc + 4; + endcase + end + + // Part Controller + controller ctrl(.inst(inst), + .we_reg(we_reg), + .we_mem(we_mem), + .re_mem(re_mem), + .is_b(), + .is_j(), + .npc_sel(npc_sel), + .immgen_op(immgen_op), + .alu_op(alu_op), + .cmp_op(cmp_op), + .alu_asel(alu_asel), + .alu_bsel(alu_bsel), + .wb_sel(wb_sel), + .mem_op(mem_op), + .memdata_width(memdata_width) + ); + + + + assign cosim_valid = 1'b1; + assign cosim_core_info.pc = pc; + assign cosim_core_info.inst = {32'b0,inst}; + assign cosim_core_info.rs1_id = {59'b0, rs1}; + assign cosim_core_info.rs1_data = read_data_1; + assign cosim_core_info.rs2_id = {59'b0, rs2}; + assign cosim_core_info.rs2_data = read_data_2; + assign cosim_core_info.alu = alu_res; + assign cosim_core_info.mem_addr = dmem_ift.r_request_bits.raddr; + assign cosim_core_info.mem_we = {63'b0, dmem_ift.w_request_valid}; + assign cosim_core_info.mem_wdata = dmem_ift.w_request_bits.wdata; + assign cosim_core_info.mem_rdata = dmem_ift.r_reply_bits.rdata; + assign cosim_core_info.rd_we = {63'b0, we_reg}; + assign cosim_core_info.rd_id = {59'b0, rd}; + assign cosim_core_info.rd_data = wb_val; + assign cosim_core_info.br_taken = {63'b0, npc_sel}; + assign cosim_core_info.npc = next_pc; + +endmodule + +module MultiFSM( + input clk, + input rst, + Mem_ift.Master imem_ift, + Mem_ift.Master dmem_ift, + input we_mem, + input re_mem, + input CorePack::addr_t pc, + input CorePack::addr_t alu_res, + input CorePack::data_t data_package, + input CorePack::mask_t mask_package, + output stall +); + import CorePack::*; + + // fill your code for bonus + +endmodule \ No newline at end of file diff --git a/Computer Science/Buffer/240602/RegFile.sv b/Computer Science/Buffer/240602/RegFile.sv new file mode 100644 index 0000000..6b69549 --- /dev/null +++ b/Computer Science/Buffer/240602/RegFile.sv @@ -0,0 +1,44 @@ +`include "core_struct.vh" +module RegFile ( + input clk, + input rst, + input we, + input CorePack::reg_ind_t read_addr_1, + input CorePack::reg_ind_t read_addr_2, + input CorePack::reg_ind_t write_addr, + input CorePack::data_t write_data, + output CorePack::data_t read_data_1, + output CorePack::data_t read_data_2 +); + import CorePack::*; + + integer i; + data_t register [1:31]; // x1 - x31, x0 keeps zero + + // fill your code + data_t reg_0; + assign reg_0 = 0; + always_ff @(posedge clk) begin + if (rst) begin + for (i = 1; i <= 31; i = i + 1) begin + register[i] <= 0; + end + end else begin + if (we) begin + register[write_addr] <= write_data; + end + end + end + always_comb begin + read_data_1 = (read_addr_1 == 0) ? reg_0 : register[read_addr_1]; + read_data_2 = (read_addr_2 == 0) ? reg_0 : register[read_addr_2]; + end +endmodule + +/* + typedef logic [ADDR_WIDTH-1:0] addr_t; + typedef logic [DATA_WIDTH-1:0] data_t; + typedef logic [MASK_WIDTH-1:0] mask_t; + typedef logic [31:0] inst_t; + typedef logic [4:0] reg_ind_t; +*/ \ No newline at end of file diff --git a/Computer Science/Buffer/index.html b/Computer Science/Buffer/index.html new file mode 100644 index 0000000..69e0b56 --- /dev/null +++ b/Computer Science/Buffer/index.html @@ -0,0 +1,799 @@ + + + + + + + + + + + + + + + + + + + + + Index - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Index

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Basis/GNU Make/index.html b/Computer Science/Programming Basis/GNU Make/index.html new file mode 100644 index 0000000..7d25c36 --- /dev/null +++ b/Computer Science/Programming Basis/GNU Make/index.html @@ -0,0 +1,1526 @@ + + + + + + + + + + + + + + + + + + + + + + + + + GNU Make - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

GNU Make

+
+

约 1950 个字 13 行代码 预计阅读时间 7 分钟

+
+
+

Abstract

+

GNU Make是一个用于自动化编译的工具,它可以根据文件的依赖关系自动执行编译任务.本文将介绍GNU Make的基本使用方法.

+

为啥要学Make?

+

属于是为了这盘醋包了顿饺子,由于数据结构基础这门课的大作业或多或少需要用到多文件编译,我干脆就希望使用Make进行自动化编译,而且在系统课上接触了Makefile的编写,所以就有了这篇文章.

+
+

Part 1 别急,先看看 gcc 编译!

+

gcc的编译过程可以简要分为四个阶段:预处理编译汇编链接.

+

gcc编译工具链是以gcc编译器为核心的一整套工具,主要包含以下三部分内容:

+
    +
  • gcc-core:亦即gcc编译器,用于完成预处理过程和编译过程,将C代码转换成汇编代码;
  • +
  • Binutils:包含了除了gcc编译器以外的一系列小工具,比如汇编器as、连接器ld、目标文件格式查看器readelf等;
  • +
  • glibc:GNU C Library,是GNU组织为了GNU系统以及Linux系统编写的C语言标准库.
  • +
+

1.1 预处理/Pre-Processing

+

预处理阶段的主要任务是处理源文件以#开头的预处理指令,比如#include#define等.这里主要是将#include的一些头文件宏定义进行展开,生成一个.i文件.

+

预处理过程输入的是C的源文件,输出的是一个中间/预加载文件,这个文件还是C代码.此阶段使用gcc参数-E,同时参数-o指定了最后输出文件的名字,下面的例子就将main.c文件经过预处理生成main.i文件

+
gcc -E main.c -o main.i
+
+

1.2 编译/Compiling

+

编译过程使用gcc编译器将预处理后的.i文件通过编译转换为汇编语言,生成一个.s文件.这是gcc编译器完成的工作,在这部分过程之中,gcc编译器会检查各个源文件的语法,即使我们调用了一个没有定义的函数,也不会报错,

+

编译过程输入的是一个中间/预加载文件,输出的是一个汇编文件,当然,直接以C文件作为输入进行编译也是可以的.此阶段使用gcc参数-S,具体例子如下:

+
1
+2
gcc -S main.i -o main.s
+gcc -S main.c -o main.s
+
+

1.3 汇编/Assembling

+

汇编阶段的主要任务是将汇编语言文件经过汇编,生成目标文件.o文件,每一个源文件都对应一个目标文件.即把汇编语言的代码转换成机器码,这是as汇编器完成的工作.

+

汇编过程输入的是汇编文件,输出.o后缀的目标文件,gcc的参数-c表示只编译源文件但不链接,当然,我们也可以直接输入C源文件,就直接包含了前面两个过程.

+
1
+2
gcc -c main.s -o main.o
+gcc -c main.c -o main.o
+
+

Linux下生成的.o目标文件、.so动态库文件以及下一小节链接阶段生成最终的可执行文件都是elf格式的, 可以使用 readelf 工具来查看它们的内容.

+

从 readelf 的工具输出的信息,可以了解到目标文件包含ELF头、程序头、节等内容,对于.o目标文件或.so库文件,编译器在链接阶段利用这些信息把多个文件组织起来,对于可执行文件,系统在运行时根据这些信息加载程序运行.

+

1.4 链接/Linking

+

最后将每个源文件对应的.o文件链接起来,就生成了一个可执行程序文件,这是这是链接xx器ld完成的工作.

+

例如一个工程里包含了A和B两个代码文件,在链接阶段,链接过程需要把A和B之间的函数调用关系理顺,也就是说要告诉A在哪里能够调用到fun函数,建立映射关系,所以称之为链接.若链接过程中找不到fun函数的具体定义,则会链接报错.

+

链接分为两种:

+
    +
  • 动态链接:gcc编译时的默认选项.动态是指在应用程序运行时才去加载外部的代码库,不同的程序可以共用代码库.所以动态链接生成的程序比较小,占用较少的内存.
  • +
  • 静态链接:链接时使用选项--static,它在编译阶段就会把所有用到的库打包到自己的可执行程序中.所以静态链接的优点是具有较好的兼容性,不依赖外部环境,但是生成的程序比较大.
  • +
+
1
+2
gcc main.o -o main
+gcc main.c -o main --static
+
+

Part 2 Makefile

+

2.1 书写规则

+

Makefile的规则包括两个部分:一个是依赖关系/prerequisites,另一个是生成目标的方法/command.在Makefile中,规则的顺序是很重要的,Makeflie中有且仅有一个最终目标,其他目标都是这个目标连带出来的,一般来说,定义在第一条规则的第一个目标就是最终目标,make完成的就是这个目标.

+

但是我们经常会遇见make a.o这样的命令,make后可以跟着一个或多个target,a.o作为make的参数,指定了执行的内容,优先级比Makefile里边的定义要高.换句话说,倘若make后边有目标,这个目标就是最终目标,make后边没目标,默认执行Makefile的第一个目标.

+

规则的语法是这样的:

+
1
+2
+3
targets : prerequisites
+    recipe
+    ...
+
+

或者这样的:

+
1
+2
+3
targets : prerequisites ; command
+    recipe
+    ...
+
+

targets是文件名,可以使用通配符,基本来说,我们的目标基本上是一个文件,可以是一个目标文件,可以是一个可执行文件,还可以是一个标签,是多个文件也是有可能的.

+

prerequisites是生成该target所依赖的文件或者target.

+

recipe是命令行,可以是任意的shell命令,如果其不与target:prerequisites在一行,那么,必须以 Tab 键开头,如果和prerequisites在一行,那么可以用分号做为分隔.如果命令太长,我们可以使用反斜杠\来作为换行符.

+

规则告诉make两件事:一个是文件的依赖关系,target依赖于prerequisites中的文件;另一个时就会如何生成目标文件,生成规则定义在recipe中,makefile最核心的内容是:

+

prerequisites中如果有一个以上的文件比target文件要新的话,recipe所定义的命令就会被执行.

+

2.2 使用变量

+

Makefile中的变量就像是C语言的宏一样,代表着一个文本字符串,在执行的时候会自动展开在所使用的地方,不过,我们可以在Makefile中改变其值.变量可以使用在目标,规则,依赖目标或者其他部分之中.

+

在声明变量的时候,我们需要给予其初值,使用的时候需要在变量名前面加上$符号,最好还用小括号括起来(),变量的名字可以包含字符,数字,下划线,甚至还可以数字开头,但是不能含有:#=或者空字符.

+

我们可以使用其他变量来构造变量的值,比如foo = $(bar),这里的bar不一定非要是已经定义好的值,我们可以使用后面定义的值,这就很好了嘛,我们可以把变量的真实值退到后面去定义,但是无法避免递归定义,虽然make有能力检测这样的定义。

+

为了避免这个问题,我们使用:=操作符,对于VAR := value,右边的value会在定义的时候就被展开.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Basis/Git/index.html b/Computer Science/Programming Basis/Git/index.html new file mode 100644 index 0000000..56eeaa8 --- /dev/null +++ b/Computer Science/Programming Basis/Git/index.html @@ -0,0 +1,1245 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Git - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Git

+
+

约 1 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Basis/Linux/index.html b/Computer Science/Programming Basis/Linux/index.html new file mode 100644 index 0000000..cc42393 --- /dev/null +++ b/Computer Science/Programming Basis/Linux/index.html @@ -0,0 +1,1237 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Linux - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Linux

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Basis/MIT Missing Semester/index.html b/Computer Science/Programming Basis/MIT Missing Semester/index.html new file mode 100644 index 0000000..e01b370 --- /dev/null +++ b/Computer Science/Programming Basis/MIT Missing Semester/index.html @@ -0,0 +1,1241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + MIT Missing Semester - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

MIT Missing Semester

+ +
+

约 4 个字

+
+
+

Warning

+

待更新!

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Basis/Regular Expression/index.html b/Computer Science/Programming Basis/Regular Expression/index.html new file mode 100644 index 0000000..2230997 --- /dev/null +++ b/Computer Science/Programming Basis/Regular Expression/index.html @@ -0,0 +1,1245 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Regular Expression - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Regular Expression

+
+

约 2 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Basis/Shell/index.html b/Computer Science/Programming Basis/Shell/index.html new file mode 100644 index 0000000..ca47ab6 --- /dev/null +++ b/Computer Science/Programming Basis/Shell/index.html @@ -0,0 +1,1332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Shell - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Shell

+
+

约 305 个字 5 行代码 预计阅读时间 1 分钟

+
+
+

Abstract

+

这份笔记将专注于bash(也就是Bourne Again SHell),暂不涉及其他种类的shell。

+

下面代码均以本人 Ubuntu 22.04.3 系统中的bash为例。

+
+

Basis

+

我们所熟悉的图像用户界面/Graphical User Interface/GUI在某些情况下反而限制了我们对计算机的使用,shell为我们提供了一种充分利用计算机的方式,它允许我们执行程序、输入并且获取某种半结构化的输出。

+

打开终端,我们就可以使用shell,下面就是我们一般看起来的样子。

+
test@testMachine:~$
+
+

其中test是用户名;testMachine是主机名;~是当前工作目录,特别地,~代表home$是提示符,表示现在的身份不是root用户。在提示符后面,我们可以输入命令,命令最终会被shell解析并且执行。我们现在执行一些基本的命令:

+
1
+2
+3
+4
test@testMachine:~$ date
+Thu 14 Oct 2021 10:00:00 PM CST
+test@testMachine:~$ echo hello
+hello
+
+

在这个例子中:

+
    +
  • +

    我们不仅可以直接输入类似date的命令,还可以向shell传递参数,比如echo hello

    +
  • +
  • +

    如果我们想让shell输出hello world,方法之一是使用单引号或者双引号包裹起来,

    +
  • +
  • +

    我们让shell执行了echo命令

    +
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Basis/index.html b/Computer Science/Programming Basis/index.html new file mode 100644 index 0000000..18deb1c --- /dev/null +++ b/Computer Science/Programming Basis/index.html @@ -0,0 +1,1229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Index - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Index

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Basis/tmux/index.html b/Computer Science/Programming Basis/tmux/index.html new file mode 100644 index 0000000..2b54e58 --- /dev/null +++ b/Computer Science/Programming Basis/tmux/index.html @@ -0,0 +1,1249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Tmux Cheatsheet - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Tmux Cheatsheet

+
+

约 78 个字

+
+
+

What is tmux?

+

tmux’s authors describe it as a terminal multiplexer. Behind this fancy term hides a simple concept: Within one terminal window you can open multiple windows and split-views (called "panes" in tmux lingo). Each pane will contain its own, independently running shell instance (bash, zsh, whatever you're using). This allows you to have multiple terminal commands and applications running side by side without the need to open multiple terminal emulator windows.

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Language/C++/Basic Syntax/index.html b/Computer Science/Programming Language/C++/Basic Syntax/index.html new file mode 100644 index 0000000..5e1c89d --- /dev/null +++ b/Computer Science/Programming Language/C++/Basic Syntax/index.html @@ -0,0 +1,1513 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Basic Syntax - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Basic Syntax

+
+

约 519 个字 4 行代码 预计阅读时间 2 分钟

+
+

Initialization

+

初始化是指在创建对象(为特定类型的对象申请存储空间)的同时赋初始值。C++ 的初始化方式与规则五花八门,大概包括以下几种:直接初始化、拷贝初始化、列表初始化、默认初始化、值初始化、类内初始值、构造函数初始值列表。

+

一般有着四类初始化方式,现代 C++ 的内置类型和类类型都支持这四种初始化方式:

+
    +
  • 等号:int a = 1; 或者 std::string s = "hello";
  • +
  • 等号加花括号:int a = {1}; 或者 std::string s = {"hello"};
  • +
  • 花括号:int a{1}; 或者 std::string s{"hello"};
  • +
  • 圆括号:int a(1); 或者 std::string s("hello");
  • +
+

默认初始化/Default Initialization:当对象未被显示地赋予初值时执行的初始化行为。

+
    +
  • 类类型:由类的默认无参构造函数决定,如果没有默认无参构造函数,则该类不支持默认初始化。
  • +
  • 内置类型(指针、intdoublefloatboolchar 等)及其数组:
      +
    • 全局(包括定义在任何函数之外、命名空间之内的)变量或局部静态变量:初始化为 0(这种情况也叫值初始化);
    • +
    • 局部非静态变量或类成员:未定义(未初始化)。
    • +
    +
  • +
+
1
+2
+3
+4
int i;                    // 默认初始化:未定义
+std::string s;            // 默认初始化:调用默认构造函数,得到空字符串
+MyClass* p = new MyClass; // 默认初始化:全看构造函数
+double* pd = new double   // 默认初始化:0.0
+
+

值初始化/Value Initialization:默认初始化的特殊情况,此时内置类型会被初始化为 0。基本场景:

+
    +
  • STL 容器只指定元素数量,而不指定初值时,就会执行值初始化,如 vector<int> vec(10);:10 个 int,初始化为 0
  • +
  • 全局(包括定义在任何函数之外、命名空间之内的)变量或局部静态变量:初始化为 0;
  • +
  • new 类型,后面带括号,如:new int(), new string{};
  • +
  • 初始值列表为空 {},如 double d{};int *p{};
  • +
+

对于类类型,其实不需要区分默认初始化和值初始化,因为类类型的初始化只决定于构造函数,与对象在函数内/外、全局/局部/类成员、静态/非静态、默认初始化/值初始化无关。

+

Iterator

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Language/C++/C++/index.html b/Computer Science/Programming Language/C++/C++/index.html new file mode 100644 index 0000000..c67ea5d --- /dev/null +++ b/Computer Science/Programming Language/C++/C++/index.html @@ -0,0 +1,1396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + C++ - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

C++

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Language/C++/Object Oriented Programming/index.html b/Computer Science/Programming Language/C++/Object Oriented Programming/index.html new file mode 100644 index 0000000..acfdd2b --- /dev/null +++ b/Computer Science/Programming Language/C++/Object Oriented Programming/index.html @@ -0,0 +1,827 @@ + + + + + + + + + + + + + + + + + + + + + Object Oriented Programming - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Object Oriented Programming

+
+

约 53 个字

+
+
+

Info

+
+

本部分对应 《C++之旅》的第三章到第七章,并且包含了《C++ Primer》的某些内容。主要是以实现类似于标准库 vector 的容器类 Vector 为例。

+

Template

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Language/C++/Standard Library/index.html b/Computer Science/Programming Language/C++/Standard Library/index.html new file mode 100644 index 0000000..ca01926 --- /dev/null +++ b/Computer Science/Programming Language/C++/Standard Library/index.html @@ -0,0 +1,1769 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Standard Library - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Standard Library

+
+

约 2915 个字 15 行代码 预计阅读时间 10 分钟

+
+

General Introduction to Containers

+

容器是一些特定类型对象的集合,顺序容器提供了控制元素存储与访问顺序的能力。在这里,我们将介绍对于所有容器都适用的操作,除此之外的仅仅针对于顺序容器关联容器以及无序容器或一小部分特定容器的操作将在后续介绍。

+

容器均定义为模版类,需要提供额外信息来特定的容器类型,对于大多数容器,我们需要额外提供元素类型信息,比如 vector<int>list<Sales_data> 等。容器几乎可以保存任意类型的对象,甚至可以是另一个容器。

+

对于一个类型为 C 的容器对象 c 来说,我们有下面操作或者属性:

+
    +
  • 类型别名:
      +
    • iterator:此容器类型的迭代器类型;
    • +
    • const_iterator:可以读取元素,但是不能修改元素的迭代器类型;
    • +
    • size_type:无符号整数类型,足够存储容器中最大可能的元素数量;
    • +
    • difference_type:有符号整数类型,足够存储两个迭代器之间的距离;
    • +
    • value_type:容器中元素的类型;
    • +
    • reference:元素的左值类型,与 value_type& 的类型相同;
    • +
    • const_reference:元素的 const 左值类型,也就是 const value_type&
    • +
    +
  • +
  • 构造函数:
      +
    • C c:默认构造函数,创建一个空容器;
    • +
    • C c(c2):构造 c2 的拷贝 c
    • +
    • C c(b, e):构造 c,并且将迭代器 be 之间的元素拷贝到 c 中,但是 array 类型的容器除外;
    • +
    • C c{a, b, c, d}:列表初始化 c
    • +
    +
  • +
  • 赋值与交换:
      +
    • c = c2:将 c2 中的元素拷贝给 c
    • +
    • c = {a, b, c, d}:将 c 中的元素替换为列表中的元素,不适用于 array
    • +
    • c.swap(c2):交换 cc2 中的元素;
    • +
    • swap(c, c2):交换 cc2 中的元素。
    • +
    +
  • +
  • 大小与容量:
      +
    • c.size():返回 c 中元素的数量,不支持 forward_list
    • +
    • c.max_size():返回 c 中最多可以存储的元素数量;
    • +
    • c.empty():判断 c 是否为空,非空则返回 false
    • +
    +
  • +
  • 添加与删除(不适用于 array):
      +
    • c.insert(args):将 args 中的元素拷贝到 c 中;
    • +
    • c.erase(args):删除 args 中指定的元素;
    • +
    • c.emplace(inits):使用 initsc 中构造一个元素;
    • +
    • c.clear():删除 c 中所有元素,返回 void
    • +
    +
  • +
  • 获取迭代器:
      +
    • c.begin():返回指向 c 的首元素的迭代器;
    • +
    • c.end():返回指向 c 尾元素的下一个位置的迭代器;
    • +
    • c.cbegin():返回 const_iterator,指向 c 的首元素;
    • +
    • c.cend():返回 const_iterator,指向 c 尾元素的下一个位置;
    • +
    +
  • +
  • 反向容器特供:
      +
    • reverse_iterator:按逆序寻址元素的迭代器;
    • +
    • const_reverse_iterator:不能修改元素的逆序迭代器;
    • +
    • c.rbegin():返回指向 c 尾元素的迭代器;
    • +
    • c.rend():返回指向 c 首元素前一个元素的迭代器;
    • +
    • c.crbegin():返回 const_reverse_iterator,指向 c 尾元素;
    • +
    • c.crend():返回 const_reverse_iterator,指向 c 首元素前一个元素。
    • +
    +
  • +
+

并不是所有标准库容器都支持下标运算符,但是所有标准库容器都支持迭代器,迭代器类似于指针类型,提供对对象的间接访问。我们一般有下面操作:

+
    +
  • C::iterator iter:声明一个 C 类型容器的迭代器,比如 vector<int>::iterator iter
  • +
  • C::const_iterator iter:声明一个只能读取元素的 C 类型容器的迭代器;
  • +
  • auto iter = c.begin():返回指向容器 c 的首元素的迭代器,类型根据 c 的类型而定;
  • +
  • auto iter = c.cbegin():返回的迭代器类型为 const_iterator
  • +
  • auto iter = c.end():返回指向容器 c 的尾后元素的迭代器,类型根据 c 的类型而定;
  • +
  • auto iter = c.cend():返回的迭代器类型为 const_iterator
  • +
  • *iter:解引用迭代器,返回迭代器指向的元素的引用,但是不能对尾后迭代器解引用;
  • +
  • iter->mem:解引用迭代器,返回迭代器指向的元素的 mem 成员的引用,等价于 (*iter).mem
  • +
  • ++iter:递增迭代器,返回当前指示元素的下一个元素;
  • +
  • --iter:递减迭代器,返回当前指示元素的前一个元素;
  • +
  • iter1 == iter2iter1 != iter2:比较两个迭代器是否相等,如果两个迭代器指示的是同一个元素或者是同一个容器的尾后迭代器,则相等;
  • +
+

需要注意的是:首先,如果对于容器的操作让容器的容量发生了变化,那么指向该容器元素的迭代器就会失效;另一方面,并不是所有容器类型都支持了更多的迭代器运算,比如关系运算或者 +-

+

迭代器的接口是公共的,如果一个迭代器提供某个操作,那么所有提供相同操作的迭代器对这个操作的实现方式都是相同的。迭代器范围由一对迭代器表示,两个迭代器分别指向同一个中的元素或者尾后位置,一般分别称为 beginendfirstlast。迭代器范围包含着 [begin, end) 之内的所有元素,这种范围叫做左闭合区间。这其实就隐含着构成迭代器范围的迭代器的另一个要求:begin 必须在 end 之前,也就是可以通过反复递增 begin 来得到 end

+

每个容器类型都定义了一个默认构造函数,除了 array 之外的所有容器类型的默认构造函数都会创建一个指定类型的空容器,并且可以接受指定容器大小和元素初始值的参数。

+

容器的初始化方式很多,不接受参数就构造一个空容器,括号初始化就会创建一个拷贝,使用 = 也会初始化为一个拷贝,列表初始化需要列表内的元素类型与容器内元素类型相同,对于 array 类型而言,需要列表内元素树木小于等于 array 的大小,任何遗漏的部分都会进行值初始化。使用迭代器进行初始化的时候,给定范围 [begin, end) 之间的元素会被拷贝到新容器中,但是 array 类型的容器并不适用这一点,我们还可以让顺序容器内包含 n 个相同的元素 val,如果不提供元素的值 val 就会执行值初始化,但是只有顺序容器支持这一点。

+

赋值运算符 = 将左侧容器的全部元素替换成右边容器中元素的拷贝,对于除了 array 之外的顺序容器而言,我们还有对应的赋值函数 assign

+
    +
  • seq.assign(b, e):将迭代器范围 [b, e) 之间的元素拷贝到 seq 中,但是迭代器不能指向 seq 中的元素;
  • +
  • seq.assign(n, val):将 seq 中的元素替换为 nval
  • +
  • seq.assign(il):将 seq 中的元素替换为列表 il 中的元素。
  • +
+

赋值相关的运算会导致左侧容器内部的迭代器、引用和指针失效,但是 swap 对于除了 arraystring 之外的容器而言,就不会出现这种情况,这是因为 swap 仅仅交换了两个容器内部的数据结构,而不会改变容器内部的元素,但是在 swap 完成之后,这些元素都不属于原来的容器了。

+

assign 比简单的 = 更加灵活,并且生成的还不是拷贝了(这才是真正的赋值),它允许我们从一个不同但相容的类型赋值,比如将 char* 赋值给 string,或者将 vector<int> 赋值给 list<int>

+
1
+2
+3
+4
list<string> names;
+vector<const char*> oldstyle;
+names.assign(oldstyle.cbegin(), oldstyle.cend());   // 允许
+names = oldstyle;                                   // 不允许,因为容器类型不匹配
+
+

Sequetial Containers and Adapters

+

Introduction

+

除了 array 之外,所有的标准库内的顺序容器都提供灵活的内存管理,运行时可以动态添加或者删除元素来改变容器大小,下面是例子:

+
    +
  • c.push_back(t):在 c 的尾部添加一个值为 t 的元素,返回 void
  • +
  • c.emplace_back(args):在 c 的尾部构造一个元素,元素由参数 args 构造;
  • +
  • c.push_front(t):在 c 的首部添加一个值为 t 的元素,返回 void
  • +
  • c.emplace_front(args):在 c 的首部构造一个元素,元素由参数 args 构造;
  • +
  • c.insert(p, t):在迭代器 p 指向的元素之前插入一个值为 t 的元素,返回指向新元素的迭代器;
  • +
  • c.emplace(p, args):在迭代器 p 指向的元素之前构造一个元素,元素由参数 args 构造;
  • +
  • c.insert(p, n, t):在迭代器 p 指向的元素之前插入 n 个值为 t 的元素,返回指向第一个新元素的迭代器,如果 n 为 0 则返回 p
  • +
  • c.insert(p, b, e):在迭代器 p 指向的元素之前插入迭代器范围 [b, e) 之间的元素,返回指向第一个新元素的迭代器,如果范围为空则返回 pbe 不能指向 c 中的元素;
  • +
  • c.insert(p, il)il 是一个花括号抱着的元素值列表,将列表中的元素插入到 p 指向的元素之前,返回指向第一个新元素的迭代器,如果列表为空则返回 p
  • +
+

需要注意的是,forward_list 有自己专用版本的 insertemplace,并且也不支持 push_frontemplace_front; vectorstring 也不支持 push_frontemplace_front,因为在头部插入元素就需要移动元素,代价太高了。并且向 vector stringdeque 插入元素会使得所有指向容器的迭代器、引用和指针失效。

+

使用一个对象去初始化容器的时候,或者将一个对象插入容器之中的时候,实际上放进去的是对象值的一个拷贝,并不是对象本身,这和参数传递一样,容器内的元素和提供的对象之间没有任何关联。

+

insert 返回插入的第一个元素的迭代器这一点可以允许我们在一个容器的同一个特定位置反复插入元素。

+
1
+2
+3
+4
list<string> lst("hello");
+auto iter = lst.begin() + 2;
+while (cin >> word)
+    iter = lst.insert(iter, word);
+
+

对于顺序容器而言,emplace 系列成员函数允许我们通过参数 args 构造元素并且插入,而不是类似于 push_backinsert 那样拷贝元素。调用 emplace 成员函数的时候,接受的参数被传递给元素类型的构造函数,使用这些参数在容器管理的内存空间中直接构造函数,这就要求 emplace 接受的参数必须和元素类型的构造函数相匹配。

+

Vector

+

需要使用 #include<vector> 来使用 vector,vector 是一个可变大小的数组,支持快速随机访问,但是在尾部以外的部分插入或者删除元素的速度可能很慢。

+
    +
  1. 创建与初始化
  2. +
+
1
+2
+3
+4
+5
+6
+7
vector<ElementType> v1;                 // 空 vector,潜在元素是 ElementType 类型,执行默认初始化
+vector<ElementType> v2(v1);             // 拷贝 v1 副本
+vector<ElementType> v3 = v1;            // 拷贝 v1 副本
+vector<ElementType> v4(n, value);       // n 个元素,每个元素的值为 value
+vector<ElementType> v5(n);              // n 个元素
+vector<ElementType> v6{a, b, c, d};     // 列表初始化
+vector<ElementType> v7 = {a, b, c, d};  // 和 v6 等价
+
+
    +
  1. 访问与操作
  2. +
+

除了最初提到的通用操作,vector 还有下面的操作:

+
    +
  • vec.at(n):返回 vector 中第 n 个元素的引用,同时检查是否越界;
  • +
  • vec.front():返回 vector 的第一个元素的引用;
  • +
  • vec.back():返回 vector 的最后一个元素的引用;
  • +
  • vec.data():返回指向作为存储工作的底层数组的指针;
  • +
  • vec.push_back(ele):在 vector 尾部添加元素;
  • +
  • vec.pop_back():删除 vector 尾部元素;
  • +
  • vec.insert(pos, ele):在 pos 位置插入元素;
  • +
  • vec.erase(iter):删除迭代器 iter 指向的元素;
  • +
  • vec.erase(beg, end):删除 [beg, end) 区间的元素;
  • +
  • vec.find(first, end, v):在 [first, end) 区间内查找值为 v 的元素,返回指向该元素的迭代器,否则返回 end;
  • +
  • vec[n]:下标运算符,返回 vector 中第 n 个元素的引用;
  • +
  • ==, !=, <, <=:诸如此类按照字典序比较两个 vector,同时考虑元素数量;
  • +
+
    +
  1. 迭代器运算
  2. +
+

vector 支持了更多的迭代器运算,一方面可以使得迭代器的每次移动都夸跨过多个元素,也支持迭代器进行关系运算,这些运算都被称为迭代器运算:

+
    +
  • iter +/- n:返回迭代器 iter 向前/后移动 n 个元素的迭代器;
  • +
  • iter +/-= n:迭代器 iter 向前/后移动 n 个元素;
  • +
  • iter1 - iter2:返回两个迭代器之间的距离;
  • +
  • > >= < <=:若某个迭代器在另一个迭代器之前,则认为前者小于后者;
  • +
+

Array

+

Queue

+

需要使用 #include<queue> 来使用 queue,queue

+

Priority Queue

+

Stack

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Language/C/index.html b/Computer Science/Programming Language/C/index.html new file mode 100644 index 0000000..3058c24 --- /dev/null +++ b/Computer Science/Programming Language/C/index.html @@ -0,0 +1,3858 @@ + + + + + + + + + + + + + + + + + + + + + + + + + C - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +
+

Warning

+

未完工!等我学完CS61A后再接着写吧QAQ。

+
+

EVERYTHING begins with C

+
+

约 1171 个字 175 行代码 预计阅读时间 6 分钟

+
+

Chapter 0:Preface

+

0.1 初衷

+

这个笔记建立的初衷是帮助笔者深刻记忆C语言的语法和特性,也作为加深对C语言的理解的工具(似乎终极目的就是提升程算分数编程能力)使用。

+

C语言因为其比较贴近底层,语法精简而高效,扩展性和可移植性强而闻名,因而作为计算机专业学生的第一门语言存在。另外,笔者在学习完C后,学习Python的过程极其愉悦()

+

Chapter 1 Basis

+

常见数据类型

+

字面量即一个值:

+
    +
  • +

    整型:123表示十进制的123;0123表示八进制的123,亦即十进制的83;0x123是十六进制的123,亦即十进制的291。

    +
  • +
  • +

    字符型:

    +
  • +
  • +

    一个字符类型相当于一个字节的整型,所以字符类型可以通过整型来表示:char c = 65

    +
  • +
  • 引号里的反斜杠\有转义的效果,比如'\n'表示一个控制字符,而反斜杠只有通过\\才能表示出来。
  • +
  • 反斜杠后边可以接最多三个数字,并且此时使用八进制表示一个字节,且遇见0~7之外的数字就会阶数当前字节,比如'\101'表示A,而'08'由于8超过了八进制的范围,这就是两个字符放在了一个单引号里边,是错误的用法,如果写成字符串,"\08"就表示两个字符:一个空字符和一个8
  • +
  • \x后边接在0-9A-F内的字符,可以通过十六进制表示一个字符,不过没有长度限制,遇到范围外的字符就结束,比如\x000041也是一个字符。
  • +
+

字节分配:char1byte,short2byte,int4byte,long 4byte,long long8byte, float4byte,double8byte,pointer4/8byte。

+

运算符优先级

+
    +
  • 优先级最高的:(Left-to-Right)后缀运算符:后缀形式的递增递减、函数调用、数组下标、访问结构、复合字面量。
  • +
  • 优先级略低的:(Right-to-Left)单目运算符:前缀形式的递增递减、单目的正负、逻辑非和按位非、强制类型转换、解引用、取地址、sizeof、对齐。
  • +
  • 算数运算:(Left-to-Right)乘除取余、加减、移位——优先级递减。
  • +
  • 关系运算:(Left-to-Right)不等关系、相等关系。
  • +
  • 位运算:(Left-to-Right)按位与、异或、或。
  • +
  • 逻辑运算:(Left-to-Right)逻辑与、逻辑或。
  • +
  • 条件运算:(Right-to-Left)三目运算符?:
  • +
  • 赋值运算:(Right-to-Left)各种赋值,包括复合的赋值运算。
  • +
  • 逗号运算符:(Left-to-Right),
  • +
+

% & <<不能用在double\float上。

+

printf()的转换说明修饰符

+

const

+

Chapter 3 函数

+

3.2 内联函数

+

Chapter 4 数组和指针

+

重要:声明一个指针只会分配一个给指针变量的空间(这部分空间用来存储它指向的位置的地址值),而不会分配指向的空间。使一个指针可用可以将其它变量取地址赋值给它,这样它指向的位置就是有效的。或者通过 malloc来新分配一块堆上的内存,malloc 的返回值就是这块内存的首地址,也是你可用的。

+

:二维数组不能退化为二级指针;数组名不能被重新赋值。

+

:数组是数组,指针是指针(这里指类型)。

+

:指针相减的意义是计算两个指针相差几个“单位”的距离,而不是将其值简单的相减。比如:

+
    +
  • +

    c + int a[] = {1, 2, 3, 4, 5}; + int *p = a, *q = &a[2]; + printf("%lu", q-p); // Output: 2

    +
  • +
  • +

    c + double a[]={1, 2, 3, 4, 5}; + printf("%d", (int)&a[3] - (int)&a[0]); // Output: 24

    +
  • +
  • +
+

神坑:变长数组不能通过int a[n] = {0};的方式初始化

+

Chapter 5:字符串和字符串函数

+

5.1 字符串的定义与初始化

+

字符串其实是以空字符\0结尾的char类型数组,因此,我们可以像处理一般数组的方式处理字符串,比如:

+
1
+2
+3
char words[81] = "I am a string in an array.";//定义字符串words
+words[8] = 'p';//将字符串的第9个字符改为'p'
+const char* MSG = "This cannot be changed";//定义只读字符串MSG
+
+

如果要打印MSG[22],则输出的是空字符,空字符不是空格,不会在输出窗口占用位置,只是标志字符串数组的结束。

+

我们一般用三种方法定义字符串:字符串常量、char类型数组、指向char类型的指针。被双引号括起来的内容被视为指向该字符串存储位置的指针,这类似于将数组名作为指向该数组的指针。比如以下程序:

+
1
+2
printf("%s,%p,%c","We","are","champions");
+//Output: We,0x10000f61,c
+
+

我们对字符串用%c%p进行转换的时候,转换过去的其实是字符串第一个元素的地址和其对应的字符

+

数组形式的字符串(如char arr1[] = "III" )在计算机的内存中分配一个内含4个元素的数组,每个元素作为一个字符,且最后一个元素为空字符。先将字符串常量存储在静态存储区中,程序开始运行之后为数组分配内存,初始化数组将静态存储区的字符串拷贝到数组中,编译器将数组名arr1作为该数组首元素地址的别名,而且作为地址常量,不能被改变。

+

一般来说,指针形式的定义一般于字符串字面量一起使用,被双引号括起来的内容是字符串字面量,而且被视为字符串的地址。指针形式(如char *pt1 = "III"让编译器在静态存储区中分配4个元素的空间,开始运行程序时,编译器为指针变量(*pt1)留出一个存储位置,该变量最初指向该字符串的首字母,但是它的值可以被改变,即可以使用递增运算符。

+

由于指针形式字符串的存储形式,一般建议将指针初始化为字符串自变量时使用const 限定符。

+

编译器可以使用内存中的一个副本来表示所有完全相同的字符串字面量,所以下面程序打印出来的都是"Jey"

+
1
+2
+3
+4
char *p1 = "Hey";
+p1[0] = 'J';
+printf("Hey");
+printf("%s","Hey");
+
+

由于数组名是一个指针变量,所以不能用str1 = str2 来简单地拷贝数组,这样只会让两个指针指向相同的内存区域。

+

我们可以定义字符串数组,也就是通过数组下标来访问不多个不同的字符串,有两种方式:使用存储字符串指针的数组或者多维数组:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
const char* strarr1[3] = {
+    "Hello",
+    "Pardon",
+    "Excuse me";
+};
+char strarr2[3][10] = {
+    "Hello",
+    "Pardon",
+    "Excuse me";
+};
+
+

这两种方式最后实现的效果是几乎一样的,都代表着五个字符串,只使用一个下标时只代表一个字符串。比如strarr1[0]strarr2[0]都代表着字符串 "Hello"

+

一般来说对数组的操作都是依赖于指针进行的。

+

5.2 字符串输入和输出

+

5.2.1 分配空间

+

最简单的分配空间的方式就是在 stack 上建立数组变量,而且还只能如此建立

+
1
+2
char name[81];
+scanf("%s",name);
+
+

再就是利用C库函数malloc()分配内存,比如char *name = (char *) malloc (sizeof(char)*8)这样就可以按照数组形式的字符串来使用字符串了

+

5.2.2 危险的gets()函数

+

C11标准中,废弃了不安全的gets()函数,但是大多数编译器为了兼容性,仍然保留gets()函数。

+

gets()函数读取一整行输入,直到遇到换行符,然后丢弃换行符,存储其余字符在传递进来的字符串指针指向的地址上,并在字符的末尾添加一个空字符,使其成为字符串。比如:

+
1
+2
+3
+4
+5
int strl = 10;
+char words[strl];
+puts("Enter a string please.");
+gets(words);
+puts(words):
+
+

puts()函数经常和gets()函数一起使用,这个函数用于显示字符串,并且在字符串的末尾添加换行符。

+

使用gets()函数时,gets()函数只知道数组的开始处,而不会检查数组的长度和字符串的长度是否相融洽。如果输入的字符串过长,超出了数组的存储范围,就会造成缓冲区溢出(buffer overflow),读取的数据将一直向后存储,覆盖掉后边内存上的内容,如果这些多余的字符只是占用了未被使用的内存,就不会立刻出现问题,而如果擦写掉了程序中的其余内存,这样就会让程序异常终止,或者出现其他情况。

+

出现fragmentation fault的错误的时候,一般是程序试图访问某些未被分配的内存。

+

5.2.3 gets()的替代品

+
    +
  • fgets()fputs()函数
  • +
+

fgets()函数接受三个参数:字符串存储的位置、读入字符的最大数量和要输入的文件。

+

fgets()函数接受的第二个参数时读入数组的最大数量,如果该参数的值是n那么fgets()将读入n-1个字符,并且在最后加上一个空字符,或者读到第一个换行符号为止。

+

fgets()函数的第三个参数指明要读入的文件,如果是从键盘读入数据,那么以stdin作为参数,或者输入文件指针。

+

当输入行不溢出的时候,fgets()函数将换行符放在结尾,这与fputs()函数的特性相仿:这个函数在打印字符串的时候不会在最后加上换行符。可是如果使用puts()函数一起使用,那么可能就会发现出现了两个换行。

+

fputs()函数接受两个参数:第一个指出要写入的字符串的位置,第二个指出目标写入的位置,如果输出到屏幕上,那么输入stdout作为参数。

+

fgets()返回指向char的指针,如果一切顺利,函数返回的地址和传入的第一个参数相同,如果传到文件的结尾,将返回一个特殊的指针:空指针(null pointer),这个指针不会指向有效的数据,所以可以用来标识特殊情况。在代码钟可以用数字0来代替,但是C利用宏NULL来代替。下面是一个很有意思的例子:

+
1
+2
+3
+4
+5
+6
+7
+8
char words[10];
+while(fgets(words,10,stdin) != NULL && words[0]!='\n')
+{
+    fputs(words,stdout);
+}
+
+//Input :By the way,it returns a NULL pointer.
+//Output:By the way,it returns a NULL pointer.
+
+

这个程序的实际操作过程是:首先fgets()函数读入9个字符,在后边加入\\0之后交给fputs()函数输出,但是此时不输出换行符,接着进入下一轮迭代,fgets()函数继续读入字符、交给fputs()函数输出……

+
    +
  • +

    gets_s()函数

    +
  • +
  • +

    s_gets()函数

    +
  • +
+

我们可以利用fgets()函数自行创建一个读取整行输入,并且利用空字符取代换行符、或者读取一部分字符,丢弃溢出的字符(其余部分的字符)的函数:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
char *s_gets(char *st, int n){
+    char *ret_val;
+    int i = 0;
+    ret_val = fgets(st, n, stdin);
+    if(ret_val){
+        while(st[i] != '\n' && st[i] != '\0')
+            i++;
+        if(st[i] == '\n')
+            st[i] = '\0';
+        else
+            while(getchar()!= '\n')
+                continue;
+    }
+    return ret_val;
+}
+
+

利用字符串函数,我们可以对函数进行修改,让它更加简洁。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
char *s_gets(char *st, int n)
+{
+    char *ret_val;
+    char *find;
+
+    ret_val = fgets(st, n, stdin);
+    if(ret_val)
+    {
+        find = strchr(st, '\n');
+        if(find)
+            *find = '\0';
+        else
+            while(getchar() != '\n')
+                continue;
+    }
+    return ret_val;
+}
+
+

如果fgets()函数返回NULL,则证明读到文件结尾或者读取错误,s_gets()函数跳过了这个过程。

+

我们丢弃多余的字符的原因是:这些多余的字符都存储于缓冲区之中,如果我们下一个要读取的数据是double类型的,那么就可能造成程序崩溃(因为输入了char类型甚至char*类型的数据),丢弃剩余行的数据可以令读取语句和键盘输入同步。

+

这个函数并不完美,因为它在遇到不合适的输入的时候毫无反应,并且丢弃多余的字符的时候,不会告诉程序也不会告诉用户。但是至少会比gets()函数安全的多;-)。

+
    +
  • scanf()函数
  • +
+

scanf()函数和%s转换说明可以读取字符串,但是scanf()函数在读取到空白字符(包括空格、换行符和空字符)的时候会终止对字符串的读取。scanf()函数还有另外一种确定输入结束的方法,也就是指定字符宽度,比如%5d,那么scanf()将在读取完五个字符或者读取到第一个空白字符后停止。

+

5.2.4 字符串输出

+
    +
  1. 在输出字符串的时候,我们必须确定字符串末尾有指示终止的空字符,下面就是一个错误的例子:char words[]={'H','e','y','!'};
  2. +
+

由于这个字符数组(不是字符串!)结尾并未有空字符,所以words不是字符串,如果我们使用这样的代码:put(words)puts()函数由于未识别到空字符,就会一直向下读取、输出后续内存中的内容,这或许是 garbage value ,直到读到内存中的空字符(内存中还是有不少空字符的)。

+
    +
  1. +

    puts()函数很容易使用,只需要传入需要输出的字符串的地址就可以了,它在输出的时候会在后边加上一个换行符。但是puts()函数的返回值众说纷纭:某些编译器返回的是输出的字符的个数,某些编译器输出的是输出的最后一个字符,有的干脆就返回一个非零的整数。

    +
  2. +
  3. +

    fputs()函数需要接受两个参数,一个是字符串的地址,另一个是写入的地址:这一般是文件指针,如果需要输出到屏幕上,传入stdout则可。这个函数的特点在于不会输出换行符。

    +
  4. +
  5. +

    printf()函数需要转换说明,它的形式更复杂些,需要输入更多的代码,计算机执行的时间会更长,但是优点在于可以更容易地输出更复杂、更多的字符串。

    +
  6. +
+

5.2.5 自定义输入输出函数

+

5.3 字符串函数

+

这里讲的字符串函数是指定义在头文件string.h内的函数。

+
    +
  1. strlen()函数
  2. +
+

strlen()函数的实现其实很简单,我们写一个while循环就好了(),strlen()函数接受字符串地址,返回一个unsigned int的值来表示字符串的长度。

+

重要的是我们可以利用strlen()函数来得到字符串的一些性质参数,进而更容易实现对字符串的操作,比如我们可以利用下面自行设计的函数来实现字符串的截断:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
char *vit(char str[],unsigned int point)
+{
+     unsigned int length = strlen(str);
+     if(point > length - 1)
+     {
+         return str;
+     }
+     else
+     {
+         str[point]='\\0';
+         return str;
+     }   
+ }
+ //或者:if(strlen(str)>point)
+ //      {
+ //      str[point] = '\\0';
+ //  }
+
+
    +
  1. strcat()函数
  2. +
+

strcat()函数接受两个字符串作为参数,用于将两个字符串拼接在一起,更确切地说是将第二个字符串的拷贝附加在第一个字符串的末尾,并且将拼接后的字符串作为第一个字符串,第二个字符串不变。strcat()函数返回第一个参数。

+

strcat()函数和gets()函数一样,如果使用不当,也会导致缓冲区溢出。但是gets()函数被废弃的原因在于无法控制用户向程序里边输入什么,但是程序员是可以控制程序干什么的。因此,在经历输入的检查之后,我们认为至少程序是比较安全的,而使用strcat()函数不当导致缓冲区溢出的情况,被认为是程序员粗心导致的,而C语言相信程序员,程序员也有责任确保strcat()函数的使用安全。

+
    +
  1. strncat()函数
  2. +
+

为了避免strcat()函数的不安全的可能,我们类似fputs()函数那样,添加第二个参数,确定最大添加字符数,这就是strncat()函数的逻辑。

+

strncat()函数接受三个参数,两个字符串指针和最大添加字符量,在加到最大字符量或者遇到空字符的时候停止。

+

配合strlen()函数,strncat()函数可以很好用。

+
    +
  1. strcmp()函数和strncmp()函数
  2. +
+

首先,我们比较两个字符串的时候,比较的是字符串的内容,而不是字符串的地址,所以我们不能做判断指针是否相等的操作,而利用循环挨个判断还蛮复杂,这就是strcmp()函数诞生的逻辑。

+

strcmp()函数接受两个字符串指针参数,如果字符串内容完全相等(包括大小写),strcmp()函数就会返回0,否则返回非零值。

+

在字符串内容不一样的时候,如果第一个字符串的字符在ASCII码在第二个字符串的之前,strcmp()返回负数,反之返回正数;在某些编译器中,会作更加复杂的操作,也就是返回两字符的ASCII码的差。

+

strcmp()函数会一直比较字符是否相同,直到出现不同或者字符串结束,这样的比较方式显得就非常笨重,而strncmp()函数提供了一种更为灵活的选择:strncmp()函数接受的第三个整数参数指定了比较到第几个字符(这里从1开始计数 ;-) )比如strncmp(str1,"strings",7)就指定只查找strings这七个字符。

+
    +
  1. strcpy()函数和strncpy()函数
  2. +
+

strcpy()函数

+
    +
  1. +

    sprint()函数

    +
  2. +
  3. +

    memcpy()函数

    +
  4. +
  5. +

    Others.

    +
  6. +
+
    +
  • +

    strchr()函数

    +
  • +
  • +

    strrchr()函数

    +
  • +
  • +

    strstr()函数

    +
  • +
  • +

    atoi()函数

    +
  • +
  • +

    Character Classification

    +

    isalpha()函数

    +

    isalpha()函数属于一类的函数还有

    +

    tolower()toupper()函数

    +

    cppreference 上对这两个函数归类为 Character Manipulation 解释是:converts a character to lowercase/uppercase.

    +
  • +
+

+

Chapter 6:存储类别和内存管理

+

6.1 存储类别

+

6.1.1 总览

+

6.1.2 关键词

+
    +
  • 其实这种关键词叫做存储类别说明符。
  • +
  • static关键词让变量具有内部链接,同时具有静态存储期。
  • +
  • extern关键词让变量具有外部链接,同时具有静态存储期。
  • +
+

6.1.3 作用域

+

作用域描述程序中可以访问标识符的区域,包括:块作用域,函数作用域,函数原型作用域和文件作用域。

+
    +
  • +

    是用一对花括号括起来的代码区域,包含for循环、while循环、do while循环和if语句所控制的代码,就算这些代码没有被花括号括起来,这也算是一个块。定义在块中的变量具有块作用域(block scope),它的可见范围只是在块内,或者说从定义处到包含该定义的块的末尾。此外,函数的形式参数虽然在花括号表示的块之前,但还是具有块作用域。只有在块内的语句才能访问具有块定义域的变量。

    +
  • +
  • +

    函数作用域仅仅用于goto语句的标签,当这个标签首次出现在函数的内层时,作用域也延伸到整个函数。函数作用域有效防止了标签混乱的情况发生,当然更好的处理方式或许是干脆不用goto语句()

    +
  • +
  • +

    函数原型作用域的作用范围时从形式参数定义处到函数原型声明结束。这表明编译器更多的关心形式参数的类型而不是形参名,而只有在变长数组中,形参名才更有用。

    +
  • +
  • +

    如果在函数的外边定义了一个变量,比如以下程序:

    +
  • +
+
1
+2
+3
+4
+5
+6
#include<stdio.h>
+int glb_val =1;
+int main(void)
+{
+    printf("%d",glb_val);
+}
+
+

这里的变量glb_val就具有文件作用域,更确切地说,具有外部链接的文件作用域,我们也叫它为全局变量。

+

Tip:这里的glb_val它的作用域是从定义处到文件结束。

+

6.1.4 翻译单元

+

某些我们认为的多个文件可能在编译器里边以单个文件的形式出现,比如C预处理器就将头文件里边的内容替换#include指令。所以,编译器将源代码文件和所有的头文件都看作是一个包含着信息的单独文件,这个文件被称为是翻译单元(translation unit)。

+

如果程序由多个源代码文件组成,那么这个程序也由多个翻译单元组成,每个翻译单元对应着一个源代码文件和它的头文件。

+

目前我们的程序还不进行多文件处理。

+

6.1.5 链接

+

C 文件有着三种链接属性:外部链接、内部链接和无连接。具有块作用域、函数作用域和函数原型作用域的变量都是无连接变量。具有文件作用域的变量可以是外部链接也可以是内部链接。具有内部链接的变量只能在一个翻译单元使用,而具有外部链接的变量能在多文件程序中使用。

+

使用extern关键词,或者直接在函数外边定义的变量都是具有外部链接的变量,而使用static关键词的变量是具有内部链接的变量。

+

6.1.6 存储期

+

存储期(storage duration)描述了通过这些标识符访问的对象的生存期,某些变量存储期一过,它所占的内存就会被释放,相应的,存储的内容也会丢失。C对象有着四种存储期:静态存储期、自动存储期、线程存储期和动态分配存储期。

+
    +
  • 如果对象具有静态存储期,那么对象在程序的执行期间就会一直存在,并且只在主调函数前初始化一次,内存不会被释放。关键词externstatic表明了对象的链接属性与存储期(静态存储期)。The static/extern specifier specifies both static storage duration (unless combined with _Thread_local) and internal/external linkage.
  • +
  • 具有块作用域的变量一般具有自动存储期,当程序进入这些变量的块的时候时,为这+些变量分配内存,当退出这个块的时候,就释放刚才分配的内存。值得注意的时,变长数组的存储期是声明处到块的末尾。
  • +
  • 线程存储期用于并发程序设计
  • +
  • 动态分配存储期
  • +
+

6.1.7 自动变量

+

声明在函数头、块内的变量属于自动存储类别的变量,具有自动存储期,块作用域且无连接。我们可以在C中使用关键词auto来表明这个变量的存储类型是自动变量。

+

6.1.8 寄存器变量

+

我们使用关键词register来表示该变量的存储类型为寄存器变量。寄存器变量存储在CPU的寄存器之中,寄存器是计算机最快的可用内存,因此访问并且处理这些变量的速度会更快,但是无法获取寄存器变量的地址(因为它没有内存位置)。寄存器变量在绝大多数方面都和自动变量一样,也就是具有块作用域、无链接和自动存储期。

+

声明变量为register类型更像是一种请求而不是命令,因为编译器必须根据寄存器或者最快可用内存数量来衡量请求;并且由于寄存器的大小有限(通常是一个字,亦即4或8字节),可以声明为寄存器变量的数据类型有限,比如寄存器可能就没有足够大的空间来存储double类型的值。计算机很可能会忽略我们的请求,变量则被声明成一般的自动变量(也就是存储在内存之中),即使这样,仍然不能对该变量使用取地址运算符。

+

6.1.9 块作用域的静态变量

+

我们可以创建具有块作用域、无连接的静态变量,只需要在块中(这样就提供块作用域和无连接了)用存储类别说明符static(提供静态存储期)说明这个变量就可以了。

+

编译器在程序的生命周期内保证静态变量的存在,静态变量只会在程序中被初始化一次,不会在离开和进入作用域时被销毁或者重置。这是因为静态变量和外部变量在程序被载入内存的时候已经执行完毕,所以在逐个步骤调试的时候会发现含有 static声明的变量不太像时程序中的变量 ;-)

+

6.1.10 外部链接和内部链接的静态变量

+

外部链接的静态变量具有文件作用域、外部链接和静态存储期,该类别有时被称为外部存储类别,属于该类别的变量称为外部变量。如果未初始化外部变量,则其被默认初始化为0只能用常量表达式初始化文件作用域变量(除了变长数组以外,sizeof()表达式可以看作常量表达式)。

+

全局变量在main()函数执行之前完成初始化。

+

我们在文件之间共享全局变量的时候需要特别小心,可以使用以下两个策略:其一,遵循外部变量的常用规则,亦即在一个文件之中使用定义式声明,在另一个文件之中使用引用式说明(使用extern关键字);其二,将需要共享的全局变量放在一个头文件之中,在其他文件中包含这个头文件就可以了,然而,这种处理方式需要我们在头文件中使用static关键词,如果我们不使用static关键词或者使用extern关键词,那么我们就在每一个文件之中都包含了一个定义式声明,C标准是不允许这样子的。然而头文件实际上是给每一个文件提供了一个单独的数据副本,数据是重复的,浪费了很多的内存。

+
1
+2
+3
+4
+5
+6
int exint = 1;          //declaration 1
+extern int falseint;    //declaration 2
+int main(void){
+    /*内部不表*/
+    extern int exint;   //declaration 3
+}
+
+

考虑上面的例子:对于外部变量来说,第一次声明declaration 1被称为定义式声明(defining definition),为变量预留了存储空间;第二次声明declaration 3被称为引用式声明(referencing definition),关键词extern表明此次声明不是定义,指示编译器到别处查询定义,这表明declaration 2是不正确的,这时编译器假定falseint定义在程序别处,不会引起分配空间。因此我们不要用extern关键字创建外部定义只使用它引用外部定义

+

使用关键字static可以声明内部链接的静态变量,只需要在函数外使用static声明就可以,并且在函数内使用时使用extern进行引用式声明即可,但是extern并不改变链接属性

+

6.1.11 存储类别和函数

+

函数也有存储类别,可以是外部函数(默认)、静态函数或者内联函数。

+
    +
  • 使用extern关键词定义的函数是外部函数,是为了表明当前文件中使用的函数被定义在别处,除非使用static关键词,一般函数声明都默认为extern
  • +
  • 使用static关键词定义的函数是静态函数,静态函数只能用于其定义所在的文件。可以在其他文件中定义与之同名的函数,这样子就避免了名称冲突的问题。
  • +
  • 内联函数:inline
  • +
+

6.2 动态分配内存

+

我们在前面所探讨的存储类别都有一个共同之处,在确定好存储类别之后,就只能根据确定好的内存存储规则,自动指定存储期和作用域。但是我们也可以利用库函数灵活分配和管理内存,只不过必须好好利用指针。

+

我们下面讨论malloc()free()calloc()realloc()函数。

+

6.2.1 void* malloc(size_t size)函数

+

malloc()函数接受一个参数:所需要的内存字节数,之后它会找到合适的内存块,匿名分配sizebyte大小的内存,返回动态分配内存块的首字节地址。如果无法分配内存,malloc()函数就会返回一个空指针。最早,由于char类型只占用一个字节,所以malloc()函数返回一个char *类型的指针,后来malloc()返回void *类型的通用指针,指向什么都可以,完全不需要考虑类型匹配的问题,但是为了增加代码的可读性,应该坚持强制类型转换。

+

我们可以利用malloc()函数提供第三种声明数组的方式:将调用malloc()函数的返回值赋给指针,利用指针访问数组的元素,这样创建的其实是一个动态数组。比如:

+
1
+2
double *ptd;
+ptd = (double *) malloc(30*sizeof(double));
+
+

我们完全可以使用正常声明数组一样的方式访问这个数组ptd,比如ptd[18]

+

malloc()函数也可以声明多维数组,但是语法会复杂一些:

+
1
+2
+3
+4
+5
+6
+7
+8
int numrow = 6,numcolumn = 5;
+int **array2 = (int **)malloc(sizeof(int*)*numrow);
+for(int i = 0; i<m; i++)
+{
+    array2[i] = (int *)malloc(sizeof(int)*numcolumn);
+}
+//或者
+int (* array)[numcolumn] = (int (* array)[numcolumn])malloc(sizeof(int)*numcolumn*numrow);
+
+

先看第一种定义方式:在第二行创建了一个二级指针,也就是存储着指针的数组array2,在接下来的循环中,逐个为二维数组的每一行分配空间,同时将数组指针存储在array2[i]中。在读取元素array2[1][2]的时候,我们先读取出array2[1],发现是个指针(其实是数组),然后读取这个数组的第三个元素(编号是2),这样就读出来了元素array2[1][2]

+

再看第二种定义方式:简而言之,等号左侧定义了一个指针变量array,指向的是int[numcolumn]类型的指针,说白了array也是一个二级指针。如果还要整花活,我们发现*(*(array+1)+2)array[1][2]其实是一样的。换句话说,array指向一个内含6个整型的数组,因此array[i]表示一个由numcolumn个整数构成的元素,array[i][j]表明一个整数。

+

逻辑上看,二维数组是指针的数组(亦即二级数组);但是从物理上来看,二维数组是一块连续的内存,对于二维数组array3[4][5]:我们完全可以按照5进制来理解这块内存的排布,五进制数 ij 表示的数所对应的内存上边的内容就是array[i][j]存储的内容。

+

6.2.2 void* calloc(size_t num,size_t size)函数

+

calloc()函数分配numsize大小的连续内存空间,并且将每一个字节都初始化为0,所以calloc()调用的结果是分配了num*size个字节长度的内存空间。calloc()函数的返回值和malloc()函数的一样。

+

6.2.3 void* realloc(void* ptr,size_t new_size)函数

+

realloc()函数重新分配指针ptr指向位置内存块的大小。函数返回新分配内存块的起始位置的地址,并且原指针ptr在调用后不再可用。

+

realloc()函数被调用时,只会做下面两种行为之中的一种:

+
    +
  • 其一,将ptr指向的内存区域扩大或者缩小,并且尽可能保留剩余原有区域的内容(The contents of the area remain unchanged up to the lesser of the new and old sizes.),如果内存区域扩大,新的内存内容为未定义的(the contens of the new part of the array are undefined.)。
  • +
  • 其二,重新分配一块新的内存,将原内存区域的内容拷贝过来,并释放原内存(copying memory area with size equal the lesser of the new and the old sizes, and freeing the old block.)。
  • +
+

6.2.4 void free(void *ptr)函数

+

free()函数接受先前被malloc(),calloc(),realloc()动态分配过的内存地址,之后将这些内存释放(deallocate),如果free()接受一个空指针,那么它什么都不会做。free()函数不返回任何值。如果free()函数接受的参数不是先前被malloc(),calloc(),realloc()分配过的内存地址,它的行为并未被定义。(The behavior is undefined if the value of ptr does not equal a value returned earlier by malloc(),calloc(),realloc())我们也不能释放同一内存两次(The behavior is undefined if the memory area referred to by ptr has already been deallocated, that is, free(), free_sized(), free_aligned_sized() (since C23), or realloc() has already been called with ptr as the argument and no calls tomalloc(), calloc(), realloc() or aligned_alloc() (since C11) resulted in a pointer equal to ptr afterwards.)。

+

最重要的是:动态分配的内存必须被释放,否则会发生内存泄漏(memory leak)

+

6.3 ANSI C 类型限定符

+

值得注意的是,C99标准为限定符增加了一个新的属性:幂等性。也就是说可以在同一个声明之中使用多个相同的限定符,多余的限定符将被忽略。

+

6.3.1 const限定符

+

const关键词声明的对象将成为只读变量,其值不能通过赋值、递增或递减等方式修改,但是至少初始化变量是没问题的,这样我们就只可以使用但不能修改对象的值了。

+

如果对指针使用const限定符,如果const限定符在*的前面,也就是const int *num或者int const *num,其实限定了指针指向的值为constnum指向了一个int类型的const值。如果const限定符在*的后面,也就是int * const num,则我们创建的指针本身的值不能改变,但是它指向的值可以改变。

+

更加常见的用法是声明为函数形参的指针。比如void display(const int array[], int num),另外一个更熟悉的例子是字符串函数void strcat(char * restrict string1,const char * restrict string2)。 这使得传进去的数组的值没有被修改,这其实表明了const限定符实际提供了一种保护数据的方法。

+

我们同样可以对全局变量使用const限定符保护数据,因为extern限定符使得程序的任何一个部分都能使用并且改变这个变量,所以会平白无故产生许多危险,而const限定符让变量变成只读变量,这样就可以另程序更加安全。

+

6.3.2 volatile限定符

+

6.3.3 restrict限定符

+

Chapter 7:文件处理

+

7.1 文件和文件类型

+

7.1.1 文件

+

文件其实是硬盘上的一段已经被命名的存储区域,C将文件看成一系列连续的字节,每一段字节都可以被单独读取。

+

7.1.2 文件模式

+

C提供两种文件模式:文本模式和二进制模式。

+
    +
  • 所有文件的内容都以二进制形式存储,但是如果文件最初使用二进制编码的字符表示文本,那么这个文件就是文本文件,其中包含文本内容。如果文件中的二进制值表示机器语言代码或者数值数据或者图片以及音乐编码,那么这个文件就是二进制文件,其中包含二进制内容。
  • +
  • C提供了两种访问文件的途径:文本模式和二进制模式。在二进制模式之中,程序可以访问文件的每一个字节,而在文本模式之中,程序看见的内容和文件实际的内容不同,换行符会进行不同样式的映射转换。
  • +
+

7.2 基本的文件处理

+

7.2.1 标准文件和标准I/O

+

C程序会自动打开三个文件:标准输入、标准输出和标准错误输出。通常时候下,标准输入是普通的输入设备,一般是键盘;标准输出和标准错误输出都是系统的普通输出设备,一般是显示屏。函数getchar()、函数printf()和函数puts()都使用的是标准输出。标准错误输出提供了一个逻辑上不同的地方来显示错误输出,如果我们将输出发送给文件,那么发送到标准错误输出的内容仍然会被发送到屏幕上。

+

7.2.2 基本文件处理

+
    +
  • [[noreturn]] void exit(int exit_code)函数
  • +
+

exit()函数关闭所有打开的文件并且结束程序,正如函数声明处所说

+
    +
  • File *fopen(const char *restrict filename, const char *restrict mode)函数
  • +
+

fopen()函数打开一个文件,其文件名由传入函数的第一个参数标识,返回文件指针。其需要的第二个参数是一个字符串,指定了待打开文件的模式。

+

我们常见的打开文件模式有下面这些:

+
    +
  • "r" 以只读模式打开文件;
  • +
  • "w" 以写模式打开文件,并且将现有文件的长度截为 0,如果文件不存在,则创建一个新文件;
  • +
  • "a" 以写模式打开文件,在现有文件结尾添加内容,若文件不存在,则创建一个新文件;
  • +
  • "r+" 以更新模式打开文件,亦即可以读写文件。
  • +
+

如果打开文件失败,且不创建新文件,返回一个空指针

+

值得注意的是,文件指针并不指向任何实际文件,只是指向一个包含文件信息的数据对象(换句话说是一个结构)其中包含了操作文件所用函数所需要的缓冲区信息。

+
    +
  • int fclose(FILE *stream)函数
  • +
+

fclose()函数关闭由stream给出的文件流,无论关闭是否成功,stream均与这个文件无关。The behavior is undefined if the value of the pointer stream is used after fclose returns.

+

如果关闭成功,fclose()函数返回0,反之返回EOF

+
    +
  • int fprintf(FILE *restrict stream, const char *restrict format, ...)函数
  • +
+

fprintf()函数和printf()函数基本相同,只不过输出流从默认的stdout变成了需要自行给出的stream,亦即函数接受的第一个参数表示需要输出的位置。

+
    +
  • int fscanf(FILE *restrict stream,const char *restrict format, ...)函数
  • +
+

这个函数和scanf()函数大差不差,只不过接受的第一个参数需要是待读取文件的文件指针。

+
    +
  • char *strerror(int errnum)函数
  • +
+

返回一个指针,指向错误代码errnum代表的文字描述。errnum一般需要从变量errno中取得。

+
    +
  • long ftell(FILE *stream)函数
  • +
+

ftell()函数返回一个long类型的值,为stream的位置标识符的当前值,亦即。如果出现错误,ftell()函数将会返回-1,全局变量errno被设置为一个正值,我们可以使用errno变量来查看错误代码。比如:

+
1
+2
+3
+4
+5
+6
if(fseek(fp, 0L, SEEK_END) == -1)
+{
+    fprintf(stderr,"ERROR:%s\n",strerror(errno));
+    fclose(fp);
+    return 1;
+}
+
+
    +
  • int fseek(FILE *stream, long offset, int origin)函数
  • +
+

fseek()函数将文件看做是数组,将位置标识符stream移动到目标位置。函数的第三个参数是模式,这个参数确定起始点。stdio.h 头文件内有三个表示模式的文件常量:SEEK_SET 表示文件开始处;SEEK_CUR 表示当前位置;SEEK_END 表示文件末尾。第二个参数是相对于origin的偏移量,以字节为单位,可以为正值(前移)、负值(后移)或者0(保持不动)。

+

如果一切正常,fseek()返回0,若出现错误(比如试图移动的距离超出文件范围了),返回值为-1

+

ftell()函数在文本模式和在二进制模式的工作方式不同,ANSI C规定,ftell()函数的返回值可以当做fseek()函数的第二个参数。对于MS-DOS,ftell()返回的值将\r\n当做一个字节计数。

+
    +
  • +

    函数

    +
  • +
  • +

    函数

    +
  • +
  • +

    函数

    +
  • +
  • +

    size_t fread(void *restrict buffer, size_t size, size_t count, FILE * resrict stream)函数

    +
  • +
+

fread()函数接受的参数和fwrite()相同。在fread()函数之中,buffer是待读取文件数据在内存之中的地址,stream指定要读取的文件,该函数可以用于读取文件之中的数据,size代表着待读取数据每个元素的大小,count代表待读取项的项数。函数返回成功读取项的项数,一般是count,如果出现错误或者读到EOF,返回的值就会比count小。

+

值得一提的是:The file position indicator for the stream is advanced by the number of characters read.

+
    +
  • size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream)函数
  • +
+

fwrite()函数将缓冲数组buffer里面的count个元素写入到流stream之中。函数将需要写入的数据重新编译为unsigned char类型的数组,通过重复调用fptc()函数将其写入stream之中。和fread()函数相同,The file position indicator for the stream is advanced by the number of characters read. + 在实际使用fread()函数和fwrite()函数读写文件之中的数据时,文件位置指示符不断前进,这使得我们不会重复读取数据,亦即可以实现这样的操作,一个循环就能实现文件从头读到尾的操作:

+
1
+2
+3
+4
+5
 while(fread(&buffer, sizeof(int16_t), 1, input))
+{
+    buffer *= factor;
+    fwrite(&buffer, sizeof(int16_t), 1, output);
+}
+
+

7.3 流简介

+

在C中,我们处理的是流是一系列连续的字节,不同属性和不同种类的输入由属性更加统一的流来表示。流告诉我们,我们可以利用和处理文件相同的方式来处理键盘输入。打开文件的过程就是把流与文件相关联,读写都通过流来完成。

+

在标准头文件stdio.h之中,定义了三个文本流stdin stdout stderr

+

Chapter 8:结构和其他数据形式

+

8.1 结构

+

8.1.1 结构的定义与基本属性

+

结构的声明描述了一个结构的组织布局:

+
1
+2
+3
+4
struct book{
+    int index;
+    int val;
+};
+
+

结构体struct book描述了由两个整数类型组成的一个结构体,后续程序中可以利用模板struct book来声明具有相同数据组织结构的结构变量。

+

一般使用的结构初始化方式有三种,除了对于每一个结构成员进行值初始化之外,可以直接进行列表初始化和利用初始化器初始化:

+
1
+2
struct book bk1 = {231, 1219};
+struct book bk2 = {.val = 2023, .index = 1, 23};
+
+

指向结构的指针具有指针的优点。指向结构的指针比结构本身更加容易操控、在函数中执行更有效率,并且有可能数据表示数据的结构中包含指向其他结构的指针。结构和数组不同,结构名代表的是这个数据集合,而不是结构变量的地址。

+

结构允许嵌套,也允许使用匿名结构,还允许定义结构数组,但是结构中的的匿名结构就很恶心。

+

在两个结构类型相同的情况下,我们允许将一个结构赋值给另外一个结构,这是将每个成员的值都赋给另外一个结构的相应成员。

+

结构不仅可以作为参数传递,也可以作为返回值返回。与传递结构参数相比,传递结构指针执行起来很快,并且在不同版本的C上都可以执行;缺点是不能保护数据(const限定符就可以解决了)。将结构作为参数传递的优点是,函数处理的是原始数据的副本,可以保护数据,但是需要拷贝副本,浪费了时间和内存。

+

8.1.2 结构中的字符数组和字符指针

+

我们可以在结构之中使用以下两种方式存储字符串:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
#define LEN 20
+struct names{
+    char first[LEN];
+    char last[LEN];
+}
+
+struct names1{
+    char *first1;
+    char *last1;
+}
+
+

如果仅仅是声明数组并且随即初始化,那么两种声明方式是没有区别的。但是如果使用类似于scanf("%s",&names1.first1);的方式,第二种声明方式就会出现危险。因为程序并未给first1分配存储空间,它对应的是存储在静态存储区的字符串字面量,换言之,结构体names1里存储的只是两个字符串的指针,如果仍要实行该操作,因为scanf()函数将字符串放在names1.first1对应的地址上,但是由于这是没有经过初始化的变量,地址可以是任何值,因此程序会将字符串放在任何地方。简而言之,结构变量中的指针应该只是用来程序中管理那些已经分配或者分配在别的地方的字符串。

+

如果使用malloc()函数来分配内存并且用指针来存储地址,这样处理字符串就会比较合理,当然需要记得使用free()释放相关内存。

+

8.1.3 复合字面量和结构

+

复合字面量可以用于数组或者结构,如果活只需要一个临时结构值,符合字面量很好用,比如我们可以使用复合字面量创建一个结构赋给另外一个结构或者作为函数的参数。语法是将类型名放在圆括号之中,后面紧跟花括号括起来的初始化列表。比如(某些代码进行了适当的精简):

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
struct book{
+    char title[10];
+    char auther[10];
+    double value;
+}
+struct book POMA = (struct book){
+    "thistitle",
+    "thisman",
+    11.11
+};
+int cal(struct book tmp);
+cal((struct book){"thattitle","thatman",22.2});
+
+

8.1.4 伸缩型数组成员

+

利用伸缩型数组成员这一特性声明的结构,起最后一个数组成员具有一些特性:其一,该数组不会立刻存在;其二,使用这个伸缩型数组成员可以编写合适的代码,就好像这个数组确实存在并且具有所需数目的元素一样。但是对这个数组有这以下要求:首先,这个数组成员必须是结构的最后一个成员;其次,结构中至少拥有一个成员;最后,伸缩数组的声明类似于普通数组,只不过其中括号是空的。另外,声明一个具有伸缩型数组成员的结构时,我们不能使用这个数组干任何事,必须先给它分配内存空间后才能以指针形式使用它。比如:

+
1
+2
+3
+4
+5
+6
+7
+8
struct flex{
+    size_t count;
+    double average;
+    double array[];
+}
+struct flex *ptr;
+ptr = malloc(sizeof(struct flex) + n*sizeof(double));
+ptr->count = n;
+
+

使用伸缩型数组成员的结构具有一下要求:第一,我们不能用结构进行赋值或者拷贝,比如*ptr1 = *ptr2,不然这样只能拷贝非伸缩型数组成员外的所有成员,如果非要拷贝,应该使用mencpy()函数;第二,不要按值方式将这种结构传递给函数,应该传递指针;第三,不应该将使用伸缩型数组成员的结构作为数组成员或者另外一个结构的成员。

+

8.2 联合

+

联合(union)是一种数据类型,可以在同一个内存空间之中存储不同的数据类型(但是不是同时)。其典型用法是,设计一种表以存储既无规律,实现也不知道顺序的混合类型。使用联合类型的数组,每个联合都大小相等,每个联合可以存储各种数据类型。

+
1
+2
+3
+4
+5
union hold{
+    int digit;
+    double bigfl;
+    char letter;
+};
+
+

以上声明的联合可以存储一个int类型、一个double类型或者一个char类型的值。联合只能存储一个值,其占用的内存空间是占用内存最大类型所占用的内存。使用联合的方法如下:

+
1
+2
+3
union hold fix;
+fix.digit = 1;          //把1存储在fix,占用两个字节
+fix.bigfl = 1.1;        //把先前存储的内容抹去,把1.1存储在fix,占用八个字节
+
+

8.3 枚举

+

可以使用枚举类型(enumerated type)声明符号名称表示整型常量。使用关键字enum可以声明枚举类型并且指定其可以具有的值(事实上,enum常量就是int类型,所有可以使用int类型的地方都可以使用枚举类型)。enum类型的用法如下:

+
1
+2
+3
enum spectrum {red, orange, yellow, green = 100, blue, violet};
+enum spectrum color = red;
+printf("%d, %d, %d, %d", red, orange, blue, violet);    //输出为0, 1, 101, 102
+
+

在使用完枚举声明后,red等就成了具有名称的常量。第二个语句声明了枚举变量color,并且拿red的值初始化color。这种不连续的枚举直接按照整数进行处理,无法按照想象中直接遍历枚举内的元素。

+

8.4 typedef

+

利用typedef可以为某一类型自定义名称。我们之前已经利用define进行了自定义名称,但是define只是单纯的文本替换,并且相比于typedef要更为死板很多。比如:

+
1
+2
+3
+4
#define STRING char*
+typedef char* String;
+STRING str1, str2;              //其实是char *str1, str2;只创建了一个字符串和一个字符
+String strr1, strr2;            //其实是char *strr1, *strr2;创建了两个字符串
+
+

这就明白为什么define只不过是单纯的文本替换了。同时,利用typedef为结构变量命名的时候,可以省略掉这个结构的标签,比如:

+
1
+2
+3
typedef struct{
+    int data; int index;
+}pair;
+
+

其实这是为一个匿名结构命名。typedef更好的一点是可以为更加复杂的类型命名:比如typedef char (* FRPTC()) [5];FRPTC声明为一个函数类型,这个函数返回一个指针,指针指向内含五个char元素的数组。

+

8.5 函数和指针

+

Chapter 9:位操作

+

9.1 进制、位和字节

+

9.1.1 计数

+

计算机基于二进制,通过关闭和打开状态的组合来表示信息。C语言利用字节表示存储系统字符集所需的大小,通常一字节(byte)包含八(bit),计算机界用八位组(octet)特指八位字节。可以从左到右给这八位编码为7 ~0,编号为7的位被称为高阶位,编号为0的被称为低阶位。

+

如何利用二进制表示有符号整数取决于硬件,最通用的做法是利用补码。二进制补码利用一字节的第一位(高阶位)表示数值的正负,如果高阶位是0,则此时表示非负数,其值与正常情况相同;如果高阶位为1,则此时表示负数,但是这时负值的量是九位组合100000000(256的位组合)减去这个负数的位组合。比如某负数为10011010,其表示-12211111111则表示-1。这样,我们就可以用一字节来表示从-128~127的所有数字。

+

浮点数分两部分存储:二进制小数和二进制指数。计算机中存储浮点数的时候,要留出若干位存储二进制小数,剩下的位存储指数。二进制小数用有限多个\(1/2\)的幂的和近似表示数字(事实上,二进制小数只能精确表示有限多个\(1/2\)的幂的和)。一般而言,数字的实际值是由二进制小数乘以\(2\)的指定次幂组成。

+

9.1.2 其他进制数

+

计算机界常用八进制十六进制计数系统,这些计数系统比十进制更加接近计算机的二进制系统。

+
    +
  • 八进制(octal)基于八的幂,每个八进制位对应三个二进制位。我们在数字前加上一个0来特别表示一个数是八进制。
  • +
  • 十六进制(hexadecimal)基于十六的幂,每个十六进制位对应四个二进制位。我们在数字前加上0x来特别表示一个数是十六进制。十六进制是表示字节的非常好的方式。
  • +
+

9.2 按位运算符

+

9.2.1 按位逻辑运算符

+
    +
  • +

    按位取反(反码):~

    +
  • +
  • +

    按位与:&

    +
  • +
  • +

    按位或:|

    +
  • +
  • +

    按位异或:^

    +
  • +
+

9.2.2 移位运算符

+
    +
  • 左移:<<
  • +
  • 右移:>>
  • +
+

9.2.3 应用

+
    +
  • 掩码
  • +
  • 打开位
  • +
  • 关闭位
  • +
  • 切换位
  • +
  • 检查位的值
  • +
  • 快速乘除运算
  • +
+

9.3 位字段

+

9.4 对齐特性

+

没看懂,先不写。

+

Chapter 10 C预处理器和C库

+

Chapter 11

+

C常用库

+

assert

+

stdio

+

int sprintf(char *buffer, const char *format,...)函数

+

向字符串buffer里写入,相当于多了一个转换格式/读写的工具函数。

+

int fprintf(FILE *stream, const char *format,...)函数

+

sscanf()函数

+

fscanf()函数

+

向输出流stream中写入。

+

stdlib

+

x.2.x 随机数

+
    +
  • void srand(unsigned int seed)
  • +
+

srand()函数为伪随机数生成器rand()播种,正常的用法是:srand((unsigned int) time(NULL))

+

这段代码利用当前时间为伪随机数生成器rand(0)提供种子,这样子就可以得到了近似于真随机的随机数。

+
    +
  • int rand(void)
  • +
+

伪随机数生成器rand()生成一个介于0RAND_MAX的随机数。如果没有srand()的播种,rand()函数就会默认生成种子为1的随机数。每次调用rand()函数,我们得到的都是上次生成的随机数的下一个数

+

值得注意的是,在调用函数rand()之前的时候,伪随机数生成器只应该被播种一次。

+
+

Generally speaking, the pseudo-random number generator should only be seeded once, before any calls to rand(), and the start of the program. It should not be repeatedly seeded, or reseeded every time you wish to generate a new batch of pseudo-random numbers.

+
+

更重要的是,当rand()接受相同的种子的时候,他会生成相同的随机数数列。

+

time

+

x.3.1 变量类型

+
    +
  • time_t 这是一个适合储存日历时间的长整型(long int)变量,表示着从POSIX time (1970年1月1日00:00)开始的总秒数。
  • +
+

x.3.2 函数

+
    +
  • time_t time(time_t *seconds)
  • +
+

time()函数将当前日历时间作为一个time_t类型的变量返回,并且将这个变量存储在输入的指针seconds中(前提是这个指针不为空指针)。

+

由于time_t类型其实是一个long int转换成int(或者unsigned int)的时候还是需要强制转换说明的2

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Language/Haskell/Haskell/index.html b/Computer Science/Programming Language/Haskell/Haskell/index.html new file mode 100644 index 0000000..0d56254 --- /dev/null +++ b/Computer Science/Programming Language/Haskell/Haskell/index.html @@ -0,0 +1,1354 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Haskell - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Haskell

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Language/Java/index.html b/Computer Science/Programming Language/Java/index.html new file mode 100644 index 0000000..1445943 --- /dev/null +++ b/Computer Science/Programming Language/Java/index.html @@ -0,0 +1,2121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Java - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Java

+
+

约 6007 个字 57 行代码 预计阅读时间 21 分钟

+
+
+

Abstract

+

这是我学习Java语言的笔记,动机很简单,我想听的CS61BAlgorithms课程都是基于Java的,所以我需要学习Java。

+

参考书籍:

+
    +
  • 《Java核心技术》 卷I
  • +
  • 《On Java》 基础卷
  • +
  • 《Algorithms》
  • +
+
+
+

Java is a high-level, class-based, object-oriented programming language.

+
+

Basic

+

1.1 在写代码之前

+

Java的类库源文件在JDK中以压缩文件lib/src.zip的形式发布,其包括了所有公共类库的源代码,解压缩这个文件就可以得到源代码。

+

使用命令行工具,我们可以编译和运行Java程序。编译Java程序使用javac命令,javac程序是一个Java编译器,将我们的代码编译成字节码文件,也就是类文件(扩展名为.class);再使用java命令启动Java虚拟机,执行编译器编译到类文件的字节码。

+

编译器需要文件名,需要提供扩展名.java,而虚拟机需要类名,不需要提供扩展名。

+

1.2 基本程序结构

+

调用方法的通用语法是object.method(parameters),其中object是一个对象,method是对象的一个方法,parameters是方法的参数。

+

对于这段最简单的代码:

+
1
+2
+3
+4
+5
public class FirstSample{
+    public static void main(String[] args){
+        System.out.println("We will not use 'Hello, World!'");
+    }
+}
+
+

关键词public被称为访问修饰符/Access modifier,决定了控制程序其他部分对这部分代码的访问级别。class表示Java程序中的全部内容都包含在类中,类是Java应用的构建模块。一个源文件只能有一个公共类但是可以有任意数量的非公共类,源文件的文件名必须和公共类的类名相同,并且用.java作为扩展名。

+

在执行已经编译的程序的时候,虚拟机总是从指定类的main方法的代码开始执行,所以类的源代码中必须包含一个main方法,且main方法必须声明为public,当然直接声明全套public static也是极好的。方法其实就是函数的另外一种说法,我们也可以自行定义方法并且添加到类中。

+

1.3 对象与类

+

Java是一种纯粹的面对对象的语言,面对对象的程序是由对象组成的,每个对象包括对用户公开的特定功能与隐藏的实现。在面对对象程序设计中,数据是第一位的,之后我们才考虑操作数据的大小。

+

1.3.1 类

+

类/Class指定了如何构造对象,通过一个类构造/Construct对象的过程称为创建这个类的一个实例/Instance封装/Encapsulation是面对对象程序设计的一个重要概念,是指将数据与行为组合在一个包中,并对对象的使用者隐藏了具体的实现细节。对象中的数据称为实例字段/Instance field,操作数据的过程称为方法/Method,作为一个类的实例,一个对象有一组特定的实例字段值,这些值的集合就是这个对象的当前状态/State。只要在对象上调用一个方法,它的状态就有可能发生改变。

+

封装的关键在于,不能让其他类的方法直接访问这个类的实例字段。我们还可以通过扩展其他的类来构建新类,这个新类具有被扩展的类的所有属性与方法,这种通过扩展一个类来得到另外一个类的过程叫做继承/Inheritance

+

使用面对对象编程之前,必须清楚对象的三个主要特性:

+
    +
  • 对象的行为/Behavior:可以对对象施加哪些操作,或者应用哪些方法?
  • +
  • 对象的状态/State:调用那些方法的时候,对象将会如何响应?
  • +
  • 对象的标识/Identity:如何区分可能具有相同行为和状态的不同对象?
  • +
+

对象的标识是两两不同的,每个对象都有一个唯一的标识。

+

类之间的最常见的关系有:依赖/uses-a聚合/has-a继承/is-a

+

依赖/Dependence是最一般且最明显的关系,比如Order类使用了Account类,因为Order类需要访问Account类来获取信息。应该尽可能减少相互依赖的类,或者说减少类之间的耦合/Coupling。因为耦合度越低,越不容易在修改一个类的时候影响其他类。

+

聚合/Aggregation表明了一个类包含另外一个类的对象。

+

继承/Inheritance表示了一个更特殊的类与一个更一般的类之间的关系,在特殊化的类里边定义了更多的特殊方法与额外功能。

+

1.3.2 预定义类

+

在Java中,没有类就不能做任何事情,但是并不是所有类都表现出面对对象的典型特征,比如Math类,它只包括了一些方法,甚至没有实例字段。下面我们将以Date类与LocalDate类为例说明类的使用。

+

在Java中,我们需要使用构造器/构造函数/Constructor来构造新的实例,构造器是一种特殊的方法,用来构造并且初始化对象,并且构造器总是与类同名。我们看几个例子:

+
    +
  • new Date();:使用new操作符,我们就可以构造一个Date对象,并且将这个对象初始化为当前的日期与时间。
  • +
  • String s = new Date().toString();我们可以对这个对象应用一个方法,将这个日期转换成一个字符串。
  • +
  • System.out.println(new Date());我们也可以将这个对象传递给一个方法。
  • +
  • Date rightNow = new Date();我们定义了一个对象那个变量rightNow,其可以引用Date类型的变量,并且将新构造的对象存储在对象变量rightNow中。
  • +
+

对于对象变量而言,他们并不包含一个对象,只是引用一个对象,我们可以显式地将对象变量初始化为null,这就表明这个变量目前没有引用任何对象,对一个赋值为null的变量,我们不允许应用任何方法。

+

尽管我们使用了引用这个词,但是Java中的对象变量更像是C++中的对象指针,并且Java的语法甚至和C++的是一样的。所有的Java对象都存储在堆之中,当一个对象包含另外一个对象变量的时候,其实只是包含了另外一个堆对象的指针。

+

上面提到的Date类的实例有一个状态,就是一个特定的时间点,时间是距离另外一个固定的时间点的毫秒数,这个时间点就是所谓的纪元/Epoch,在Java中,纪元是UTC时间1970年1月1日00:00:00。

+
    +
  • LocalDate.now();
  • +
  • LocalDate newYearsEve = LocalDate.of(1999, 12, 31);
  • +
  • int year = newYearsEve.getYear();/int month = newYearsEve.getMonthValue();/int day = newYearsEve.getDayOfMonth();
  • +
  • LocalDate aThousandDaysLater = newYearsEve.plusDays(1000);访问器方法/Accessor method,与更改器方法/Mutator method
  • +
+

1.3.3 自定义类

+

我们不仅仅需要学会使用常用的类与配套的方法,还需要学会编写类。我们经常写的一种类叫做主力类/Workhorse class,这种类没有 main 方法,但是有自己的实例字段和实力方法,是构建一个完整程序的众多部分之一。

+

最简单的类形式为:

+
1
+2
+3
+4
+5
type class ClassName{
+    field;          // 实例字段
+    constructor;    // 构造器
+    method;         // 方法
+}
+
+

实例字段可以是基本类型,也可以是对象。我们一般需要将实例字段声明为 private,这确保只有这个类的方法可以访问这种字段,这就是封装的一部分。而方法可以声明为 private 或者 publicpublic 方法可以被任何类的任何方法调用。private 方法只可以被本类的其他方法调用。

+

我们先看一个自定义类的例子:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
public class Employee{
+    private String name;
+    private double salary;
+    private LocalDate hireDay;
+
+    public Employee(String n, double s, int year, int month, int day){
+        name = n;
+        salary = s;
+        hireDay = LocalDate.of(year, month, day);
+    } // constructor
+
+    public String getName(){
+        return name;
+    } // more methods
+}
+
+

构造器开始看,构造器与类同名。构造Employee类的对象时,构造器会运行,将实例字段初始化为所希望的初始状态。构造器没有返回值,可以有参数,也可以没有参数。

+

在声明对象变量的时候,我们可以用var关键字声明,Java会根据变量的初始值推导出其类型。比如,对上面的类,我们只需要声明var harry = new Employee("Harry Hacker", 50000, 1989, 10, 1);就可以了。

+

在使用构造器初始化一个对象的时候,有可能将某个实例字段初始化为null,但又有可能对这个字段应用某个方法,一个“宽容”的解决方法就是将null参数转换成一个适当的非null值,Objects类给予了一种便利方法:Objects.requireNonNullElse(T, defalt obj),如果输入的对象Tnull,那么就将返回默认值default obj。同样地,其实还提供了一种“严格”的方法Objects.requireNonNull(T, string message),如果输入的对象Tnull,那么就将抛出一个NullPointerException异常并且显示出问题的描述。

+

方法会操作对象并且访问其实例字段,方法一般会有两个参数,第一个参数是隐式参数/Implicit parameter,出现在方法名之前;第二个参数是显式参数/Explicit parameter,出现在方法名之后的括号里面。在方法中,我们可以使用this关键字来引用隐式参数。

+

封装是极其有必要的,我们来看一些比较特殊的方法,这些方法只访问并且返回实例字段的值,因此被称为字段访问器/Field accessor。相比于将实例字段声明为public,编写单独的访问器会更加安全:外界的代码不能修改这些实例字段,并且如果这些实例字段出了问题,我们直接调试字段访问器就可以了,如果是public的话,我们就需要在所有的代码中寻找问题。

+

有时,想要获取或者改变一个实例字段的值,我们需要提供下面三项内容:

+
    +
  • 一个私有的实例字段;
  • +
  • 一个公共的字段访问器方法;
  • +
  • 一个公共的字段更改器方法。
  • +
+

这样的处理非常好,首先可以改变内部实现而不改变该类方法之外的任何其他代码;其次,更改器方法可以完成错误检查,这就非常好了!

+

另外,不要编写返回可变对象引用的访问器方法,这样我们好好的封装就毁了!如果硬要返回一个可变对象的引用的话,首先应该对它进行克隆/Clone,克隆是指存放在另外一个新位置上的对象副本,使用类重的clone方法可以完成这个操作。

+

访问权限是一件非常重要的事情。方法可以访问所属类的对象的任何数据,当然包括私有数据,但是不能访问其他对象的私有数据

+

尽管大部分方法都是公共的,但是某些情况下,私有方法可能会更加有用,比如我们希望将一个计算方法分解成若干个独立的辅助方法,但是这些方法不应该作为公共接口,这是因为其与当前实现关系非常紧密,或者需要一个特殊的协议或者调用次序,这些方法就应该实现为私有方法。实现私有方法很简单,只需要将关键字public改为private就好了。

+

如果一个方法是私有的,并且类的作者确信这个方法不会在别处使用,这个方法就可以被简单地剔除,但是如果方法是公共的,就不能简单地删除一个方法了,因为还有可能会有其余的代码依赖于这个方法。

+

我们可以将一些变量、类与方法设置为final。当我们定义一个类时使用了final修饰,这个类就不能被继承,这个类的成员变量可以根据需要设为final,但是类中的所有成员方法都会被设为final。如果定义了一个方法为final,这个方法就被“锁定”了,无法被子类的 方法重写,对方法定义为final一般常见于认为这个方法已经足够完整,不需要改变了。修饰变量是final用的最多的地方,final变量必须显式指定初始值,并且一旦被赋值,就不能给被重新赋值;如果final的是一个基本变量,这个变量就不能改动了,如果是一个引用变量,那么对其初始化之后就不能再指向其他变量

+

比如private final StringBuilder evaluations = new StringBuilder();,这里的evaluations就不能指向别的对象了,但是这个对象可以修改,比如evaluations.append(LocalDate.now() + ":Yes!")final修饰符对于类型为基本类型或者不可变类的字段尤其有用,并且final修饰符一般与static修饰符一起使用。

+

1.3.4 static 静态

+

我们发现,先前的很多方法都标记了 static 修饰符,下面会讨论这个修饰符的含义。

+
    +
  • 静态字段:如果将一个字段定义为 static,那么这个字段并不会出现在每个类的对象之中。静态字段只有一个副本,可以认为这个字段属于整个类,这个类的所有实例将共享这个字段。
  • +
  • 静态常量相对很常用,就比如 Math 类的 PI 字段,这个字段是一个不会改变的常量,事实上被定义为 public static final double PI = 3.14159265358979323846;System.out 也是一个经常使用的 final 的静态常量。
  • +
  • 静态方法是不操作对象的方法:这个方法没有隐式参数,因此不能访问实例字段,也不能使用 this 关键字,但是可以访问静态字段。一般使用类名来调用静态方法,比如 Math.pow(2, 3),但是甚至可以使用对象调用静态方法,虽然静态方法的调用的结果和这个对象毫无关系。 + 当方法不需要访问对象状态的时候,可以使用静态方法,这种情况下所有的参数都由现实参数提供;只要访问静态字段的时候,当然应该使用静态方法。
  • +
  • 工厂方法:工厂方法是静态方法最为常见的用途。工厂方法是一个返回类的对象的静态方法,这样我们就可以使用这个方法来构造对象,而不使用构造器。比如 LocalDate.now() 就是一个工厂方法。
  • +
  • main 方法:main 方法是一个特殊的静态方法,是程序的入口,虚拟机调用这个方法来执行程序。事实上启动程序的时候还没有对象,就只好让入口方法是静态的了。
  • +
+

1.3.5 参数与调用

+

程序设计语言中,将参数传递给方法一般有两种方法,按值调用/Call by Value按引用调用/Call by Reference。在 Java 中,所有的参数总是按值调用的,也就是说,方法得到的是所有参数值的一个拷贝。下面看三段代码:

+
+
+
+

1
+2
+3
+4
+5
public static void tripleValue(double x){
+    x = 3 * x;
+}
+double percent = 10;
+tripleValue(percent);
+
+如果我们企图使用这段代码令 percent 的值变为 30,那么我们就错了,percent 的值仍然是 10。这是因为传递的是 percent 的值,x 被初始化为 percent 的值的一个副本,然后 x 被修改,这个方法结束之后,参数 x 被丢弃,但是 percent 没有被修改。这个例子表明一个方法是无法修改基本数据类型的参数的

+
+
+

尽管基本数据类型的参数无法被修改,但是毕竟方法参数有两种,另一种是对象引用。对象参数还是可以修改的,尤其是作为隐式参数的对象的字段。 +

 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
class Employee{
+    private int salary;
+    public Employee(int sal){
+        salary = sal;
+    }
+    public void RaiseSalary(int times){
+        salary *= times;
+    }
+    public static void s_RaiseSalary(Employee x, int times){
+        x.salary *= times;
+    }
+}
+Employee sam = new Employee(100);
+sam.RaiseSalary(3);
+s_RaiseSalary(sam, 3);
+

+
+
+
+

1.3.6 对象构造

+

1.4 数据类型

+

数据类型就是一组数据与对其能进行的操作的集合。

+

Java是典型的C类语言,声明变量的方法与C极为相似,但是在Java中,变量名的标识符的组成得到了扩充:字母、数字、货币符号与“标点链接符”组成变量名,首字母不能为数字。特别地,字母、数字与货币符号的范围更大,字母可以是一种语言表示中的任何Unicode字符,数字可以是09表示一位数字的任何Unicode字符。

+

1.4.1 基本类型

+

Java最基本的类型有下面几种,六种数字类型,一种字符类型,一种布尔型:

+
    +
  • +

    整型

    +
  • +
  • +

    双精度实数类型,与其对应的算数运算符(double)。

    +

    我们使用double类型来表示双精度实数,使用64位,值域非常之大。

    +
  • +
  • +

    字符型charchar使用UTF-16方案进行编码,以前原本用于表示单个字符,但是现在情况变化了,有的Unicode字符需要两个char值。char类型的字面量要用单引号括起来,也可以表示为十六进制的值,比如\u0041就是A

    +

    在Unicode编码之前,已经有许多编码标准了,我们最熟悉的就是美国的ASCII编码。标准不统一会出现下面两个问题:对一个特定的代码值,在不同的机制中对应不同的字母;大字符集的语言的编码长度会有不同,有的是单字节编码,有的就使用双字节或者多字节编码。

    +

    Java的字符型使用的16位编码在当时设计时的确是很好的改进,但是现在的Unicode字符已经超过65536个,这就尴尬住了。所以一个实用的建议就是不要在程序之中使用char类型,除非要处理UTF-16代码单元,否则就使用String类型。

    +

    还是简单介绍一下Unicode编码吧:码点/Code point是指与一个编码表中某个字符对应的代码值,Unicode中的码点使用十六进制书写,并且在前面加上一个U+U+0041就是A的码点。Unicode中的码点可以分为17个代码平面/Code plane。第一个代码平面被称为基本多语言平面/Basic multilingual plane,其包含了从U+0000U+FFFF的“经典”Unicode编码,其余的16个代码平面从U+10000U+10FFFF,包含了各种辅助字符/Supplementary character,这些平面包含了一些不常用的字符,比如一些古代文字、表意文字等等。

    +

    UTF-16使用不同长度的代码表示所有Unicode码点,在基本多语言平面之中,每个字符使用16位表示,被称为代码单元/Code unit,辅助字符使用一对连续的代码单元表示,这种编码对使用基本多语言平面中未采用的2048个值范围(称为替代区域,U+D800U+DBFF用于第一个代码单元,U+DC00U+DFFF用于第二个代码单元)。而Java中的char类型描述就采用了UTF-16编码的一个代码单元。

    +
  • +
+

1.4.2 运算符

+

1.5 控制语句

+

1.6 字符串

+

概念上讲,Java 字符串就是字符序列,Java 没有内置的字符串类型,但是标准库中提供了预定义类 String,每个被双引号括起来的都是一个 String 类的实例,下面聊的主要是 String 类的使用。

+

首先,字符串可以为空,比如 String emp = "";,空串是一个长度为 0 的字符串,可以使用 "" 表示,null 是一个特殊的值,表示没有任何对象和这个对象关联。不能对 null 调用任何方法,否则会抛出 NullPointerException 异常。

+

如果要检查某个字符串既不是空串也不是 null,一般会这样做 if (str != null && str.length() != 0)

+

1.6.1 子串与拼接

+

子串更像切片,我们可以使用 substring 方法来获取一个字符串的子串,substring 方法有两个参数,第一个参数是子串的起始位置,第二个参数是子串的结束位置,但是不包括结束位置的字符,我们也可以认为第二个参数指的是尾后字符,这种尾后元素的使用其实蛮常见的,在 C++ 的学习中就可以看见这一点。比如 String greeting = "Hello"; String s = greeting.substring(0, 3);,这样 s 就是 Hel

+

拼接很简单,使用 + 号就可以了,比如 String expletive = "Expletive"; String PG13 = "deleted"; String message = expletive + PG13;,这样 message 就是 Expletivedeleted。任何非字符串的值和字符串进行拼接的时候,Java 会将非字符串的值转换为字符串,甚至任何一个 Java 对象都可以转换成字符串

+

值得一提的是,String 的运算符 ++= 是 Java 里边仅有的重载的运算符,Java 不允许程序员重载别的运算符。

+

1.6.2 字符串的不可变性

+

如果我们查看 JDK 文档,就会发现 String 类其实是不可变的/Immutable,每个看似会修改 String 值的方法,实际上都创建并且返回了一个全新的 String 对象,这个对象包括了修改后的字符串内容,但是原始的 String 对象保持不变。这样设计的原因之一是:参数一般是用来提供信息的,而不是用来修改的,这对代码的可读性和可理解性有很大的帮助。同时,编译器甚至可以让字符串共享。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
public class Immutable{
+    public static String upcase(String s){
+        return s.toUpperCase();
+    }
+    public static void main(String[] args){
+        String greeting = "Hello";
+        System.out.println(greeting);       // Hello
+        String GREETING = upcase(greeting);
+        System.out.println(greeting);       // Hello
+        System.out.println(GREETING);       // HELLO
+    }
+}
+
+

1.6.3 比较字符串

+

使用 equal 方法检测两个字符串是否相等,对于表达式 s.equals(t),如果相等就返回 true,否则返回 false,这个方法是区分大小写的,如果不区分大小写,可以使用 equalsIgnoreCase 方法。

+

由于每个被双引号括起来的字符串都是一个 String 类的实例,所以我们可当然可以对其使用 equals 方法,"HeLLo".equals("HeLLo") 就是 true

+

int compareTo(String other)int compareToIgnoreCase(String other) 方法用于比较两个字符串,如果调用字符串 this 在字典中排在参数字符串 other 之前,就返回一个负数,如果调用字符串在字典中排在参数字符串之后,就返回一个正数,如果两个字符串相等,就返回 0

+

matches

+

1.6.4 码点和代码单元

+

1.6.5 String API

+
    +
  • int length():返回字符串的长度。
  • +
  • boolean isEmpty()boolean isBlank():判断字符串是否为空或者由空白符组成。
  • +
  • boolean startsWith(String prefix)boolean endsWith(String suffix):判断字符串是否以指定的前缀或者后缀开始或者结束。
  • +
+

1.7 输入输出

+

1.7.3 格式化输出

+

1.7.2 格式化输入

+

从人类可读的文件或者标准输入中读取输入非常重要,但是比较痛苦,一般的解决方法是读入一行文本,然后进行分词解析,再使用 Integer 类和 Double 类中的方法解析数据。但是 Java 提供的 Scanner 类就大大减轻了这个负担。

+

传统一点的做法是:

+

但是使用 Scanner 类就简单多了,Scanner 类定义在 java.util 包之中,首先还是需要构造一个与输入流相关联的 Scanner 对象,Scanner in = new Scanner(System.in);,然后就可以使用 nextIntnextDoublenext 等方法来读取输入了。

+
    +
  • Scanner(InputStream in) 用给定的额输入流构造一个 Scanner 对象。
  • +
  • String nextLine() 读取下一行输入。
  • +
  • int nextInt()int nextDouble() 读取下一个整数或浮点数,String next() 读取下一个单词,这些都是以空白符作为分隔符的。
  • +
  • boolean hasNext() 用于检查是否还有其他单词。
  • +
  • boolean hasNextInt()boolean hasNextDouble() 用于检查下一个字符序列是否表示整数或浮点数。
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Language/Python/Library/index.html b/Computer Science/Programming Language/Python/Library/index.html new file mode 100644 index 0000000..147ef0f --- /dev/null +++ b/Computer Science/Programming Language/Python/Library/index.html @@ -0,0 +1,799 @@ + + + + + + + + + + + + + + + + + + + + + Library - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Library

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Language/Python/Python/index.html b/Computer Science/Programming Language/Python/Python/index.html new file mode 100644 index 0000000..e7d86f5 --- /dev/null +++ b/Computer Science/Programming Language/Python/Python/index.html @@ -0,0 +1,2462 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Python Saves The World - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Python Saves The World

+
+

约 3112 个字 66 行代码 预计阅读时间 11 分钟

+
+

Basic Note

+

变量的命名

+

变量名只能包含字母、数字和下划线 “_”,变量名的第一个字符只能是字母或者下划线,变量名对大小写敏感,且不能将关键字 (亦即保留字) 作为变量名。

+

数据类型

+

Python中的变量不需要声明数据类型,每个变量在使用之前必须赋值,变量在赋值之后才会被创建。我们在创建变量的时候不需要考虑变量的类型——这和C不同——变量就是变量,没有类型,而我们所说的“类型”只是变量所指的内存中对象的类型,因为不同的对象 (比如字符串和整数) 需要以不同的方式存储。并且我们可以为多个变量同时赋值,也可以为多个对象指定多个变量。比如下面的例子:

+
1
+2
+3
+4
+5
+6
counter = 100          # 整型变量
+miles   = 1000.0       # 浮点型变量
+name    = "runoob"     # 字符串
+
+a = b = c = 1          # 为多个变量同时赋值
+a, b, c = 1, 2, "Hi"   # 为多个对象指定多个变量
+
+

Python内置的type()函数可以用来查询变量所指的对象类型,并且可以使用isinstance()来判断:

+
1
+2
+3
+4
+5
a, b, c, d =20, 5.5, True, 4+3j
+print(type(a), type(b), type(c), type(d))
+>>> <class 'int'> <class 'float'> <class 'bool'> <class 'complex'>
+print(isinstance(a, int))
+>>> True
+
+

type()isinstance()的区别在于:

+
    +
  • type()不会认为子类是一种父类类型;
  • +
  • isinstance()会认为子类是一种父类类型。
  • +
+

字符串 (string)

+

对字符串的操作

+

字符串就是一系列字符,由引号 (可以是单引号或者双引号) 确定,其列表有两种索引方式:从左到右默认从0开始;或者从右向左从-1开始。对于字符串的某些处理和C类似,比如我们可以实现以下操作:

+
1
+2
+3
+4
+5
+6
str = "Hello"
+print(str[0])               #Output:H
+print(str[2:4])             #Output:ll
+print(str * 2)              #Output:HelloHello
+print(str + " " + "world")  #Output:Hello world
+print(str[0:4:2])           #Output:Hl
+
+

我们可以发现,字符串的某些处理其实就是对列表的处理。但是值得注意的是,Python没有单独的字符类型,一个字符就是长度为1的字符串,并且Python的字符串不能被改变。

+

在Python中,我们可以使用方法进行对数据的操作,某些方法会改变数据内容 (比如reverse()),某些则不会 (比如下面这些)。对于字符串,利用lower()upper()title()strip()lstrip()rstrip(),我们可以去除字符串两侧的空格,并且调整字符的大小写。比如:

+
1
+2
+3
+4
+5
name = "hEllo "
+print(name.title())         #Output:Hello 
+print(name.upper())         #Output:HELLO 
+print(name.lower(),end="")  #Output:hello  (后边没有换行)
+print(name.rstrip(),end="@")#Output:hEllo@ 
+
+

在Python中,空白泛指所有非打印字符,比如空格、列表和换行符。print()在打印结束之后会自动换行,但是如果在print()函数之后参加end=""参数,我们就可以实现不换行效果,事实上Python里end参数的默认值为"\n",表明在打印的字符串的末尾自动添加换行符,来设定特定符号,比如上面代码的最后一行将字符串的末尾自动添加了一个@

+

对字符串的比较

+

数字 (Number)

+

类型

+

Python支持intfloatboolcomplex四种类型。整数类型只有一种int,表示为长整型。

+

运算

+

求模运算符%、四则运算符+ - * /与取余运算符%均和C语言中的相同,只是默认情况下的除法/的结果是一个浮点数,而使用运算符//就可以得到一个整数。此外,运算符**表示乘方。

+

类型转换

+

以下函数均将接受的参数进行转化并返回。

+

str()函数

+

int()函数将字符串表示的整形数值转化成整型数字。

+

float()函数将字符串表示的浮点数转化成浮点数。

+

列表 (List)

+

列表由一系列按照特定顺序排列的元素组成,我们用方括号 [] 表示列表,并且用逗号分隔其中的元素。列表中的元素可以不相同,甚至可以包含列表 (也就是嵌套)。列表的索引和字符串的索引相同,从0开始;或者从尾部开始,最后一个元素的索引为-1,往前一位为-2,以此类推。

+

需要注意的是,sorted()函数和sort()方法 (和排序相关的) 均不能用在字符串和数字混合的列表 (元组和字典) 排序之中。

+

元组 (Tuple)

+

使用圆括号 () 表示元组,当元组只有一个元素的时候,只能写成 (a, ) 的形式,这是因为 (a) 其实表示的是一个值。

+

集合

+

使用花括号 {} 括起来表示集合,内部元素使用逗号来分割。

+

字典 (Dictionary)

+

也是使用花括号 {} 括起来表示,但是字典内部存储的是键值对 {key: value, ...}

+
1
+2
+3
+4
+5
+6
+7
dictionary1 = dict()
+dictionary1['first'] = "1st"    #添加键-值对
+dictionary1['first'] = "111"    #修改值
+print(dictionary['first'])      #访问值
+del dictionary1['first']        #删除值的同时删除键-值对
+dictionary1.clear()             #清空词典
+del dictionary1                 #删除词典
+
+

可以发现添加键-值对的语法和修改值的相同。

+

如果要遍历字典内的键-值对,我们需要先声明两个变量,使用items()方法,它返回一个键-值对列表,在遍历每一个键值对的过程之中,会将键和值依次存储到两个变量之中。同理keys()方法和values()方法分别返回一个存储着键和值的列表,值得注意的是这些列表的元素顺序和其原本的存储顺序不相同,因为Python只关心键与值的对应关系,而不关心存储顺序。

+
1
+2
+3
+4
+5
+6
+7
dic1 ={'name': "Hello", 'year': 18, 'position': 'hang'}
+for key,val in dic1.items():
+    print(key,val)
+for key in dic1.keys:
+    print(key.title())
+for val in dic1.values()
+    print(val.upper())
+
+

语句(statement)

+

布尔运算符(boolean operators)

+

Python支持三个布尔运算符:andornot,它们的内容和C中的&&||!相同,优先级也相同:not有最高的优先级 ,and其次,or的优先级最低。同时,布尔运算符还支持短路运算(short circiuting),即如果andor的第一个操作数(也就是operand)一定可以决定表达式的真值,就不会检查后面的表达式,所以True or 1 / 0False and 1 / 0甚至都没问题。

+

需要注意的是,andor都不将返回值限定为True或者False,相反,它们返回最后一个求值的参数(the last evaluated argument),比如字符串s需要在它为空的时候被替换成一个默认值,就可以使用s = s or "Default"来处理。但是not总需要创建一个新的值,所以不管接收到的参数是不是一个布尔值,都返回布尔值。

+

Python将0None''(空字符串)和[](空列表)都规定为False,其余值规定为True。这表明了布尔值的范围其实比纯粹的TrueFalse更加丰富。

+

复合语句(compound statement)

+

语句值由解释器运行的,执行一项操作的语句(A statement is executed by the interpreter to perform an action)。

+

复合语句由一个或者多个子句(clause)组成,每个子句由一个句头(header)和一个句体(suite)组成,组成复合语句的子句头都处于相同的缩进层级。 每个子句头以一个作为唯一标识的关键字开始并以一个冒号结束。 子句体是由一个子句控制的一组语句。 子句体可以是在子句头的冒号之后与其同处一行的一条或者由分号分隔的多条简单语句,或者也可以是在其之后缩进的一行或多行语句。 只有后一种形式的子句体才能包含嵌套的复合语句。简而言之,复合语句大概长这样:

+
1
+2
+3
+4
+5
+6
+7
<header>:           
+    <statements>        # 两个句头之间夹着的是Suite
+    ...                 # 以上是一个Clause
+<separating header>:
+    <statements>
+    ...
+...
+
+
    +
  • 第一个句头决定了这个复合语句的类型。
  • +
  • 字句的句头控制句体的执行(The header of a clause controls the suite that follows)。
  • +
  • def语句、if语句和while语句都是标准的复合语句。
  • +
  • 执行子句体指的就是按照句体内的表达式顺序执行表达式。
  • +
+

if语句

+

for循环

+

while循环

+

循环的控制

+

利用continuebreak来跳过此次循环或者跳出循环,逻辑和C一样。

+

while循环还可以这样用:根据对列表判断是否非空来控制循环。

+
1
+2
+3
+4
unconfirmed_users = ["1","2","3"]
+while unconfirmed_users
+    print(unconfirmed_users.pop())
+print(unconfirmed_users)
+
+

这个循环只会在列表unconfirmed_users非空的时候运行,当它变空的时候,就不会继续运行了。

+

assert语句

+

assert语句的基本语法如下:assert_stmt ::= "assert" <expression> ["," <expression>]。当assert后面的<expression>的布尔值是False时,程序会中断运行,并且抛出AssertionError: <expression>,这里的<expression>对应的是方括号里的<expression>。一个例子如下:

+
1
+2
+3
+4
>>> assert 2 > 3, 'Math is broken'
+# Traceback (most recent call last):
+#    File "<stdin>", line 1, in <module>
+# AssertionError: Math is broken
+
+

return语句

+

A return statement completes the evaluation of call

+

函数

+

函数就是一个带名字的代码块,用于完成具体的工作。关键字def表示开始定义一个函数,向Python指出函数名,并且提供形参。函数定义下所有缩进行构成函数体,被三个引号引起来的部分是称作文档字符串的注释,描述函数是做什么的,Python用其生成有关程序中函数的文档。

+

在定义中括号里出现的变量是形式参数 (Formal Parameter),是函数完成工作需要的信息,在调用函数时传入的是实际参数 (Actual Argument),是调用函数的时候传递给函数的信息,值存储在相应的形式参数之中。

+
1
+2
+3
+4
+5
+6
def calc(number,times=2):               # Function signature
+    """完成乘方的操作,默认为平方"""
+    ret = 1                             # Function body
+    for cnt in range(0,times):
+        ret *= number
+    return ret
+
+

我们认为赋值操作是一种简单的抽象(abstraction)方式,它将变量的名字与其值联系到了一起;而函数定义是一种更强大的抽象方式,它允许将名字与表达式联系到了一起。函数由函数签名与函数体组成。

+
    +
  • +

    函数签名(function signature)<name>(<formal parameters>)表明了函数的名字与接受的形式参数的数量;

    +
  • +
  • +

    函数体(function body)<expression>决定了使用函数时的计算过程。

    +
  • +
+

def语句的执行过程如下:

+
    +
  • Create a function with signature <name>(<formal parameters>);
  • +
  • Set the body of that function to be everything indented after the first line;
  • +
  • Bind <name> to that function in current frame.
  • +
+

Procedure for calling/applying user-defined functions(version 1):

+
    +
  • Add a local frame, forming a new environment;
  • +
  • Bind the function's formal parameters to is arguments in that frame;
  • +
  • Execute the body of the function in that new environment.
  • +
+

函数的定义域(domain):

+

函数的值域(range):

+

函数可以分为纯函数(pure function)和非纯函数(non-pure function)两类,纯函数指的是没有副作用(side-effect)的函数,反之,非纯函数有副作用,print()函数就是典型的非纯函数,它将内容显示在终端上。如果一个函数体内没有return语句,函数会自动返回Noneprint()就是这样返回的。A side effect isn't a value:it is anything that happens as a consequence of calling a function.

+

有意思的是,在终端中,print()会显示没有引号的文本,但是return会保留引号。下面是一个例子:

+
1
+2
+3
+4
+5
+6
+7
def what_prints():
+    print('Hello World!')
+    return 'Exiting this function.'
+
+>>> what_prints()
+Hello World!
+'Exiting this function.'
+
+

None

+

None在Python里面表示一种特殊的值:Nothing

+

None其实有着其相应的数据类型:NoneType,所以在进行None + 4的操作的时候,就会出现类型错误:TypeError: unsupported operand type(s) for +: 'NoneType' and 'int',这表明None和一般的数据类型不能相加。

+

用户输入

+

input()函数接受一个参数,即需要向用户显示的提示 (prompt) ,暂停程序运行并将提示输出到屏幕上,等待读取用户输入,在按下回车键之后继续运行,并且将用户的输入作为input()函数的返回值。

+

转义字符

+

Lambda Expressions

+
lambda_expr ::= "lambda" [parameter_list] ":" return_expression
+
+

Lambda expressions (sometimes called lambda forms) are expressions that evaluate to fuctions by specifying two things: the parameters and a return expression. Lambda expressions are used to create anonymous functions. The expression lambda parameters : expression yields a function object, and this unnamed object behaves as a functions object defined with:

+
1
+2
def <lambda>(parameters):
+    return expression
+
+

While both lambda expressions and def statements create function objects, there are some notable differences. lambda expressions work like other expressions; much like a mathematical expression just evaluates to a number and does not alter the current environment, a lambda expression evaluates to a function without changing the current environment: It does not create or modify any variables.

+

Recursive Functions

+

Definition: A function is called recursive if the body of that function calls itself, either directly or indirectly.

+

Implication: Executing the body of a recursive function may require applying that function again.

+

The anatomy of a recursive function:

+
    +
  • the def statement header is similiar to other functions.
  • +
  • Conditional statements check for base cases.
  • +
  • Base cases are evaluated without recursive calls.
  • +
  • Recursive cases are evaluated with recursive calls.
  • +
+

Object-Oriented Programming

+

Standard Library

+

operator模块

+

opertaor模块包含了一套和Python内置的运算符对应的高效率函数,包含的种类有:对象的比较运算、逻辑运算、数学运算和序列运算。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
---------
operator.add()add(1,2)3
operator.mul()mul(2,3)6
+

CS61A

+

Lab 0

+

Docstring:

+

Lecture 2: Functions

+

An expression describes a computation and evaluates to a value.

+

Evaluation procedure for call expressions:

+
    +
  • Evaluate the operator and then the operand subexpressions (from left to right).
  • +
  • Apply the function that is the value of the operator subexpression to the arguments that are the values of the operand subexpression.
  • +
+

All expressions can use function call notation. (demo)

+

Call expression:

+

Environment diagrams visualize the interpreter's progress.

+

a function's signature has all the information needed to create a local frame.

+

Pure functions: only return values.

+

Non-pure functions: have side effects.

+

print() is a non-pure function because it displays its output depending on the argument passed in , and returning None.

+

Debug

+

Using print() statements

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Language/Rust/Basic Syntax/index.html b/Computer Science/Programming Language/Rust/Basic Syntax/index.html new file mode 100644 index 0000000..f60c6ab --- /dev/null +++ b/Computer Science/Programming Language/Rust/Basic Syntax/index.html @@ -0,0 +1,2253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Basic Syntax - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Basic Syntax

+
+

约 3220 个字 56 行代码 预计阅读时间 11 分钟

+
+

1 变量

+

1.1 命名惯例

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
条目惯例
模块 Modulessnake_case
类型 TypesUpperCamelCase
特征 TraitsUpperCamelCase
枚举 EnumerationsUpperCamelCase
结构体 StructsUpperCamelCase
函数 Functionssnake_case
方法 Methodssnake_case
通用构造器 General constructorsnew or with_more_details
转换构造器 Conversion constructorsfrom_some_other_type
宏 Macrossnake_case!
局部变量 Local variablessnake_case
静态类型 StaticsSCREAMING_SNAKE_CASE
常量 ConstantsSCREAMING_SNAKE_CASE
类型参数 Type parametersUpperCamelCase,通常使用一个大写字母: T
生命周期 Lifetimes通常使用小写字母: 'a'de'src
+

1.2 变量绑定

+

使用 let 关键字绑定一个变量,变量绑定默认是不可变的,如果需要可变绑定,使用 let mut 关键字如果后边不会改变的变量被声明为 mutable 的话,编译器会给出警告,如果在存在没有使用的变量的话也会给出警告,在变量名字之前加上单下划线就会忽略未使用的变量。

+

1.3 变量解构

+

使用 let 关键字还可以进行复杂变量的解构,这也就是从一个相对复杂的变量之中,匹配出这个变量的一部分内容。

+

1.4 所有权

+

1.4.1 基本规则

+
    +
  • Rust 每一个值都被一个变量所拥有,这个变量被称为这个值的所有者;
  • +
  • 一个值同时只能被一个变量所拥有;
  • +
  • 当所有者离开作用域范围的时候,值就会被丢弃。
  • +
+

作用域和别的编程语言没有区别,可以参考块作用域。

+

1.4.2 所有权转移

+

对于以拷贝值的方式完成的赋值,没有所有权的转移。

+
1
+2
let x = 5;
+let y = x;
+
+

这段代码当然是通过拷贝值完成赋值的,因为整数是 Rust 基本数据类型,是固定大小的简单值,因此这两个值都是通过自动拷贝的方式来赋值的,都被存在栈中,完全无需在堆上分配内存。当然没有所有权的转移。

+
1
+2
let s1 = String::from("hello");
+let s2 = s1;
+
+

String 类型和上面的整数类型很不一样,是由存储在栈中的堆指针、字符串长度和字符串容量共同组成的,总之指向了一个在堆上的空间。let s2 = s1; 这行代码会让 s1 被赋给 s2,而一个值同时只能被一个变量所拥有,所以 Rust 认为 s1 不再有效,在赋值完成之后就马上失效了。

+

这就是所有权转移,对应的操作是移动而不是拷贝,我们将对这个字符串的所有权从 s1 转移到了 s2s1 不指向任何数据,只有 s2 才有效。

+

如果不发生所有权转移,那么在两个变量同时同时离开作用域的时候,就会尝试释放相同的内存,这就会出现了二次释放的错误,会导致内存污染。而发生所有权转移后,如果还尝试使用旧的所有者 s1,Rust 就会禁止你使用无效的引用。

+

如果我们确实需要深度复制 String 堆上的数据,就要使用克隆/深拷贝let s2 = s1.clone(); 会在堆上分配一块新的内存,将 s1 的数据拷贝到新的内存中,这样就不会发生所有权转移了。

+

与深拷贝相对的是浅拷贝,正常的拷贝其实就是浅拷贝,浅拷贝发生在栈中,效率很高。

+

Rust 有一个叫做 Copy 的特征,可以用在类似整型这样在栈中存储的类型。如果一个类型拥有 Copy 特征,一个旧的变量在被赋值给其他变量后仍然可用,也就是赋值的过程即是拷贝的过程。

+

那么什么类型是可 Copy 的呢?可以查看给定类型的文档来确认,这里可以给出一个通用的规则: 任何基本类型的组合可以 Copy ,不需要分配内存或某种形式资源的类型是可以 Copy。如下是一些 Copy 的类型:

+
    +
  • 所有基本类型;
  • +
  • 元组,当且仅当其包含的类型也都是 Copy 的时候。比如,(i32, i32)Copy 的,但 (i32, String) 就不是
  • +
  • 不可变引用 &T但是注意:可变引用 &mut T 是不可以 Copy的
  • +
+

1.4.3 函数传值和返回

+

函数在传值的时候也会发生移动或者复制,相应的发生所有权的转移:

+
1
+2
+3
+4
+5
+6
+7
+8
+9
fn main(){
+    let s = String::from("hello");
+    takes_ownership(s);
+    // println!("{}", s); // error: value borrowed here after move
+}
+
+fn takes_ownership(some_string: String) {
+    println!("{}", some_string);
+}
+
+

如果在 takes_ownership 函数后边尝试再使用 s ,就会出现所有权报错,因为 s 对于 String 的所有权在函数传值的时候已经移动给了 some_string,随后 take_owmership 结束的时候,some_string 的值内存被 drop 了,加上原本的 s 的所有权已经移动,所以 s 就无效了。如果函数调用完了还想使用 s,一种方法是传递 s.clone(),另一种方法是返回值:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
fn main(){
+    let mut s = String::from("hello");
+    s = takes_ownership(s);
+    println!("{}", s);  // no error
+}
+
+fn takes_ownership(some_string: String) -> String {
+    println!("{}", some_string);
+    some_string
+}
+
+

这里利用了函数返回的时候也会发生所有权的转移,所以 some_string 的所有权在函数返回的时候又转移给了 ss 又可以使用了。但这里要求 s 是可变的,即便传来传去都是一个 String 类型,但是变量还是发生了变化。

+

1.5 引用和借用

+

Rust 也支持类似于使用指针和引用的方式简化传值的流程,利用借用/Borrowing这个概念完成上述目的。借用是指获取变量的引用。

+

常规引用是一个指针类型,指向了对象存储的内存地址。使用 & 进行引用,使用 * 进行解引用。

+
1
+2
+3
let x: i32 = 5;
+let y: &i32 = &x;
+assert_eq!(*y, x);
+
+

使用借用可以进行函数调用,并且维持所有权:

+
1
+2
+3
+4
+5
+6
+7
+8
+9
fn main() {
+    let s = String::from("hello");
+    let len = calculate_length(&s);     
+    println!("The length of '{}' is {}.", s, len);
+}
+
+fn calculate_length(string: &String) -> usize {
+    string.len()
+}
+
+

我们首先创建了 s 的引用并且将其传入,这样,我们通过操纵引用来操纵 s,在函数调用结束的时候,string 离开作用域,但是它并不拥有任何值,所以不会发生什么。

+

上面创建的都是不可变引用,一直处于只读状态,也就是说,不能在 calculate_length 函数中修改 string 的值,比如 string.push_str("...");,如果需要修改,可以使用 &mut 创建可变引用:

+
1
+2
let mut x: i32 = 1;
+let y: &mut i32 = &mut x;
+
+
1
+2
+3
+4
+5
+6
+7
+8
+9
fn main() {
+    let mut s = String::from("hello");
+    change(&mut s);
+    println!("{}", s);
+}
+
+fn change(string: &mur String) {
+    string.push_str(" world!");
+}
+
+

这里创建的就是可变引用了,可以通过引用来更改变量的值。但是对于可变引用, Rust 存在着一些限制:

+
    +
  • 在同一个作用域之中,一个数据只能存在一个可变引用;
  • +
  • 可变引用和不可变引用不能同时存在;
  • +
+

这样做的目的是避免产生数据竞争,以及防止不可变引用的值被可变引用所改变。数据竞争可由以下行为造成:

+
    +
  • 两个或更多的指针同时访问同一数据;
  • +
  • 至少有一个指针被用来写入数据;
  • +
  • 没有同步数据访问的机制。
  • +
+

另外,引用的作用域 s 从创建开始,一直持续到它最后一次使用的地方,这个跟变量的作用域有所不同,变量的作用域从创建持续到某一个花括号 }

+

以及如果存在引用,且后面用到了这个引用,则被引用的即使是 mut 的,也不能被修改,例如:

+

我们也应该注意悬垂引用/Dangling Reference,悬垂引用也叫做悬垂指针,意思为指针指向某个值后,这个值被释放掉了,而指针仍然存在,其指向的内存可能不存在任何值或已被其它变量重新使用。Rust 编译器会在编译时检测到悬垂引用并且报错。下面是一个悬垂引用的例子:

+
1
+2
+3
+4
fn dangle() -> &String {
+    let s = String::from("hello");
+    &s  // this function's return type contains a borrowed value
+}       // but there is no value for it to be borrowed from.
+
+

1.6 遮蔽

+

2 类型和值

+

Rust 的类型可以分为两类:基本类型和符合类型。基本类型意味着其是一个最小化原子类型,无法解构为其他类型,有以下几种:

+
    +
  • 数值类型:有符号整数 i8, i16, i32, i64, i128, isize, 无符号整数 u8, u16, u32, u64, u128, usize, 浮点数 f32, f64
  • +
  • 布尔类型:bool, 字面量为 truefalse
  • +
  • 字符类型:char,用单引号括起来的 Unicode 字符;
  • +
  • 单元类型:(),只有一个值 ()main 函数的返回值就是 (),这玩意其实就是一个零长度的元组。
  • +
+

复合类型是由其他类型组合而成的,最典型的就是结构体 struct,有以下几种:

+
    +
  • 字符串
  • +
  • 元组
  • +
  • 结构体
  • +
  • 枚举
  • +
  • 数组
  • +
+

2.1 数值类型

+

序列是生成连续的数值的

+

要显式处理溢出,可以使用标注怒对原始数字类型提供的这些方法:

+
    +
  • wrapping_*:在所有模式下都按照补码循环溢出规则处理;
  • +
  • overflowing_*:返回该值和一个指示是否发生溢出的布尔值;
  • +
  • saturating_*:限定计算后的结果不超过目标类型的最大值或最小值;
  • +
  • checked_*:如果溢出则返回 None
  • +
+

2.2 布尔类型

+

2.3 单元类型

+

2.4 字符类型

+

2.5 字符串

+

字符串大抵分为两种,被硬编码到程序代码之中的不可变的字面量 str,和用堆动态分配内存的可变的 String 类型。在语言级别来说,其实只有一种字符串类型 str,并且一般是以引用形式 &str 出现的,存储的时候是一个指针和字符串长度。String 类型是标准库提供的一个字符串类型,它是一个可变的、可增长的、具有所有权的 UTF-8 编码的字符串类型。

+

2.5.1 String 和切片

+

使用 String::from 方法将一个字符串字面量转换为 String 类型,这里的 :: 是一种调用操作符,这里表示调用 String 模块中的 from 方法,由于 String 类型的变量 s 存储在堆上,因此它是动态的,如果 s 是 mut 的,可以通过 s.push_str("...") 来追加字面量:

+
1
+2
+3
let mut s = String::from("Hello");
+s.push_str(" world!");
+println!("{}", s);
+
+

基于上面的代码,下面介绍切片:切片就是对 String 类型之中某一部分的引用,类型就是 &str,通过 [begin..off_the_end] 指定引用范围,这个范围是左闭右开的(参考 C++ 的尾后迭代器),这和别的编程语言一样。我们可以认为这个语法其实就是数值类型一节中范围的语法,所以 [begin..=end] 就生成了一个闭区间的范围。

+

2.6 元组

+

2.7 结构体

+

2.8 枚举

+

2.9 数组

+

3 语句、函数和控制流

+

3.1 语句与表达式

+

简单说来:

+
    +
  • 带分号的就是一个语句,不带分号的就是一个表达式;
  • +
  • 能返回一个值的就是一个表达式,表达式会在求值后返回该值,语句会执行一些操作但是不返回值,let 就是一个经典的语句,只负责绑定变量和值,但是不返回值;
  • +
  • 表达式可以是语句的一部分,let a = 1; 就是一个语句,1 其实就是一个表达式;
  • +
  • 函数调用是表达式,因为返回了一个值,就算不返回值,就会隐式的返回一个 ()
  • +
  • 用花括号括起来的能返回值的代码块是一个表达式,代码块的类型和值就是最后一个表达式的类型和值,如果最后一个表达式是一个分号结尾的语句,那么代码块的类型就是 ()
  • +
+

3.2 函数

+
1
+2
+3
fn add(x: i32, y: i32) -> i32 {
+    x + y
+}
+
+

上面是典型的函数定义,下面是几个需要注意的点:

+
    +
  • 使用关键词 fn 定义一个函数;
  • +
  • 必须显示指定参数类型,除了返回单元类型 (),因为这种情况下编译器会自动推断返回类型,都要显式指定返回类型;
  • +
  • 中途返回使用 return 关键字,带不带分号都可以;
  • +
  • 以语句为最后一行代码的函数,返回值是 ()
  • +
  • 永远不返回的函数类型为 !,一般用于一定会抛出 panic 的函数,或者无限循环的函数。
  • +
  • 由于函数也返回值,所以函数调用也是一个表达式,可以用在赋值语句的右边。
  • +
+

3.3 控制流

+

3.4 简单的宏

+

宏在编译过程中会扩展为 Rust 代码,并且可以接受可变数量的参数。它们以 ! 结尾来进行区分。Rust 标准库包含各种有用的宏。

+
    +
  • println!(format, ..) 在标准输出中打印一行字符串;
  • +
  • format!(format, ..) 的用法与 println! 类似,但并不打印,它以字符串形式返回结果;
  • +
  • dbg!(expression) 会记录表达式的值并返回该值;
  • +
  • todo!() 用于标记尚未实现的代码段。如果执行该代码段,则会触发 panic;
  • +
  • unreachable!() 用于标记无法访问的代码段。如果执行该代码段,则会触发 panic;
  • +
  • assert_eq!(left, right) 用于断言两个值是否相等;
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Language/Rust/Rust/index.html b/Computer Science/Programming Language/Rust/Rust/index.html new file mode 100644 index 0000000..b1312c6 --- /dev/null +++ b/Computer Science/Programming Language/Rust/Rust/index.html @@ -0,0 +1,1472 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Rust - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Rust

+
+

约 88 个字

+
+
+

Info

+

为啥要学 Rust?我暂时还不知道,或许你可以问半年之后的我:-)

+

Rust 有一些强大的优势,在 Comprehensive Rust 中是这么讲的:

+
    +
  • Compile time memory safety - whole classes of memory bugs are prevented at compile time;
  • +
  • No undefined runtime behavior - what a Rust statement does is never left unspecified;
  • +
  • Modern language features - as expressive and ergonomic as higher-level languages.
  • +
+
+

Reading List

+

Table of Contents

+ + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Programming Language/index.html b/Computer Science/Programming Language/index.html new file mode 100644 index 0000000..ce8bd29 --- /dev/null +++ b/Computer Science/Programming Language/index.html @@ -0,0 +1,1324 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Programming Language - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Programming Language

+
+

约 2 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Web/CSS/index.html b/Computer Science/Web/CSS/index.html new file mode 100644 index 0000000..b3404f9 --- /dev/null +++ b/Computer Science/Web/CSS/index.html @@ -0,0 +1,1174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + CSS - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

CSS

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Web/HTML/index.html b/Computer Science/Web/HTML/index.html new file mode 100644 index 0000000..9bd9904 --- /dev/null +++ b/Computer Science/Web/HTML/index.html @@ -0,0 +1,1437 @@ + + + + + + + + + + + + + + + + + + + + + + + + + HTML - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

HTML

+
+

约 993 个字 20 行代码 预计阅读时间 4 分钟

+
+
+

Abstract

+

这是我的HTML笔记。

+

为啥要学HTML?

+

都学计算机了,总得学点前端吧。况且对于一个强迫症而言,我需要合适的工具来改进排版。

+
+
+

Info

+

HTML(HyperText Markup Language)是用来描述网页的一种标记语言。标记语言使用一套标记标签来描述内容。

+
+

01 HTML基础

+

01.1 HTML基本结构

+

下面是一个完整的HTML页面:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
<!DOCTYPE HTML>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title> 第一个HTML页面 </title>
+    </head>
+
+    <body>
+        <h1> 第一个标题 </h1>
+        <p> 第一个段落 </p>
+    </body>
+</html>
+
+

其中: +- <!DOCTYPE HTML> 声明了文档类型,为HTML5文档。 +- <html> 元素是HTML页面的根元素,定义了整个HTML文档。 +- <head> 元素包含了文档的元(meta)数据,如标题、链接到外部样式表等。 +- <meta charset="utf-8"> 这就是一个元数据,定义了网页的编码格式为UTF-8。 +- <title> 元素描述了文档的标题。 +- <body> 元素包含了可见的页面内容,定义了HTML文档的主体。 +- <h1> 元素定义了一个大标题,这是最高级的标题,<h6> 定义了最低级的标题。 +- <p> 元素定义了一个段落。

+

我们能看出来,HTML标签是由尖括号包围的关键词,比如<html>,并且大多数标签都是成对出现的,比如<html></html>,其中前者是开始标签/开放标签,后者是结束标签/闭合标签

+

HTML元素和HTML标签表示的是一样的意思,但是严格来说,HTML元素包括了开始标签和结束标签,元素的内容就是标签之间塞进去的部分。

+

下面就是一个可视化的HTML页面结构:

+
<html> +
<head> +
<title>页面标题</title> +
+</head> +
+
<body> +
<h1>这是一个标题</h1>
+
<p>这是一个段落。</p>
+
<p>这是另外一个段落。</p>
+</body> +
+</html> +
+


+

01.2 最基础的语法

+
    +
  • +

    标题:标题是通过<h1><h6>标签来定义的,<h1>是最大的标题,<h6>是最小的标题。

    +
    1
    +2
    +3
    <h1> 最大的标题</h1>
    +<h2> 次大的标题</h2>
    +<h3> 更小的标题</h3>
    +
    +
  • +
  • +

    段落:段落是通过<p>标签来定义的。

    +
    1
    +2
    <p> 这是一个段落。</p>
    +<p> 这是另外一个段落。</p>
    +
    +
  • +
  • +

    链接:链接是通过<a>标签来定义的,在href属性中指定连接的URL。

    +
    <a href="http://www.baidu.com"> 这是一个链接</a>
    +
    +
  • +
  • +

    图像:图像是通过<img>标签来定义的,通过src属性指定图像的URL。图像的名称和尺寸是通过属性的方式指定的。

    +
    <img src="/images/logo.png" width="258" height="39" />
    +
    +
  • +
+

01.3 HTML元素

+

HTML元素以开始标签开始,以结束标签终止,结束标签里边会塞一个斜杠/,中间塞的就是元素内容。值得注意的是:

+
    +
  • 某些标签具有空内容
  • +
  • 大多数元素可以具有属性
  • +
  • 空元素在开始标签就进行关闭;
  • +
  • HTML元素可以嵌套,HTML文档就是由嵌套的元素构成的。
  • +
+

没有内容的HTML元素称为空元素,空元素在开始标签内关闭。比如定义换行的标签<br>就是没有关闭标签的空元素。尽管空元素给我们一种错觉,似乎空元素就不用关闭了,但是在开始标签内添加一个斜杠才是空元素的正确关闭方式,比如<br />,虽然现在的标准与当前的浏览器对于<br>都是有效的,但是XHTML、XML和未来版本的HTML都要求所有元素必须关闭。

+

HTML标签对于大小写不敏感,<P><p>是一样的,甚至很多网站都使用大写的HYML标签。但是标准推荐小写,并且在XHTML和未来版本的HTML中,都强制使用小写

+

01.4 HTML属性

+

对于HTML属性,有下面信息:

+
    +
  • HTML元素可以设置属性;
  • +
  • 属性可以在元素中添加附加信息;
  • +
  • 属性一般描述于开始标签
  • +
  • 属性一般是以键值对的形式出现,比如name="value"
  • +
+

我们拿链接元素来举例:

+
<a href="http://baidu.com">这是定向到百度的超文本链接</a>
+
+

属性值应该始终被包括在引号之内,双引号是最常用的,但是单引号也可以,如果属性值本身就有了双引号,那么必须在外边使用单引号。

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Web/Javascript/index.html b/Computer Science/Web/Javascript/index.html new file mode 100644 index 0000000..709b3ce --- /dev/null +++ b/Computer Science/Web/Javascript/index.html @@ -0,0 +1,1174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + JavaScript - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

JavaScript

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Web/YAML/index.html b/Computer Science/Web/YAML/index.html new file mode 100644 index 0000000..0e52cae --- /dev/null +++ b/Computer Science/Web/YAML/index.html @@ -0,0 +1,1600 @@ + + + + + + + + + + + + + + + + + + + + + + + + + YAML - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

YAML

+ +

YAML是一种数据序列化语言,更多用于编写配置文件

+

基本语法

+
    +
  • +

    大小写敏感

    +
  • +
  • +

    使用缩进表示层级关系

    +
  • +
  • +

    缩进只能使用空格,不能使用tab

    +
  • +
  • +

    缩进的空格数目不重要,但是同一个层级上的元素左侧必须对齐

    +
  • +
  • +

    #表示注释,但是只支持单行注释

    +
  • +
+

数据类型

+

YAML支持下面几种数据类型:

+
    +
  • +

    对象:是键值对的集合,也叫映射(Mapping)

    +
  • +
  • +

    数组:一组按照次序排列的值,有成为序列(Sequence)或者列表(List)

    +
  • +
  • +

    纯量:单个的、不可再分的值,也叫标量(Scalar)

    +
  • +
+

对象

+

对象键值对使用冒号结构表示:key: value,冒号的后面要加一个空格。对象支持多级嵌套,也支持流式风格的语法(亦即使用花括号包裹,拿逗号分割),比如:

+
1
+2
+3
+4
key:
+  value
+  chile-key: value
+  flow-style-key: {child-key1: value1, child-key2: value2}
+
+

当遇到复杂对象时,我们允许使用问号?来声明,这样就可以使用多个词汇(其实是数组)来组成键,亦即对象的属性是一个数组,对应的值也是一个数组:

+
1
+2
+3
+4
+5
+6
?
+  - keypart1
+  - keypart2
+:
+  - value1
+  - value2
+
+

数组

+

一组以区块格式(Block Format)(亦即短横线+空格)开头的数据构成一个数组:

+
1
+2
+3
+4
values: 
+  - value1
+  - value2
+  - value3
+
+

YAML也支持*内联格式(Inline Format)的数组(拿方括号包裹,逗号加空格分割):

+
values: [value1, value2, value3]
+
+

同样,嵌套格式的数组也是完全支持的,只需要使用缩进表示层级关系就好了。

+

纯量

+

字符串一般不需要使用引号包裹,但是如果在字符串之中使用了反斜杠开头的转义字符就必须用引号包裹了:

+
1
+2
+3
+4
+5
strings:
+  - this is a string
+  - 'this is s string'
+  - "this is a string"
+  - this is "a 'string'"
+
+

布尔值TruetrueTRUEYesyesYES都为真;FalsefalseFALSENonoNO皆为假。

+

整数:除了可以正常写十进制,YAML还支持二进制(前缀0b)和十六进制(前缀0x)表示:

+
1
+2
+3
+4
int: 
+  - 666
+  - 0b1010_0111
+  - 0x10
+
+

浮点数:字面量(3,14)和科学计数法(6.8523015e+5)都可以。

+

nullNull~都是空,不指定默认也是空。

+

时间戳:使用ISO 8601格式的时间数据(日期和时间之间使用T链接,使用+表示时区):

+
1
+2
date1: 2024-02-10 # 这是日期
+date2: 2024-02-10T20:30:00+08:00 # 这是时间戳
+
+

引用

+

为了保持内容的简洁,避免过多的重复的定义,YAML使用&表示建立锚点,*表示引用锚点、<<表示合并到当前数据:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
defaults: &defaults
+  adapter:  postgres
+  host:     localhost
+
+development:
+  database: myapp_development
+  <<: *defaults
+
+test:
+  database: myapp_test
+  <<: *defaults
+
+

上面的代码相当于:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
defaults:
+  adapter:  postgres
+  host:     localhost
+
+development:
+  database: myapp_development
+  adapter:  postgres
+  host:     localhost
+
+test:
+  database: myapp_test
+  adapter:  postgres
+  host:     localhost
+
+

特殊语法支持

+

保留换行

+

使用竖线|来表示该语法,这时每行的缩进和尾行空白都会去掉,而额外的缩进则被保留: +

 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
lines: |
+  我是第一行
+  我是第二行
+    我是吴彦祖
+      我是第四行
+  我是第五行
+
+# JSON
+<div markdown="1" style="margin-top: -30px; font-size: 0.75em; opacity: 0.7;">
+:material-circle-edit-outline: 约 608 个字 :fontawesome-solid-code: 71 行代码 :material-clock-time-two-outline: 预计阅读时间 3 分钟
+</div>
+# "lines": "我是第一行\n我是第二行\n  我是吴彦祖\n    我是第四行\n我是第五行"
+

+

折叠换行

+

使用右尖括号>表示该语法,这时只有空白行才会被识别为换行,原来的换行符都会被转换为一个空格:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
# YAML
+lines: >
+  我是第一行
+  也是第一行
+  仍是第一行
+  依旧是第一行
+
+  第二行
+  也是第二行
+
+# JSON
+# "lines": "我是第一行 也是第一行 仍是第一行 依旧是第一行\n第二行 也是第二行"
+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/Web/index.html b/Computer Science/Web/index.html new file mode 100644 index 0000000..ccab273 --- /dev/null +++ b/Computer Science/Web/index.html @@ -0,0 +1,1166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Index - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Index

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Computer Science/index.html b/Computer Science/index.html new file mode 100644 index 0000000..8e21088 --- /dev/null +++ b/Computer Science/index.html @@ -0,0 +1,1152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Computer Science - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Computer Science

+
+

约 106 个字

+
+
+

Abstract

+

有关计算机的都在这了!

+

这里是我在浙江大学图灵班期间的学习笔记。

+
+
+

Warning

+

这里有部分为了整齐而放弃了一部分考究的内容分类,请不要在意,谢谢!

+
+

Table of Contents

+

Programming Basis

+ +

Programming Language

+ +

Web

+ + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Javascripts/katex.js b/Javascripts/katex.js new file mode 100644 index 0000000..6db5642 --- /dev/null +++ b/Javascripts/katex.js @@ -0,0 +1,39 @@ +(function () { + 'use strict'; + + var katexMath = (function () { + var maths = document.querySelectorAll('.arithmatex'), + tex; + + for (var i = 0; i < maths.length; i++) { + tex = maths[i].textContent || maths[i].innerText; + if (tex.startsWith('\\(') && tex.endsWith('\\)')) { + katex.render(tex.slice(2, -2), maths[i], {'displayMode': false}); + } else if (tex.startsWith('\\[') && tex.endsWith('\\]')) { + katex.render(tex.slice(2, -2), maths[i], {'displayMode': true}); + } + } + }); + + (function () { + var onReady = function onReady(fn) { + if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", fn); + } else { + document.attachEvent("onreadystatechange", function () { + if (document.readyState === "interactive") { + fn(); + } + }); + } + }; + + onReady(function () { + if (typeof katex !== "undefined") { + katexMath(); + } + }); + })(); + + }()); + \ No newline at end of file diff --git a/Javascripts/mathjax.js b/Javascripts/mathjax.js new file mode 100644 index 0000000..dd987d4 --- /dev/null +++ b/Javascripts/mathjax.js @@ -0,0 +1,19 @@ +window.MathJax = { + tex: { + inlineMath: [["\\(", "\\)"]], + displayMath: [["\\[", "\\]"]], + processEscapes: true, + processEnvironments: true, + }, + options: { + ignoreHtmlClass: ".*|", + processHtmlClass: "arithmatex", + }, +}; + +document$.subscribe(() => { + MathJax.startup.output.clearCache(); + MathJax.typesetClear(); + MathJax.texReset(); + MathJax.typesetPromise(); +}); \ No newline at end of file diff --git a/Javascripts/scheme.js b/Javascripts/scheme.js new file mode 100644 index 0000000..b73a6c7 --- /dev/null +++ b/Javascripts/scheme.js @@ -0,0 +1,98 @@ +(() => { + + const preferToggle = e => { + if (localStorage.getItem("data-md-prefers-color-scheme") === "true") { + document.querySelector("body").setAttribute("data-md-color-scheme", (e.matches) ? "slate" : "default") + } + var frame = document.querySelector(".giscus-frame") + var theme = document.querySelector("body").getAttribute("data-md-color-scheme") === "slate" ? "https://gcore.jsdelivr.net/gh/TonyCrane/note/docs/css/giscus.css" : "light" + frame.contentWindow.postMessage( + { giscus: { setConfig: { theme } } }, + "https://giscus.app" + ) + } + + const setupTheme = body => { + const preferSupported = window.matchMedia("(prefers-color-scheme)").media !== "not all" + let scheme = localStorage.getItem("data-md-color-scheme") + let prefers = localStorage.getItem("data-md-prefers-color-scheme") + let oldversion = localStorage.getItem("/.__palette") + + if (oldversion) { + localStorage.removeItem("/.__palette") + } + + if (!scheme) { + scheme = "slate" + } + if (!prefers) { + prefers = "false" + } + + if (prefers === "true" && preferSupported) { + scheme = (window.matchMedia("(prefers-color-scheme: dark)").matches) ? "slate" : "default" + } else { + prefers = "false" + } + + body.setAttribute("data-md-prefers-color-scheme", prefers) + body.setAttribute("data-md-color-scheme", scheme) + + if (preferSupported) { + const matchListener = window.matchMedia("(prefers-color-scheme: dark)") + matchListener.addListener(preferToggle) + } + } + + const observer = new MutationObserver(mutations => { + mutations.forEach(mutation => { + if (mutation.type === "childList") { + if (mutation.addedNodes.length) { + for (let i = 0; i < mutation.addedNodes.length; i++) { + const el = mutation.addedNodes[i] + + if (el.nodeType === 1 && el.tagName.toLowerCase() === "body") { + setupTheme(el) + break + } + } + } + } + }) + }) + + observer.observe(document.querySelector("html"), {childList: true}) + setupTheme(document.querySelector("body")) +})() + +window.toggleScheme = () => { + const body = document.querySelector("body") + const preferSupported = window.matchMedia("(prefers-color-scheme)").media !== "not all" + let scheme = body.getAttribute("data-md-color-scheme") + let prefer = body.getAttribute("data-md-prefers-color-scheme") + + if (preferSupported && scheme === "default" && prefer !== "true") { + prefer = "true" + scheme = (window.matchMedia("(prefers-color-scheme: dark)").matches) ? "slate" : "default" + } else if (preferSupported && prefer === "true") { + prefer = "false" + scheme = "slate" + } else if (scheme === "slate") { + prefer = "false" + scheme = "default" + } else { + prefer = "false" + scheme = "slate" + } + localStorage.setItem("data-md-prefers-color-scheme", prefer) + localStorage.setItem("data-md-color-scheme", scheme) + body.setAttribute("data-md-prefers-color-scheme", prefer) + body.setAttribute("data-md-color-scheme", scheme) + + var frame = document.querySelector(".giscus-frame") + var theme = scheme === "slate" ? "https://gcore.jsdelivr.net/gh/TonyCrane/note/docs/css/giscus.css" : "light" + frame.contentWindow.postMessage( + { giscus: { setConfig: { theme } } }, + "https://giscus.app" + ) +} diff --git a/Javascripts/tablesort.js b/Javascripts/tablesort.js new file mode 100644 index 0000000..545388f --- /dev/null +++ b/Javascripts/tablesort.js @@ -0,0 +1,6 @@ +document$.subscribe(function () { + var tables = document.querySelectorAll("article table:not([class])"); + tables.forEach(function (table) { + new Tablesort(table); + }); +}); \ No newline at end of file diff --git a/Javascripts/toc.js b/Javascripts/toc.js new file mode 100644 index 0000000..6b58905 --- /dev/null +++ b/Javascripts/toc.js @@ -0,0 +1,80 @@ +(function (window, document) { + function register($toc) { + const currentInView = new Set(); + const headingToMenu = new Map(); + const $menus = Array.from($toc.querySelectorAll('.md-nav__list > li > a')); + + for (const $menu of $menus) { + const elementId = $menu.getAttribute('href').trim().slice(1); + const $heading = document.getElementById(elementId); + if ($heading) { + headingToMenu.set($heading, $menu); + } + } + + const $headings = Array.from(headingToMenu.keys()); + + const callback = (entries) => { + for (const entry of entries) { + if (entry.isIntersecting) { + currentInView.add(entry.target); + } else { + currentInView.delete(entry.target); + } + } + let $heading; + if (currentInView.size) { + // heading is the first in-view heading + $heading = [...currentInView].sort(($el1, $el2) => $el1.offsetTop - $el2.offsetTop)[0]; + } else if ($headings.length) { + // heading is the closest heading above the viewport top + $heading = $headings + .filter(($heading) => $heading.offsetTop < window.scrollY) + .sort(($el1, $el2) => $el2.offsetTop - $el1.offsetTop)[0]; + } + if ($heading && headingToMenu.has($heading)) { + $menus.forEach(($menu) => $menu.classList.remove('is-active')); + + const $menu = headingToMenu.get($heading); + $menu.classList.add('is-active'); + let $menuList = $menu.parentElement.parentElement.parentElement; + while ( + $menuList.classList.contains('md-nav') && + $menuList.parentElement.tagName.toLowerCase() === 'li' + ) { + $menuList.parentElement.children[0].classList.add('is-active'); + $menuList = $menuList.parentElement.parentElement.parentElement; + } + } + }; + const observer = new IntersectionObserver(callback, { threshold: 0 }); + + for (const $heading of $headings) { + observer.observe($heading); + // smooth scroll to the heading + if (headingToMenu.has($heading)) { + const $menu = headingToMenu.get($heading); + $menu.setAttribute('data-href', $menu.getAttribute('href')); + $menu.setAttribute('href', 'javascript:;'); + $menu.addEventListener('click', () => { + if (typeof $heading.scrollIntoView === 'function') { + $heading.scrollIntoView({ behavior: 'smooth' }); + } + const anchor = $menu.getAttribute('data-href'); + if (history.pushState) { + history.pushState(null, null, anchor); + } else { + location.hash = anchor; + } + }); + $heading.style.scrollMargin = '4em'; + } + } + } + + if (typeof window.IntersectionObserver === 'undefined') { + return; + } + + document.querySelectorAll('.md-sidebar--secondary').forEach(register); +})(window, document); diff --git a/Math/Abstract Algebra/index.html b/Math/Abstract Algebra/index.html new file mode 100644 index 0000000..a016166 --- /dev/null +++ b/Math/Abstract Algebra/index.html @@ -0,0 +1,980 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Abstract Algebra - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Abstract Algebra

+
+

约 2 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Math/Analysis/A Little More Analysis.pdf b/Math/Analysis/A Little More Analysis.pdf new file mode 100644 index 0000000..f48f375 Binary files /dev/null and b/Math/Analysis/A Little More Analysis.pdf differ diff --git a/Math/Analysis/index.html b/Math/Analysis/index.html new file mode 100644 index 0000000..325cbe2 --- /dev/null +++ b/Math/Analysis/index.html @@ -0,0 +1,1010 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Analysis - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Analysis

+
+

约 57 个字

+
+
+
+
+
复习:级数
+
6.10 MB / 17 P / 2024-06-18
+
+

下载

+
+
+
+
+
复习:重积分
+
3.10 MB / 10 P / 2024-06-15
+
+

下载

+
+
+
+
+
复习:曲线积分和曲面积分
+
7.60 MB / 14 P / 2024-06-18
+
+

下载

+
+
+
+
+
A Little More Analysis
+
383 KB / 63 P / 2024-02-16
+
+

下载

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Math/Analysis/line_surface_integral.pdf b/Math/Analysis/line_surface_integral.pdf new file mode 100644 index 0000000..133283c Binary files /dev/null and b/Math/Analysis/line_surface_integral.pdf differ diff --git a/Math/Analysis/mul_integral.pdf b/Math/Analysis/mul_integral.pdf new file mode 100644 index 0000000..e3467b8 Binary files /dev/null and b/Math/Analysis/mul_integral.pdf differ diff --git a/Math/Analysis/series.pdf b/Math/Analysis/series.pdf new file mode 100644 index 0000000..87b9747 Binary files /dev/null and b/Math/Analysis/series.pdf differ diff --git a/Math/Discrete Mathematics/01 Propositional Logic/index.html b/Math/Discrete Mathematics/01 Propositional Logic/index.html new file mode 100644 index 0000000..50eb408 --- /dev/null +++ b/Math/Discrete Mathematics/01 Propositional Logic/index.html @@ -0,0 +1,1591 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Propositional Logic - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Part 01 Propositional Logic

+
+

约 3014 个字 预计阅读时间 10 分钟

+
+

1.1 Propositions

+

A proposition is a declarative sentence that is either true or false, but not both. We use letters to denote propositional variables, or sentential variables, i.e. variables that represent propositions. The truth value of a proposition is true, denoted by T, if it is a true proposition, and similiarly, the truth value of a proposition is false, denoted by F, if it is a false proposition.Propositions that cannot be expressed in terms of simpler propositions are called atomic propositions.

+

We can form new propostions from existing ones using logical connectives. Here are six useful logical connectives: Negation/NOT (\(\neg\)), Conjunction/AND (\(\land\)), Disjunction/OR (\(\lor\)), Exclusive Or/XOR (\(\oplus\)), Conditional/IF-THEN (\(\to\)), and Biconditional/IFF AND ONLY IF (\(\leftrightarrow\)).

+

More on IMPLICATION:

+
    +
  • In \(p\to q\), \(p\) is the hypothesis/antecedent前件/premise前提, and \(q\) is the conclusion/consequent后件.
  • +
  • In \(p\to q\) there does not need to be any connection between the antecedent or the consequent. The “meaning” of \(p\to q\) depends only on the truth values of \(p\) and \(q\).
  • +
+

From \(p\to q\), we can form the converse \(q\to p\), the inverse \(\neg p\to \neg q\), and the contrapositive \(\neg q\to \neg p\). The converse and the inverse are not logically equivalent to the original conditional, but the contrapositive is.

+

Construction of a truth table:

+
    +
  • Rows: Need a row for every possible combination of values for the atomic propositions.
  • +
  • Columns.1: Need a column for the compound proposition (usually at far right)
  • +
  • Columns.2: Need a column for the truth value of each expression that occurs in the compound proposition as it is built up. (This includes the atomic propositions.)
  • +
+

The truth value of \(p\leftrightarrow q\) is the same as the truth value of \((p\to q)\land (q\to p)\), that is to say, \(p\leftrightarrow q\) is true if and only if \(p\) and \(q\) have the same truth value.

+

Precedence of Logical Operators: From highest to lowest, the precedence of logical operators is \(\neg\), \(\land\), \(\lor\), \(\to\), and \(\leftrightarrow\).

+

1.3 Logical Equivalence

+

Basic terminology and its concepts:

+
    +
  • Tautologies/永真式: A tautology is a proposition which is always true, e.g. \(p\lor \neg p\);
  • +
  • Contradictions/矛盾式: A contradiction is a proposition which is always false, e.g. \(p\land \neg p\);
  • +
  • Contingencies/可能式: A contingency is a proposition which is neither a tautology nor a contradiction, e.g. \(p\).
  • +
+

Two compound propositions \(p\) amd \(q\) are logically equivalent if \(q\leftrightarrow q\) is a tautology. We denote this by \(p\equiv q\) or \(p\Leftrightarrow q\).

+

Compound propositions that have the same truth values for all possible cases, in other words, the columns in a truth table giving their truth values agree, are called equivalent.

+

(Important) Conditional-disjunction equivalence states that for any propositions \(p\) and \(q\), we have

+
\[p\to q\equiv \neg p\lor q.\]
+

Absorption laws states that for any propositions \(p\) and \(q\), we have

+
\[p\lor (p\land q)\equiv p.\]
+
\[p\land (p\lor q)\equiv p.\]
+

De Morgan's Laws states that for any propositions \(p\) and \(q\), we have

+
\[\neg(p\land q)\equiv \neg p\lor \neg q\]
+
\[\neg(p\lor q)\equiv \neg p\land \neg q.\]
+

Distribution laws states that for any propositions \(p\), \(q\), and \(r\), we have

+
\[p\lor (q\land r)\equiv (p\lor q)\land (p\lor r).\]
+
\[p\land (q\lor r)\equiv (p\land q)\lor (p\land r).\]
+

Identity Laws states that for any propositions \(p\), we have

+
\[p\land T\equiv p.\]
+
\[p\lor F\equiv p.\]
+

Domination Laws states that for any propositions \(p\), we have

+
\[p\lor T\equiv T.\]
+
\[p\land F\equiv F.\]
+

Idempotent Laws states that for any propositions \(p\), we have

+
\[p\lor p\equiv p.\]
+
\[p\land p\equiv p.\]
+

Moreover, Commutative Laws and Associative Laws are also valid for logical connectives: for any propositions \(p\), \(q\), and \(r\), we have

+
\[p\lor q\equiv q\lor p.\]
+
\[p\land q\equiv q\land p.\]
+
\[(p\lor q)\lor r\equiv p\lor (q\lor r).\]
+
\[(p\land q)\land r\equiv p\land (q\land r).\]
+

Involving Conditional and Biconditional statements, we have

+

Conditional and Biconditional statements

+ + +

The Dual of compound proposition that contains only the logic operators \(\land\), \(\lor\), and \(\neg\) the proposition obtained by replacing each \(\land\) by \(\lor\), each \(\lor\) by \(\land\), each \(T\) by \(F\), and each \(F\) by \(T\). The dual of \(S\) is denoted by \(S^*\). For example, the dual of \(p\lor (q\land \neg r)\) is \(\neg p\land (q\lor \neg r)\).

+

We already know that only two logical operators \(\{\neg,\land\}\) or \(\{\neg,\lor\}\) are enough to express all logical propositions. Thus, a collection of logical operators is called functionally complete if every possible logical proposition is logically equivalent to a compound proposition involving only these operators.

+

The Sheffer Stroke/与非 is a functionally complete set of logical operators. It is denoted by \(p|q\), and \(p|q\) is false when both \(p\) and \(q\) are true, and true otherwise. The Peirce Arrow/或非 is also a functionally complete set of logical operators. It is denoted by \(p\downarrow q\), and \(p\downarrow q\) is true when both \(p\) and \(q\) are false, and false otherwise.

+

A compound proposition is satisfiable if there is an assignment of truth values to its variables that makes it true. When no such assignments exits, the compound proposition is unsatisfiable.

+

A compound proposition is unsatisfiable if and only if it is a contradiction or its negation is a tautology.

+

1.4 Applications of Propositional Logic

+

A list of propositions is consistent if it is possible to assign truth values to the proposition variables so that each proposition is true.

+

1.5 Propositional Normal Forms

+

Propositional formula/命题公式 is a compound proposition that is built up from atomic propositions using logical connectives with the following criteria:

+
    +
  • Each propositional variable is a formula, and the truth values T and F are formulas.
  • +
  • If \(A\) is a formula, then \(\neg A\) is a formula.
  • +
  • If \(A\) and \(B\) are formulas, then \((A\land B)\), \((A\lor B)\), \((A\to B)\), and \((A\leftrightarrow B)\) are formulas.
  • +
  • A string of symbols is a formula if and only if it is determined by (finitely maly applications of) the above three rules.
  • +
+

Formulas can be transformed into standard forms so that they become more convenient for symbolic manipulations and make identification and comparison of two formulas easier. There are two types of normal forms in propositional calculus:

+
    +
  • +

    the Disjunctive Normal Form/DNF/析取范式: A formula is said to be in DNF if it written as a disjuction, in which all terms are conjunctions of literals.
    + For example, \((p\land q)\lor (\neg p\land r)\), \(p\lor (q\land r)\), \(\neg p\lor T\) are in DNF, and the disjunction \(\neg(p\land q)\lor r\) is not.

    +
  • +
  • +

    the Conjunctive Normal Form/CNF/合取范式: A formula is said to be in CNF if it written as a conjunction, in which all terms are disjunctions of literals.

    +
  • +
+

We can introduce the concept of Clauses/子句 to simplify the concept of DNF and CNF. A disjunction/conjunction with literials as disjuncts/conjuncts are called a Disjunctive/Conjunctive clause/析取子句/合取子句. Disjunctive/conjunctive clauses are simply called clauses. Moreover, conjunctive clause is also called Basic product and disjunctive clause is also called Basic addition.

+

Thus, a CNF is a conjunction of disjunctive clauses, and a DNF is a disjunction of conjunctive clauses.

+

A Midterm/极小项 is a conjunction of literials in which each variable is represented exactly once.

+

(IMPORTANT) There are \(2n\) different minterm for \(n\) propositional variables. For example there \(4\) different minterm for \(p\), \(q\), they are \(p\land q\), \(p\land\neg q\), \(\neg p \land q\), \(\neg p\land\neg q\). For the sake of simplification, we use \(m_j\) denote the minterms. Where \(j\) is a integer, its binary representation corresponds the evaluation of variables that make \(m_j\) be equal to T.

+

If a proposition form is denoted by: \(f=m_j\lor m_k\lor\cdots\lor m_l\), then we simply denote

+
\[f=\sum m(j,k,\cdots,l).\]
+

Properties of minterms:

+
    +
  • Each minterm is true for exactly one assignment.
  • +
  • The conjunction of two different minterm is always false.
  • +
  • The disjunction of all minterms is T.
  • +
  • A disjinction of minterms is true only if at least one of the constituent minterms is ture.
  • +
+

If a function, as \(f\), is given by truth table, we know exactly for which assignments it is true. Consequently, we can select the minterms that make the function true and form the disjunction of these minterms.

+

If a Boolean function is expressed as a disjunction of minterms, it is said to be in full disjunctive form.

+

All above is the concept of DNF and the concept and use of minterms. Now we turn to CNF.

+

A compound proposition is in CNF if it is a conjunction of disjunctive clauses. Every proposition can be put in an equivalent CNF. CNF is useful in the study of resolution theorem proving used in AI.

+

A compound proposition can be put in conjunctive normal form through repeated application of the logical equivalences covered earlier.

+

A Maxterm/极大项 is a disjunction of literials in which each variable is represented exactly once. If a Boolean function is expressed as a conjunction of maxterms, it is said to be in full conjunctive form.

+

We can get the full conjunctive form of a Boolean function from its full disjunction form: Let \(f=\sum f(j,k,\cdots,l)\), \(g=\sum m(\{0,1,2,\cdots,2^{n-1}\}-\{j,k,\cdots,l\})\), then \(f\lor g = T\), \(f\land g = F\).

+
\[f = \neg g = \prod M(\{0,1,2,\cdots,2^{n-1}\}-\{j,k,\cdots,l\}).\]
+

The \(M_i\) is a maxterm defined by \(M_i=\neg m_i\).

+

1.6 Predicates and Quantifiers

+

In this section, we will introduce Predicate logic/谓词逻辑. A predicate refers to a property that the subject of the statement can have. We can denote the statement "\(x\) is greater than \(3\)" by \(P(x)\), where \(P\) denotes the predicate "is greater than \(3\)" and \(x\) is the variable. The statement \(P(x)\) is also said to be the value of the propositional function \(P\) at \(x\).

+

Propositional functions become propositions when their variables are each replaced by a value from the domain.

+

We need quantifiers/量词 to express the meaning of English words including all and some. Two most important quantifiers are:

+
    +
  • Universal Quantifier: \(\exists\) means "There exists";
  • +
  • Existential Quantifier: \(\forall\) means "For all".
  • +
+

Domain/domain or discourse/universe of discourse: the range of the possible values of the variable.

+

Given the domain as \(\{x_1, x_2, \cdots, x_n\}\), the proposition \(\forall xP(x)\) is equivalent to \(P(x_1)\land P(x_2)\land\cdots\land P(x_n)\), and the proposition \(\exists xP(x)\) is equivalent to \(P(x_1)\lor P(x_2)\lor\cdots\lor P(x_n)\).

+

Uniqueness Quantifier: \(\exists !\) means "There exists a unique", that is \(P(x)\) is true for one and only one \(x\) in the domain. The uniqueness quantifier can be expressed without the symbol \(!\) : \(\exists x(P(x)\land \forall y(P(x)\to y=x))\).

+

Precedence of Quantifiers: The quantifiers \(\forall\) and \(\exists\) have higher precedence than the logical connectives \(\neg\), \(\land\), \(\lor\), \(\to\), and \(\leftrightarrow\). For example, \(\forall xP(x)\land Q(x)\) means \((\forall xP(x))\land Q(x)\).

+

Bound Variable: A variable is bound if it is known or quantified. A variable is free if it is neither quantified or specified with a value.

+

All the variables in a propositional function must be quantified or set equal to a particular value to turn it into a proposition.

+

Scope of a quantifier: the part of a logical expression to which the quantifier is applied

+

Logical Equivalence with Logical Quantifiers:

+

alt text

+

De Morgan's Laws for Quantifiers:

+
\[\neg\forall xP(x)\equiv \exists x\neg P(x).\]
+
\[\neg\exists xP(x)\equiv \forall x\neg P(x).\]
+

1.7 Nested Quantifiers

+

Nested Quantifiers: Two quantifiers are nested if one is within the scope of the other. For example, \(\forall x\exists yP(x,y)\) means "For every \(x\), there exists a \(y\) such that \(P(x,y)\) is true".

+

Order of Quantifiers: Only both quantifiers are universal or both are existential, the order of quantifiers can be changed. +alt text

+

Distributions for Quantifiers over Logical Connectives: Here I list two examples: \(\forall x(P(x)\land Q(x))\equiv \forall xP(x)\land \forall xQ(x)\) is True, whereas \(\forall x(P(x)\to Q(x))\equiv \forall xP(x)\to \forall xQ(x)\) is False.

+

1.8 Rules of Inference

+

Valid Argumemts:An argument in propositional logic is a sequence of propositions. All but the final proposition are called premises/前提. The last statement is the conclusion/结论. The argument is valid/有效 if the premises imply the conclusion. An argument form is an argument that is valid no matter what propositions are substituted into its propositional variables.

+

If the premises are \(p_1, p_2,\dots, p_n\) and the conclusion is \(q\) then \((p_1\land p2 \land \cdots\land p_n )\to q\) is a tautology.

+

Inference Rules are all argument simple argument forms that will be used to construct more complex argument forms.

+

Modus Ponens/假言推理: If \(p\to q\) and \(p\) are true, then \(q\) is true. Corresponding Tautology: \((p\land (p\to q))\to q\).

+

Modus Tollens/取拒式: If \(p\to q\) and \(\neg q\) are true, then \(\neg p\) is true. Corresponding Tautology: \(((p\to q)\land \neg q)\to \neg p\).

+

Hypothetical Syllogism/假言三段论: If \(p\to q\) and \(q\to r\) are true, then \(p\to r\) is true. Corresponding Tautology: \(((p\to q)\land (q\to r))\to (p\to r)\).

+

Disjunctive Syllogism/析取三段论: If \(p\lor q\) and \(\neg p\) are true, then \(q\) is true. Corresponding Tautology: \(((p\lor q)\land \neg p)\to q\).

+

Addition/附加律: If \(p\) is true, then \(p\lor q\) is true. Corresponding Tautology: \(p\to (p\lor q)\).

+

Simplification/简化律: If \(p\land q\) is true, then \(p\) is true. Corresponding Tautology: \((p\land q)\to p\).

+

Conjunction/合取律: If \(p\) and \(q\) are true, then \(p\land q\) is true. Corresponding Tautology: \((p\land q)\to (p\land q)\).

+

Resolution/消解律: If \(p\lor q\) and \(\neg p\lor r\) are true, then \(q\lor r\) is true. Corresponding Tautology: \(((p\lor q)\land (\neg p\lor r))\to (q\lor r)\).

+

Universal Instantiation/全称实例: If \(\forall xP(x)\) is true, then \(P(c)\) is true for any \(c\) in the domain. Corresponding Tautology: \(\forall xP(x)\to P(c)\).

+

Universial Generalization/全称引入: If \(P(c)\) is true for any \(c\) in the domain, then \(\forall xP(x)\) is true. Corresponding Tautology: \(P(c)\to \forall xP(x)\).

+

Existential Instantiation/存在实例: If \(\exists xP(x)\) is true, then \(P(c)\) is true for some \(c\) in the domain. Corresponding Tautology: \(\exists xP(x)\to P(c)\).

+

Existential Generalization/存在引入: If \(P(c)\) is true for some \(c\) in the domain, then \(\exists xP(x)\) is true. Corresponding Tautology: \(P(c)\to \exists xP(x)\).

+

Universial Modus Ponens/全称假言推理: If \(\forall x(p(x)\to q(x))\) and \(p(a)\) are true, then \(q(a)\) is true. Corresponding Tautology: \((\forall x(p(x)\to q(x))\land p(a))\to q(a)\).

+

1.9 Introduction to Proofs

+

A proof is a valid argument that establishes the truth of a statement. In math, CS, and other disciplines, informal proofs which are generally shorter, are generally used.

+

A theorem/定理 is a statement that can be shown to be true using: definitions, other theorems, axioms (statements which are given as true), rules of inference.

+

A lemma/引理 is a 'helping theorem' or a result which is needed to prove a theorem.

+

A corollary/推论 is a result which follows directly from a theorem.

+

Less important theorems are sometimes called propositions/命题.

+

A conjecture/猜想 is a statement that is being proposed to be true. Once a proof of a conjecture is found, it becomes a theorem. It may turn out to be false.

+

Direct Proof: Assume that \(p\) is true. Use rules of inference, axioms, and logical equivalences to show that \(q\) must also be true.

+

Proof by Contraposition/反证法: Assume \(\neg q\) and show \(\neg p\) is true also. This is sometimes called an indirect proof method. If we give a direct proof of \(\neg q\to\neg p\) then we have a proof of \(p\to q\).

+

Proof by Contradiction/归谬证明法/Reductio ad absurdum: To prove \(p\), assume \(\neg p\) and derive a contradiction such as \(r\land \neg r\). (an indirect form of proof). Since we have shown that \(\neg p\to F\) is true , it follows that the contrapositive \(T\to p\) also holds.

+

1.10 Proof Method and Strategy

+

Proof by cases: To prove \((p_1\lor p_2\lor \cdots\lor p_n)\to q\), using the tautology \((p_1\to q)\land (p_2\to q)\land\cdots\land (p_n\to q)\leftrightarrow (p_1\lor p_2\lor \cdots\lor p_n)\to q\), we need to prove \(p_1\to q\), \(p_2\to q\), \(\cdots\), and \(p_n\to q\).

+

Existence Proofs/存在性证明,Without Loss of Generality/不失一般性,Nonconstructive Proofs/非构造性证明,Proof by Counterexample/反例证明,Uniqueness Proofs/唯一性证明,Backward Proof/逆向证明.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Math/Discrete Mathematics/02 Basic Structures/index.html b/Math/Discrete Mathematics/02 Basic Structures/index.html new file mode 100644 index 0000000..2253200 --- /dev/null +++ b/Math/Discrete Mathematics/02 Basic Structures/index.html @@ -0,0 +1,1401 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Basic Structures - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + +

Basic Structures: Sets, Functions, Sequences, Sums, and Matrices

+
+

约 1413 个字 预计阅读时间 5 分钟

+
+

2.1 Sets

+

A set is an unordered collection of distinct objects, called elements or members of the set. A set is said to contain its elements. We write \(a\in A\) to denote that \(a\) is an element of the set \(A\). The notation \(a\notin A\) denotes that \(a\) is not an element of the set \(A\).

+

Roster method: A set can be described by listing its elements between braces. For example, the set of vowels in the English alphabet can be written as \(V=\{a,e,i,o,u\}\). Listing an element more than once does not change the set. The set \(\{a,e,i,o,u\}\) is the same as the set \(\{a,e,i,o,u,u\}\).

+

Set-builder notation: A set can be described by specifying a property that its members must satisfy, for example \(\{x:x\equiv 0\pmod 2\}\)

+

Universal Set: The set \(U\) containing all the objects currently under consideration.

+

Empty Set: The set containing no elements, denoted by \(\emptyset\) or \(\{\}\).

+

Set Equality: Two sets are equal if and only if they have the same elements. i.e.

+
\[\forall x(x\in A\leftrightarrow x\in B)\]
+

Subset: A set \(A\) is a subset of a set \(B\) if every element of \(A\) is also an element of \(B\). We write \(A\subseteq B\).

+
\[\forall x(x\in A\rightarrow x\in B)\]
+

Proper Subset: If \(A\subseteq B\) and \(A\neq B\), then \(A\) is a proper subset of \(B\), denoted by \(A\subset B\).

+

Set Cardinality: If there are exactly \(n\) distinct elements in a set \(A\), where \(n\) is a nonnegative integer, then \(A\) is a finite set otherwise it is an infinite set. The cardinality of a finite set \(A\), denoted by \(|A|\), is the number of elements in \(A\).

+

Power Sets: The set of all subsets of \(A\), denoted by \(\mathcal{P}(A)\) is called the power set of \(A\). If \(|A|=n\), then \(|\mathcal{P}(A)|=2^n\).

+

Tuples: The ordered \(n\)-tuple \((a_1,a_2,\cdots,a_n)\) is the ordered collection that has \(a_1\) as its first element, \(a_2\) as its second element, and so on. Two \(n\)-tuples are equal if and only if their corresponding elements are equal. \(2\)-tuple is called an ordered pair/序偶.

+

Cartesian Product: The Cartesian product of sets \(A\) and \(B\), denoted by \(A\times B\), is the set of all ordered pairs \((a,b)\) where \(a\in A\) and \(b\in B\). Similarly, the Cartesian product of \(n\) sets \(A_1,A_2,\cdots,A_n\) is the set of all ordered \(n\)-tuples \((a_1,a_2,\cdots,a_n)\) where \(a_i\in A_i\) for \(i=1,2,\cdots,n\).

+
\[A\times B=\{(a,b):a\in A\land b\in B\}\]
+

Relation: A subset \(R\) of the Cartesian product \(A\times B\) is called a relation from \(A\) to \(B\).

+

Truth Set: Given a predicate \(P\) and a domain \(D\), the truth set of \(P\) is the set of all elements in \(D\) for which \(P\) is true.

+
\[\{x\in D:P(x)\}\]
+

2.2 Set Operations

+

Union: The union of sets \(A\) and \(B\), denoted by \(A\cup B\), is the set containing all elements that are in \(A\) or in \(B\) or in both.

+
\[A\cup B=\{x:x\in A\lor x\in B\}\]
+

Intersection: The intersection of sets \(A\) and \(B\), denoted by \(A\cap B\), is the set containing all elements that are in both \(A\) and \(B\).

+
\[A\cap B=\{x:x\in A\land x\in B\}\]
+

Difference: The difference of sets \(A\) and \(B\), denoted by \(A-B\), is the set containing all elements that are in \(A\) but not in \(B\).

+
\[A-B=\{x:x\in A\land x\notin B\}\]
+

Symmetric Difference: The symmetric difference of sets \(A\) and \(B\), denoted by \(A\oplus B\), is the set containing all elements that are in \(A\) or in \(B\) but not in both. Remember the XOR/\(\oplus\) operation.

+
\[A\oplus B=\{x:x\in A\oplus x\in B\}=(A-B)\cup(B-A)\]
+

Complement: The complement of a set \(A\) with respect to the universal set \(U\), denoted by \(\overline{A}\) or \(A^c\), is the set \(U-A\).

+
\[\overline{A}=\{x:x\in U\land x\notin A\}\]
+

Includsion-Exclusion Principle: For anzy two sets \(A\) and \(B\),

+
\[|A\cup B|=|A|+|B|-|A\cap B|\]
+

alt text

+

To prove set identies, the most effective way is to show that each side of the identity is a subset of the other side, builder notation and propositional logic are also used in our proof.

+

2.3 Functions

+

Function: Let \(A\) and \(B\) be nonempty sets. A function \(f\) from \(A\) to \(B\) denoted by \(f:A\rightarrow B\) is an assignment of exactly one element of \(B\) to each element of \(A\). We write \(f(a)=b\) if \(b\) is the unique element of \(B\) assigned by \(f\) to the element \(a\) of \(A\). Functions are sometimes called mappings or transformations.

+
\[\forall a(a\in A\rightarrow \exists!b(b\in B\land f(a)=b))\]
+

A function \(f:A\rightarrow B\) can also be defined as a subset of the Cartesian product \(A\times B\), that is a relation. This subset is restricted be a relation where no two elements of the relation have the first element.

+
\[\forall x(x\in A\to\exists y(y\in B\land (x,y)\in f))\]
+
\[\forall x,y_1,y_2((x,y_1)\in f\land (x,y_2)\in f\to y_1=y_2)\]
+

Domain: The set \(A\) is called the domain of the function \(f:A\rightarrow B\).

+

Codomain: The set \(B\) is called the codomain of the function \(f:A\rightarrow B\).

+

Range: The set of all images of elements in the domain is called the range of the function.

+

Two functions are equal if and only if they have the same domain, the same codomain, and assign the same value to each element in their domain.

+

Definitions of Injection Surjection Bijection Inverse Function Composition and Graph of Function are omitted, because I assume you know them well.

+

2.4 Sequences and Summations

+

2.5 Cardinality of Sets

+

Cardinality: The cardinality of a set \(A\), denoted by \(|A|\), is the number of elements in \(A\). Two sets \(A\) and \(B\) have the same cardinality if and only if there is a bijection from \(A\) to \(B\).

+

Countable Set: A set is said to be countable if it is either finite or its elements can be put into one-to-one correspondence with the set of positive integers \(\mathbb{Z}^+\). When an infinite set is countable/countably infinite, its cardinality is \(\aleph_0\).

+

Cantor Diagonalization Method: The set of real numbers is uncountable.

+

Proof: To show that the set of real numbers is uncountable, we suppose that the set of real numbers is countable and arrive at a contradiction. Then, the subset of all real numbers that fall between \(0\) and \(1\) would also be countable (because any subset of a countable set is also countable). Under this assumption, the real numbers between \(0\) and \(1\) can be listed in some order, say, \(r_1\), \(r_2\), \(r_3\), \(\dots\). Let the decimal representation of these real numbers be

+
\[r_1=0.d_{11}d_{12}d_{13}\cdots\]
+
\[r_2=0.d_{21}d_{22}d_{23}\cdots\]
+
\[r_3=0.d_{31}d_{32}d_{33}\cdots\]
+
\[\vdots\]
+

where \(d_{ij}\) is the \(j\)th digit in the decimal representation of \(r_i\). We construct a real number \(r\) between \(0\) and \(1\) as follows: We choose the first digit of \(r\) to be different from the first digit of \(r_1\), the second digit of \(r\) to be different from the second digit of \(r_2\), and so on. In general, we choose the \(i\)th digit of \(r\) to be different from the \(i\)th digit of \(r_i\). The real number \(r\) is different from every real number in the list, so the list does not contain all real numbers between \(0\) and \(1\). This contradiction shows that the set of real numbers between \(0\) and \(1\) is uncountable, which finishes the proof.

+

Moreover, we can prove a stronger result: The set of all real numbers with decimal representations consisting only of \(0\) and \(1\) is uncountable. This comes from the observation that the Cantor diagonalization method only need two distinct digits to construct a real number that is different from every real number in the list.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Math/Discrete Mathematics/03 Algorithms/index.html b/Math/Discrete Mathematics/03 Algorithms/index.html new file mode 100644 index 0000000..f6dbf87 --- /dev/null +++ b/Math/Discrete Mathematics/03 Algorithms/index.html @@ -0,0 +1,1310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Algorithms - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Part 3 Algorithms

+
+

约 343 个字 预计阅读时间 1 分钟

+
+
+Tip +

This part should be trivial and useless for ALL students learning computer science, and it is covered in the course Foundamental Data Structures.

+
+

3.1 Introduction to Algorithms

+

Properties of Algorithms: Input, Output, Definiteness (每一步都有明确定义), Finiteness (有限步出结果), Effectiveness (有限时间), Correctness, Generality.

+

3.3 Complexity of Algorithms

+

We will measure time complexity in terms of the number of operations an algorithm uses and we will use big-O and big-Theta notation to estimate the time complexity.

+

If there exists a constant \(c > 0\) and a positive integer \(n_0\) such that \(\vert f(n) \vert \leqslant c \cdot \vert g(n) \vert\) for all \(n \geqslant n_0\), then \(f(n)\) is said to be \(O(g(n))\).

+

If there exists a constant \(c > 0\) and a positive integer \(n_0\) such that \(\vert f(n) \vert \geqslant c \cdot \vert g(n) \vert\) for all \(n \geqslant n_0\), then \(f(n)\) is said to be \(\Omega(g(n))\).

+

If there exists two constant \(c_1, c_2 > 0\) and a positive integer \(n_0\) such that \(c_1 \cdot \vert g(n) \vert \leqslant \vert f(n) \vert \leqslant c_2 \cdot \vert g(n) \vert\) for all \(n \geqslant n_0\), then \(f(n)\) is said to be \(\Theta(g(n))\).

+

alt text

+
    +
  • Tractable/易解 Problem: There exists a polynomial time algorithm to solve this problem. These problems are said to belong to the Class P.
  • +
  • Intractable/难解 Problem: There does not exist a polynomial time algorithm to solve this problem.
  • +
  • Unsolvable Problem: No algorithm exists to solve this problem, e.g., halting problem.
  • +
  • Class NP: Solution can be checked in polynomial time. But no polynomial time algorithm has been found for finding a solution to problems in this class.
  • +
  • NP Complete Class: If you find a polynomial time algorithm for one member of the class, it can be used to solve all the problems in the class.
  • +
+

P Versus NP Problem: Go to ADS.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Math/Discrete Mathematics/04 Number Theory/index.html b/Math/Discrete Mathematics/04 Number Theory/index.html new file mode 100644 index 0000000..1bfaf78 --- /dev/null +++ b/Math/Discrete Mathematics/04 Number Theory/index.html @@ -0,0 +1,1300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Number Theory - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Part 4 Number Theory and Cryptography

+
+

约 428 个字 预计阅读时间 1 分钟

+
+

4.1 Divisibility and Modular Arithmetic

+

Division: An integer \(a\) divides \(b\) if and only if there exists an integer \(c\) such that \(b = ac\). We write \(a|b\).

+

Divisibility Properties:

+
    +
  • If \(a|b\) and \(b|c\), then \(a|c\).
  • +
  • If \(a|b\) and \(a|c\), then \(a|(bx + cy)\) for any integers \(x\) and \(y\).
  • +
  • If \(a|b\) and \(a\) and \(b\) are both positive, then \(a \leq b\).
  • +
+

The Division Algorithm/带余除法: For any integers \(a\) and \(b\), with \(b > 0\), there exist unique integers \(q\) and \(r\) such that \(a = bq + r\) and \(0 \leq r < b\). Here \(a\) is called the dividend, \(b\) is called the divisor, \(q\) is the quotient and \(r\) is the remainder.

+

Congruence: Let \(a\), \(b\) and \(n\) be integers with \(n > 0\). We say that \(a\) is congruent to \(b\) modulo \(n\) if \(n|(a - b)\). We write \(a \equiv b \pmod{n}\).

+

The congruence relation has the following properties:

+
    +
  • If \(a \equiv b \pmod{n}\), then \(b \equiv a \pmod{n}\).
  • +
  • \(a \equiv a \pmod{n}\).
  • +
  • If \(a \equiv b \pmod{n}\) and \(b \equiv c \pmod{n}\), then \(a \equiv c \pmod{n}\)
  • +
  • If \(a \equiv b \pmod{n}\) and \(c \equiv d \pmod{n}\), then \(a + c \equiv b + d \pmod{n}\) and \(ac \equiv bd \pmod{n}\).
  • +
+

The first three properties show that the congruence relation is an equivalence relation. The last property shows that the congruence relation is compatible with addition and multiplication.

+

Moreover, \(a \equiv b \pmod{n}\) if and only if \(a\!\!\mod{n} = b\!\!\mod{n}\).

+

Arithmetic Modulo \(m\): Define \(\mathbb{Z}_m = \{0, 1, 2, \cdots, m - 1\}\). The operationn \(+_m\) and \(\times_m\) are defined as \(a +_m b = (a + b)\!\!\mod{m}\) and \(a \times_m b = (a \times b)\!\!\mod{m}\). Thry satisfy the following properties:

+
    +
  • Closure: If \(a, b \in \mathbb{Z}_m\), then \(a +_m b \in \mathbb{Z}_m\) and \(a \times_m b \in \mathbb{Z}_m\).
  • +
  • Associativity: For all \(a, b, c \in \mathbb{Z}_m\), \((a +_m b) +_m c = a +_m (b +_m c)\) and \((a \times_m b) \times_m c = a \times_m (b \times_m c)\).
  • +
  • Commutativity: For all \(a, b \in \mathbb{Z}_m\), \(a +_m b = b +_m a\) and \(a \times_m b = b \times_m a\).
  • +
  • Identity: The identity element for \(+_m\) is \(0\) and the identity element for \(\times_m\) is \(1\).
  • +
  • Additive Inverse: For all \(a \in \mathbb{Z}_m\), there exists \(b \in \mathbb{Z}_m\) such that \(a +_m b = 0\), and \(b=m-a\).
  • +
  • Distributive Property: For all \(a, b, c \in \mathbb{Z}_m\), \(a \times_m (b +_m c) = (a \times_m b) +_m (a \times_m c)\).
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Math/Discrete Mathematics/05 Induction and Recursion/index.html b/Math/Discrete Mathematics/05 Induction and Recursion/index.html new file mode 100644 index 0000000..e6d3ada --- /dev/null +++ b/Math/Discrete Mathematics/05 Induction and Recursion/index.html @@ -0,0 +1,1332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Induction and Recursion - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Part 5 Induction and Recursion

+
+

约 342 个字 预计阅读时间 1 分钟

+
+

5.2 Strong Induction and Well-Ordering

+

Strong Induction: To prove a statement \(P(n)\) for all \(n\in \mathbb{Z}\), we need to complete the following steps:

+
    +
  • Basis Step: Prove \(P(1)\) is true.
  • +
  • Inductive Step: Show that \([P(1) \land P(2) \land \cdots \land P(k)] \rightarrow P(k+1)\) is true for all \(k\geq 1\).
  • +
+

Strong Induction is sometimes called the Second Principle of Mathematical Induction.

+

Well-Ordering Property: Every nonempty set of nonnegative integers has a least element.

+

Generalized Definition: A set is well-ordered if every subset has a least element.

+

5.3 Recursive Definitions and Structural Induction

+

Recursive Definition: A recursive or inductive definition of a function consists of two steps.

+
    +
  • Basis Step: Specify the value of the function at zero. (Specifies an initial collection of elements)
  • +
  • Recursive Step: Give a rule for finding its value at an integer from its values at smaller integers. (Gives the rules for forming new elements in the set from those already in the set)
  • +
+

Sometimes the recursive definition has an exclusion rule, which specifies that the set contains nothing other than those elements specified in the basis step and generated by applications of the rules in the recursive step.

+

Structural Induction: To prove a property of the elements of a recursively defined set, we use structural induction.

+
    +
  • Basis Step: Show that the result holds for all elements specified in the basis step of the recursive definition.
  • +
  • Recursive Step: Show that if the statement is true for each of the elements used to construct new elements in the recursive step of the definition, the result holds for these new elements.
  • +
+

Generalized induction is used to prove results about sets other than the integers that have the well-ordering property.

+

5.4 Recursive Algorithms

+

Recursive Algorithms: An algorithm is called recursive if it solves a problem by reducing it to an instance of the same problem with smaller input.For the algorithm to terminate, the instance of the problem must eventually be reduced to some initial case for which the solution is known.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Math/Discrete Mathematics/06 Counting/index.html b/Math/Discrete Mathematics/06 Counting/index.html new file mode 100644 index 0000000..78dfa86 --- /dev/null +++ b/Math/Discrete Mathematics/06 Counting/index.html @@ -0,0 +1,1415 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Counting - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Part 6 Counting

+
+

约 888 个字 预计阅读时间 3 分钟

+
+

6.1 The Basics of Counting

+

The Product Rule: A procedure can be broken down into a sequence of two tasks. There are \(n_1\) ways to do the first task and \(n_2\) ways to do the second task. Then there are \(n_1*n_2\) ways to do the procedure.

+

The Product Rule in Terms of Sets: If \(A_1\), \(A_2\), \(\cdots\), \(A_m\) are all finite sets, then the number of elements in the Cartesian product \(A_1 \times A_2 \times \cdots \times A_m\) is \(|A_1| * |A_2| * \cdots * |A_m|\).

+

The Sum Rule: If a task can be done either in one of \(n_1\) ways or in one of \(n_2\) ways to do the second task, where none of the set of \(n_1\) ways is the same as any of the set of \(n_2\) ways, then there are \(n_1 + n_2\) ways to do the task.

+

The Sum Rule in Terms of Sets: If \(A\) and \(B\) are disjoint sets, then \(|A \cup B| = |A| + |B|\).

+

6.2 The Pigeonhole Principle

+

The Pigeonhole Principle: If \(k\) is a positive integer and \(k+1\) or more objects are placed into \(k\) boxes, then there is at least one box containing two or more of the objects.

+

Corolary: A function \(f\) from a set with \(k+1\) elements to a set with \(k\) elements is not one-to-one.

+

Generalized Pigeonhole Principle: If \(N\) objects are placed into \(k\) boxes, then there is at least one box containing at least \(\lceil N/k \rceil\) objects.

+

6.3 Permutations and Combinations

+

I assume everyone has learned about permutations and combinations during high school period, so I omitted most of this part.

+

Generalized Combinational Numbers: If \(n\geq 0\) and \(n\geq m\), then the Generalized Combinational Number \(\binom{m}{n} = C^n_m\) is defined as

+
\[\binom{m}{n} = C^m_m = \frac{\prod\limits_{i = m-n+1}^{m}i}{n!}.\]
+

Combinatorial Proofs: A combinatorial proof of an identity is a proof thar uses one of the following methods:

+
    +
  • A Double Counting Proof uses counting arguments to prove that both sides of an identity count the same objects but in different ways.
  • +
  • A Bijective Proof shows that there is a bijection between the sets of objects counted by the two sides of the identity.
  • +
+

6.4 Binomial Coefficients and Identities

+

Binomial Expression: A binomial expression is the sum of two terms, such as \(x + y\).

+

Binomial Theorem: Let \(x\) and \(y\) be variables and \(n\) be a nonnegative integer. Then

+
\[(x + y)^n = \sum_{k=0}^{n} \binom{n}{k}x^{n-k}y^k = \binom{n}{0}x^n + \binom{n}{1}x^{n-1}y + \cdots + \binom{n}{n-1}xy^{n-1} + \binom{n}{n}y^n.\]
+

Corollary 1: For all nonnegative integers \(n\),

+
\[\sum_{k=0}^{n} \binom{n}{k} = 2^n.\]
+

Corollary 2: For all positive integers \(n\),

+
\[\sum_{k=0}^{n} (-1)^k\binom{n}{k} = 0.\]
+

Pascal's Identity: If \(n\) and \(k\) are integers with \(0 \leq k \leq n\), then

+
\[\binom{n+1}{k} = \binom{n}{k-1} + \binom{n}{k}.\]
+

Vandermonde's Identity: If \(m\), \(n\), and \(r\) are nonnegative integers with \(r \leq m\) and \(r \leq n\), then

+
\[\binom{m+n}{r} = \sum_{k=0}^{r} \binom{m}{k}\binom{n}{r-k}.\]
+

We only need to consider choosing \(r\) elements from two sets \(A\) and \(B\) with \(m\) and \(n\) elements respectively.

+

Corollary 4: If \(n\) is a nonnegative integer, then

+
\[\binom{2n}{n} = \sum_{k=0}^{n} \binom{n}{k}^2.\]
+

Identity: Let \(n\) and \(r\) be nonnegative integers with \(r \leq n\). Then

+
\[\binom{n+1}{r+1} = \sum_{j=r}^{n}\binom{j}{r}.\]
+

Consider choosing \(r+1\) elements from a set with \(n+1\) elements, and the RHS sets the last element be the \(j\)th element, from the \(r+1\)th to the \(n+1\)th.

+

6.5 Generalized Permutations and Combinations

+

Permutations with Repetition: The number of r-permutations of a set with n elements, where repetition is allowed, is \(n^r\).

+

Combinations with Repetition: The number of r-combinations of a set with n elements, where repetition is allowed, is \(\binom{n+r-1}{r}\).

+

Permutations with Indistinguishable Objects: The number of different permutations of n objects, where \(n_1\) are of one type, \(n_2\) are of a second type, \(\cdots\), and \(n_k\) are of a \(k\)th type, is \(\frac{n!}{n_1!n_2!\cdots n_k!}.\)

+

6.6 Generating Permutations and Combinations

+

Lexicographic Order: The permutation \(a_1a_2\cdots a_n\) precedes the permutation \(b_1b_2\cdots b_n\) in lexicographic order if there is an integer \(j\) with \(1 \leq j \leq n\) such that \(a_i = b_i\) for \(i = 1, 2, \cdots, j-1\) and \(a_j < b_j\).

+

Find the Next Permutation: If \(a_1a_2\cdots a_n\) is a permutation of \(1, 2, 3, \cdots, n\), then the next permutation in lexicographic order is obtained by:

+
    +
  • Locate the integers \(a_j\) and \(a_{j+1}\) with \(a_j < a_{j+1}\) and \(a_{j=1} > a_{j+2} > \cdots > a_n\).
  • +
  • Put in the smallest integer that is larger than \(a_j\) in the position \(j\).
  • +
  • List in increasing order the remaining integers \(a_j\), \(a_{j+1}\), \(\cdots\), \(a_n\) in the positions \(j+1\), \(j+2\), \(\cdots\), \(n\).
  • +
+

Find the Next Combination: If \(S_j\in S = \{1, 2, 3, \cdots, n\}\) is the \(j\)th element in a combination of \(r\) elements from \(S\), then the next combination in lexicographic order is obtained by:

+
    +
  • Locate the last element \(a_i\) in the sequence such that \(a_i\neq n-r+i\).
  • +
  • Then replace \(a_i\) by \(a_i + 1\) and \(a_j = a_i +j - i +1\) for \(j = i+1, i+2, \cdots, r\).
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Math/Discrete Mathematics/08 Advanced Counting Techniques/index.html b/Math/Discrete Mathematics/08 Advanced Counting Techniques/index.html new file mode 100644 index 0000000..94d3291 --- /dev/null +++ b/Math/Discrete Mathematics/08 Advanced Counting Techniques/index.html @@ -0,0 +1,1410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Advanced Counting Techniques - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Part 8 Advanced Counting Techniques

+
+

约 782 个字 预计阅读时间 3 分钟

+
+

8.1 Applications of Recurrence Relations

+

A solution of a Recurrence Relation is a sequence that satisfies the recurrence relation.

+

Normally, there are infinitely many sequences which satisfy a recurrence relation. We distinguish them by the initial conditions, the values of \(a_1\), \(a_2\), \(\cdots\), \(a_k\) to uniquely identify a sequence.

+

The Degree of a Recurrence Relation: \(a_n = a_{n-1} + a_{n-5}\) is a recurrence relation with degree 5.

+

8.2 Solving Linear Recurrence Relations

+

Linear Homogeneous Recurrence Relations: A Linear Homogeneous Recurrence Relation of degree \(k\) with constant coefficients is a recurrence relation of the form \(a_n = c_1a_{n-1} + c_2a_{n-2} + \cdots + c_ka_{n-k}\), where \(c_1, c_2, \cdots, c_k\) are constants and \(c_k \neq 0\).

+
    +
  • It is linear because the right-hand side is a linear combination of the previous terms.
  • +
  • It is homogeneous because no terms occur that are not multiples of \(a_j\)s and each coefficient is a constant.
  • +
  • The degree is \(k\) because the relation involves \(k\) previous terms.
  • +
+

Solving Linear Homogeneous Recurrence Relations: The general solution of a linear homogeneous recurrence relation of degree \(k\) with constant coefficients \(a_n = c_1a_{n-1} + c_2a_{n-2} + \cdots + c_ka_{n-k}\) can be obtained by:

+
    +
  • Solving the characteristic equation \(x^k - c_1x^{k-1} - c_2x^{k-2} - \cdots - c_k = 0\), with roots \(r_1, r_2, \cdots, r_l\) of multiplicity \(m_1, m_2, \cdots, m_l\).
  • +
  • The general solution is \(a_n = P_1(n)r_1^n + P_2(n)r_2^n + \cdots + P_l(n)r_l^n\), where \(P_i(n)\) is a constant coefficient polynomial of degree \(m_i - 1\).
  • +
+

Linear Nonhomogeneous Recurrence Relations with Constant Coefficients: A Linear Nonhomogeneous Recurrence Relation with Constant Coefficients is a recurrence relation of the form \(a_n = c_1a_{n-1} + c_2a_{n-2} + \cdots + c_ka_{n-k} + f(n)\), where \(f(n)\) is a function of \(n\). The general solution of a linear nonhomogeneous recurrence relation with constant coefficients is in the form of

+
\[a_n = P_1(n)r_1^n + P_2(n)r_2^n + \cdots + P_l(n)r_l^n + g(n),\]
+

where \(g(n)\) is a particular solution of the nonhomogeneous recurrence relation for \(f(n)\).

+

Theorem: For \(a_n = c_1a_{n-1} + c_2a_{n-2} + \cdots + c_ka_{n-k} + F(n)\) and \(F(n) = (b_tn^t + b_{t-1}n^{t-1} + \cdots + b_1n + b_0)s^n\), then:

+
    +
  • If \(s\) is not a root of the characteristic equation, then \(g(n) = (p_tn^t + p_{t-1}n^{t-1} + \cdots + p_1n + p_0)s^n\).
  • +
  • If \(s\) is a root of the characteristic equation with multiplicity \(m\), then \(g(n) = n^m(p_tn^{t+1} + p_{t-1}n^t + \cdots + p_1n + p_0)s^n\).
  • +
+

8.3 Divide-and-Conquer Algorithms and Recurrence Relations

+

8.4 Generating Functions

+

Generating Functions: The Generating Function of a sequence \(a_0, a_1, a_2, \cdots\) is the formal power series

+
\[G(x) = a_0 + a_1x + a_2x^2 + \cdots = \sum_{n=0}^{\infty}a_nx^n.\]
+

Generating functions can be used to solve a wide variety of counting problems, such as

+
    +
  • Count the number of combinations from a set when repetition is allowed and additional constraints exist.
  • +
  • Count the number of permutations.
  • +
+
+Using generating functions to solve recurrence relations +

Using generating functions to solve recurrence relations

+
+

8.5 Inclusion-Exclusion

+

Principle of Inclusion-Exclusion: For any two sets \(A\) and \(B\),

+
\[\left\vert A \cup B\right\vert = \vert A\vert + \vert B\vert - \left\vert A \cap B\right\vert.\]
+

Generalized Principle of Inclusion-Exclusion: For any \(n\) sets \(A_1, A_2, \cdots, A_n\),

+
\[ \begin{aligned} \left\vert A_1 \cup A_2 \cup \cdots \cup A_n\right\vert &= \sum_{i=1}^{n}\left\vert A_i\right\vert - \sum_{1 \leq i < j \leq n} \left\vert A_i \cap A_j\right\vert + \sum_{1 \leq i < j < k \leq n}\left\vert A_i \cap A_j \cap A_k\right\vert - \cdots \\ +&+ (-1)^{n-1}\left\vert A_1 \cap A_2 \cap \cdots \cap A_n\right\vert. \end{aligned} \]
+

8.6 Applications of Inclusion-Exclusion

+

Derangements: A derangement is a permutation of objects that leaves no object in the original position.

+

Theorem: The number of derangements of a set with n elements is

+
\[ D_n = n! \left(1 - \frac{1}{1!} + \frac{1}{2!} - \frac{1}{3!} + \cdots + (-1)^n\frac{1}{n!}\right). \]
+

The Hatcheck Problem: A new employee checks the hats of n people at restaurant, forgetting to put claim check numbers on the hats. When customers return for their hats, the checker gives them back hats chosen at random from the remaining hats. What is the probability that no one receives the correct hat.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Math/Discrete Mathematics/09 Relations/index.html b/Math/Discrete Mathematics/09 Relations/index.html new file mode 100644 index 0000000..d75f722 --- /dev/null +++ b/Math/Discrete Mathematics/09 Relations/index.html @@ -0,0 +1,1450 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Relations - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Part 9 Relations

+
+

约 2043 个字 4 行代码 预计阅读时间 7 分钟

+
+

9.1 Relations and Their Properties

+

Binary Relations: A binary relation \(R\) from a set \(A\) to a set \(B\) is a subset \(R\subset A\times B\). We can represent

+

Example: Let \(A = \{0, 1, 2\}\) and \(B = \{a, b\}\), then \(\{(0, a), (0, b), (1, a), (2, b)\}\) is a relation from \(A\) to \(B\).

+

Reflexive Relations/自反关系: A relation \(R\) on a set \(A\) is reflexive if and only if for all \(a\in A\), \((a, a)\in R\). Written symbolically, \(R\) is reflexive if and only if

+
\[\forall x[x\in U \rightarrow (x, x)\in R].\]
+

Symmetric Relations/对称关系: A relation \(R\) on a set \(A\) is symmetric if and only if for all \(a, b\in A\), if \((a, b)\in R\), then \((b, a)\in R\). Written symbolically, \(R\) is symmetric if and only if

+
\[\forall x\forall y[(x, y)\in R \rightarrow (y, x)\in R].\]
+

Antisymmetric Relations/反对称关系: A relation \(R\) on a set \(A\) is antisymmetric if and only if for all \(a, b\in A\), if \((a, b)\in R\) and \((b, a)\in R\), then \(a = b\). Written symbolically, \(R\) is antisymmetric if and only if

+
\[\forall x\forall y[(x, y)\in R \land (y, x)\in R \rightarrow x = y].\]
+

Transitive Relations/传递关系: A relation \(R\) on a set \(A\) is transitive if and only if for all \(a, b, c\in A\), if \((a, b)\in R\) and \((b, c)\in R\), then \((a, c)\in R\). Written symbolically, \(R\) is transitive if and only if

+
\[\forall x\forall y\forall z[(x, y)\in R \land (y, z)\in R \rightarrow (x, z)\in R].\]
+

Composition: The composition of relations \(R\) and \(S\) is the relation \(T\) such that \((a, c)\in T\) if and only if there exists an element \(b\) such that \((a, b)\in R\) and \((b, c)\in S\).

+

Powers of a Relation: Let \(R\) be a binary relation on a set \(A\). The \(n\)th power of \(R\) is the relation \(R^n\) defined recursively as follows:

+
    +
  • Basis Step: \(R^1 = R\).
  • +
  • Inductive Step: \(R^{n+1} = R^n \circ R\).
  • +
+

Theorem 1: The relation \(R\) is transitive if and only if \(R^n\subseteq R\).

+
    +
  • If Part: \(R^n\subseteq R\), and \(R^2\subseteq R\). If \((a, b)\in R\) and \((b, c)\in R\), then \((a, c)\in R^2\subseteq R\). Thus, \(R\) is transitive.
  • +
  • Only If Part: If \(R\) is transitive and \((a, c)\in R^2\), then there exists a \(b\) such that \((a, b)\in R\) and \((b, c)\in R\), hence \((a, c)\in R^2\subseteq R\). And induction completes the proof.
  • +
+

Inverse Relation: The inverse of a relation \(R\) is the relation \(R^{-1}\) such that \((b, a)\in R^{-1}\) if and only if \((a, b)\in R\).

+
\[R^{-1} = \{(b, a)|(a, b)\in R\}.\]
+

For a set with \(n\) elements, there are \(2^{n^2}\) possible relations, \(2^{n(n+1)/2}\) possible symmetric relations, \(2^{n}3^{n(n-1)/2}\) possible antisymmetric relations, \(3^{n(n-1)/2}\) asymmetric relations, \(2^{n(n-1)}\) irreflexive relations, \(2^{n(n-1)/2}\) reflexive and symmetric relations, \(2^{n^2}-2^{n(n-1)+1}\) neither reflexive nor irreflexive relations.

+

Combining Relations: Given two relations \(R_1\) and \(R_2\), we can combine them using basic set operations to form new realtions such as \(R_1\cup R_2\), \(R_1\cap R_2\), \(R_1 - R_2\), \(R_1\oplus R_2\).

+

9.3 Representing Relations

+

Matrix Representation: A relation \(R\) between finite sets can be represented using a zero-one matrix. The matrix \(M\) representing the relation \(R\) is defined as follows: Suppose \(R\) is a relation from \(A=\{a_1, a_2, \ldots, a_m\}\) to \(B=\{b_1, b_2, \ldots, b_n\}\), then the matrix \(M\) representing \(R\) is an \(m\times n\) matrix such that \(M[i, j] = 1\) if \((a_i, b_j)\in R\) and \(M[i, j] = 0\) otherwise.

+

If \(R\) is reflexive, then all the elements on the diagonal of \(M_R\) are \(1\). If \(R\) is symmetric, then \(M_R\) is symmetric, i.e. \(m_{ij} = 1\) if and only if \(m_{ji} = 1\). \(R\) is antisymmetric if and only if \(m_{ij} = 0\) or \(m_{ji} = 0\) for all \(i\neq j\).

+

Graph Representation: A directed graph, or digraph, consists of a set \(V\) of vertices/nodes together with a set \(E\) of edges/arcs, where each edge is an ordered pair of vertices. The vertex \(a\) is called the initial vertex of the edge \((a, b)\), and the vertex \(b\) is called the terminal vertex of the edge \((a, b)\). An edge of the form \((a, a)\) is called a loop. Then we can draw a graph to represent a relation.

+

Reflexivity: A relation \(R\) on a set \(A\) is reflexive if and only if there is a loop at each vertex in the graph representing \(R\).

+

Symmetry: A relation \(R\) on a set \(A\) is symmetric if and only if \((a, b)\) is in the graph representing \(R\) whenever \((b, a)\) is in the graph.

+

Antisymmetry: A relation \(R\) on a set \(A\) is antisymmetric if and only if \((y, x)\) is not an edge when \((x, y)\) with \(x\neq y\) is an edge. In other words, whenever there is an edge from one vertex to another, there is no edge comming back.

+

Transitivity: A relation \(R\) on a set \(A\) is transitive if and only if whenever \((a, b)\) and \((b, c)\) are edges in the graph representing \(R\), then \((a, c)\) is also an edge.

+

Reverse in the Version of Relation Representation: For matrix representation, the inverse relation is the transpose of the matrix. For graph representation, the inverse relation is the graph with all the edges reversed.

+

Properties of Relation Operations: Suppose \(R\) and \(S\) are the relations from \(A\) to \(B\), \(T\) is the relation from \(B\) to \(C\), \(P\) is the relation from \(C\) to \(D\), then

+
    +
  • \((R\cup S)^{-1} = R^{-1}\cup S^{-1}\).
  • +
  • \((R\cap S)^{-1} = R^{-1}\cap S^{-1}\).
  • +
  • \((R - S)^{-1} = R^{-1} - S^{-1}\).
  • +
  • \((\overline{R})^{-1} = \overline{R^{-1}}\).
  • +
  • \((A\times B)^{-1} = B\times A\).
  • +
  • \(\overline{R} = A\times B - R\).
  • +
  • \((S\circ T)^{-1} = T^{-1}\circ S^{-1}\).
  • +
  • \((R\circ T)\circ P = R\circ (T\circ P)\).
  • +
  • \((R\cup S)\circ T = (R\circ T)\cup (S\circ T)\).
  • +
+

9.4 Closures of Relations

+

Closure: The Closure of a relation \(R\) with respect to the property \(P\) is the relation obtained by add the minimum numnber of ordered pairs to \(R\) to satisfy property \(P\).

+

Reflexive Closure: \(r(R) = R\cup \Delta\) where \(\Delta = \{(a, a)\vert a\in A\}\).

+

Symmetric Closure: \(S(R) = R\cup R^{-1}\).

+

Transitive Closure: \(T(R) = R\cup R^2\cup R^3\cup \cdots = \cup_{n=1}^{\infty}R^n\). To get this, we need some lemmas:

+
    +
  • Lemma 1: Let \(R\) be a relation on a set \(A\), there is a path of length \(n\) from \(a\) to \(b\) in \(R\) if and only if \((a, b)\in R^n\).
  • +
  • Connectivity Relation: \(R^* = R\cup R^2\cup R^3\cup \cdots\) is called the connectivity relation of \(R\), which consists of all the \((a, b)\) such as there is a path from \(a\) to \(b\) in \(R\).
  • +
  • Lemma 2: The transitive closure of a relation \(R\) is the connectivity relation of \(R\).
      +
    1. \(R\subseteq R^*\). is obvious by definition.
    2. +
    3. \(R^*\) is transitive: If \((a, b)\in R^*\) and \((b, c)\in R^*\), then there is a path from \(a\) to \(b\) and a path from \(b\) to \(c\), then there is a path from \(a\) to \(c\), hence \((a, c)\in R^*\).
    4. +
    5. \(R^*\) is minimum: If \(S\) is also a transitive relation containing \(R\), then \(R^*\subseteq S\). Because \(S^* = S\) and \(R\subseteq S\), then \(R^*\subseteq S^*\), then \(R^*\subseteq S\).
    6. +
    +
  • +
+

Lemma 3: A is a set consisting of \(n\) elements, \(R\) is a relation on \(A\). If there is a path from \(a\) to \(b\) in \(R\), then there is a path of length not exceeding \(n\). If \(a\neq b\), then such path has length not exceeding \(n-1\).

+

From Lemma 3, we can see \(t(R) = \cup_{i=1}^{n}R^i\) or \(t(R) = \cup_{i=1}^{n-1}R^i\cup \Delta\).

+

Moreover, \(M_{R^*} = M_R\lor M_{R^2}\lor M_{R^3}\lor \cdots\lor M_{R^n}\).

+

Warshall's Algorithm: The transitive closure \(T\) of a relation \(R\) on a set \(A\) can be computed using Warshall's algorithm. The algorithm is as follows:

+
1
+2
+3
+4
for (k = 1; k <= n; k++)
+    for (i = 1; i <= n; i++)
+        for (j = 1; j <= n; j++)
+            T[i][j] = T[i][j] || (T[i][k] && T[k][j]);
+
+

9.5 Equivalence Relations

+

Equivalence Relation: A relation \(R\) on a set \(A\) is an equivalence relation if and only if \(R\) is reflexive, symmetric, and transitive. And we denote \(a\sim b\) for \((a, b)\in R\) or \(aRb\).

+

Equivalence Class: The equivalence class of an element \(a\in A\) with respect to an equivalence relation \(R\) is the set of all elements in \(A\) that are related to \(a\), and \(a\) is called the representative of the equivalence cass \([a]_R\).

+
\[[a]_R = \{x\in A\vert xRa\}.\]
+

Theorem 1: Let \(R\) be an equivalence relation on a set \(A\). Then the statements for elements \(a\) and \(b\) of \(A\) are equivalent:

+
    +
  • \(aRb\).
  • +
  • \([a]_R = [b]_R\).
  • +
  • \([a]_R\cap [b]_R\neq \emptyset\).
  • +
+

Partition: A partition \(\mathit{pr}(A) = \{A_i\vert i\in I\}\) of a set \(A\) is a collection of disjoint nonempty subsets of \(A\) whose union is \(A\). In other words, the collection of subsets \(A_i\) where \(i\in I\) (\(I\) is an index set), forms a partition of \(A\) if and only if

+
    +
  • \(A = \cup_{i\in I}A_i\).
  • +
  • \(A_i\neq \emptyset\) for all \(i\in I\).
  • +
  • \(A_i\cap A_j = \emptyset\) for all \(i\neq j\).
  • +
+

Theorem 2: Let \(R\) be an equivalence relation on a set \(A\). Then the equivalence classes of \(R\) form a partition of \(A\). Conversely, given a partition \(\mathit{pr}(A) = \{A_i\vert i\in I\}\) of the set \(A\), there is an equivalence relation \(R\) on \(A\) such that the equivalence classes of \(R\) are the sets in the partition.

+

Let \(R\) and \(S\) be equivalence relations on the set \(A\), then \(R\cap S\) is also an equivalence relation on \(A\).

+
    +
  • Reflexive: \((a, a)\in R\) and \((a, a)\in S\), then \((a, a)\in R\cap S\).
  • +
  • Symmetric: Since \(R^{-1} = R\) and \(S^{-1} = S\), then \((R\cap S)^{-1} = R^{-1}\cap S^{-1} = R\cap S\).
  • +
  • Transitive: Since \(R\) and \(S\) are transitive, then \(R^2\subseteq R\) and \(S^2\subseteq S\), then \((R\cap S)^2 = R^2 \cap R\circ S\cap S \circ R \cap R^2 \subseteq R\cap S\). Then \(R\cap S\) is transitive.
  • +
+

However, \(R\cup S\) is not necessarily an equivalence relation. It is indeed reflexive and symmetric. And \((R\cup S)^*\) is an equivalence relation.

+

9.6 Partial Orderings

+

Partial Ordering: A relation \(R\) on a set \(A\) is called a partial ordering or partial order if and only if \(R\) is reflexive, antisymmetric and transitve. A set with a partial ordering is called a partially ordered set or poset and denoted by \((A, R)\).

+

Comparability: The elements \(a\) and \(b\) of a poset \((S, \leq)\) are comparable if and only if either \(a\leq b\) or \(b\leq a\). Otherwise, \(a\) and \(b\) are incomparable.

+

Total Ordering: A partial ordering \(R\) on a set \(A\) is called a total ordering or total order if and only if for all \(a, b\in A\), either \(aRb\) or \(bRa\). A totally ordered set is called a chain.

+

Well-ordered: A set \(A\) with a partial ordering \(R\) is called well-ordered if and only if \(R\) is totally ordered and every nonempty subset of \(A\) has a least element.

+

Lexicographic Order

+

Hasse Diagram: A Hasse diagram is a visual representation of a partial ordering that leaves out edges that must be present because of the reflexive and transitive properties.

+

Hasse Diagram Terminology: \(a\) is a maximal in \((A, \leq)\) if there is no \(b\in A\) such that \(a\leq b\).

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Math/Discrete Mathematics/10 Graph Theory/index.html b/Math/Discrete Mathematics/10 Graph Theory/index.html new file mode 100644 index 0000000..68f0851 --- /dev/null +++ b/Math/Discrete Mathematics/10 Graph Theory/index.html @@ -0,0 +1,1655 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Graph Theory - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Part 10 Graph Theory

+
+

约 3221 个字 12 行代码 预计阅读时间 11 分钟

+
+

10.1 Graphs and Graph Models

+

Graph: A graph \(G = (V, E)\) consists of a nonempty set of Vertices/Nodes \(V\) and a set of Edges \(E\). Each edge has either one or two vertices associated with it, called its Endpoints. An edge is said to connect its endpoints. If the edges connect only one vertex, it is called a Loop.

+

Simple Gpaph: A graph in which each edge connects two different vertices and no two edges connect the same pair of vertices.

+

Multigraph: A graph that may have multiple edges connecting the same vertices.

+

Pseudograph: A graph that may have loops, and possibly multiple edges connecting the same pair of vertices.

+

Directed Graph/Digraph: A graph \((V,E)\) consists of a nonempty set of vertices \(V\) and a set of Directed Edges/Arcs \(E\). Each directed edge is associated with ann ordered pair of vertices. The directed edge associated with the ordered pair \((u,v)\) is said to start at \(u\) and end at \(v\).

+

10.2 Graph Terminology and Special Types of Graphs

+

For an undirected graph \(G = (V, E)\):

+
    +
  • Two vertices, \(u\) and \(v\) in an undirected graph \(G\) are called adjacent (or +neighbors) in \(G\), if \(\{u, v\}\) is an edge of \(G\).
  • +
  • An edge \(e\) connecting \(u\) and \(v\) is called incident with vertices \(u\) and \(v\), or is +said to connect \(u\) and \(v\).
  • +
  • The vertices \(u\) and \(v\) are called endpoints of edge \(\{u, v\}\).
  • +
  • The degree of a vertex in an undirected graph is the number of edges incident with it, except that a loop at a vertex contributes twice to the degree of that vertex. The degree of \(v\) is denoted by \(deg(v)\). If \(\deg(v) = 0\), then \(v\) is isolated. If \(\deg(v) = 1\), then \(v\) is pendant.
  • +
  • The set of all neighbors of a vertex \(v\) of \(G\), denoted by \(N(v)\), is called the neighborhood of \(v\). If \(A\) is a subset of \(V\), we denote by \(N(A)\) the set of all vertices in \(G\) that are adjacent to at least one vertex in \(A\). So, \(N(A) = \cup_{v\in A} N(v)\).
  • +
+

The Handshaking Theorem: Let \(G = (V, E)\) be an undirected graph with \(e\) edges. Then

+
\[\sum_{v\in V}\deg(v) = 2e.\]
+

Theorem 2: An undirected graph has an even number of vertices of odd degree.

+

For a directed graph \(G = (V, E)\):

+
    +
  • Let \((u, v)\) be an edge in \(G\). Then \(u\) is an initial vertex and is adjacent to \(v\) and \(v\) is a terminal vertex and is adjacent from \(u\).
  • +
  • The in degree of a vertex \(v\), denoted \(\deg^-(v)\) is the number of edges which terminate at \(v\).
  • +
  • Similarly, the out degree of \(v\), denoted \(deg^+(v)\), is the number of edges which initiate at \(v\).
  • +
+

Theorem 3: Let \(G = (V, E)\) be a directed graph. Then

+
\[\sum_{v\in V}\deg^-(v) = \sum_{v\in V}\deg^+(v) = |E|.\]
+

Some special simple graphs:

+
    +
  • Complete Graph - \(K_n\): A simple graph with \(n\) vertices and exactly one edge between each pair of distinct vertices.
  • +
  • Cycles - \(C_n\): A simple graph with \(n\) vertices and \(n\) edges that form a cycle.
  • +
  • Wheels - \(W_n\): Add one additional vertex to the cycle \(C_n\) and add an edge from each vertex in \(C_n\) to the new vertex to produce \(W_n\).
  • +
  • \(n\)-Cubes - \(Q_n\): \(Q_n\) is the graph with \(2^n\) vertices representing bit strings of length \(n\). An edge exists between two vertices that differ in exactly one bit position.
  • +
  • Bipartite Graph: A graph \(G = (V, E)\) is bipartite if \(V\) can be partitioned into two disjoint sets \(V_1\) and \(V_2\) such that every edge in \(E\) connects a vertex in \(V_1\) to a vertex in \(V_2\). There are no edges which connect vertices in the same set.
  • +
  • Complete Bipartite Graph - \(K_{m, n}\): The complete bipartite graph \(K_{m, n}\) is the simple graph that has its vertex set partitioned into two disjoint subsets \(V_1\) and \(V_2\) of size \(m\) and \(n\) respectively, and every vertex in \(V_1\) is adjacent to every vertex in \(V_2\).
  • +
  • Regular Graph: A graph in which each vertex has the same degree \(n\) is called an \(n\)-regular graph.
  • +
+

Theorem 4: A simple graph is bipartite if and only if it is possible to assign one of two different colors to each vertex of the graph so that no two adjacent vertices have the same color.

+

Matching: A matching \(M\) in a simple graph \(G = (V, E)\) is a subset of \(E\) such that no two edges are incident with the same vertex.

+

A Maximum matching is a matching with the largest number of edges.

+

We say that a matching \(M\) in a bipartite graph \(G = (V, E)\) with bipartition \((V_1, V_2)\) is a complete matching from \(V_1\) to \(V_2\) if every vertex in \(V_1\) is an endpoint of an edge of the matching.

+

Hall's Marriage Theorem: The bipartite graph \(G = (V, E)\) with bipartition \((V_1, V_2)\) has a complete matching from \(V_1\) to \(V_2\) if and only if \(\vert N(A)\vert \geqslant \vert A\vert\) for all subsets \(A\) of \(V_1\). A vertex that is the endpoint of an edge of a matching \(M\) is said to be matched by \(M\).

+

A good but long proof.

+

Proof:

+
    +
  • If part:
  • +
  • Only if part:
  • +
+

For \(G = (V, E)\) and \(H = (W, F)\).

+
    +
  • \(H\) is a subgraph of \(G\) if \(W \subseteq V\) and \(F \subseteq E\).
  • +
  • \(H\) is a proper subgraph of \(G\) if \(H\) is a subgraph of \(G\) and \(H \neq G\).
  • +
  • \(H\) is a spanning subgraph of \(G\) if \(W = V\) and \(F \subset E\).
  • +
  • \(H\) is a subgraph induced by a subset \(W\) of \(V\) if \(F\) contains an edge in \(E\) is and only if its endpoints are in \(W\).
  • +
  • The union of two graphs \(G\) and \(H\) is the simple graph \(G\cup H\) with the vertex set \(V \cup W\) and edge set \(E \cup F\).
  • +
+

10.3 Representing Graphs and Graph Isomorphism

+

Adjacency Matrix: A simple graph \(G = (V, E)\) with \(n\) vertices \((v_1,v_2,\cdots, v_n)\) can be represented by its adjacency matrix, A, with respect to this listing of the vertices, where

+
\[ + a_{ij} = \begin{cases} 1 & \text{if } \{v_i, v_j\} \text{ is an edge} \\ + 0 & \text{otherwise} \end{cases} +\]
+

For multigraphs and pseudographs, the adjacency matrix is defined similarly, but the entries can't be just \(0\) or \(1\) anymore.

+

Incidence Martix: Let \(G = (V, E)\) be an undirected graph. Suppose that \(v_1, v_2, \cdots, v_n\) are the vertices and \(e_1, e_2, \cdots, e_m\) are the edges of \(G\). Then the incidence matrix with respect to this ordering of \(V\) and \(E\) is \(n\times m\) matrix \(M = [m_{ij}]_{n\times m}\), where

+
\[ + m_{ij} = + \begin{cases} 1 & \text{when edge } e_j \text{ is incident with } v_i \\ + 0 & \text{otherwise} \end{cases} +\]
+

Isomorphism of Graphs: Graphs with the same structure are said to be isomorphic. Formally, two simple graphs \(G_1= (V_1, E_1)\) and \(G_2= (V_2, E_2)\) are isomorphic if there is a \(1-1\) and onto bijection \(f\) from \(V_1\) to \(V_2\) such that for all \(a\) and \(b\) in \(V_1\), \(a\) and \(b\) are adjacent in \(G_1\) iff \(f(a)\) and \(f(b)\) are adjacent in \(G_2\). Such a function \(f\) is called an isomorphism.

+

In other words, when two simple graphs are isomorphic, there is a one-to-one correspondence between vertices of the two graphs that preserves the adjacency relationship.

+

Important Invariants:

+
    +
  • The number of vertices;
  • +
  • The number of edges;
  • +
  • The degrees of the corresponding vertices;
  • +
  • If one is bipartite, the other must be bipartite;
  • +
  • If one is completed, the other must be complete;
  • +
+

10.4 Connectivity

+

A path of length \(n\) in a simple path is a sequence of vertices \(v_0, v_1, \cdots, v_n\) such that \(\{v_0, v_1\}\), \(\{v_1, v_2\}\), \(\cdots\), \(\{v_{n-1}, v_n\}\) are \(n\) edges of the graph.

+

The path is a circuit if the beginning and ending vertices are the same and the length of the path is greater than \(0\).

+

A path is simple if it doesn't contain the same edge more than once.

+

A path of length \(n\) in a directed graph is a sequence of vertices \(v_0, v_1, \cdots, v_n\) such that \((v_0, v_1)\), \((v_1, v_2)\), \(\cdots\), \((v_{n-1}, v_n)\) are \(n\) edges of the graph. Circuits, cycles and simple paths are defined as before.

+

Theorem 5: The number of different paths of length \(r\) from \(v_i\) to \(v_j\) is equal to the \((i, j)\) entry in the matrix \(A^r\), where \(A\) is the adjacency matrix of the graph. Easy to prove.

+

Connected Graph: An undirected graph is connected if there is a path between every pair of distinct vertices of the graph.

+

Theorem 6: There is a simple path between every pair of distinct vertices in a connected undirected graph. Just the definition.

+

Components: The maximally connected subgraphs of \(G\) are called the connected components or just the components.

+

Cut Vertex/Articulation Point: A vertex is a cut vertex or articulation point if removing it and all edges incident with is results in more connected compotents than the original graph.

+

Similarly, if removal of an edge results in more connected components, then the edge is a cut edge or a bridge.

+

Strongly Connected: A directed graph is strongly connected if there is a directed path from \(u\) to \(v\) and a directed path from \(v\) to \(u\) for every pair of vertices \(u\) and \(v\) in the graph.

+

Weakly Connected: A directed graph is weakly connected if the underlying undirected graph is connected. Every strongly connected graph is weakly connected.

+

Strongly Connected Components: For a directed graph, the maximal strongly connected subgraphs are called the strongly connected components.

+

Left issues: Kosaraju's algorithm and Tarjan's algorithm.

+

Some Other Invariants:

+
    +
  • The number and size of connected components;
  • +
  • Paths;
  • +
  • Two graphs are isomorphic only if they have simple circuits of the same length;
  • +
  • Two graphs are isomorphic only if they contain paths that go through vertices so that the corresponding vertices in the two graphs have the same degree.
  • +
+

10.5 Euler and Hamilton Paths

+

Euler Path: An Euler Path is a simple path containing every edge in \(G\).

+

Euler Circuit: An Euler Circuit is not only an Euler path but also a circuit.

+

Euler Graph: A graph that contains an Euler circuit is called an Euler graph.

+

Theorem 7: A connected multigraph has an Euler circuit if and only if each of its vertices has even degree.

+

Proof:

+
    +
  • Necessary Condition:
  • +
  • Sufficient Condition:
  • +
+

Build and Find a Euler Circuit and Path:

+
    +
  • Start from a vertex that has even degree.
  • +
  • Add paths that from a circuit until you can't add any more.
  • +
  • Ommitting all the edges that have been used, find a vertex that has an odd degree and repeat the process.
  • +
+

This will produce an Euler circuit, since every path is included and no edge is included more than once.

+

Theorem 8: A connected multigraph has an Euler path but not an Euler circuit if and only if it has exactly two vertices of odd degree.

+

Theorem 9: A directed multigraph having no isolated vertices has an Euler circuit if and only if the graph is weakly connected and the in-degree and out-degree of each vertex are equal.

+
+

所有顶点的出度入度相等的弱联通有向多图有欧拉回路。

+
+

Theorem 10: A directed multigraph having no isolated vertices has an Euler path but not an Euler circuit if and only if:

+
    +
  • the graph is weakly connected;
  • +
  • the in-degree and out-degree of each vertex are equal for all but two vertices, one that has in-degree \(1\) larger than its out-degree and the other that has out-degree \(1\) larger than its in-degree.
  • +
+
+

没法翻译了,太抽象了。

+
+

Hamilton Path: A Hamilton path in a graph \(G\) is a path which visits every vertex exactly once.

+

Hamilton Circuit: A Hamilton circuit is a circuit that visits every vertex exactly once except for the first vertex.

+

Hamilton Graph: A graph that contains a Hamilton circuit is called a Hamilton graph.

+

Theorem 11 (DIRAC): If \(G\) is a simple graph with \(n\) vertices \((n \geqslant 3)\) and if the degree of each vertex is at least \(n/2\), then \(G\) has a Hamilton circuit.

+

Theorem 12 (ORE): If \(G\) is a simple graph with \(n\) vertices \((n \geqslant 3)\) and if for every pair of nonadjacent vertices \(u\) and \(v\) of \(G\), the sum of the degrees of \(u\) and \(v\) is at least \(n\), i.e. \(\deg(u) + \deg(v) \geqslant n\), then \(G\) has a Hamilton circuit.

+

Necessary Condition for Hamilton Path and Halmiton Circuit: For undirected graph: The necessary condition for the existence of Hamilton path:

+
    +
  • \(G\) is connected;
  • +
  • There are at most two vertices which degree are less than \(2\).
  • +
+

The necessary condition for the existence of Hamilton circuit:

+
    +
  1. +

    The degree of each vertex is larger than \(1\).

    +

    Some properties:

    +
      +
    • If a vertex in the graph has degree two, then both edges that are incident with this vertex must be part of any Hamilton circuit.
    • +
    • When a Hamilton circuit is being constructed and this circuit has passed through a vertex, then all remaining edges incident with this vertex, other than the two used in the circuit , can be removed from consideration.
    • +
    +
  2. +
  3. +

    \(G\) is a Hamilton graph, for any nonempty subset \(S\) of set \(V\), the number of connected components in \(G-S\) does not exceed \(\vert S\vert\).

    +
  4. +
+

10.6 Shortest Path Problems

+

Weighted Graph: \(G = (V, E, W)\), where \(W\) is a function that assigns a real number \(W(e)\) to each edge \(e\) in \(E\). The number \(W(e)\) is called the weight of edge \(e\).

+

Length of a Path: The length of a path in a weighted graph is the sum of the weights of the edges in the path.

+

Shortest Path: The shortest path between two vertices \(u\) and \(v\) in a weighted graph is a path of minimum length between \(u\) and \(v\).

+
    +
  1. +

    For undirected graphs with positive graphs: Dijkstra's Algorithm.

    +

    Theorem 13: Dijkstra’s algorithm finds the length of a shortest path between two vertices in a connected simple undirected weighted graph.

    +

    Theorem 14: Dijkstra’s algorithm uses \(O(n^2)\) operations (additions and comparisons) to find the length of the shortest path between two vertices in a connected simple undirected weighted graph.

    +
  2. +
  3. +

    Floyd's Algorithm: Allow negative weights but no negative cycles.

    +
     1
    + 2
    + 3
    + 4
    + 5
    + 6
    + 7
    + 8
    + 9
    +10
    +11
    +12
    Procedure Floyd(G: weighted simple graph):
    +    {G has vertices v_1, ..., v_n and weights w(v_i, v_j) with
    +     w(v_i, v_j) = infty if {v_i, v_j} is not an edge}
    +    for i := 1 to n:
    +        for j := 1 to n:
    +            d(v_i, v_j) := w(v_i, v_j)
    +    for i := 1 to n:
    +        for j := 1 to n:
    +            for k := 1 to n:
    +                if d(v_j, v_i) + d(v_i, v_k) < d(v_j, v_k):
    +                    then d(v_j, v_k) := d(v_j, v_i) + d(v_i, v_k)
    +{d(v_i, v_j) is the length of a shortest path between v_i and v_j}
    +
    +
  4. +
+

10.7 Planar Graphs

+

Planar Graphs: A graph is called planar if it can be drawn in the plane without any edges crossing. Such a drawing is called a planar representation of the graph.

+

Region: A region is a part of the plane completely disconnected off from other parts of the plane by the edges of the graph. We have Bounded Region and Unbounded Region.

+

There is one unbounded region in a planar graph.

+

Theorem 15 (Euler's Formula): Let \(G\) be a connected planar simple graph with \(e\) edges and \(v\) vertices. Let \(r\) be the number of regions in a planar representation of \(G\). Then \(r=e-v+2\).

+

Proof: OMITTED.

+

Degree of a Region: Suppose \(R\) is a region of a connected planar simple graph, the number of the edges on the boundary of \(R\) is called the Degree of \(R\), denoted by \(\mathrm{Deg}(R)\).

+

Corollary: If \(G\) is a connected planar simple graph with \(e\) edges and \(v\) vertices where \(v\geqslant 3\), then \(e\leqslant 3v-6\). The equality holds if and only if every region has exactly three edges.

+

Proof: From \(2e = \sum \mathrm{Deg}(R) > 3r\), we can derive \(r \leqslant \dfrac{2e}{3}\). Under the Euler's formula, we have \(r = e - v + 2\), so \(e - v + 2 \leqslant \dfrac{2e}{3}\), which means \(e \leqslant 3v - 6\).

+

Corollary: If \(G\) is a connected planar simple graph, then \(G\) has a vertex of degree not exceeding five.

+

Corollary: If a connected planar simple graph has \(e\) edges and \(v\) vertices with \(v\geqslant 3\) and no circuits of length \(3\), then \(e \leqslant 2v-4\). Generally, if every region of a connected planar simple graph has at least \(k\) edges, then

+
\[e \leqslant \frac{k(v - 2)}{k - 2}.\]
+

Elementary Subdivision: If a graph is planar, so will be any graph obtained by removing an edge \(\{u, v\}\) and adding a new vertex \(w\) together with edges \(\{u, w\}\) and \(\{w, v\}\). Such an operation is called an elementary subdivision.

+
+

移除度为 2 的顶点或者在边上加一个顶点。

+
+

Homeomorphic: The graph \(G_1=(V_1,E_1)\) and \(G_2=(V_2,E_2)\) are called homeomorphic if they can be obtained from the same graph by a sequence of elementary subdivision.

+

Theorem 16 (KURATOWSKI): A graph is nonplanar if and only if it contains a subgraph homeomorphic to \(K_{3,3}\) or \(K_5\).

+

10.8 Graph Coloring

+

Each map in the plane can be represented by a graph, namely the dual graph of the map.

+
    +
  • Each region of the map is represented by a vertex.
  • +
  • An edge connect two vertices if the regions represented by these vertices have a common border.
  • +
  • Two regions that touch at only one point are not considered adjacent.
  • +
+

Coloring: A coloring of a simple graph is the assignment of a color to each vertex of the graph so that no two adjacent vertices are assigned the same color.

+

Chromatic number/色数: The Chromatic number of a graph is the least number of colors needed for a coloring of this graph, denoted by \(x(G)\).

+

The Four Color Theorem: Every planar graph is \(4\)-colorable.

+

10.9 Netflow

+

Flowgraph: Directed graph with distinguished vertices s/source and t/sink.

+

Capacities on the edges: \(:c(e) \geqslant 0\).

+

Target: Maximize the flow from \(s\) to \(t\) with the constraint that the flow on each edge does not exceed its capacity.

+

Cut: Partition of \(V\) into disjoint sets \(S\), \(T\) with \(s\) in \(S\) and \(t\) in \(T\).

+

\(Cap(S, T)\): Sum of the capacities of edges from \(S\) to \(T\).

+

\(Flow(S, T)\): Net flow out of \(S\), i.e. the sum of flows out of \(S\) minus sum of flows into \(S\).

+

Residual Graph: For flow graph \(G\), the residual graph \(G_f\) is defined as follows:

+
    +
  • \(G\): Edge \(e\) from \(u\) to \(v\) with capacity \(c\) and flow \(f\).
  • +
  • \(G_R\): Edge \(e\) from \(v\) to \(u\) with capacity \(f\).
  • +
  • \(G_R\): Edge \(e\) from \(u\) to \(v\) with capacity \(c-f\).
  • +
+

Argumenting Path: A path from \(s\) to \(t\) whose flow can be increased. Iff for all edges \(f(u, v) < c(u, v)\) and \(f(v, u) > 0\).

+

Ford-Fulkerson Algorithm: Build argument path until there is no forward path from source to sink.

+

Augmenting path theorem: Flow \(f\) is a max flow iff there are no augmenting paths.

+

Max-flow Min-cut Theorem: The value of the max flow equals the capacity of the min cut.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Math/Discrete Mathematics/11 Trees/index.html b/Math/Discrete Mathematics/11 Trees/index.html new file mode 100644 index 0000000..20bc436 --- /dev/null +++ b/Math/Discrete Mathematics/11 Trees/index.html @@ -0,0 +1,1407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Trees - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Part 11 Trees

+
+

约 510 个字 14 行代码 预计阅读时间 2 分钟

+
+

11.1 Introduction to Trees

+

I assume you have learned FDS.

+

11.2 Application of Trees

+

Prefix Codes: To ensure that no bit string corresponds to more than one sequence of letters, the bit string for a letter must never occur as the first part of the bit string for another letter. Codes with this property are called prefix codes.

+

We can use a binary tree to construct prefix codes: The left edge and the right edge at each internal vertex are labeled by 0 and 1 respectiely.

+

Huffman Coding: Minimize the average number of bits per letter: \(\mathrm{min}(f_1l_1 + f_2l_2 + \cdots + f_nl_n)\), where \(f_i\) is the frequency of the \(i\)th letter and \(l_i\) is the length of the code for the \(i\)th letter.

+
+

出现概率最小的两棵树最小在右,第二小在左。

+
+

11.3 Tree Traversal

+

I assume you have learned FDS.

+

11.4 Spanning Trees

+

Spanning Tree: Let \(G\) be a simple graph. A spanning tree of \(G\) is a subgraph of \(G\) that is a tree containing every vertex of \(G\).

+

Find a Spanning Tree: By removing edges from simple circuits in \(G\).

+

Theorem: A simple graph is connected if and only if it has a spanning tree.

+

Proof:

+

Depth-First Search (DFS): A procedure that forms a rooted tree, and the underlying graph is a spanning tree.

+
    +
  1. Arbitrarily choose a vertex of the graph as root.
  2. +
  3. Form a path starting at this vertex by successively adding edges, where each new edge is incident with the last vertex in the path and a vertex not already in the path.
  4. +
  5. Continue adding edges to this path as long as possible.
  6. +
  7. If the path goes through all vertices of the graph, the tree consisting of this path is a spanning tree.
  8. +
  9. If the path does not go through all vertices, more edges must be added. Move back to the next to last vertex in the path, if possible, form a new path starting at this vertex passing through vertices that were not already visited. If this cannot be done, move back another vertex in the path. Repeat this process.
  10. +
+

Breadth-First Search (BFS):

+
    +
  1. Arbitrarily choose a vertex of the graph as a root, and add all edges incident to this vertex.
  2. +
  3. The new vertices added at this stage become the vertices at level 1 in the spanning tree. Arbitrarily order them.
  4. +
  5. For each vertex at level 1, visited in order, add each edge incident to this vertex to the tree as long as it does not produce a simple circuit. Arbitrarily order the children of each vertex at level 1. This produces the vertices at level 2 in the tree.
  6. +
  7. Follow the same procedure until all the vertices in the tree have been added.
  8. +
+

11.5 Minimum Spanning Trees

+

Minimum Spanning Tree (MST): A Minimum Spanning Tree in a connected weighted graph is a spanning tree that has the smallest possible sum of weights of its edges.

+

Prim's Algorithm:

+
1
+2
+3
+4
+5
+6
+7
Procedure Prim (G: weighted connected undirected graph with n vertices)
+    T:= a minimum-weight edge 
+    for i:= 1 to n-2 begin
+        e:= an edge of minimum weight incident to a vertex in T and not forming a simple circuit in T if added to T.
+        T:= T with e added
+    end
+endprocedure {T is a minimum spanning tree of G}
+
+

Kruskal's Algorithm:

+
1
+2
+3
+4
+5
+6
+7
procedure Kruskal (G: weighted connected undirected graph with n vertices)
+    T:= empty graph 
+    for i:= 1 to n-1 begin
+        e:= any edge in G with smallest weight that does not form a simple circuit when added to T
+        T:= T with e added
+    end 
+endprocedure {T is a minimum spanning tree of G}
+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Math/Discrete Mathematics/Discrete Mathematics/index.html b/Math/Discrete Mathematics/Discrete Mathematics/index.html new file mode 100644 index 0000000..5521d2d --- /dev/null +++ b/Math/Discrete Mathematics/Discrete Mathematics/index.html @@ -0,0 +1,1296 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Discrete Mathematics - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Discrete Mathematics

+
+

约 167 个字 预计阅读时间 1 分钟

+
+
+

Abstract

+

这是我在2023-2024学年春夏学期修读《离散数学理论基础》的课程笔记。

+

离散数学的内容繁杂,包含逻辑、集合论、图论等内容。对于计算机专业的学生来说,这部分包含的内容更加宽泛,可以说是“在数理基础课上讲不到的都在这了”

+

可能有一些部分还没写完,但是既然考完了,我也不想补了。。。

+

参考书籍:

+
    +
  • 《Discrete Mathematics and Its Applications》 By Kenneth H. Rosen
  • +
  • 《Concrete Mathmatics》 By Ronald L. Graham
  • +
+
+

Table of Contents

+ + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Math/Discrete Mathematics/images/08-01.png b/Math/Discrete Mathematics/images/08-01.png new file mode 100644 index 0000000..2bd3f5a Binary files /dev/null and b/Math/Discrete Mathematics/images/08-01.png differ diff --git a/Math/Discrete Mathematics/images/image.png b/Math/Discrete Mathematics/images/image.png new file mode 100644 index 0000000..6bce031 Binary files /dev/null and b/Math/Discrete Mathematics/images/image.png differ diff --git a/Math/Discrete Mathematics/images/image1-1.png b/Math/Discrete Mathematics/images/image1-1.png new file mode 100644 index 0000000..c418f95 Binary files /dev/null and b/Math/Discrete Mathematics/images/image1-1.png differ diff --git a/Math/Discrete Mathematics/images/image1-2.png b/Math/Discrete Mathematics/images/image1-2.png new file mode 100644 index 0000000..c3ed31c Binary files /dev/null and b/Math/Discrete Mathematics/images/image1-2.png differ diff --git a/Math/Discrete Mathematics/images/image2-1.png b/Math/Discrete Mathematics/images/image2-1.png new file mode 100644 index 0000000..7c9869d Binary files /dev/null and b/Math/Discrete Mathematics/images/image2-1.png differ diff --git a/Math/Discrete Mathematics/images/image3-1.png b/Math/Discrete Mathematics/images/image3-1.png new file mode 100644 index 0000000..c17c674 Binary files /dev/null and b/Math/Discrete Mathematics/images/image3-1.png differ diff --git a/Math/index.html b/Math/index.html new file mode 100644 index 0000000..7bb5a4c --- /dev/null +++ b/Math/index.html @@ -0,0 +1,995 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Basic Courses - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+ +
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Reading/Taking Sides/Sustainability/index.html b/Reading/Taking Sides/Sustainability/index.html new file mode 100644 index 0000000..1def2ae --- /dev/null +++ b/Reading/Taking Sides/Sustainability/index.html @@ -0,0 +1,1037 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Sustainability - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Taking Sides: Clashing Views in Sustainability

+
+

约 39 个字

+
+

Introduction

+

The Brundtland Commission laid out the most famous definition of sustainable development as development that "meets the needs of the present without compromising the ability of future generations to meet their needs."

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Reading/Taking Sides/index.html b/Reading/Taking Sides/index.html new file mode 100644 index 0000000..b1f7b32 --- /dev/null +++ b/Reading/Taking Sides/index.html @@ -0,0 +1,973 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Taking Sides - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Taking Sides

+
+

约 11 个字

+
+
+

Info

+

Taking Sides,亦即《立场》丛书

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Reading/The Western Heritage/Chapter00/index.html b/Reading/The Western Heritage/Chapter00/index.html new file mode 100644 index 0000000..79735f4 --- /dev/null +++ b/Reading/The Western Heritage/Chapter00/index.html @@ -0,0 +1,1010 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Chapter 0 - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 0 : What Is The Western Heritage?

+
+

约 1881 个字 预计阅读时间 6 分钟

+
+

The western heritage emerges from an evolved and evolving story of human actions and interactions, peaceful and violent, that arose in the eastern Mediterranean, then spread across the western Mediterranean into northern Europe, and eventually to the American continents, and in their broadest impact, to the peoples of Africa and Asia as well.

+

The Western Heritage as a distinct portion of world history descends from the ancient Greeks, who saw their own political life based on open discussion of law and policy. The Greeks invented the concept of citizenship, defining it as engagement in some form of self-government. The Greeks also established their conviction that reason can shape and analyze physical nature, politics, and morality.

+

Rome spread its authority through military conquest across the Mediterranean world, embracing Greek literature and philosophy. Romans' conquest and imposition of law created the Western world as a vast empire stretching from Egypt and Syria in the east to Britain in the West. Although the Roman Republic, governed by Senate and popular political institutions (元老院与公众政治机构), gave way to the autocratic rule of Roman Empire, the idea of a free republic law and constitutional (宪法的) arrangements limiting political authority survived centuries of arbitrary (武断专制的、随心所欲的) rule by emperors.

+

Emperor Constantine reorganized the Roman Empire in two fundamental ways: First, he moved the capital from Rome to Constantinople. Thereafter (其后) large portions of the Western empire became subject to the rulers of Germanic tribes. In the confusion of these times, most of the texts embodying ancient philosophy, literature, and history became lost in the West, and for centuries Western Europeans became intellectually severed from that ancient heritage. Second, Constantine's recognition of Christianity as the official religion of the empire.

+

康斯坦丁将基督教作为帝国的官方宗教,由于基督教是单神论宗教,康斯坦丁对基督教的接纳导致了异端多神论宗教的消亡。此后,西方世界或多或少的都有与基督教相连,或者与承认罗马主教为首的基督教会相连。

+

随着皇权逐渐崩溃,主教变成了西欧许多区域的事实上的统治者,但是基督教会从未在未与世俗的统治者协商或者冲突的情况下加以统治,并且宗教法也没有取代世俗法,况且世俗的统治者也无法在忽略教会的影响下加以统治。Hence, from the fourth century C.E. to the present day, rival claims to political and moral authority between ecclesiastical and political officials have characterized the west.

+

In the seventh century, the rise of Islam, a new monotheistic religion, which spread rapidly through conquests across North Africa and eventually into Spain, confronted a new challenge to the Western World. Christians attempted to reclaim the Holy Land (圣地,亦即巴勒斯坦) from Muslim control in church-inspired military crusades (十字军东征) that still resonate negatively in the Islamic world.

+

However, while intellectual life languished in the West, most of the texts of ancient Greek and Latin learning survived and were studied in the Muslim world. By the fourteenth century, European thinkers redefined themselves and their intellectual ambitions by recovering the literature and science from the ancient world, reuniting Europe with its Graeco-Roman past.

+

From the twelfth through the eighteenth centuries, a new European political system arose based on centralized monarchies (中央集权的君主制) characterized by large armies, navies and bureaucracies loyal to the monarch (忠诚于皇帝的官僚体制), and by the capacity to raise revenues (提升税收). Most of these monarchies recognized both the political role of local or national assemblies drawn from the propertied elites (有产阶级精英) and the binding power of constitutional law on themselves. ** (宪法对于他们自己的约束力) The monarchies, their military, and their expanding commercial economies became the basis for the extension of European and Western influence around the globe.**

+

In the late fifteenth and early sixteenth centuries, two transforming events occurred. The first was the European discovery and the conquest of American continents, thus opening the Americas to Western institutions, religion, and economic exploitation. The labor shortage of Americas led to the forced migration of millions of Africans as slaves to the America. By the mid-seventeenth century the West consequently embraced the entire transatlantic world and its multiracial societies.

+

Second, shortly after the American encounter, a religious schism erupted within Latin Christianity. (基督教分裂) Reformers rejecting both many medieval Christian doctrines as unbiblical and the primacy of the Pope in Rome established Protestant churches across much of northern Europe. (宗教改革者不仅反对许多中世纪的基督教义,认为它们是不符合圣经的,还反对罗马天主教教皇的至高无上的地位,并且在北欧的大部分土地上建立了新教教堂) As a consequence, for almost two centuries religious warfare between Protestants and Roman Catholics overwhelmed the continent as monarchies chose to defend one side or the other. The religious turmoil meant that Europeans who conquered and settled the Americans carried with them particularly energized religious convictions, with **Roman Catholics dominating Latin America and English Protestants most of North America. **

+

By the late eighteenth century, the idea if the West denoted a culture increasingly dominated by two new forces. First, science arising from a new understanding of nature achieved during the sixteenth and seventeenth centuries persuaded growing numbers of the educated elite that human beings can rationally master nature for ever-expanding productive purposes improving the health and well-being of humankind. From this era to the present, the West has been associated with advances in technology, medicine, and scientific research. Second, during the eighteenth century, a drive for economy improvement that vastly increased agricultural production and then industrial manufacturing transformed economic life, especially in Western Europe and later the United States. Both of these economic development went hand in hand with urbanization and the movement of industrial economy into cities where the new urban populations experienced major urban dislocation (社会失序).

+

During the last quarter of eighteenth century, political revolution erupted across the transatlantic world. The British colonies of North America revolted, and then revolution occurred in France and spread across much of Europe. The Wars of Independence liberated Latin America from its European conquerors. Those revolutions created bold new modes of political life, rooting the legitimacy of the state in some form of popular government and generally written constitutions. Thereafter, despite the presence of authoritarian governments on the European continent, the idea of West, now including the new republics of the United States and Latin America, became associated with liberal democratic governments. (这些革命创造了新的政治生活模式,将国家的合法性和某种形式的人民政府和成文宪法联系到了一起。自此之后,除了欧洲大陆某些独裁政府,西方的概念,变得与自由民主的政府联系到了一起。)

+

During the nineteenth century, most major European states came to identify themselves in terms of nationality - language, history, and ethnicity - rather than loyalty to a monarch. Nationalism eventually inflamed popular opinion and unloosed unprecedented political ambition by European governments.

+

These ambitions led to imperialism and the creation of new overseas European empires in the late nineteenth century. For people living in European-administered Asian and African colonies, the idea and reality of the West embodied foreign domination and often disadvantageous involvement in a world economy. Even after colonial peoples around the globe challenged European imperial authority and gained independence, these former colonial peoples often suspected the West of seeking to control them. Hence, anticolonialism like colonialism before it redefined definitions of the West far from its borders.

+

Late nineteenth-century nationalism and imperialism also unleashed with World War I in 1914 unprecedented military hostilities among European nations that spread around the globe, followed a quarter century later by an even greater world war. As one result of World War, revolution occurred in Russia with the establishment of the communist Soviet Union. During the interwar years, a Fascist Party seized power in Italy and a Nazi Party took control of Germany. In response to these new authoritarian regimes, West European powers and the United States identified themselves with liberal democratic constitutionalism, individual freedom, commercial capitalism, science and learning freely pursued, and religious liberty, all of which they defined as the Western Heritage. (将他们自己认为是自由民主立宪政府、拥有个人自由、商业资本主义、拥有追求知识和科学的自由、宗教信仰自由,他们将这些定义为 Western Heritage。)

+

During the Cold War , conceived of as an East-West, democratic versus communist struggle that concluded with the collapse of the Soviet Union in 1991, the Western Powers led by the United States continued to embrace those values in conscious opposition to the Soviet government, which since 1945 had also dominated much of Eastern Europe.

+

Since 1991 the West has again become redefined in the minds of many people as a world political and economic order dominated by the United States. Europe clearly remains the West, but political leadership has moved to Northern America. That American domination and recent American foreign policy have led throughout the West and elsewhere to much criticism of United States.

+

Such self-criticism itself embodies one of the most important and persistent parts of the Western Heritage. From Hebrew prophets and Socrates to the critics of European imperialism, American foreign policy, social inequality, and environmental devastation, voices in the West have again and again been raised to criticize often in the most strident manner the policies of Western governments and the thought, values, social conditions, and the inequalities of Western societies.

+

Consequently, we study the Western Heritage not because the subject always or even primarily presents an admirable picture, but because the study of the Western Heritage like the study of all history calls us to an integrity of research, observation, and analysis that clarifies our minds and challenges our moral sensibilities. The challenge of history is the challenge of thinking, and it is to that challenge that this book invites its readers.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Reading/The Western Heritage/The Western Heritage/index.html b/Reading/The Western Heritage/The Western Heritage/index.html new file mode 100644 index 0000000..e5614dd --- /dev/null +++ b/Reading/The Western Heritage/The Western Heritage/index.html @@ -0,0 +1,1057 @@ + + + + + + + + + + + + + + + + + + + + + + + + + The Western Heritage - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +
+

Info

+

未完工!我会加紧进度的!

+
+
+

Warning

+

本文仅作为本人对《The Western Heritage》一书的笔记,除记录知识以外再无其它意义

+
+

The Western Heritage

+
+

约 170 个字 预计阅读时间 1 分钟

+
+

Chapter 1 The Birth of Civilization

+

Culture may be defined as the ways of living built up by a group and passed on from a generation to another. It includes behavior such as courtship and child-rearing practices; material things such as tools, clothing, and shelter; and ideas, institutions, and beliefs. Language, apparently a uniquely human trait, lies behind our ability to create ideas and institutions and to transmit culture from one generation to another. Our flexible and dexterous hands enable us to hold and make tools and so to create the material artifacts of culture. Because culture is learned and not inherited, it permits rapid adaption to changing conditions, making possible the spread of humanity to almost all the lands of the globe.

+

During the Paleolithic,

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Reading/index.html b/Reading/index.html new file mode 100644 index 0000000..06a4517 --- /dev/null +++ b/Reading/index.html @@ -0,0 +1,937 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Reading - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Reading

+
+

约 47 个字

+
+
+

Abstract

+

在这里的都是我的读书笔记!包括但不限于哲学、历史学、心理学与社会学。

+

当然挖的坑越多就越难填(x

+

加油哦!

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/COAD/COAD/index.html b/System/COAD/COAD/index.html new file mode 100644 index 0000000..bb7b252 --- /dev/null +++ b/System/COAD/COAD/index.html @@ -0,0 +1,1396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + COAD - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

COAD

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/COAD/Chapter1/index.html b/System/COAD/Chapter1/index.html new file mode 100644 index 0000000..442b4da --- /dev/null +++ b/System/COAD/Chapter1/index.html @@ -0,0 +1,1425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + COAD-Computer Abstractions and Technology - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Computer Abstractions and Technology

+
+

约 4 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/COAD/Chapter2/index.html b/System/COAD/Chapter2/index.html new file mode 100644 index 0000000..ff267ce --- /dev/null +++ b/System/COAD/Chapter2/index.html @@ -0,0 +1,1940 @@ + + + + + + + + + + + + + + + + + + + + + + + + + COAD-Arithmetic for Computers - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Instructions: Language of the Computer

+
+

约 271 个字 143 行代码 预计阅读时间 3 分钟

+
+

Temporary Variables

+

在 RV32I 之中只有寄存器 x5 x6 x7 是临时寄存器,被命名为 t0 t1 t2,这些寄存器可以用于存储临时变量或者任意修改,同时可以将临时变量存储在栈之中,这就需要调整栈指针 x2 也就是 sp 的值。下面是几个例子:

+
1
+2
+3
+4
+5
+6
int a = 5;
+char b[] = "string";
+int c[10];
+uint8_t d = b[3];
+c[4] = a + d;
+c[a] = 20;
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
# a in 0(sp), b in 4(sp), c in 12(sp), d in 52(sp)
+addi    sp, sp, -56
+li      t0, 5
+sw      t0. 0(sp)       # a = 5
+li      t0, 0x69727473
+sw      t0, 4(sp)
+li      t0, 0x0000676E
+sw      t0, 8(sp)       # b = "string"
+lb      t0, 7(sp)
+sb      t0, 52(sp)      # d = b[3]
+lw      t0, 0(sp)
+lbu     t1, 52(sp)
+add     t2, t0, t1
+sw      t2, 28(sp)      # c[4] = a + d
+li      t0, 20
+lw      t1, 0(sp)
+slli    t1, t1, 2       # a * 4
+addi    t1, t1, 12
+add     t1, t1, sp
+sw      t0, 0(t1)       # c[a] = 20     
+
+

Control Flow

+

if-then statements

+
+
if-then in C
1
+2
+3
+4
+5
+6
if (x >= 10)
+    y = x;
+// reduce with goto
+if (x < 10) goto skip;
+    y = x;
+skip: ...
+
+
if-then in RISC-V
1
+2
+3
+4
+5
# assume x in a3, y in a4
+    li  t0, 10
+    blt a3, t0, skip 
+    add a4, a3, zero
+skip: ...
+
+
+

while loop

+

do-while loop

+

for loop

+

使用移位指令与 lw 实现 lbu 指令。

+
1
+2
+3
+4
+5
# lbu using lw: lbu s1, 1(s0)
+lw      s1, 0(s0)       # load word
+li      t0, 0x0000FF00  # load bitmask
+and     s1, s1, t0      # get target byte
+srli    s1, s1, 8       # shift right
+
+

使用移位指令与 sw 实现 sb 指令。

+
1
+2
+3
+4
+5
+6
+7
# sb using sw: sb s1, 3(s0)
+lw      t0, 0(s0)       # load current word
+li      t1, 0x00FFFFFF  # load bitmask
+and     t0, t0, t1      # zero top byte
+slli    t1, s1, 24      # little-endian & shift left
+or      t0, t0, t1      # combine
+sw      s1, 0(s0)       # store
+
+
while ((*q++ = *p++) != '\0') ;
+
+
1
+2
+3
+4
+5
+6
+7
+8
+9
# copy String p to q
+# p -> s0, q -> s1
+loop:
+    lb      t0, 0(s0)       # load byte
+    sb      t0, 0(s1)       # store byte
+    addi    s0, s0, 1       # increment p
+    addi    s1, s1, 1       # increment q
+    bne     t0, x0, loop    # loop if not null
+    j       exit            # exit if null
+
+

Function Calls

+

Six steps of calling a function:

+
    +
  • Put arguments in a place where the function can access them.
  • +
  • Transfer control to the function.
  • +
  • The function will acquire any (local) storage it needs.
  • +
  • The function performs its task.
  • +
  • The function puts the return value in an accessible place and cleans up.
  • +
  • Transfer back the control to the caller.
  • +
+

Arguments registers:

+
    +
  • a0 to a7 for arguments.
  • +
  • a0 and a1 for return values.
  • +
  • sp for the stack pointer, holding the current memory address of the bottom of the stack.
  • +
  • Order of arguments matters.
  • +
  • If need extra arguments, use the stack.
  • +
+

Example:

+
1
+2
+3
+4
+5
+6
+7
+8
+9
void main(void) {
+    int a = 3;
+    int b = a + 1;
+    a = add(a, b);
+}
+
+int add(int x, int y) {
+    return x + y;
+}
+
+
1
+2
+3
+4
+5
+6
+7
main:
+    addi a0, x0, 3
+    addi a1, a0, 1
+    jal  ra, add
+add:
+    add  a0, a0, a1
+    jr   ra
+
+

Basic structure of a function:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
Prologue
+    func_label:
+    addi sp, sp, -framesize
+    sw   ra, (framesize-4)(sp)
+    # store other callee-saved registers
+    # save other regs if needed
+Body
+    # function body
+Epilogue
+    # restore other regs if needed
+    # restore callee-saved registers
+    lw ra, (framesize-4)(sp)
+    addi sp, sp, framesize
+    jr ra   # or ret
+
+

Recursion in RISC-V

+
Factorial in C
1
+2
+3
+4
int factorial(int n) {
+    if (n == 0) return 1;
+    return n * factorial(n-1);
+}
+
+
Factorial in RISC-V
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
factorial:
+    addi sp, sp, -16
+    sw   ra, 12(sp)
+    li   t0, 1
+    blt  a0, t0, else
+    sw   a0, 8(sp)
+    addo a0, a0, -1
+    jal  ra, factorial
+    lw   t0, 8(sp)
+    mul  a0, t0, a0
+    j    fact_end
+else:
+    li   a0, 1
+fact_end:
+    lw   ra, 12(sp)
+    addi sp, sp, 16
+    ret
+
+
Fibonacci in C
1
+2
+3
+4
int fibonacci(int n) {
+    if (n < 2) return 1;
+    return fibonacci(n-1) + fibonacci(n-2);
+}
+
+
Fibonacci in RISC-V
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
fibonacci:
+    li t0, 2                # test if n < 2    
+    blt a0, t0, fib_base    # if n < 2, return 1
+
+    addi sp, sp, -8         # allocate stack space
+    sw   ra, 4(sp)          # store return address
+    sw   a0, 0(sp)          # store original n
+
+    addi a0, a0, -1         # n-1 in a0
+    jal  x1, fibonacci      # calculate fib(n-1)
+
+    lw   t0, 0(sp)          # load original n to t0
+    sw   a0, 0(sp)          # store fib(n-1) to stack
+    addi a0, t0, -2         # now n-2 in a0
+    jal  x1, fibonacci      # calculate fib(n-2)
+
+    lw   t0, 0(sp)          # load fib(n-1) to t0
+    add  a0, a0, t0         # calculate fib(n) = fib(n-1) + fib(n-2)
+    lw   ra, 4(sp)          # load return address
+    addi sp, sp, 8          # clean up stack
+    ret
+
+fib_base:                   # base case, return 1
+    li a0, 1
+    ret
+
+

local Storage for variables

+

Stack Pointer sp holds the address of the bottom of the stack.

+
    +
  • Decrement it (stack grows downwards), and use sw to write to a variable.
  • +
  • To clean up, just increment the stack pointer.
  • +
+
1
+2
+3
+4
# store t0 to the stack
+addi sp, sp, -4  # allocate space
+sw   t0, sp      # store t0
+addi sp, sp, 4   # clean up
+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/COAD/Chapter3/index.html b/System/COAD/Chapter3/index.html new file mode 100644 index 0000000..100b4f5 --- /dev/null +++ b/System/COAD/Chapter3/index.html @@ -0,0 +1,1523 @@ + + + + + + + + + + + + + + + + + + + + + + + + + COAD-Instructions Language of the Computer - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Arithmetic for Computers

+
+

约 3 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/COAD/Chapter4/index.html b/System/COAD/Chapter4/index.html new file mode 100644 index 0000000..c8d28fd --- /dev/null +++ b/System/COAD/Chapter4/index.html @@ -0,0 +1,1404 @@ + + + + + + + + + + + + + + + + + + + + + + + + + COAD-The Processor - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

The Processor

+
+

约 2 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/COAD/Chapter5/index.html b/System/COAD/Chapter5/index.html new file mode 100644 index 0000000..06601a3 --- /dev/null +++ b/System/COAD/Chapter5/index.html @@ -0,0 +1,1404 @@ + + + + + + + + + + + + + + + + + + + + + + + + + COAD-Large and Fast Exploiting Memory Hierarchy - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Large and Fast: Exploiting Memory Hierarchy

+
+

约 6 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/COAD/Supplement/index.html b/System/COAD/Supplement/index.html new file mode 100644 index 0000000..9ab6476 --- /dev/null +++ b/System/COAD/Supplement/index.html @@ -0,0 +1,829 @@ + + + + + + + + + + + + + + + + + + + + + Supplement - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Supplement

+
+

约 99 个字

+
+

Addressing

+
    +
  • Immediate Addressing: The operand directly contains the value we need. ADDI R1, R2, #100 reads the value of R2, adds 100 to it, and stores the result in R1.
  • +
  • Direct Addressing: The operand contains the address of the value we need. LDR R1, 100 reads the value at memory address 100 and stores it in R1.
  • +
  • Indirect Addressing: The operand contains an address, which contains the address of the value we need. LDR R1, (100) the data at the memory location 100 is an address, and we uses the address to read the value.
  • +
  • Register Direct Addressing:
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/CSAPP/index.html b/System/CSAPP/CSAPP/index.html new file mode 100644 index 0000000..a4b1c80 --- /dev/null +++ b/System/CSAPP/CSAPP/index.html @@ -0,0 +1,1486 @@ + + + + + + + + + + + + + + + + + + + + + + + + + CSAPP - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

CSAPP

+
+

约 102 个字

+
+
+

Abstract

+

这是我对《深入理解计算机系统》一书的读书笔记。

+

参考:

+
    +
  • 《深入理解计算机系统》
  • +
  • Computer System: A Programmer's Perspective
  • +
  • CMU 15-213
  • +
+
+

Table of Content

+ + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/Chapter1/index.html b/System/CSAPP/Chapter1/index.html new file mode 100644 index 0000000..85c1ea8 --- /dev/null +++ b/System/CSAPP/Chapter1/index.html @@ -0,0 +1,1559 @@ + + + + + + + + + + + + + + + + + + + + + + + + + CSAPP-A Tour of Computer Systems - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 1 A Tour of Computer Systems

+
+

约 613 个字 预计阅读时间 2 分钟

+
+

1.4.1 Hardware Organization of a System

+

计算机系统的硬件组成包括:总线/BusI/O设备/IO devices主存/Main memory处理器/Processor

+
    +
  • +

    总线是贯穿整个系统的一组电子管道,携带信息字节并负责在各个设备之间传输。总线被设计成传送定长的字节块,被称为字/Word,现代的计算机的字长大多为4个字节/32位或者8个字节/64位。

    +
  • +
  • +

    I/O设备

    +
  • +
  • +

    主存是一个临时存储设备,在处理器执行程序的时候,用来存放程序和程序处理的数据。主存是由一组动态随机存取存储器/Dynamic random access memory/DRAM组成的,在逻辑上看是一个线性的字节数组,每个字节都有唯一的地址,且地址从零开始。

    +
  • +
  • +

    中央处理器单元/Central processing unit简称为处理器,处理器负责解释(或者执行)主存中的指令。处理器的核心是大小为一个字的寄存器/Register,称为程序计数器/Program counter/PC

    +
  • +
+

1.9.1 Amdahl's Law

+

当我们对系统的某个部分加速的时候,其对整个系统性能的影响取决于该部分的重要性和加速程度。特别地,假设系统执行某个应用程序需要的时间为\(T_{old}\),某部分所需执行时间与该时间所用的比例为\(\alpha\),而这部分性能提升的比例为\(k\),改进之后,总的执行时间为

+
\[T_{new}=T_{old}*(1-\alpha)+T_{old}*\alpha/k.\]
+

那么,我们可以的到加速比\(S\)

+
\[S=\frac{T_{old}}{T_{new}}=\frac{1}{(1-\alpha)+\alpha/k}.\]
+

我们同时也考虑极限情况,也就是 \(k\to\infty\) 的情况,此时加速比\(S\)

+
\[S=\frac{1}{1-\alpha}.\]
+

这就是加速比的上界了。

+

总之,Amdahl's Law告诉我们,为了显著提升系统性能,必须提升全系统中相当大的部分的性能

+

1.9.2 Concurrency and parallelism

+

并发(concurrency)和并行(parallelism)是两个不同的概念。并发是一个通用的概念,指一个同时具有多个活动的系统。并行是指使用并发来使一个系统运行得更快。并行可以在计算机系统的多个抽象层次上运用,我们按照系统层次结构中从高到底的顺序重点强调三个层次:

+
    +
  • 线程级并发:使用
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/Chapter10/index.html b/System/CSAPP/Chapter10/index.html new file mode 100644 index 0000000..8ca6c80 --- /dev/null +++ b/System/CSAPP/Chapter10/index.html @@ -0,0 +1,1509 @@ + + + + + + + + + + + + + + + + + + + + + + + + + System-Level I/O - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 10 System-Level I/O

+
+

约 4 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/Chapter11/index.html b/System/CSAPP/Chapter11/index.html new file mode 100644 index 0000000..6ce5a26 --- /dev/null +++ b/System/CSAPP/Chapter11/index.html @@ -0,0 +1,1509 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Network Programming - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 11 Network Programming

+
+

约 4 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/Chapter12/index.html b/System/CSAPP/Chapter12/index.html new file mode 100644 index 0000000..e082125 --- /dev/null +++ b/System/CSAPP/Chapter12/index.html @@ -0,0 +1,1509 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Concurrent Programming - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 12 Concurrent Programming

+
+

约 4 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/Chapter2/index.html b/System/CSAPP/Chapter2/index.html new file mode 100644 index 0000000..147ef71 --- /dev/null +++ b/System/CSAPP/Chapter2/index.html @@ -0,0 +1,1741 @@ + + + + + + + + + + + + + + + + + + + + + + + + + CSAPP-Presenting and Manipulating Information - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Chapter 2 Representing and Manipulating Information

+
+

约 1359 个字 预计阅读时间 5 分钟

+
+
+CMU 15-213 +

Why Bits?

+

Because of electronic implementation: Easy to store bistable elements, and reliable transmitted on noisy and inaccurate wires.

+
+

2.1 Information Storage

+

2.1.6 Introduction to Boolean Algebra

+

十九世纪中期,布尔通过将逻辑值TRUEFALSE编码为二进制值10,能够设计为一种代数,以研究逻辑推理的基本原则,这种代数叫做布尔代数/Boolean algebra

+

布尔代数有四种基本运算~&|^,分别对应于逻辑运算NOTANDOREXCLUSIVE-OR,我们可以列出简单的真值表如下:

+

alt text

+

接下来,我们将上述四个布尔运算推广到位向量/Bit vectors的运算,所谓位向量就是固定长度\(w\),由01组成的串。所谓的推广也非常简单,就是将上述四个布尔运算应用到位向量的每一位上,得到的结果也是一个位向量。换句话说,就是我们在C语言中学的按位运算。

+

2.1.9 Shift Operations in C

+

C语言提供了一组移位运算,右移有两种,算数右移与逻辑右移,算数右移在左侧补上最高位有效值/符号位,逻辑右移在左侧补上0。左移就简单的多,就是在右侧补上0

+

为什么会有两种右移呢?因为两种右移对应着两种不同的数据类型的计算:算数右移对应的是有符号数的计算,逻辑右移对应的是无符号数的计算,这在下面会讲到。

+

2.2 Integer Representations

+

2.2.1 Unsigned Encodings

+

无符号数的编码就是经典的二进制编码,假设一个无符号整数数据有\(w\)位,我们可以将位向量写作\(\vec{x}\),也就是\([x_{w-1},x_{w-2},\cdots,x_0]\)来表示向量的每一位。我们用一个函数\(B2U_w\)(是Binary to Unsigned的缩写)来表示二进制向无符号整数的转换:

+
\[B2U_w(\vec{x}) = \sum_{i=0}^{w-1}x_i2^i.\]
+

我们很容易可以得知:

+
    +
  • \(w\)位能表示的无符号整数的范围为\([0,2^w-1]\)
  • +
  • 函数\(B2U_w\)是一个双射。\(B2U_w\)将每一个长度为\(w\)的位向量映射为唯一的无符号整数,相对地,每一个在区间\([0,2^w-1]\)内的整数都可以唯一表示为一个长度为\(w\)的位向量。
  • +
+

2.2.2 Two's-Complement Encodings

+

最常见的有符号整数编码是补码/Two's-complement编码。在补码编码中,一个\(w\)位的有符号整数\(\vec{x}\)的值可以表示为:

+
\[B2T_w(\vec{x}) = -x_{w-1}2^{w-1}+\sum_{i=0}^{w-2}x_i2^i.\]
+

最高有效位也称为符号位,其权重为\(-2^{w-1}\),其余位的权重和无符号整数编码一样。同样,我们可以得知:

+
    +
  • \(w\)位能表示的有符号整数的范围为\([-2^{w-1},2^{w-1}-1]\)
  • +
  • 函数\(B2T_w\)是一个双射。
  • +
+

类似的,我们可以定义四进制与十六进制的编码。

+

补码编码有十分有趣的特性:

+
    +
  • 补码的范围是不对称的,负数的范围比整数的范围大1,也就是说编码的最小值\(T_{{Min}}\)没有与之对应的整数。
  • +
  • 最大的无符号数值刚刚好比最大值的两倍多一点点\(U{{Max}}_w=2T{Max}_w+1\)。补码的负数的位模式在无符号表示中都变成了比原补码整数大的正数。
  • +
+
+C库里的整数类型 +

在C库中的limits.h中定义了一些常用的整数的最大值与最小值,用来限制编译器运行的不同整型数据的取值范围,例如INT_MAXINT_MINUINT_MAX等。

+

在C库中的stdint.h中定义了一些固定大小的整数类型,例如int8_tuint8_tint16_tuint16_t等,这些类型很好地提升了程序的可移植性。

+
+

有符号数还有下面两种其他的表示方法:

+
    +
  • 反码/Ones'-complement:除了最高位有效的权是\(-(2^{w-1}-1)\),其余和补码是一样的:
  • +
+
\[B2O_w(\vec{x}) = -x_{w-1}(2^{w-1}-1)+\sum_{i=0}^{w-2}x_i2^i.\]
+
    +
  • 原码/Sign-magnitude:最高位是符号位,用来确定剩下的位应该取正权还是取负权,其余位表示数值的绝对值:
  • +
+
\[B2S_w(\vec{x}) = (-1)^{x_w-1}\cdot\left(\sum_{i=0}^{w-2}x_i2^i\right).\]
+

这两种编码方式都有统一的缺点:对于数字0,有两种完全不同的表示方法,并且这两种编码不能很好地支持算数运算,因而,我们现在开始使用更加方便的补码编码。

+
+Numbers to Memory +

对于32位的整型,下面的几个数还是很重要的:U{Max}=4294967295T{Max}=2147483647T{Min}=-2147483648

+

另外,T{Min}被定义为-T{Max}-1而不是-2147483648,这是因为-2147483648在C语言中是对2147483648取负号,而2147483648超出了32位正整型的范围,所以只好用-T{Max}-1来表示。

+
+

2.3 Integer Arithmetic

+

2.3.1 Unsigned Addition

+

2.4 Floating Point

+

2.4.2 IEEE

+

Case 1:规格化值

+

这种情况下阶码的位表示不全为 01

+

Case 2:非规格化值

+

阶码的位表示全为 0,尾数的位表示不全为 0,这时指数 \(E = 1 - \mathrm{bias} = -2^{k-1} + 2\),尾数 \(1\),这时数值表示为 \(1\)

+

Case 3:特殊值

+
    +
  • 阶码全为 1,尾数全为 0,表示无穷大;
  • +
  • 阶码全为 1,尾数非全为 0,表示 NaN
  • +
  • 阶码全为 0,尾数全为 0,表示 0
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/Chapter3/index.html b/System/CSAPP/Chapter3/index.html new file mode 100644 index 0000000..faea045 --- /dev/null +++ b/System/CSAPP/Chapter3/index.html @@ -0,0 +1,2653 @@ + + + + + + + + + + + + + + + + + + + + + + + + + CSAPP-Machine-Level Representation of Programs - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 3 Machine-Level Representation of Programs

+
+

约 3091 个字 33 行代码 预计阅读时间 11 分钟

+
+
+

CMU 15-213

+

这里使用的 x86-64 汇编的形式是 AT&T 语法,而不是 Intel 语法。AT&T 语法与 Intel 语法的区别在于操作数的顺序,AT&T 语法是 source, destination,而 Intel 语法是 destination, source。这种描述的语法会用在 Linux 系统之中,但是当我们阅读 Intel 和 Microsoft 的代码与文档的时候,就要换换脑筋了。

+
+
+Tools: Disassembler +
+

3.4 Accessing Information

+

一个 x86-64 的 CPU 包含一组 16 个存储 64 位值的通用目的寄存器/General-Purpose Registers,这些寄存器可以用来存储整数数据和指针。这些寄存器用来存储整数数据和指针。由于指令集与处理器架构的历史演化,它们的长度从 16 位逐渐变成 64 位,名字也并不规则,但是寄存器的分布保证了令人震惊的向下兼容性。虽然他们的名字是通用目的的,但是根据 x86-64 规定的使用惯例,每个寄存器都有一定的特殊用途,这样就保证了后调用的进程可以接受传递过来的参数,同时运行的过程之中不会覆盖调用进程的寄存器的值。

+

img.png

+

3.5 Arithmetic and Logical Operations

+

3.6 Control

+

3.6.1 Conditional Codes

+

除了整数寄存器,CPU 还维护着一组单个位条件码/Conditional Code 寄存器,他们描述了最近一次算术或者逻辑操作的结果。这些条件码寄存器包括:

+
    +
  • CF/Carry Flag:进位标志。如果最近一次的操作导致了一个无符号数的溢出,这也就是进位,那么 CF 就会被设置为 1。
  • +
  • ZF/Zero Flag:零标志。如果最近一次的操作的结果为 0,那么 ZF 就会被设置为 1。
  • +
  • SF/Sign Flag:符号标志。如果最近一次的操作的结果为负数,那么 SF 就会被设置为 1。
  • +
  • OF/Overflow Flag:溢出标志。如果最近一次的操作导致了一个有符号数/补码的溢出,那么 OF 就会被设置为 1。
  • +
+

以算数操作 t = a + b 举例,设置条件码的操作与逻辑类似于下面的 C 代码:

+
    +
  • CF:(unsigned) t < (unsigned) a
  • +
  • ZF:t == 0
  • +
  • SF:t < 0
  • +
  • OF:((a < 0 ) == (b < 0)) && ((a < 0) != (t < 0))
  • +
+

除了 leaq 指令类以外——因为 leaq 是用来完成地址计算的——所有操作都会隐式的设置操作码。对于逻辑操作而言,进位标志与溢出标志都会被设置成 0。对于移位操作,进位标志被设置成为最后一个被移出的位,溢出标志设置成 0. incdec 指令会会设置溢出标志和零标志,但是不会改变进位标志。

+

cmptest指令类会设置条件码,但是不会改变目的寄存器的值。cmp指令会计算第二个操作数减去第一个操作数的结果,但是不会存储结果。test指令会计算两个操作数的按位与,但是不会存储结果。

+

3.6.2 Accessing the Conditional Codes

+

条件码一般不会直接读取,常用的使用方法有三种:

+
    +
  • 根据条件码的某种组合,将一个字节设置为 0 或者 1,这类指令就是 set 指令。
  • +
  • 可以条件跳转到程序的某个其他的部分。
  • +
  • 可以有条件地传送数据。
  • +
+

3.6.3 Jump Instructions

+

jmp 指令会导致程序执行切换到程序中的一个全新的位置,这些跳转的目的地通常用一个标号来标识。jmp 指令可以是直接跳转,亦即跳转目标是作为指令的一部分编码的,直接在跳转指令后边跟上一个标号作为跳转目标;也可以是间接跳转,亦即跳转目标是从寄存器或者内存之中读出来的。我们还允许有条件的跳转,这就可以对程序进行控制。

+

3.6.4 Implementing Conditional Branches

+

3.6.4.1 Conditional Control

+

3.6.4.2 Conditional Move

+

实现条件操作的传统方法就是通过使用控制的条件转移,当条件满足的时候,就沿着一条路径进行运行,不满足就使用另一种路径。这种策略简单而通用,但是在现代计算机上可能很低效,原因就是现代计算机使用流水线/Pipelining来获得高性能,流水线中,每条指令的处理都被分为了多个小阶段,每个阶段执行操作的一小个部分,通过重叠连续指令的方法来获得高性能,比如在取一条指令的同时,执行前面一条指令的算数运算。要做到这一点,就需要实现确定要执行的指令序列,这样才能保持整个流水线充满了指令,进而保持最优的性能。

+

一旦遇到条件跳转了(也就是分支),流水线处理器就会采用分支预测,猜测每条跳转指令是否会执行,猜对了还好,猜错了就会遇到招致很严重的惩罚,会浪费大约 15~30 个时钟周期,程序性能会大幅下降。为了减少这种性能损失,除了不断提升分支预测的正确率之外,现代处理器会使用条件传送指令,这种指令会根据条件码的值来决定是否传送数据,这样就可以避免分支预测错误的惩罚,并且极大避免随机情况下分支预测的错误。

+

但是条件传送也不总是好的,下面三种情况会让条件传送变得难办:

+
    +
  • 两个计算都很难办,比如对于:val = Test(x) ? Hard1(x) : Hard2(x);,这样我们就要算两个很难算的东西,反而更加浪费时间;
  • +
  • 计算有可能出错,比如对于:val = p ? *p : 0;,这样就有可能会出现段错误;
  • +
  • 计算有副作用,比如对于:val = x > 0 ? x*=7 : x+=13;,这样算出来的结果就不对了。
  • +
+

所以我们的编译器(gcc)当分支的计算比较简单(至少多算一个花费的时间要比预测错误惩罚低)、比较安全并且没有副作用的时候,才会使用条件传送进行优化。

+

3.6.5 Loop

+
+Aside: Reverse engineer loops +
+

3.6.6 Switch

+

switch 语句可以根据一个整数索引值来进行多重分支,我们使用跳转表/Jump Table 这种数据结构来让实现更加高效。跳转表是一个数组,数组的每一个元素都是一个代码段的地址,在代码段内实现当开关的索引值等于 i 的时候程序应该采取的动作。当开关情况值的数量比较大而且跨度比较小的情况下,跳转表是一个很好的选择。

+

下面是描述 switch 的实现的一个例子,右侧依赖了 gcc 对跳转表语法的支持

+
Original Code
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
void switch_eg(long x, long n, long *dest){
+    long val = x;
+    switch (n) {
+        case 100:
+            val *= 13;
+            break;
+        case 102:
+            val += 10; // Fall through
+        case 103:
+            val += 11;
+            break;
+        case 104:
+        case 106:
+            val *= val;
+            break;
+        default:
+            val = 0;
+    }
+    *dest = val;
+}
+
+
Implemented with Jump Table
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
void switch_eg_impl(long x, long n, long *dest){
+    static void *jt[7] = {&&loc_A, &&loc_def, &&loc_B, &&loc_C, &&loc_D, &&loc_def, &&loc_D};
+    unsigned long index = n - 100;
+    long val;
+    if (index > 6) goto loc_def;
+    goto *jt[index];
+    loc_A: val = x * 13; goto done; // case 100
+    loc_B: val = x + 10; // case 102
+    loc_C: val = x + 11; goto done; // case 103
+    loc_D: val = x * x; goto done; // case 104, 106
+    loc_def: val = 0; // default case
+    done: *dest = val;
+}
+
+

3.7 Procedures

+

3.7.1 The Run-Time Stack

+

3.7.2 Control Transfer

+

3.7.3 Data Transfer

+

在 x86-64 中,绝大多数的过程之间的数据传送是通过寄存器实现的,我们可以将被调用过程需要用到的参数按照约定的顺序塞到某些特定的寄存器之中,这样被调用的过程就可以使用这些参数了。类似地,当被调用过程返回的时候,要先将返回值放到特定的寄存器 %rax 之中,这样就可以让调用者使用这个返回值了。

+

在 x86-64 之中,我们可以使用寄存器最多传送 6 个整型(包括整数和指针)参数,寄存器的使用是有特殊顺序的,使用的名字取决于要传递的数据类型的大小,比如 64 位的指针类型就可能用到寄存器 %rdi,并且这个还是作为第一个参数传递,而 32 位的整数就可能用到寄存器 %esi,并且这个还是作为第二个参数传递。下边这个表还是记一下,不然查表很痛苦 (谁愿意看代码的时候被打断呢),不过看多了汇编就会形成肌肉记忆了。

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
操作数大小(位)参数数量
123456
64%rdi%rsi%rdx%rcx%r8%r9
32%edi%esi%edx%ecx%r8d%r9d
16%di%si%dx%cx%r8w%r9w
8%dil%sil%dl%cl%r8b%r9b
+
+

如果有超过 6 个参数,我们就需要使用栈来传递参数了,前 6 个参数照常被复制到寄存器传递,后边的参数依次被放入栈中,参数 7 置于栈顶,所有的数据大小都向着 8 的倍数对齐,所以一般我们不使用 pushq 指令,而是使用 subq 指令来调整栈的大小,然后使用 movq 指令来将参数放入栈中。

+

3.7.4 Local Storage on the Stack

+

有些时候,局部数据必须存储在内存之中,常见的情况包括:

+
    +
  • 寄存器不足够存放所有的本地数据;
  • +
  • 代码之中对某一个局部变量使用了取地址操作 &,而寄存器是没有地址而言的;
  • +
  • 某些局部变量是一个数组或者结构体,这样就需要通过数组和结构引用来访问。
  • +
+

可以通过减小栈指针 %rsp 的方法来在栈上分配空间,一般分配的空间都是 8 字节的倍数,分配的结果作为栈帧的一部分,标号为局部变量。局部变量的存储不需要考虑向 8 的倍数对齐,能存下就行。在程序结束之前,需要将栈指针恢复,释放掉局部变量的空间。

+

3.7.5 Local Storage in Registers

+

3.7.6 Recursive Procedures

+

3.8 Array Allocation and Access

+

3.8.1 Basic Principles

+

3.8.2 Pointer Arithmetic

+

3.8.3 Nested Arrays

+

没啥好说的,多维数组其实就是数组的数组,数组的分配和引用的一般原则也成立,并且会在内存里面分配连续的空间。比如对于声明成 ElementType D[R][C] 的数组,它的数组元素 D[i][j] 的地址就是 &D[i][j] = D + L(C * i + j),其中 L=sizeof(ElementType)

+

3.8.4 Fixed-Size Arrays

+

3.8.5 Variable-Size Arrays

+

3.9 Heterogeneous Data Structures

+

3.9.1 Structures

+

结构的所有组成部分都存放在内存的一段连续的区域内,指向结构的指针就是结构第一个字节的地址。

+

也没啥好说的,只需要知道编译器维护每个字段的字节偏移量进而产生内存引用指令的位移,从而产生对结构元素的引用,进而操纵字段。值得注意的是,结构之中的数组等元素是嵌入在结构之中的,而不是存储指向数组的指针,所以产生结构体 struct {int* i; long array[2];} 需要分配 24 字节的空间,而不是 16 字节。

+

最需要注意的是对齐的问题,下边马上就讲了。

+
+CMU 15-213 +
    +
  1. Structure represented as block of memory, which is big enough to hold all the fields.
  2. +
  3. Field are ordered according to declaration, even if another order could yeild a more compact representation.
  4. +
  5. Compiler determines overall size + positions of fields. Machine-level program has no understanding of the structures in the source code.
  6. +
+
+

3.9.2 Unions

+

联合可以有效规避 C 的类型系统。一个联合的总的大小等于它的最大字段的大小,而不是所有字段的大小之和。联合的字段是共享存储空间的,所以修改一个字段会影响到其他字段。联合的字段的地址都是相同的,所以可以通过一个字段来访问其他字段。联合还可以用来实现类型转换,换句话说就是访问不同数据类型的位模式,比如在联合可以包含一个长整形 long 和一个整数数组 int [2],这样就可以令两个 int 的位组合来表示一个 long

+

3.9.3 Data Alignment

+

数据对齐要求对基本数据类型的合法地址进行了一些限制,要求地址必须是某个值的倍数,这个值一般是 2、4 或 8。这是为了提升内存访问的效率,并且还可以简化处理器和内存之间的接口的硬件设计。基本原则是任何 K 字节的基本对象的地址必须是 K 的倍数。比如 4 字节的整数 int 的地址必须是 4 的倍数,8 字节的双精度浮点数 double 的地址必须是 8 的倍数。编译器会在汇编代码中放入命令,指明全局数据要求的对齐,比如在跳转表前放入伪指令 .align 8,这样就可以保证后边紧接着的的数据的起始地址是 8 的倍数,因为每个表项都长为 8 个字节,所以后边的元素就都遵守 8 字节对齐的限制了,自然而然就对齐了。

+

对于含有结构体的数据,编译器会在字段的分配之中加入间隙,保证每个字段元素都满足对齐要求,并且结构对本身的地址也有一些要求,对齐要求是结构体中最大的字段的对齐要求,比如一个结构体 struct {char c; int i;}c 的对齐要求是 1,i 的对齐要求是 4,所以整个结构体的对齐要求是 4,结构体的地址就要是 4 的倍数。

+
+Aside: Mandatory Alignment +

如果数据没有对齐,某些行好的处理器对于某些实现多媒体操作的 SSE 指令就无法正确执行,这些指令对 16 字节数据块进行操作,在 SSE 单元和内存之间传送数据的指令要求内存地址必须是 16 的倍数,任何以不满足对齐要求的资质访问内存就会导致异常。所以任何针对 x86-64 处理器的编译器和运行时系统都必须保证分配用来保存可能会被 SSE 寄存器读或写的数据结构的内存,都必须满足 16 字节对齐,所以就有下面两个后果:

+
    +
  • 任何内存分配函数,比如 malloc 分配的内存块的起止地址都要是 16 的倍数;
  • +
  • 大多数函数的栈帧边界都必须是 16 的倍数。
  • +
+

这其实也解释了有一些“莫名其妙”在栈上多分配 8 字节内存的现象,这是为了保证栈帧的对齐要求。

+
+

3.10 Combining Control and Data in Machine-Level Programs

+

3.10.1 Understanding Pointers

+

指针类型只不过是 C 提供的一种类型抽象,并不是机器代码的一部分。这里只是介绍一些基本原则:

+
    +
  • 每个指针都对应一个类型,虽然存在通用指针 void *
  • +
  • 每个指针都有一个值,这个值是某个指定类型的地址,地址可以为 0,也就是 NULL
  • +
  • 指针通过对左值使用 & 操作符来获得,反过来,通过对指针使用 * 操作符来间接引用指针;
  • +
  • 将一种指针转换为另外一种指针,只改变它的类型,并不改变它的值;
  • +
  • 甚至存在函数指针,函数指针的值是函数机器代码中第一条指令的地址,对于函数 int func(int x, int* y),可以令一个函数指针 int (*fp)(int, int*) = func,这样就可以通过 fp(1, &x) 来调用函数 func
  • +
+

3.10.2 Using the GDB Debugger

+
+

Important Tool

+
+

3.10.3 Out-of-Bounds Memory References and Buffer Overflow

+

在 Linux 的存储结构之中,栈位于最顶部,尽管 64 位允许访问的空间非常大,由于硬件与 ISA 设计因素,当时(CMU 15-213 fa15 上课时)只能使用 47 位的地址空间,栈底的地址因此是 0x7fffffffffff,并且栈的空间是有限的,一般只有 8MB,我们使用 limit 命令可以查看栈的大小。

+

3.10.4 Thwarting Buffer Overflow Attacks

+

3.10.5 Supporting Variable-Length Stack Frames

+

3.11 Floating-Point Code

+

3.11.1 Floating-Point Movement and Conversion Operations

+

3.11.2 Floating-Point Code in Procedures

+

3.11.3 Floating-Point Arithmetic Operations

+

3.11.4 Defining and Using Floating-Point Constants

+

3.11.5 Using Bitwise Operations in the Floating-Point Code

+

3.11.6 Floating-Point Comparison Operations

+

3.11.7 Observations about Floating-Point Code

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/Chapter4/index.html b/System/CSAPP/Chapter4/index.html new file mode 100644 index 0000000..dca7049 --- /dev/null +++ b/System/CSAPP/Chapter4/index.html @@ -0,0 +1,1404 @@ + + + + + + + + + + + + + + + + + + + + + + + + + CSAPP-Processor Architecture - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 4 Processor Architecture

+
+

约 4 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/Chapter5/index.html b/System/CSAPP/Chapter5/index.html new file mode 100644 index 0000000..124ab88 --- /dev/null +++ b/System/CSAPP/Chapter5/index.html @@ -0,0 +1,1523 @@ + + + + + + + + + + + + + + + + + + + + + + + + + CSAPP-Optimizing Program Performance - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 5 Optimizing Program Performance

+
+

约 5 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/Chapter6/index.html b/System/CSAPP/Chapter6/index.html new file mode 100644 index 0000000..0339b67 --- /dev/null +++ b/System/CSAPP/Chapter6/index.html @@ -0,0 +1,1492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + CSAPP-The Memory Hierarchy - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 6 The Memory Hierarchy

+
+

约 12 个字

+
+

6.1 Storage Technologies

+

6.1.1 Random-Access Memory (RAM)

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/Chapter7/index.html b/System/CSAPP/Chapter7/index.html new file mode 100644 index 0000000..1a7e4f1 --- /dev/null +++ b/System/CSAPP/Chapter7/index.html @@ -0,0 +1,1509 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Linking - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 7 Linking

+
+

约 3 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/Chapter8/index.html b/System/CSAPP/Chapter8/index.html new file mode 100644 index 0000000..8e8fcaf --- /dev/null +++ b/System/CSAPP/Chapter8/index.html @@ -0,0 +1,1509 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Exceptional Control Flow - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 8 Exceptional Control Flow

+
+

约 5 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/Chapter9/index.html b/System/CSAPP/Chapter9/index.html new file mode 100644 index 0000000..be1612f --- /dev/null +++ b/System/CSAPP/Chapter9/index.html @@ -0,0 +1,1509 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Virtual Memory - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chapter 9 Virtual Memory

+
+

约 4 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/CSAPP/Supplement/index.html b/System/CSAPP/Supplement/index.html new file mode 100644 index 0000000..26ffe91 --- /dev/null +++ b/System/CSAPP/Supplement/index.html @@ -0,0 +1,1934 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Supplement - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Supplement

+
+

约 1312 个字 预计阅读时间 4 分钟

+
+

Section 1 Foundations of Digital Logic

+

1.2 数字硬件实现

+

1.2.1 集成电路

+

集成电路/Integrated Circuit是一个硅半导体晶体,包含用来构建逻辑门和存储单元的电子元件,将二极管、晶体管以及其他原件都制作在同一块芯片上,通过陶瓷或者塑料来封装,通过焊接芯片和外界引脚来形成集成电路。

+

CMOS 电路工艺

+

CMOS/互补金属氧化物半导体/Complementary Metal-Oxide Semiconductor工艺具有高密度、高性能与低功耗的优势,是现代数字集成电路的主流工艺。具体观察 CMOS 晶体管的结构,在衬底之上有栅极/Gate,栅极之下有绝缘层/Insulator,绝缘层之下有源极/Source漏极/Drain,源极与漏极之间有一个间隙,一般称之为沟道。CMOS 电路中的晶体管有两种类型:n 沟道晶体管/nMOSp 沟道晶体管/pMOS

+

Section 2 Combinational Logic Circuit

+

2.x 门的传播延迟

+

传播延迟/Propagation delay是信号的变化从输入传播到输出所需要的时间。电路运行速度与电路中经过门的最长传播延迟成反比关系。

+

我们有三个传播延迟参数:高到低的传播时间/High-to-low propagation time\(t_{PHL}\)低到高的传播时间/Low-to-high propagation time\(t_{PLH}\)传播延迟/Propagation delay\(t_{pd}\)

+

在模拟过程对门建模的时候,往往使用传输延迟与惯性延迟。传输延迟/Transport delay是指输出响应输入的变化,在指定的传播延迟之后发生改变。惯性延迟/Inertial delay类似于传输延迟,但是如果输入变化使输出在一个小于拒绝时间/Rejection time的时间内改变,那么两次变化中的第一次将不会发生。拒绝时间是一个确定的值,不大于传播延迟,一般等于传播延迟。

+

Section 3 Sequential Logic Circuit

+

所谓时序逻辑电路,其结果输出不仅仅取决于当前的外界输入,而且取决于系统所处的内部状态,而系统当前的内部状态都是由系统的初态经过前序若干输入信息的处理加工之后到达的状态,所以我们可以认为时序逻辑电路输出的结果不仅仅取决于当前的外部输入,还取决于所有前序输入。但是对于一个简单的电路系统而言,记录所有前序输入是不现实的。通常,我们记录前序输入可能导致的影响结果输出的不同状态,根据这些状态和输入产生的结果输出。

+

处理时序逻辑的重要理论工具是有限状态机/Finite State Machine,有限状态机是一个刻画状态与状态转换的理论工具。在没有任何输入的情况下,系统处于初始状态,随着外部信息的到来,系统状态根据应用逻辑的实际需要,进入相应的下一个状态,系统还可能向外界发出信号,作为对当前输入的响应。

+

为了解决状态记忆问题,我们设计出了双稳态器件记忆状态信息,这就是下面的锁存器与触发器。

+

3.1 时序电路的定义

+

3.2 锁存器与触发器

+

3.2.1 SR 锁存器

+

3.2.2 D 锁存器

+

3.2.3 边沿触发式触发器

+

3.3 时序电路分析

+

3.3.1 输入方程

+

时序电路的逻辑图由触发器与组合逻辑门组成,在组合逻辑电路中,为触发器产生输入信号的组合电路部分可以通过一个布尔函数集合来描述,这个布尔函数集合称为触发器输入方程/Flip-flop Input Equation。组合电路的输出端与触发器的输入端项链,输入方程之中使用带有触发器输出符号的下标的触发器输入符号表示依赖变量,比如\(D_{A}=AX+BX\)就表示本触发器输出为\(A\),输入为\(AX+BX\)

+

3.4.2 状态表与状态图

+

时序电路的输入、输出和触发器状态之间的功能关系可以用一个状态表/State Table列出。状态表由四栏组成,分别是当前状态/Present State输入/Inputs输出/Outputs下一状态/Next State。当前状态表示触发器在任意给定时刻 t 的状态,输入栏表示在当前状态下的输入,下一状态栏指的是触发器在一个时钟周期之后的状态,可以哦由逻辑图或者触发器的输入方程得到,输出栏表示在当前状态与输入的组合下输出的值。

+

我们不得不提到时序逻辑电路的分类:根据输出逻辑对其输入信号依赖情况的不同,时序逻辑电路可以分为Mealy 型电路/Mealy Model CircuitMoore 型电路/Moore Model Circuit。Mealy 型电路的输出取决于当前状态和输入,而 Moore 型电路的输出仅仅取决于当前状态。

+

Section 4 RISC-V

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/DDACA/DDACA/index.html b/System/DDACA/DDACA/index.html new file mode 100644 index 0000000..78de0f7 --- /dev/null +++ b/System/DDACA/DDACA/index.html @@ -0,0 +1,805 @@ + + + + + + + + + + + + + + + + + + + + + Digital Design and Computer Architecture - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Digital Design and Computer Architecture

+
+

约 5 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/DDACA/Digital Logic/index.html b/System/DDACA/Digital Logic/index.html new file mode 100644 index 0000000..095da5f --- /dev/null +++ b/System/DDACA/Digital Logic/index.html @@ -0,0 +1,1375 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Digital Logic - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Digital Logic

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/HDL/Chisel/index.html b/System/HDL/Chisel/index.html new file mode 100644 index 0000000..fcaac1e --- /dev/null +++ b/System/HDL/Chisel/index.html @@ -0,0 +1,1404 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Chisel - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Chisel

+
+

约 1 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/HDL/Verilog/index.html b/System/HDL/Verilog/index.html new file mode 100644 index 0000000..6cf3649 --- /dev/null +++ b/System/HDL/Verilog/index.html @@ -0,0 +1,2648 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Verilog - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Verilog

+
+

约 3032 个字 201 行代码 预计阅读时间 13 分钟

+
+

Chapter 1 Basic Knowledge

+

1.1 FPGA

+

FPGA/Field Programmable Gate Array/现场可编程门阵列:FPGA器属于专用集成电路/ASIC的一种半定制电路,是可以编程的逻辑列阵,可以按照设计人员的需求配置指定的电路结构,让客户不必依赖于芯片制造商设计和制造的专用集成电路就可以实现所需要的功能,同时实现非常高效的逻辑运算。其基本结构包括可编程输入输出单元,可配置逻辑块,数字时钟管理模块,嵌入式块RAM,布线资源,内嵌专用硬核,底层内嵌功能单元。

+

1.2 Verilog

+

Verilog HDL是一种硬件描述语言,用于从算法级、门级到开关级的多种抽象设计层次的数字系统建模。Verilog HDL提供了编程语言接口,通过这个接口可以在模拟、验证期间从设计外部访问设计,包括模拟的具体控制和运行。

+

1.3 数字电路

+

根据逻辑电路的不同特点,数字电路可以分为组合逻辑时序逻辑。其中:

+
    +
  • 组合逻辑的特点是在任意时刻,模块的输出仅仅取决于此时刻的输入,与电路原本的状态无关。电路逻辑中不牵涉边沿信号的处理,也没有记忆性。
  • +
  • 时序逻辑的特点是在任意时刻,模块的输出不仅取决于此时刻的输入,而且还和电路原来的状态有关。电路里面有存储元件用于保存信息。一般仅当时钟的边沿到达时,电路内部存储的信息才有可能发生变化。
  • +
+

Chapter 2 Basic Syntax

+

2.1 数值系统

+

Verilog 这种硬件描述语言都基于基本的硬件逻辑之上,因此 Verilog 具有一套独特的基于电平逻辑的数值系统,使用下面四种基本数值表示电平逻辑:

+
    +
  • 0:表示低电平或者 False;
  • +
  • 1:表示高电平或者 True;
  • +
  • X:表示电平未知,实际情况可能是高电平或者低电平,甚至都不是;
  • +
  • Z:表示高阻态,这种情况就是来源于信号没有驱动。
  • +
+

我们还经常用到整数,可以简单使用十进制表示,也可以使用立即数表示,基于如下的基数规则表示:<bits>'<radix><value>,其中 <bits> 表示二进制位宽,空缺不填就会根据后边的数值自动分配;<radix> 表示进制, <radix> 可以是 b/o/d/h,分别是二进制,八进制,十进制以及十六进制;<value> 表示数值,插入下划线 _ 可以有效提升可读性。

+

2.2 标识符与变量类型

+

wire 用于声明线网型数据。wire 本质上对应着一根没有任何其他逻辑的导线,仅仅将输入自身的信号原封不动地传递到输出端。该类型数据用来表示以 assign 语句内赋值的组合逻辑信号,其默认初始值是 Z(高阻态)。

+

wire 是 Verilog 的默认数据类型。也就是说,对于没有显式声明类型的信号,Verilog 一律将其默认为 wire 类型。

+

wire 的电器特性:

+
    +
  • wire必须被有且仅有一个assign输入;
  • +
  • wire可以有0个或者多个assign输出。
  • +
+

reg用于声明在 always 语句内部进行赋值操作的信号。一般而言,reg 型变量对应着一种存储单元,可以在赋值之间存储数据,其默认初始值是 X(未知状态)。为了避免可能的错误,凡是在 always 语句内部被赋值的信号,都应该被定义成 reg 类型。

+

如果 always 描述的是组合逻辑,那么 reg 就会综合成一根线,如果 always 描述的是时序逻辑,那么 reg 才会综合成一个寄存器/触发器。

+

2.3 运算符

+

按位运算符:

+
    +
  • &:按位与;
  • +
  • |:按位或;
  • +
  • ^:按位异或;
  • +
  • ~:按位取反;
  • +
  • ~^ 或者 ^~:按位同或;
  • +
  • Note:如果运算符的两个操作数位宽不相等,则利用 0 向左扩展补充较短的操作数。
  • +
+

算数运算符:

+

localparamparameter

+

localparam 类似于 C 中的 const 变量,看似是定义了一个变量,其实在生成的时候,只会生成一个立即数代替 localparam 变量。localparam 只能被赋值一次,赋值表达式可以是任意的 localparamparameter 与立即数的计算结果,但不能是电路输出,这就类似于 C++ 的常量表达式 constexpr

+

2.4 模块:结构与例化

+

Verilog 的基本单元就是模块,模块是具有输入输出端口的逻辑块,可以代表一个物理器件,也可以代表一个复杂的逻辑系统,比如基础逻辑门器件或者通用的逻辑单元。一个数字电路系统一般由一个或者多个模块组成,模块化设计将总的逻辑功能分块实现,通过模块之间的互联关系实现所需要的整体系统需求。

+

2.4.1 模块结构

+

所有模块以关键词 module 开始,以关键词 endmodule 结束,从 module 开始到第一个分号的部分是模块声明,类似于 C 中的函数声明,包括了模块名称、参数列表与输入输出口列表。模块内部可以包括内部变量声明、数据流赋值语句 assign、过程赋值语句 always 以及底层模块例化。

+

端口是模块与外界交互的接口,对于外部环境来说,模块内部的信号与逻辑都是不可见的,端口的存在允许我们将端口视为一个黑盒,只需要正确链接端口并且了解模块作用,而不需要关心模块内部实现细节。端口的类型有三种:输入端口 input,输出端口 output,和双向端口 inout。端口会被默认声明为 wire 类型,如果声明为 reg 类型就不能省略对应的 reg 声明。

+

模块名与模块输入输出列表之间可以加入形如 #(parameter 参数=默认值)参数列表,参数可以有多个,拿逗号隔开,可以提供默认值也可以不提供默认值。

+

下面举个小小的例子,模块内部的内容就省略了吧:

+
1
+2
+3
+4
+5
+6
+7
+8
module example #(
+    parameter LENGTH = 32,
+    parameter TIMES = 8
+)(
+    input [LENGTH-1:0] a,
+    input reg rs1, rs2,
+    output [LENGTH-1:0] s
+);
+
+

2.5 Verilog 语句

+

2.5.1 连续赋值 assign

+

2.5.2 过程赋值 always/initial

+

除了直接使用信号作为敏感变量,Verilog 还支持通过使用 posedgenegedge 关键字将电平变化作为敏感变量。其中 posedge 对应上升沿,negedge 对应下降沿。我们将电平从低电平变成高电平的时刻称为上升沿,从高电平变为低电平的时刻称为下降沿.

+
1
+2
+3
+4
always@(posedge clk) // 上升沿触发
+always@(negedge clk) // 下降沿触发
+always@(posedge clk or negedge rstn) // 上升沿触发和下降沿复位
+always@(posedge clk or posedge rstn) // 上升沿触发和上升沿复位
+
+

实际上 reg 的触发边沿和复位电平是由寄存器本身的电气特性决定的,比如 FPGA 的触发器一般是上升沿触发和高电平复位。但是我们可以通过给 clkrstn 经过非门在连接到 reg 的方式实现所谓的下降沿触发和低电平复位(将非门和 reg 看成一个整体的话)。

+

这个地方幺蛾子比较多,下边是几个常见的问题:

+
+
+
+

核心原因:触发器只有一个时钟输入端口,综合的时候实际上并不能做到多时钟触发。 +

always@(posedge clk1 or posedge clk2) // 上升沿触发
+

+

从语义上看这个 always 块既在 clk1 上升沿触发,又在 clk2 上升沿触发。当我们仿真的时候,可以实现这个逻辑功能,但是因为触发器只有一个时钟输入端口,所以综合的时候实际上并不能做到 clk1clk2 同时作为时钟触发。

+
+
+

核心原因:不存在这样的触发器。 +

1
+2
always@(clock)          // 上升沿也触发、下降沿也触发,即时钟电平翻转就触发
+always@(a or b or c)    // a、b、c 电平反转就触发
+
+从语义上看只要 clockabc 数据变化就会引起 always 块触发。仿真可以接受这样的逻辑设计,但是因为不存在即上升沿触发又下降沿触发,所以实际上并不能综合得到这样的时序电路。

+

1
+2
+3
+4
+5
reg d;
+always@(a or b or c)begin
+    if(a) d <= c;
+    else d <= b;
+end
+
+虽然不能得到时序电路,但是可以综合得到组合电路。d 的结果依赖于 abc,一但 abc 的输入发生了变化,则 d 随着变化,这是符合组合电路的逻辑语义的。最后会得到 bc 作为数据,a 作为选择子的二选一多路选择器。既然所有的信号只依赖于 abc,所以简化成只要有信号的改变就触发 always 块。这就是我们的组合电路。

+
1
+2
+3
+4
+5
reg d;
+always @(*) begin
+    if(a) d <= c;
+    else d <= b;
+end
+
+
+
+

核心原因:一个触发器不能被两个时钟沿触发。 +

1
+2
+3
+4
+5
+6
always@(posedge clk)begin
+    d <= a;
+end
+always@(negedge clk)begin
+    d <= b;
+end
+
+上升沿的时候 d 载入 a 的值,下降沿的时候 d 载入 b 的值。仿真允许 reg 在不同的 always 块被不同的时钟沿触发,但是在综合的时候一个 reg 不能被两个时钟沿触发。

+

1
+2
+3
+4
+5
+6
always@(posedge clk)begin
+    if(c) d <= a;
+end
+always@(posedge clk)begin
+    if(~c) d <= b;
+end
+
+这个逻辑是连仿真也无法通过的,因为在同一时间 d 被两个过程同时仲裁,即使我们知道这两个过程并不冲突,但是也不可以被编译通过。类似于 wire 不能被两个输出同时输入,reg 也不能在两个 always 块内被赋值,这都会引起 multi-driven 错误。

+
+
+

核心问题:数据竞争,不同路径的电平传播速度有快慢,电平在传播期间电路本身就处在不稳定状态,很多中间态在逻辑粉丝上无法覆盖。

+
1
+2
+3
+4
+5
+6
+7
+8
+9
reg [1:0] d;
+wire problem;
+reg cond1;
+reg cond2;
+assign problem = cond1 & cond2;
+
+always@(posedge problem)begin
+    d <= d + 2'b1;
+end
+
+

当 cond1 和 cond2 同时为 1,problem 变为 1 的时候触发 always 块。这在仿真的时候不容易发现问题,但是请考虑下面这个情形:

+

1
+2
+3
+4
+5
initial begin
+    cond1=1'b0;cond2=1'b1;
+    #5;
+    cond1=1'b1;cond2=1'b0;
+end
+
+在仿真的时候会看到 problem 永远等于 0always 块不会触发。但是真实的电路综合之后会因为时延造成问题。当 cond10 变为 1 的时候高电平需要一段时间在可以到的 problem = cond1 & cond2 的与门;cond21 变为 0,低电平也需要一段时间到达与门。如果 cond1 的高电平在 cond2 的低电平之前先到达,则会短暂的出现与门的输入都是高电平,最后 problem 短暂出现高电平,进而 always 块被触发,寄存器被复制。

+

解决方法也很简单,转换为同步电路就好了,即在 always 块中使用 posedge clk 作为触发边沿。剩下的使用 if 语句来判断是否触发。

+
+
+
+

2.5.3 阻塞赋值与非阻塞赋值

+
    +
  • 阻塞赋值
  • +
+

阻塞赋值是顺序执行的,即下一条语句执行前,当前语句一定会执行完毕。这与 C 语言的赋值思想是一致的。阻塞赋值语句使用等号 = 作为赋值符。

+
    +
  • 非阻塞赋值
  • +
+

非阻塞赋值属于并行执行语句,即下一条语句的执行和当前语句的执行是同时进行的,它不会阻塞位于同一个语句块中后面语句的执行,并且相互之间没有依赖关系。非阻塞赋值语句使用小于等于号 <= 作为赋值符。

+

2.5.4 generate 语句

+

为了提升代码变量的局部性(毕竟对于常用的迭代参数,最好是每一个 generate 块对应一个 genvar 变量),所以我们常用下面的语法:

+
1
+2
+3
+4
+5
+6
generate
+    genvar i;
+    for(i=0; i<iteration_times; i=i+1)begin
+        // do something
+    end
+endgenerate
+
+

在使用 generate 语句之后,Verilog 会在对应的模块内生成一个专用的命名空间 genblk,参数式编程下,相同的模块会对应不同的名字,比如 genblk[i]:module_name,这就不需要担心命名冲突的问题。

+

2.6 元件的 Verilog 实现

+

2.6.1 触发器

+

最简单的触发器塞了两个寄存器和一根输入的线,在时钟上升沿的时候,将输入的值非阻塞地赋给第一个寄存器,在时钟下降沿的时候,将第一个寄存器的值非阻塞地赋给第二个寄存器。

+
1
+2
+3
+4
+5
+6
+7
+8
+9
wire data;
+reg a, b;
+always @(posedge clk) begin
+    a <= data;
+end
+
+always @(negedge clk) begin
+    b <= a;
+end
+
+

2.6.2 使能寄存器

+

某些寄存器会有一个额外的使能引脚EN,只有当 EN=1 的时候,寄存器才会载入输入信号,相应的 Verilog 语法如下:

+
1
+2
+3
+4
+5
+6
reg a;
+always @(posedge clk) begin
+    if(EN) begin
+        a <= data;
+    end
+end
+
+
+

Info

+

我们之前将 always@(*) 的时候,if 是需要搭配 else 使用的,不然会导致环路错误,但是这里不需要,因为 always@(*) 综合得到的电路是用 wire 搭建的,它只是借用了 regalways 块语法而已。但是 always@(posedge clk) 得到的电路使用真实的寄存器搭建的,是不会形成环路问题的。

+
+

2.6.3 寄存器的初始化

+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
reg a;  //高电平异步复位寄存器
+always@(posedge clk or posedge rst) begin
+    if(rst) begin
+        a <= INTIAL_VALUE;
+    end else if(wen)begin
+        a <= data;
+    end
+end
+
+reg b; //低电平异步复位寄存器
+always@(posedge clk or negedge rstn)begin
+    if(~rstn)begin
+        b <= INTIAL_VALUE;
+    end else if(wen)begin
+        b <= data;
+    end
+end
+
+

这段代码对应的寄存器是异步复位寄存器,这类寄存器除了有时钟输入 clk、使能输入 CE、数据输入 data 之外,还会有一个额外的输入引脚 rst/rstn。这个引脚如果输入 0 则寄存器会被复位,则该寄存器是低电平异步复位,复位引脚标注为 rstn;这个引脚如果输入 1 则寄存器会被复位,则该寄存器是高电平异步复位,复位引脚标注为 rst

+

由于复位操作不需要等待时钟信号为上升沿,只要有复位信号就可以立即复位,所以复位操作是异步的。

+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
reg a;//高电平同步复位寄存器
+always@(posedge clk)begin
+    if(rst)begin
+        a <= INTIAL_VALUE;
+    end else if(wen)begin
+        a <= data;
+    end
+end
+
+reg a;//低电平同步复位寄存器
+always@(posedge clk)begin
+    if(~rstn)begin
+        a <= INTIAL_VALUE;
+    end else if(wen)begin
+        a <= data;
+    end
+end
+
+

这段对应的是同步复位寄存器,对于高电平同步复位寄存器来说,没有显式的异步复位引脚,只有时钟信号 clk,复位信号 rst 会在时钟上升沿的时候生效,所以复位操作是同步的。

+

同步复位寄存器更像是一个带有多路选择器的使能寄存器,还是对于高电平同步复位寄存器来说,使能信号 CE 接的是 rst | wen,这样只有在复位信号 rst1 或者写使能信号 wen1 的时候,寄存器才会被写入。复位信号 rst 作为选择子对写入值进行选择,当 rst1 的时候,选择初始值 INTIAL_VALUE,当 rst0 的时候,选择输入数据 data

+
+
+

FPGA 的复位信号 rstn 由 FPGA 芯片的 C12 引脚引入。当 vivado 将 bitstream 下载到 FPGA 板之后,rstn 信号会先保持一段时间的 0,使得所有的寄存器可以被充分初始化,然后 rstn信号变为 1 且一直保持不变,这样所有的寄存器就从初始化阶段进入工作阶段,开始载入数据。

+

FPGA 进入工作阶段后,我们也可以按开发板的 reset 按钮,让 rstn 再次输入 0,重新复位所有寄存器的值。

+
set_property -dict {PACKAGE_PIN C12 IOSTANDARD LVCMOS33} [get_ports rstn]
+
+

因为 FPGA 板的 rstn 在初始化阶段是低电平,所以该信号只能直接用于复位低电平复位寄存器。对于高电平复位的寄存器可以将 rstn 取反,然后用 rst 作为复位信号。 +

1
+2
wire rst;
+assign rst = ~rstn;
+

+
+
+
+

2.6.4 移位寄存器

+
1
+2
+3
+4
+5
+6
+7
+8
+9
wire in_data;
+reg [3:0] left_shift_reg;
+reg [3:0] right_shift_reg;
+always@(posedge clk)begin
+    if(en)begin
+        left_shift_reg <= {left_shift_reg[2:0], in_data};
+        right_shift_reg <= {in_data, right_shift_reg[3:1]};
+    end
+end
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
wire [3:0] in_data;
+reg [3:0] left_shift_reg [3:0];
+reg [3:0] right_shift_reg [3:0];
+
+integer i;
+always@(posedge clk)begin
+    if(en)begin
+        for(i=0;i<3;i=i+1)begin
+            left_shift_reg[i+1] <= left_shift_reg[i];
+        end
+        left_shift_reg[0] <= in_data;
+    end
+end
+always@(posedge clk)begin
+    if(en)begin 
+        for(i=0;i<3;i=i+1)begin
+            right_shift_reg[i] <= right_shift_reg[i+1];
+        end
+        right_shift_reg[3] <= in_data;
+    end
+end
+
+

Chapter 3 SystemVerilog 高级语法

+

3.1 logicbit

+

除了熟悉的 0 与 1 之外,还拥有未知值/Unknown (x) 与高阻态/High-impedance (Z) 的值的类型叫做 4 状态类型/4-state types。注意到常用的 reg 只可以在像 initialalways 的过程赋值中被驱动,而 wire 只可以在连续赋值 assign 中被驱动,这就很不方便,所以 SystemVerilog 就引入了一种新的4状态类型 logic,它的默认值为 x,可以出现在过程赋值与连续赋值之中。

+

在一般的测试程序之中,我们并不需要未知值与高阻态值,所以衍生了只有 0 和 1 的 2 状态类型。使用 2 状态类型有很多好处,比如减少内存使用、提升模拟速度,因而在数字设计中很好用。当 4 状态类型转化为 2 状态类型的时候,未知值和高阻态都会被转换成 0。 SystemVerilog 引入的最重要的 2 状态类型就是 bit,表示单独 1 位的值(电平)。

+

3.2 typedef 语法

+
1
+2
+3
+4
parameter WIDTH = 64;
+
+typedef logic [WIDTH-1:0] data_t;
+typedef logic [WIDTH*2-1:0] sum_t;
+
+

3.3 enum 枚举

+

直接上代码。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
typedef enum logic [2:0] {S0, S1, S2, S3, S4, S5, S6, S7} state_t;
+
+state_t state;
+always@(pposedge clk or negedge rstn)begin
+    if(~rstn)begin
+        state <= S0;
+    end else begin
+        case(state)
+            S0:if(X) state<=S1; else state<=S0; 
+            S1:if(X) state<=S2; else state<=S0;
+            S2:if(X) state<=S3; else state<=S0;
+            S3:if(X) state<=S3; else state<=S4;
+            S4:if(X) state<=S1; else state<=S5;
+            S5:if(X) state<=S6; else state<=S0;
+            S6:if(X) state<=S2; else state<=S7;
+            S7:if(X) state<=S1; else state<=S0;
+        endcase
+    end
+end
+
+

需要逐句逐字分析的只有不几行:

+
    +
  • enum 定义了一个枚举类型,logic [2:0] 表示这个枚举类型是一个3位的逻辑类型,所有的枚举变量和长度都是3位数据。
  • +
  • {S0, S1, S2, S3, S4, S5, S6, S7} 一次性定义了枚举常量,从左到右依次是 0-7 的逻辑常量,这就避免了显示提供立即数的麻烦。
  • +
  • typedefstate_t 是类型定义,将这个枚举变量定义为 state_t 类型,使用 state_t 类型的变量 state 代替了原来的 logic [2:0] 类型,就不用费尽心思保持位宽相同了。
  • +
  • 对于定义的枚举变量 state,其可以存储定义的枚举类型的任意一个值。
  • +
+

3.4 数组

+

3.5 queue 队列

+
+ZJU System 1 +

queue 语法仅用于仿真,不要用它实现电路,但是作为基本数据结构辅助还是很好的,

+
+

3.6 struct 结构

+
1
+2
+3
+4
+5
parameter LEN = 4;
+typedef logic [LEN-1:0] data_t;
+typedef struct{
+    data_t data [LEN-1:0];
+} data_vector;
+
+

对应的模块端口语法需要是 input/output data_vector data_instance;

+

这样就将很多个数据打包成一个数据结构,输入与输出的结构端口可以直接用结构变量进行链接,结构变量之间可以直接赋值,方便传输与处理。

+

3.7 package

+
+

包是用来定义一堆杂七杂八的参数用的。

+
+

我们可以在包中定义各种需要的参数/parameter类型/typedef结构/struct函数/function

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
package Conv;
+    parameter WIDTH = 64;
+    parameter LEN   = 4;
+
+    typedef logic [WIDTH-1:0] data_t;
+    typedef logic [WIDTH*2-1:0] sum_t;
+
+    typedef struct{
+        data_t data [LEN-1:0];
+    } data_vector;
+
+endpackage
+
+

使用类似于 C++ 中的命名空间的语法来使用包中的定义,比如 output Conv::data_vector result;,如果要引入 Conv 内的所有定义,可以使用 import Conv::*; 来实现。

+

将包的定义放在一个文件的开头就可以引用包定义的内容,我们一般使用 Verilog 头文件 .vh 与宏实现,比如 `include "Conv.vh"

+

3.8 interface 接口

+

interface 接口是用来简化交互信号处理的。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
interface Decoupled_ift #(
+    parameter DATA_WIDTH = 64
+);
+
+    typedef logic [DATA_WIDTH-1:0] data_t;
+    typedef logic ctrl_t;
+    data_t data;
+    ctrl_t valid, ready;
+
+    modport Master(
+        output data;
+        output valid;
+        input  ready;
+    );
+
+    modport Slave(
+        input data;
+        input valid;
+        output ready;
+    );
+
+endinterface
+
+

interface name ... endinterface 定义一个 interface 块,并且可以进行参数配置。

+

3.9 always_comb 扩展

+

Chapter 4 SystemVerilog 与 C 的接口

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/Lab Record/CMU-15-213/index.html b/System/Lab Record/CMU-15-213/index.html new file mode 100644 index 0000000..6a5bc27 --- /dev/null +++ b/System/Lab Record/CMU-15-213/index.html @@ -0,0 +1,1480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + CMU 15-213 - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

CMU 15-213

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/Lab Record/NJU ICS PA/index.html b/System/Lab Record/NJU ICS PA/index.html new file mode 100644 index 0000000..fa43ee8 --- /dev/null +++ b/System/Lab Record/NJU ICS PA/index.html @@ -0,0 +1,1590 @@ + + + + + + + + + + + + + + + + + + + + + + + + + NJU ICS PA - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

NJU ISC PA

+
+

约 14 个字 6 行代码

+
+

PA0

+

1

+

第一个报错:

+
1
+2
+3
+4
+5
src/monitor/sdb/sdb.c:18:10: fatal error: readline/readline.h: No such file or directory
+   18 | #include <readline/readline.h>
+      |          ^~~~~~~~~~~~~~~~~~~~~
+compilation terminated.
+make: *** [/home/mosen/ics2023/nemu/scripts/build.mk:34: /home/mosen/ics2023/nemu/build/obj-riscv32-nemu-interpreter/src/monitor/sdb/sdb.o] Error 1
+
+

解决方法:

+
sudo apt install libreadline-dev
+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/Lab Record/UCB CS61C/index.html b/System/Lab Record/UCB CS61C/index.html new file mode 100644 index 0000000..1a0a06e --- /dev/null +++ b/System/Lab Record/UCB CS61C/index.html @@ -0,0 +1,1480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + UCB CS61C - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

UCB CS61C

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/Lab Record/ZJU System I/index.html b/System/Lab Record/ZJU System I/index.html new file mode 100644 index 0000000..f06f816 --- /dev/null +++ b/System/Lab Record/ZJU System I/index.html @@ -0,0 +1,4367 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ZJU System I - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

实验纪实与代码分析

+
+

约 1455 个字 1361 行代码 预计阅读时间 22 分钟

+
+

1 2-to-1 Multiplexer

+

我们首先以一种特别的角度看与门:与的运算的作用之一就是屏蔽,当某个输入的值为零时,与的输出就是零,不管另一个输入是什么。这就使得我想要的数据都未被屏蔽,不想要的都被屏蔽为0。比如对于运算\(A\land S\)\(S\)可以看作一个选择子,当\(S=T\)的时候,输出就是\(A\),不论\(A\)的真值为多少,输出的值就是\(A\)的值;当\(S=F\)的时候,输出就是\(F\),这时候\(A\)就被屏蔽了。

+

二路选择器的逻辑就是“屏蔽”,对于下面的二路选择器,最重要的结构就是上下两个与门中间一个非门,选择信号\(S\)分成两份,通过非门变成两个不同的信号,分别接向两个与门,如果\(S\)的信号为\(1\)/\(T\),那么就将下面的门屏蔽,输出上边的门信号;反之亦然。 +alt text

+
+
+
+

这里边利用了Verilog内置的一些门,比如ANDOR门。这种描述方式的优点就是可以很好的与真实的电路相对应,但是缺点就是不够简洁,写起来很坐牢。 +

 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
module Mux2to1 (
+    input I0,
+    input I1,
+    input S,
+    output O
+);
+    wire S0_n;
+    NOT not0 (S0_n, S);
+    // assign S0_n = ~S;
+    wire and0_s;
+    wire and1_s;
+    AND and0(and0_s, I0, S0_n);
+    AND and1(and1_s, I1, S);
+    OR or0(O, and0_s, and1_s);
+

+
+
+

这种描述方法充分利用了与&、或|、非~以及异或^等运算符代替了ANDORNOT等门的描述,使得描述更加简洁。忍不住了,直接写数组。 +

1
+2
+3
+4
+5
+6
module Mux2to1 (
+    input [1:0] I,
+    input S,
+    output O
+);
+    assign O = I[0] & ~S | I[1] & S;
+
+并且这种写法还需要注意优先级的问题,Verilog的优先级是~>&>|,所以这里的写法是正确的。

+

我们还应该知道:

+
    +
  • 一个类C的运算符其实是一个简化描述的电路
  • +
  • 一个运算符的操作数是这个电路的输入;
  • +
  • 一个运算符运算表达式的值是这个电路的输出;
  • +
  • 运算表达式的嵌套是门电路的级联;
  • +
+
+
+

这种描述方法是最简洁的,但是也是最抽象的,使用了大量的高度抽象的类C语句来提升编程的灵活性: +

1
+2
+3
+4
+5
+6
+7
module Mux2to1 (
+    input I0,
+    input I1,
+    input S,
+    output O
+);
+    assign O = S ? I1 : I0;
+

+

Verilog利用了C中的三目运算符来实现了二路选择器,语法是这样的exp0 ? exp1 : exp2,这里的赋值语句并不是表示如果选择子\(S\)\(1\),我就把I0I1连上,实际上这就是一个二路选择器exp0构造选择子电路的输出,真不是不连电路啊……

+
+
+
+

if-else 必须在always块中使用,并且输出必须是reg类型。但是在always@(*)中,内部的reg被综合成wire类型

+

2 复合多路选择器/Cascaded Mux

+

多路选择器可以根据选择子从多个单bit输入中选择单bit输出,但是如果我们需要从多个多bit输入中选择多bit输出,那么就需要使用复合多路选择器。复合多路选择器在硬件实现上其实是由多个单路选择器级联而成的。

+

3 七段数码管译码器/Seven-Segment Decoder

+

七段数码管的显示译码的对应关系如下,使用复合多路选择器,就不难得到下面源码。解释源码的方法很简单,把它的接口ag分开,当卡诺图写就好了。

+

alt text

+
+
+
+

好看一点并且比较符合选择想法的写法。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
module SegDecoder_new (
+    input wire [3:0] data,
+    input wire point,
+    input wire LE,
+    output wire a,
+    output wire b,
+    output wire c,
+    output wire d,
+    output wire e,
+    output wire f,
+    output wire g,
+    output wire p
+);
+
+    wire [6:0] segs [15:0];
+    assign segs[0] = 7'b0000001;
+    assign segs[1] = 7'b1001111;
+    assign segs[2] = 7'b0010010;
+    assign segs[3] = 7'b0000110;
+    assign segs[4] = 7'b1001100;
+    assign segs[5] = 7'b0100100;
+    assign segs[6] = 7'b0100000;
+    assign segs[7] = 7'b0001111;
+    assign segs[8] = 7'b0000000;
+    assign segs[9] = 7'b0000100;
+    assign segs[10] = 7'b0001000;
+    assign segs[11] = 7'b1100000;
+    assign segs[12] = 7'b0110001;
+    assign segs[13] = 7'b1000010;
+    assign segs[14] = 7'b0110000;
+    assign segs[15] = 7'b0111000;
+
+    assign {a, b, c, d, e, f, g} = {7{LE}} | segs[data];
+
+    assign p = ~point;
+
+endmodule //SegDecoder
+
+
+
+

这个是对应的图片,非常的朴素。 +alt text +但是这个是老实人写法,就直接按照真值表画电路硬刚,千万别这么写,丑死了。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
module SegDecoder (
+    input wire [3:0] data,
+    input wire point,
+    input wire LE,
+    output wire a,
+    output wire b,
+    output wire c,
+    output wire d,
+    output wire e,
+    output wire f,
+    output wire g,
+    output wire p
+);
+
+    assign a = LE | ( data[0] &  data[1] & ~data[2] &  data[3] | 
+                      data[0] & ~data[1] &  data[2] &  data[3] | 
+                     ~data[0] & ~data[1] &  data[2] & ~data[3] | 
+                      data[0] & ~data[1] & ~data[2] & ~data[3] );
+    assign b = LE | ( data[0] &  data[1] &  data[3] | 
+                     ~data[0] &  data[2] &  data[3] |
+                     ~data[0] &  data[1] &  data[2] | 
+                      data[0] & ~data[1] &  data[2] & ~data[3] );
+    assign c = LE | ( data[1] &  data[2] &  data[3] |
+                     ~data[0] &  data[1] & ~data[2] & ~data[3] |
+                     ~data[0] &  data[2] &  data[3] );
+    assign d = LE | (~data[0] &  data[1] & ~data[2] &  data[3] |
+                      data[0] &  data[1] &  data[2] |
+                     ~data[0] & ~data[1] &  data[2] & ~data[3] |
+                      data[0] & ~data[1] & ~data[2] & ~data[3] );
+    assign e = LE | ( data[0] & ~data[1] & ~data[2] |
+                     ~data[1] &  data[2] & ~data[3] |
+                      data[0] & ~data[3] );
+    assign f = LE | ( data[0] &  data[1] & ~data[3] |
+                      data[1] & ~data[2] & ~data[3] |
+                      data[0] & ~data[2] & ~data[3] |
+                      data[0] & ~data[1] &  data[2] &  data[3] );
+    assign g = LE | (~data[0] & ~data[1] &  data[2] &  data[3] |
+                      data[0] &  data[1] &  data[2] & ~data[3] |
+                     ~data[1] & ~data[2] & ~data[3] );
+    assign p = ~point;
+
+endmodule //SegDecoder
+
+
+
+
+

4 全加器(Full Adder)

+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
module Adder(
+    input a,
+    input b,
+    input c_in,
+    output s,
+    output c_out
+);
+
+    assign s = a ^ b ^ c_in;
+    assign c_out = a & b | a & c_in | b & c_in;
+
+endmodule 
+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
module Adders #(
+    parameter LENGTH = 32
+)(
+    input [LENGTH-1:0] a,
+    input [LENGTH-1:0] b,
+    input c_in,
+    output [LENGTH-1:0] s,
+    output c_out
+);
+
+    wire c[LENGTH:0];
+    assign c[0] = c_in;
+
+    genvar i;
+    generate
+        for(i = 0; i < LENGTH; i = i + 1)begin
+            Adder adder(.a(a[i]), .b(b[i]), .c_in(c[i]), .s(s[i]), .c_out(c[i+1]));
+        end      
+    endgenerate
+
+    assign c_out = c[LENGTH];
+
+endmodule
+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
module AddSubers #(
+    parameter LENGTH = 32
+)(
+    input [LENGTH-1:0] a,
+    input [LENGTH-1:0] b,
+    input do_sub,
+    output [LENGTH-1:0] s,
+    output c
+);
+    wire [LENGTH-1:0] res_adder;
+    assign res_adder = {LENGTH{do_sub}};
+    wire [LENGTH-1:0] tmp;
+    assign tmp = res_adder ^ b;
+    Adders #(.LENGTH(LENGTH))adder_sub(.a(a), .b(tmp), .c_in(do_sub), .s(s), .c_out(c));
+
+endmodule
+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
module Lookahead_Adder4(
+    input [3:0] a,
+    input [3:0] b,
+    input c_in,
+    output [3:0] s,
+    output c_out
+);
+
+    wire [3:0] G;
+    wire [3:0] P;
+    wire [4:0] c;
+
+    genvar i;
+    generate
+        for(i = 0; i<4; i=i+1)begin
+            assign G[i] = a[i] & b[i];
+            assign P[i] = a[i] ^ b[i];
+        end
+    endgenerate
+
+    assign c[0] = c_in;
+    assign c[1] = G[0] | P[0] & c[0];
+    // assign c[2] = G[1] | P[1] & c[1];
+    assign c[2] = G[1] | P[1] & G[0] | P[1] & P[0] & c[0] ;
+    assign c[3] = G[2] | P[2] & G[1] | P[2] & P[1] & G[0] | 
+                  P[2] & P[1] & P[0] & c[0] ;
+    assign c[4] = G[3] | P[3] & G[2] | P[3] & P[2] & G[1] | 
+                  P[3] & P[2] & P[1] & G[0] | P[3] & P[2] & P[1] & P[0] & c[0];
+    assign c_out = c[4];
+
+    generate
+        for(i = 0; i<4; i=i+1)begin
+            assign s[i] = P[i] ^ c[i];
+        end
+    endgenerate
+
+endmodule
+
+
+
+
+

5 七段数码管驱动

+

6 有限状态机

+

说是有限状态机,其实就是完成 C 程里面一个常见的小程序,记录输入 a 的数量,当连续输入三个 a 的时候,结束程序,当输入 b 的时候,计数清零。

+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
module FSM(
+    input rstn,
+    input clk,
+    input a,
+    input b,
+    output [1:0] state
+);
+
+typedef enum logic [1:0] {st0, st1, st2, st3} fsm_state_t;
+fsm_state_t state_s;
+
+always @(posedge clk or negedge rstn) begin
+    if(~rstn)
+        state_s <= st0;
+    else begin
+        case(state_s)
+            st0: begin
+                if(a) state_s <= st1; 
+                else if(b) state_s <= st0;
+            end
+            st1: begin
+                if(a) state_s <= st2;
+                else if(b) state_s <= st0;
+            end
+            st2: begin
+                if(a) state_s <= st3;
+                else if(b) state_s <= st0;
+            end
+            st3: state_s <= st3;
+        endcase
+    end
+end
+
+assign state = state_s;
+
+endmodule
+
+
+
+

实现了一个分频器,将输入的时钟信号分频为 ½ 的幂的频率输出。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
module ClkDiv(
+    input clk,
+    input rstn,
+    output reg [31:0] clk_div
+);
+    always@(posedge clk)begin
+        if(~rstn)clk_div<=32'b0;
+        else clk_div<=clk_div+32'b1;
+    end
+
+endmodule
+
+

很简单有效的实现,clk_div[0] 每个时钟周期翻转一次,其频率是时钟频率的一半,而翻转的时候会向上产生进位,从而 clk_div[1] 的频率是 clk_div[0] 的 ½,也就是时钟频率的 ¼,后边的频率依次减半。

+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
module Debouncer ( // repo/sys-project/lab3-1/syn/Debouncer.v
+    input  wire  clk,//100Mhz 2^10
+    input  wire  btn,
+    output wire  btn_dbnc
+);
+
+    reg [7:0] shift = 0;
+
+    always @ (posedge clk) begin
+        shift <= {shift[6:0], btn};
+    end
+
+    assign btn_dbnc = &shift;
+endmodule
+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
module PosSample ( // repo/sys-project/lab3-1/syn/Debouncer.v
+    input clk,
+    input data,
+    output sample
+);
+
+    reg old_data;
+    always@(posedge clk)begin
+        old_data <= data;
+    end
+
+    assign sample = ~old_data & data;
+
+endmodule
+
+
+
+
+

7 计数器 & 定时器

+
+
+
+

丑陋版,因为当初做的时候改了好多,这种形式比较好 debug,当然可能用枚举会好看一丢丢,不过好看不到哪里去。 +

 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
module Cnt #(
+    parameter BASE = 10,
+    parameter INITIAL = 0
+) (
+    input clk,
+    input rstn,
+    input low_co,
+    input high_rst,
+    output co,
+    output reg [3:0] cnt
+);
+
+logic [3:0] state;
+reg carryFlag;
+always @(posedge clk)begin
+    if (~rstn)begin
+        state <= {INITIAL[3], INITIAL[2], INITIAL[1], INITIAL[0]};
+    end else if (high_rst)begin
+        state <= 4'b0;
+    end else if (low_co)
+        case(state)
+            4'b0: begin 
+                state <= 4'b1;
+                carryFlag = 0;
+            end
+            4'b1: state <= 4'b10;
+            4'b10: state <= 4'b11;
+            4'b11: state <= 4'b100;
+            4'b100: state <= 4'b101;
+            4'b101: state <= 4'b110;
+            4'b110: state <= 4'b111;
+            4'b111: state <= 4'b1000;
+            4'b1000: begin 
+                state <= 4'b1001;
+                carryFlag = 0;
+            end
+            4'b1001: begin
+                state <= 4'b0;
+                carryFlag = 1;
+            end
+            default: state <= state + 4'b1;
+        endcase
+    else carryFlag = 0;
+end
+
+assign cnt = state;
+assign co = carryFlag;
+
+endmodule
+

+
+
+

还有优化的空间,但是最重要的想法在于全局使能信号,只有当低位有进位的时候,也就是 low_co1 的时候,传给高位的信号(包括低位向高位的信号)才会有意义,否则就有可能出现乱进位的情况。 +

 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
module Cnt2num #(
+    parameter BASE = 24,
+    parameter INITIAL = 16
+)(
+    input clk,
+    input rstn,
+    input high_rst,
+    input low_co,
+    output co,
+    output [7:0] cnt
+);
+
+    localparam HIGH_BASE = 10;
+    localparam LOW_BASE  = 10;
+    localparam HIGH_INIT = INITIAL/10;
+    localparam LOW_INIT  = INITIAL%10;
+    localparam HIGH_CO   = (BASE-1)/10;
+    localparam LOW_CO    = (BASE-1)%10;
+
+    wire low_carry, low_carry_flag;
+    assign low_carry = low_co & low_carry_flag;
+    reg HIGH_rst, tmp;
+    reg [7:0] ALL_CO;
+    assign ALL_CO = {HIGH_CO[3], HIGH_CO[2], HIGH_CO[1], HIGH_CO[0], LOW_CO[3], LOW_CO[2], LOW_CO[1], LOW_CO[0]};
+    always @(posedge clk) begin
+        if(cnt == ALL_CO)begin
+            HIGH_rst = 1'b1;
+        end else begin
+            HIGH_rst = 1'b0;
+        end
+    end
+    assign co = tmp | HIGH_rst;
+
+    Cnt #(.BASE(HIGH_BASE), .INITIAL(HIGH_INIT))cnt_high(.clk(clk), .rstn(rstn), .high_rst(HIGH_rst), .low_co(low_carry), .co(tmp), .cnt(cnt[7:4]));
+    Cnt #(.BASE(LOW_BASE), .INITIAL(LOW_INIT))cnt_low(.clk(clk), .rstn(rstn), .high_rst(HIGH_rst), .low_co(low_co), .co(low_carry_flag), .cnt(cnt[3:0]));
+
+
+endmodule
+

+
+
+
+

8 乘法器

+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
module Multiplier #(
+    parameter LEN = 32
+)(
+    input clk,
+    input rst,
+    input [LEN-1:0] multiplicand,
+    input [LEN-1:0] multiplier,
+    input start,
+
+    output [LEN*2-1:0] product,
+    output finish
+);
+
+    localparam PRODUCT_LEN = LEN*2;
+    logic [LEN-1:0] multiplicand_reg;
+    logic [PRODUCT_LEN-1:0] product_reg;
+
+    localparam CNT_LEN = $clog2(LEN);
+    localparam CNT_NUM = LEN - 1;
+    typedef enum logic [1:0] {IDLE, WORK, FINAL} fsm_state;
+    fsm_state fsm_state_reg;
+    logic [CNT_LEN-1:0] work_cnt;
+
+    logic finish_reg;
+    logic start_load;
+    logic [LEN-1:0] product_trans;
+    assign product = product_trans;
+    assign finish = finish_reg;
+
+    always @(posedge clk or posedge rst)begin
+        if(rst)begin
+            fsm_state_reg <= IDLE;
+        end else begin
+            if(start) begin
+               start_load = 1'b1; 
+            end
+            if(start_load)begin
+                case(fsm_state_reg)
+                    IDLE:begin
+                        multiplicand_reg <= multiplicand;
+                        product_reg[PRODUCT_LEN-1:LEN] = {LEN{1'b0}};
+                        product_reg[LEN-1:0] = multiplier; 
+                        fsm_state_reg <= WORK;
+                        start_load = 1'b1;
+                        work_cnt <= {CNT_LEN{1'b0}};
+                        product_trans = 0;
+                    end
+                    WORK:begin
+                        if(product_reg[0])begin
+                            product_reg[PRODUCT_LEN-1:LEN] = product_reg[PRODUCT_LEN-1:LEN] + multiplicand_reg;
+                            product_reg = product_reg >> 1;
+                            product_reg[PRODUCT_LEN-1] = (product_reg[PRODUCT_LEN-2:LEN-1] < multiplicand_reg); 
+                        end else begin
+                            product_reg = product_reg >> 1;
+                        end
+                        work_cnt <= work_cnt + 1;
+                        if(work_cnt == CNT_NUM[CNT_LEN-1:0]) begin
+                            fsm_state_reg <= FINAL;
+                            finish_reg <= 1'b1;
+                            product_trans = product_reg;
+                        end
+                    end
+                    FINAL:begin
+                        finish_reg <= 1'b0;
+                        start_load = 1'b0;
+                        fsm_state_reg <= IDLE;
+                    end
+                    default: begin fsm_state_reg <= IDLE; end
+                endcase
+            end
+        end 
+    end
+
+endmodule
+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
import "DPI-C" function int mul_judge(
+    input int unsigned multiplicand,
+    input int unsigned multiplier,
+    input longint unsigned product
+);
+
+module Judge (
+    input clk,
+    input rstn,
+    input [31:0] multiplicand,
+    input [31:0] multiplier,
+    input start,
+    input [63:0] product,
+    input finish,
+    output reg error
+);
+
+    reg [31:0] multiplicand_reg;
+    reg [31:0] multiplier_reg;
+    always@(posedge clk or negedge rstn)begin
+        if(~rstn)begin
+            multiplicand_reg <= 32'b0;
+            multiplier_reg <= 32'b0;
+        end else if(start)begin
+            multiplicand_reg <= multiplicand;
+            multiplier_reg <= multiplier;
+        end
+    end
+
+    always@(posedge clk or negedge rstn)begin
+        if(~rstn)begin
+            error <= 1'b0;
+        end else begin
+            if(finish)begin
+                if(mul_judge(multiplicand,multiplier,product)==32'b1)begin
+                    error <= 1'b0;
+                end else begin
+                    error <= 1'b1;
+                end
+            end
+        end
+    end
+
+endmodule
+
+
+
+
+

9 卷积模块

+
+
+
+

定义了需要的参数与数据类型。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
package Conv;
+    parameter WIDTH = 64;
+    parameter LEN   = 4;
+
+    typedef logic [WIDTH-1:0] data_t;
+    typedef logic [WIDTH*2-1:0] result_t;
+
+    typedef struct{
+        data_t data [LEN-1:0];
+    } data_vector;
+
+endpackage
+
+
+
+

作为外壳调用移位器与卷积计算模块

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
module ConvUnit (
+    input clk,
+    input rst,
+    input Conv::data_t in_data,
+    input Conv::data_vector kernel,
+    input in_valid,
+    output in_ready,
+
+    output Conv::result_t result,
+    output out_valid,
+    input out_ready
+);
+
+    Conv::data_vector trans_data;
+    logic trans_valid, trans_ready;
+    Shift shift(.clk(clk), .rst(rst), .in_data(in_data), .in_valid(in_valid), .in_ready(in_ready), .data(trans_data), .out_valid(trans_valid), .out_ready(trans_ready));
+    ConvOperator operator(.clk(clk), .rst(rst), .kernel(kernel), .data(trans_data), .in_valid(trans_valid), .in_ready(trans_ready), .result(result), .out_valid(out_valid), .out_ready(out_ready));
+
+endmodule
+
+
+
+

移位器模块,读入数据并且输出,注意结构体与数组/向量的转换与链接。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
module Shift (
+    input clk,
+    input rst,
+    input Conv::data_t in_data,
+    input in_valid,
+    output reg in_ready,
+
+    output Conv::data_vector data,
+    output reg out_valid,
+    input out_ready
+);
+
+    typedef enum logic {RDATA, TDATA} fsm_state;
+    fsm_state state_reg;
+    Conv::data_t data_reg [Conv::LEN-1:0];
+
+    generate
+        for(genvar i = 0; i < Conv::LEN; i = i + 1)begin
+            assign data.data[i] = data_reg[i];
+        end
+    endgenerate
+
+    always @(posedge clk or posedge rst)begin
+        if(rst)begin
+            state_reg <= RDATA;
+            in_ready <= 1'b1;
+            out_valid <= 1'b0;
+            for(integer i = 0; i < Conv::LEN; i = i + 1)begin
+                data_reg[i] <= 0;
+            end
+        end else begin
+            case(state_reg)
+                RDATA:begin
+                    if(in_ready & in_valid)begin
+                        data_reg[Conv::LEN-2:0] <= data_reg[Conv::LEN-1:1]; // transfer data
+                        data_reg[Conv::LEN-1] <= in_data;
+                        state_reg <= TDATA;
+                        in_ready <= 1'b0;
+                    end else begin ; end
+                end
+                TDATA:begin
+                    out_valid <= 1'b1;
+                    if(out_ready & out_valid)begin
+                        out_valid <= 1'b0;
+                        data <= tmp;
+                        state_reg <= RDATA;
+                        in_ready <= 1'b1;
+                    end else begin
+                        ;
+                    end 
+                end
+            endcase
+        end
+    end
+endmodule
+
+
+
+

卷积计算模块,乘法器调用的是前一个实验的乘法器。需要注意卷积核与数据的乘积(调用乘法器)与加法树在宏观上其实是组合逻辑的想法,我们完全将其作为模块化硬件的实现,不依赖于有限状态机。乘法器完成计算的时候需要传递信号给有限状态机,这里的实现容易被忽略,需要注意一下。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
module ConvOperator(
+    input clk,
+    input rst,
+    input Conv::data_vector kernel,
+    input Conv::data_vector data,
+    input in_valid,
+    output reg in_ready,
+
+    output Conv::result_t result,
+    output reg out_valid,
+    input out_ready
+);
+
+    localparam VECTOR_WIDTH = 2*Conv::WIDTH;
+    typedef struct {
+        Conv::result_t data;
+        logic valid;
+    } mid_vector;
+
+    mid_vector vector_stage1 [Conv::LEN-1:0]; 
+    mid_vector vector_stage2;
+
+    typedef enum logic [1:0] {RDATA, WORK, TDATA} fsm_state;
+    fsm_state state_reg;
+
+    Conv::result_t add_tmp [Conv::LEN-1:1] /* verilator split_var */;
+    Conv::result_t stage1 [Conv::LEN-1:0];
+    logic [Conv::LEN-1:0] start_flag, finish_flag;
+
+    generate
+        for(genvar i=0;i<Conv::LEN;i=i+1)begin
+            assign stage1[i] = vector_stage1[i].data;
+            assign finish_flag[i] = vector_stage1[i].valid;
+            Multiplier #(.LEN(Conv::WIDTH)) mul (.clk(clk), .rst(rst), .multiplicand(kernel.data[i]),
+                         .multiplier(data.data[i]), .start(start_flag[i]), .product(vector_stage1[i].data), 
+                         .finish(vector_stage1[i].valid));
+        end
+    endgenerate
+
+    generate
+        for(genvar i = 1;i < Conv::LEN;i=i+1)begin
+            if(i<Conv::LEN/2)begin
+                assign add_tmp[i] = add_tmp[i*2] + add_tmp[i*2+1];
+            end else begin
+                assign add_tmp[i] = stage1[(i-Conv::LEN/2)*2] + stage1[(i-Conv::LEN/2)*2+1]; 
+            end
+        end
+    endgenerate
+
+    always @(posedge clk or posedge rst)begin
+        if (rst)begin
+            state_reg <= RDATA;
+            in_ready <= 1'b1;
+            out_valid <= 1'b0;
+        end else begin ; end
+        case(state_reg)
+            RDATA: begin
+                if (in_ready & in_valid)begin
+                    in_ready <= 1'b0;
+                    for(integer i = 0; i <= Conv::LEN-1; i = i + 1)begin
+                        vector_stage1[i].data = {VECTOR_WIDTH{1'b0}};
+                        vector_stage1[i].valid = 1'b0;
+                    end
+                    vector_stage2.data = {VECTOR_WIDTH{1'b0}};
+                    vector_stage2.valid = 1'b0;
+                    start_flag <= {Conv::LEN{1'b1}};
+                    state_reg <= WORK;  
+                end else begin ; end
+            end   
+            WORK: begin
+                if (&finish_flag == 1)begin
+                    start_flag <= {Conv::LEN{1'b0}};
+                    state_reg <= TDATA;
+                    vector_stage2.data = add_tmp[1];
+                    result <= vector_stage2.data;
+                    out_valid <= 1'b1;
+                    vector_stage2.valid = 1'b1;
+                end else begin ; end
+            end
+            TDATA:begin 
+                if(out_ready & out_valid & vector_stage2.valid)begin
+                    out_valid <= 1'b0;
+                    state_reg <= RDATA;
+                    in_ready <= 1'b1;
+                end else begin ; end
+            end
+            default: begin ; end
+        endcase
+    end
+endmodule
+
+
+
+
+

10 串口使用

+
UartLoop.sv
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
`include"uart_struct.vh"
+module UartLoop(
+    input clk,
+    input rstn,
+    Decoupled_ift.Slave uart_rdata,
+    Decoupled_ift.Master uart_tdata,
+    input UartPack::uart_t debug_data,
+    input logic debug_send,
+    output UartPack::uart_t debug_rdata,
+    output UartPack::uart_t debug_tdata
+);
+    import UartPack::*;
+
+    uart_t rdata;
+    logic rdata_valid;
+
+    uart_t tdata;
+    logic tdata_valid;
+
+    assign debug_rdata = rdata;
+    assign debug_tdata = tdata;
+    typedef enum logic [1:0] { RDATA, TRANS, TDATA } fsm_t;
+    fsm_t fsm;
+    always @(posedge clk or negedge rstn) begin
+        if(~rstn)begin
+            rdata_valid <= 0;
+            tdata_valid <= 0;
+            uart_rdata.ready <= 1;
+            uart_tdata.valid <= 0;
+            fsm <= RDATA;
+        end
+        else begin 
+            case(fsm)
+                RDATA:begin
+                    if(uart_rdata.valid && uart_rdata.ready)begin
+                        rdata <= uart_rdata.data;
+                        rdata_valid <= 1;
+                        tdata_valid <= 0;
+                        uart_rdata.ready <= 0;
+                        uart_tdata.valid <= 0;
+                        fsm <= TRANS;
+                    end
+                end
+                TRANS: begin
+                    if(rdata_valid)begin
+                        tdata = rdata;
+                        uart_tdata.data <= tdata;
+                        rdata_valid <= 0;
+                        tdata_valid <= 1;
+                        uart_rdata.ready <= 1;
+                        uart_tdata.valid <= 1;
+                        fsm <= TDATA;
+                    end
+                end
+                TDATA: begin
+                    if(tdata_valid && uart_tdata.ready)begin
+                        uart_tdata.valid <= 0;
+                        tdata_valid <= 0;
+                        fsm <= RDATA;
+                    end
+                end
+                default: ;
+            endcase
+        end
+    end
+
+endmodule
+
+

11 汇编实验

+
+
+
+
fibonacci.s
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
# implementing fibonacci in RISC-V assembly
+# n in a0
+fibonacci:
+    li t0, 2                # test if n < 2    
+    blt a0, t0, fib_base    # if n < 2, return 1
+
+    addi sp, sp, -8         # allocate stack space
+    sw   ra, 4(sp)          # store return address
+    sw   a0, 0(sp)          # store original n
+
+    addi a0, a0, -1         # n-1 in a0
+    jal  x1, fibonacci      # calculate fib(n-1)
+
+    lw   t0, 0(sp)          # load original n to t0
+    sw   a0, 0(sp)          # store fib(n-1) to stack
+    addi a0, t0, -2         # now n-2 in a0
+    jal  x1, fibonacci      # calculate fib(n-2)
+
+    lw   t0, 0(sp)          # load fib(n-1) to t0
+    add  a0, a0, t0         # calculate fib(n) = fib(n-1) + fib(n-2)
+    lw   ra, 4(sp)          # load return address
+    addi sp, sp, 8          # clean up stack
+    ret
+
+fib_base:                   # base case, return 1
+    li a0, 1
+    ret
+
+
+
+
bubble_sort.s
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
bubble_sort:
+    # arr in a0, len in a1
+    # i in t0, j in t1, len - i - 1 in t2
+    # swap procedure uses t3 and t4
+    li   t0, 0
+outer_loop_begin:
+    bge  t0, a1, outer_loop_end
+    li   t1, 0              # j = 0
+    sub  t2, a1, t0         # len - i
+    addi t2, t2, -1         # t2 = len - i - 1
+inner_loop_begin:
+    bge  t1, t2, inner_loop_end
+    # read from array uses t5 for the address
+    slli t5, t1, 3
+    add  t5, t5, a0         # t5 = &arr[j]
+    ld   t3, 0(t5)          # t3 = arr[j]
+    ld   t4, 8(t5)          # t4 = arr[j + 1]
+    bge  t4, t3, no_swap
+    # swap procedure
+    sd   t4, 0(t5)          # arr[j] = arr[j + 1]
+    sd   t3, 8(t5)          # arr[j + 1] = arr[j] 
+no_swap:
+    addi t1, t1, 1          # j++
+    j    inner_loop_begin
+inner_loop_end:
+    addi t0, t0, 1          # i++
+    j    outer_loop_begin
+outer_loop_end:
+    ret
+
+
+
+
+ + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/Lab Record/ZJU System II/index.html b/System/Lab Record/ZJU System II/index.html new file mode 100644 index 0000000..0112f7c --- /dev/null +++ b/System/Lab Record/ZJU System II/index.html @@ -0,0 +1,1480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ZJU System II - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

ZJU System II

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/Lab Record/ZJU System III/index.html b/System/Lab Record/ZJU System III/index.html new file mode 100644 index 0000000..348395e --- /dev/null +++ b/System/Lab Record/ZJU System III/index.html @@ -0,0 +1,1480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ZJU System III - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

ZJU System III

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/RISC-V/RISC-V-pr/index.html b/System/RISC-V/RISC-V-pr/index.html new file mode 100644 index 0000000..012242c --- /dev/null +++ b/System/RISC-V/RISC-V-pr/index.html @@ -0,0 +1,1585 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Privileged ISA - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Privileged ISA

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/RISC-V/RISC-V-upr/index.html b/System/RISC-V/RISC-V-upr/index.html new file mode 100644 index 0000000..961c4c9 --- /dev/null +++ b/System/RISC-V/RISC-V-upr/index.html @@ -0,0 +1,2925 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Unprivileged ISA - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

RISC-V Unprivileged ISA

+
+

约 4862 个字 129 行代码 预计阅读时间 18 分钟

+
+

1 Basic

+

Registers Convents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
寄存器ABI 名称用途描述caller-savedcallee-saved
x0zero硬件 0
x1ra返回地址(return address)yes
x2sp栈指针(stack pointer)yes
x3gp全局指针(global pointer)
x4tp线程指针(thread pointer)
x5t0临时变量/备用链接寄存器(alternate link reg)yes
x6-7t1-t2临时变量yes
x8s0/fp需要保存的寄存器/帧指针(frame pointer)yes
x9s1需要保存的寄存器yes
x10-11a0-a1函数参数/返回值yes
x12-17a2-a7函数参数yes
x18-27s2-s11需要保存的寄存器yes
x28-31t3-t6临时变量yes
pcpc程序计数器(program counter)
+

Caller-Saved:调用者保存寄存器,也被称为可变寄存器/Volatile Registers,被调用者可以自由地改变这些寄存器的值,如果调用者需要这些寄存器的值,就必须在执行程序调用之前保存这些值。t0-t6(临时寄存器)、a0-a7(返回地址与函数参数)与 ra(返回地址)都是调用者保存寄存器。

+

Callee-Saved:被调用者保存寄存器,这些寄存器的值在过程调用之前和之后必须保持不变,被调用者如果要使用这些寄存器,就必须在返回之前保存这些值。这就意味着要保存原来的值,正常使用寄存器,恢复原来的值s0-s11(被保存的寄存器)和 sp(栈指针)都是被调用者保存寄存器。

+

全局指针 gp 和线程指针 tp 很特殊,先不考虑。

+

Instruction and its Formats

+

RV32I 有 4 种基础的指令格式(R/I/S/U),再根据立即数解码的不同又分出两种(B/J),总共六种指令格式

+
    +
  • +

    R 型指令

    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    312524201915141211760
    funct7rs2rs1funct3rdopcode

    +

    使用寄存器进行数字逻辑运算的指令格式,运算由 opcode funct3 funct7 决定,rd = rs1 op rs2shift 类例外,它们用 rs2 位置表示移位数的立即数)。

    +
  • +
  • +

    I 型指令

    +

    + + + + + + + + + + + + + + + + + + + + + + + + +
    31201915141211760
    imm[11:0]rs1funct3rdopcode

    +

    使用寄存器和立即数进行数字逻辑运算,以及 load 类指令等的指令格式,运算类型等由 opcode funct3 决定,如果是 ALU 运算,则 rd = rs1 op imm

    +

    立即数是 {{20{inst[31]}}, inst[31:20]},也就是对 imm[11:0] 进行符号位扩展到 32 位。

    +
  • +
  • +

    S 型指令

    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    312524201915141211760
    imm[11:5]rs2rs1funct3imm[4:0]opcode

    +

    store 类指令,store 的大小由 funct3 决定,以变址模式进行寻址,即 rs1 = [rs2+imm]

    +

    立即数是 {{20{inst[31]}}, inst[31:25], inst[11:7]}

    +
  • +
  • +

    B 型指令

    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    312524201915141211760
    imm[12,10:5]rs2rs1funct3imm[4:1,11]opcode

    +

    由 S 型指令分来,与之区别是立即数读取顺序不同,是所有分支类指令。是否分支由 funct3 rs1 rs2 决定。

    +

    立即数是 {{19{inst[31]}}, inst[31], inst[7], inst[30:25], inst[11:8], 1'b0}

    +
  • +
  • +

    U 型指令

    +

    + + + + + + + + + + + + + + + + +
    311211760
    imm[31:12]rdopcode

    +

    LUIAUIPC,立即数都是在高 20 位,而且没有源操作数。

    +

    立即数是 {inst[31:12], 12'b0}

    +
  • +
  • +

    J 型指令

    +

    + + + + + + + + + + + + + + + + +
    311211760
    imm[20,10:1,11,19:12]rdopcode

    +

    由 U 型指令分来,区别也是立即数读取不同,仅有 JAL 一个指令。

    +

    立即数是 {{11{inst[31]}}, inst[31], inst[19:12], inst[20], inst[30:21], 1'b0}

    +
  • +
+

Immediate Values

+

与正常无异,十六进制数前加 0x,二进制数前加 0b,十进制数直接写或者在前面加 0。用单引号括起来的字母数字字符/Alphanumeric Characters 会根据 ASCII 表转化为相应的数值,比如 'a' 会转化为 97

+
1
+2
+3
+4
li a0, 0x42     # load value sixty-six into a0
+li a1, 0b1010   # load value ten into a1
+li a2, 42       # load value forty-two into a2
+li a3, -'a'     # load value negative ninety-seven into a3
+
+

Symbol Names and Labels

+

符号是和数值联系在一起的名字,标签会自动地转化为符号,我们也可以使用 .set 指令显式地声明一个符号。符号名可以包含数字、字母与下划线,但是不能以数字开头。符号名是大小写敏感的。在下面的程序中,我们就定义了一个符号 max_temp,并且将其值设置为 100

+
1
+2
+3
+4
+5
+6
+7
+8
.set max_temp, 100      # set the max_temp limit
+
+check_temp:
+    li t0, max_temp     # load the max_temp value into t0
+    ble a0, t0, ok_temp # branch to ok_temp if a0 <= t0
+    jal alarm           # else, call the alarm routine
+ok_temp:
+    ret                 # return from the routine
+
+

标签是表示程序位置的一个记号,可以被汇编指令(Instructions and Directives)引用并且在汇编与链接过程之中翻译为地址。GNU 汇编器一般会接受两种类型的标签:符号标签/Symbolic Labels 和数字标签/Numeric Labels。符号标签以符号存储在符号表中,一般用来表示全局变量与某个过程,使用标识符加上冒号 name: 来定义,标识符的命名与符号的命名一样。

+

数字标签通过单独一位数字加上冒号来定义,一般用于局部的引用,并且也不会存储在可执行文件的符号表之中。数字标签可以在同一个汇编程序之中重复定义,但是符号标签不能。

+

对数字标签的引用需要加上后缀 bf来表明是引用前边定义的标签 b 还是后边定义的标签 f。下面是对标签的一个例子:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
# set age to 20
+age: .word 20        # define a global variable age
+set_age:
+    la t0, age       # load the address of age into t0
+    lw a0, 0(t0)     # load the value of age into a0
+    ret
+
+# pow function -- compute a^b
+# Inputs: a in a0, b in a1
+# Outputs: a^b in a0
+pow:
+    mv a2, a0        # copy a0 to a2
+    li a0, 1         # set a0 to 1
+1:
+    beqz a1, 1f      # if a1 == 0, goto 1f/done
+    mul a0, a0, a2   # a0 *= a2
+    addi a1, a1, -1  # a1--
+    j 1b             # goto 1b/repeat
+1:
+    ret              # done and return
+
+

Location Counter and Assembling Process

+

Assembly Directives

+

汇编指令(Directives)用来控制汇编器,比如 .section .data 就是用来告诉汇编器接下来的指令将放到 .data 节之中;.word 10 则告诉汇编器分配一个 32 位的值并且将其放到当前节之中。

+

一般的汇编指令被编码成一个字符串,包含着指令名与指令参数。在 GNU 汇编器上,汇编名以一个点 . 作为前缀,比如 .section.word.globl 等等。

+

下面是一些最常用的汇编指令:

+
    +
  • 向程序中添加值的指令:
      +
    • .dword arg_expr [, arg_expr]*: 添加一个或多个以逗号分隔的 64 位值到程序中;
    • +
    • .word arg_expr [, arg_expr]*: 添加一个或多个以逗号分隔的 32 位值到程序中;
    • +
    • .half arg_expr [, arg_expr]*: 添加一个或多个以逗号分隔的 16 位值到程序中;
    • +
    • .byte arg_expr [, arg_expr]*: 添加一个或多个以逗号分隔的 8 位值到程序中;
    • +
    • .string string: 添加一个以 NULL 结尾的字符串到程序中;
    • +
    • .ascii string: 添加不以 NULL 结尾一个字符串到程序中。
    • +
    • .asciz string:这是 .string 的别名;
    • +
    +
  • +
  • 切换程序节
  • +
  • .bss 节添加值
  • +
  • 向符号表添加符号
  • +
  • 定义一个全局符号
  • +
  • 对齐指令
  • +
+

2 RV32I Base Integer Instruction Set

+

Logic Instructions

+
    +
  • 逻辑指令:andorxorandiorixori,均执行按位运算;
  • +
  • 指令格式:lop dest, src1, src2lopi dest, src1, imm
  • +
  • 指令类型:
  • +
+
1
+2
+3
+4
+5
+6
and   rd, rs1, rs2   # rd = rs1 & rs2
+or    rd, rs1, rs2   # rd = rs1 | rs2
+xor   rd, rs1, rs2   # rd = rs1 ^ rs2
+andi  rd, rs1, imm   # rd = rs1 & imm
+ori   rd, rs1, imm   # rd = rs1 | imm
+xori  rd, rs1, imm   # rd = rs1 ^ imm
+
+

Shift Instructions

+
    +
  • 移位指令:sllsrlsrasllisrlisrai,算数移位和逻辑移位根据 al 区分;
  • +
  • 指令格式:sop dest, src1, src2sopi dest, src1, imm
  • +
  • 指令类型:
  • +
  • Tip:注意一般使用小端序存储,即低位在低地址,高位在高地址。
  • +
+
1
+2
+3
+4
+5
+6
sll  rd, rs1, rs2   # rd = rs1 << rs2
+srl  rd, rs1, rs2   # rd = rs1 >> rs2 (logical)
+sra  rd, rs1, rs2   # rd = rs1 >> rs2 (arithmetic)
+slli rd, rs1, imm   # rd = rs1 << imm
+srli rd, rs1, imm   # rd = rs1 >> imm (logical)
+srai rd, rs1, imm   # rd = rs1 >> imm (arithmetic)
+
+

Arithmetic Instructions with M Extension

+
1
+2
+3
+4
+5
+6
add    rd, rs1, rs2   # rd = rs1 + rs2
+sub    rd, rs1, rs2   # rd = rs1 - rs2
+addi   rd, rs1, imm   # rd = rs1 + imm
+mul    rd, rs1, rs2   # rd = rs1 * rs2
+riv{u} rd, rs1, rs2   # rd = rs1 / rs2
+rem{u} rd, rs1, rs2   # rd = rs1 % rs2 
+
+

Data Transfer Instructions

+
    +
  • 语法:memop reg, off(addr)
  • +
  • memop 为指令名,reg 为指令的目标/源寄存器,off 为偏移量,addr 为基址寄存器/Base Address。
  • +
  • 通过 off(addr) 可以计算地址为 addr + off 的内存位置,按字节寻址。
  • +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
lw  rd, off(rs1)   # rd = M[rs1 + off] (signed word)
+lh  rd, off(rs1)   # rd = M[rs1 + off] (signed half)
+lhu rd, off(rs1)   # rd = M[rs1 + off] (unsigned half)
+lb  rd, off(rs1)   # rd = M[rs1 + off] (signed byte)
+lbu rd, off(rs1)   # rd = M[rs1 + off] (unsigned byte)
+lui rd, imm        # rd = imm << 12
+sw  rs1, off(rs2)  # M[rs2 + off] = rs1
+sh  rs1, off(rs2)  # M[rs2 + off] = rs1 (16 least significant bits)
+sb  rs1, off(rs2)  # M[rs2 + off] = rs1 (8 least significant bits)
+# pseudo-instructions
+mv  rd, rs         # rd = rs
+li  rd, imm        # rd = imm
+la  rd, symbol     # rd = symbol
+l*  rd, label      # rd = M[label] (* = w, h, hu, b, bu)
+s*  rd, label      # M[label] = rd (* = w, h, b)
+
+

Control Transfer Instructions

+

branch 类条件跳转指令:

+
1
+2
+3
+4
+5
+6
+7
+8
+9
beq   rs1, rs2, offset  # if rs1 == rs2, pc += offset
+bne   rs1, rs2, offset  # if rs1 != rs2, pc += offset
+blt   rs1, rs2, offset  # if rs1 < rs2, pc += offset
+bltu  rs1, rs2, offset  # if rs1 <(unsigned) rs2, pc += offset
+bge   rs1, rs2, offset  # if rs1 >= rs2, pc += offset
+bgeu  rs1, rs2, offset  # if rs1 >=(unsigned) rs2, pc += offset
+# pseudo-instructions
+beqz  rs, offset        # if rs == 0, pc += offset
+bnez  rs, offset        # if rs != 0, pc += offset
+
+

jump 类无条件跳转指令:

+
1
+2
+3
+4
+5
+6
+7
+8
jal  rd, offset      # rd = pc + 4; pc += offset
+jalr rd, imm(rs1)    # rd = pc + 4; pc = (sext(imm) + rs1) & ~1
+# pseudo-instructions
+j    offset          # pc += offset, x0 = pc + 4
+jr   rs              # pc = rs, x0 = pc + 4
+jal  offset          # pc += offset, x1 = pc + 4
+jalr rs              # pc = rs, x1 = pc + 4
+ret                  # pc = x1, x0 = pc + 4
+
+

注意到,我们这时候我们在这里用的是 offset 而不是 label,这就必须要说一下直接目标地址的编码了。当我们想要跳转到某个地址的时候,第一个反应都是直接在指令之中塞进去这个地址,但是在 RV32I 之中,我们使用的是 32 位的地址,而 RV32I 的指令都是 32 位编码的,所以将一个 32 位的地址塞到一个 32 位的指令中是不可能的,而对于一个经典的 beq 指令而言,除去 7 位的 opcode 与 3 位的 funct3,还有 5 位的 rs1rs2 之外,我们只剩下 12 位留给 label/offset 了。

+

为了克服这个限制,直接目标地址其实会编码成相对于在这条指令执行时相对于程序计数器的偏移量,本质上是一个立即数,这样我们就可以用一个 12 位的偏移量来表示跳转目标的地址了,这也阻止了指令跳转到太过于远的地方,只能跳转到 ±4KiB 范围之内。

+

注意到我们这里用到了直接目标地址/Direct Target Address 这个词,这种情况下,目标地址会直接编码到指令之中。相对地就有间接目标地址/Indirect Target Address,这种情况下,目标地址会存储在一个寄存器或者内存之中,指令会跳转到这个地址之中,典型例子就是 jr rs1

+

jal 指令其实是 Jump and Link 的缩写,表示跳转并链接,连接的是返回地址,它会将下一条指令的地址存到 rd 寄存器之中,然后跳转到 offset 之后的地址。想象一下函数调用的情景,我们跳转到函数的地址之后,根据现有寄存器的内容进行操作,然后再返回,也就是跳回来,这就需要我们提前就将返回的地址 pc + 4 存到一个规定好了的寄存器之中,下面是一个例子:

+
1
+2
+3
+4
+5
+6
+7
+8
jal ra, FOO       # invoke the FOO routine
+sub a0, a1, a2    # do something
+jal ra, FOO       # invoke the FOO routine
+mul a0, a1, a2    # do something
+
+FOO:
+    add a0, a0, a1
+    jr ra         # return to the caller
+
+

这里的 jr ra 就是返回到函数调用前下一个命令的地址——它的任务就是返回,自然也没有 link 的职责,RISC-V 只提供了 jalr 指令,所以我们看到 jr 其实是将存储链接地址的寄存器换成了硬件零寄存器 x0/zero,也就是 jalr zero, 0(ra)

+

当我们不显式指定存储返回地址的寄存器时,比如 jal offset,我们就将返回地址存储在 x1/ra 之中,ret 指令就是读取 x1 之中的地址并跳转回去的。

+

System Calls and Breaks

+

Conditional set Instructions

+
1
+2
+3
+4
+5
+6
+7
+8
+9
slt   rd, rs1, rs2   # rd = (rs1 < rs2) ? 1 : 0
+slti  rd, rs1, imm   # rd = (rs1 < sext(imm)) ? 1 : 0
+sltu  rd, rs1, rs2   # rd = ((unsigned)rs1 <(unsigned) rs2) ? 1 : 0
+sltui rd, rs1, imm   # rd = ((unsigned)rs1 <(unsigned)sext(imm)) ? 1 : 0
+# pseudo-instructions
+seqz  rd, rs         # rd = (rs == 0) ? 1 : 0
+snez  rd, rs         # rd = (rs != 0) ? 1 : 0
+sltz  rd, rs         # rd = (rs < 0)  ? 1 : 0
+sgtz  rd, rs         # rd = (rs > 0)  ? 1 : 0
+
+

Detecting Overflow

+

Arithmetic with Multi-Word Variables

+

Dealing with Large Immediate Values

+

Pseudo-Instructions

+
+

CS61C

+

But sometimes, for the programmer’s benefit, it’s useful to have additional instructions that aren't really implemented by the hardware but translated into real instructions.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
伪指令实际指令意义
lla rd, offsetauipc rd, offset[31:12]
addi rd, rd, offset[11:0]
加载局部地址
la rd, symbolPIC: auipc rd, GOT[symbol][31:12]
l{w|d} rd, GOT[symbol][11:0](rd)
Non-PIC: lla rd, symbol
加载全局地址
l{b|h|w} rd, symbolauipc rd, delta[31:12] + delta[11]
l{b|h|w} rd, delta[11:0](rd)
加载全局变量
s{b|h|w} rd, symbol, rtauipc rt, delta[31:12] + delta[11]
s{b|h|w} rd, delta[11:0](rt)
保存全局变量
nopaddi x0, x0, 0不进行任何操作
li rd, immaddi rd, imm if \(imm \in [0, 4096]\)
lui rd, (imm >> 12)
addi rd, rd, (imm & 0xFFF)
将立即数加载到 rd
mov rd, rsaddi rd, rs, 0rs 拷贝到 rd
not rd, rsxori rd, rs, -1rd = ~rs 按位取反
neg rd, rssub rd, x0, rsrd = -rs
seqz rd, rssltiu rd, rs, 1set rd if rs == 0
snez rd, rssltu rd, x0, rsset rd if rs != 0
sltz rd, rsslt rd, rs, x0set rd if rs < 0
sgtz rd, rsslt rd, x0, rsset rd if rs > 0
beqz rs, offsetbeq rs, x0, offsetbranch if rs == 0
bnez rs, offsetbne rs, x0, offsetbranch if rs != 0
blez rs, offsetbge x0, rs, offsetbranch if rs <= 0
bgez rs, offsetbge rs, x0, offsetbranch if rs >= 0
bltz rs, offsetblt rs, x0, offsetbranch if rs < 0
bgtz rs, offsetblt x0, rs, offsetbranch if rs > 0
bgt rs, rt, offsetblt rt, rs, offsetbranch if rs > rt
ble rs, rt, offsetbge rt, rs, offsetbranch if rs <= rt
bgtu rs, rt, offsetbltu rt, rs, offsetbranch if > unsigned
bleu rs, rt, offsetbgeu rt, rs, offsetbranch if <= unsigned
j offsetjal x0, offset无条件跳转,不存返回地址
jal offsetjal x1, offset无条件跳转,返回地址存到 ra
jr rsjalr x0, 0(rs)无条件跳转到 rs 位置,忽略返回地址
jalr rsjalr x1, 0(rs)无条件跳转到 rs 位置,存返回地址
retjalr x0, 0(ra)通过返回地址 x1 返回
call offsetauipc ra, offset[31 : 12]
jalr ra, offset[11:0](ra)
远调用
tail offsetauipc t1, offset[31 : 12]
jalr zero, offset[11:0](t1)
忽略返回地址远调用
+

4 From Code to Program

+

Labels and Symbols

+

标签/Label 其实是表示程序某个位置的符号,一般通过 name: 来定义,并且可以插入一个汇编程序之中来表征一个位置,这样就可以被别的汇编指令引用。符号/Symbols 是与数值相联系的名字,符号表/Symbol Table 是一个将符号与其值联系起来的映射表。汇编器将标签自动地转化成符号,并且将其与其地址联系起来,还将所有的符号放到符号表之中。使用 riscv64-unknown-elf-nm 可以查看某个目标文件的符号表。

+

符号/Symbol 可以分为全局符号/Global Symbols 和局部符号/Local Symbols。全局符号可以使用连接器在其他的目标文件中解析未定义引用,局部符号只在当前文件之中可见,也就是不可以用来解析其他文件之中的未定义引用。

+
+

Symbols are classified as local or global symbols. Local symbols are only visible on the same file, i.e. the linker does not use them to resolve undefined references on other files. Global symbols, on the other hand, are used by the linker to resolve undefined reference on other files.

+
+

默认来讲,汇编器会将标签/Label 作为局部符号,但是可以通过 .globl 指令来声明全局符号。程序的入口和出口都需要定义全局符号,比如:

+
1
+2
+3
+4
+5
+6
# contents of the exit.s file
+.globl exit
+exit:
+    li a7, 93
+    li a0, 0
+    ecall
+
+

Basic Routine

+

对于一个典型的 C 程序,程序的源代码经过编译器与连接器等工具处理、打包成一个包含了数据等信息与指令的可执行文件,载入进内存之后,操作系统再执行它。精确地讲,一个 .c 程序经过编译器得到一个 .s 的汇编程序,然后通过汇编器得到一个机器语言模块目标文件 .o,与别的库文件如 lib.o 一起通过连接器得到一个可执行文件

+

编译过程可以分解为下面的步骤:词法分析/Lexical Analysis,语法分析/Syntax Analysis,语义分析/Semantic Analysis,中间代码生成/Intermediate Representation Code Generation,中间代码优化/Intermediate Representation Code Optimization,目标代码生成/Object Code Generation,目标代码优化/Object Code Optimization 这几步。

+

中间代码生成这一步允许我们将整个编译过程模块化,对于很多不同的语言,比如 C,C++,Rust,我们可以生成同一种中间语言 IRC,然后再将 IRC 转化为不同的机器码。不仅如此,IRC 的存在还显著降低编译优化的难度。

+

汇编器不仅仅只做将汇编代码转换成机器码的工作,还会将不在指令集架构之中的伪指令转换成真实的指令,进而生成 ELF/Extensible Linking Format 格式的目标文件。ELF 文件是可执行文件,目标文件,共享库与核心转储文件/Core Dump 的标准格式。目标文件主要有三种:可重定位文件/Relocatable File,可执行文件/Executable File 与共享目标文件/Shared Object File。

+

可重定位文件存储着二进制代码与数据,适合与别的目标文件链接并生成一个可执行文件或者共享目标文件。可执行文件包含了二进制代码与数据,告诉操作系统如何加载程序,初始化程序的内存与状态并且进行执行,在执行可执行文件的时候,shell 调用操作系统中一个称为加载器/loader 的函数,将可执行文件中的代码与数据复制到内存之中,然后将控制转移到这个程序的开头。共享目标文件主要面对链接,连接器处理共享目标文件与其他的可重定位文件或者共享目标文件来生成另一个目标文件,动态连接器将功效目标文件与可执行文件结合,创建进程映像。

+

从上到下,ELF 文件由 ELF 头,程序头表,数据(节或者段)与节头表组成。ELF 头包含了文件的基本信息,节头表是一个节头数组,每一个节头记录了对应的的节的信息,比如节的名字、大小、在文件的偏移与读写权限等,连接器与装载器都是通过节头表来定位和访问节的属性,我们使用 readelf 工具来查看节头表。程序头表描述了系统如何创建一个程序的进程映像,每一个表项都定义了一个段/Segment,并且引用了节。

+

可以清晰的得出,可重定位文件必须要有节头表,但是程序头表并不必须,可执行文件必须要有程序头表,但是节头表并不必须。汇编器生成的就是

+

Program Entry Point

+

每一个可执行文件都有一个包含了程序的信息的文件头,其中的一个字段就存储了程序的入口地址/Entry Point Address。一旦操作系统将整个程序加载进主存,就将程序计数器的值设置成程序的入口地址,这样程序就开始执行了。

+

连接器负责设置可执行文件的入口地址字段。它首先会寻找一个全局符号 start(某些连接器会寻找 _start),如果找到了,就将程序的入口字段设置为 start 的地址。如果没有找到,就将入口地址设置为一个默认的值,一般是整个程序的第一个指令的地址。比如:

+
1
+2
+3
+4
+5
+6
# contents of the main.s file
+.global _start
+_start:
+    li a0, 42
+    li a7, 93
+    jal exit
+
+

使用下面指令进行编译:

+
1
+2
+3
$ riscv64-unknown-elf-as -march=rv32im main.s -o main.o
+$ riscv64-unknown-elf-as -march=rv32im exit.s -o exit.o
+$ riscv64-unknown-elf-ld -m elf32lriscv exit.o main.o -o main.x
+
+

在链接的时候,我们将 exit.o 放在了 main.o 的前面,这样 exit.o 的内容就会放在 main.o 的前面,使用 riscv64-unknown-elf-objdump 就能发现这一点,但是程序仍然以 main.o_start 作为入口。使用 riscv64-unknown-elf-readelf 可以查看程序的入口地址,这就可以验证程序的入口地址是 _start

+

Program Sections

+

无论是可执行文件、目标文件还是汇编程序,他们都是按照不同的节组织的,每个节都包含了数据或者指令,并且都映射到内存中一段连续的区域。Linux 系统的可执行文件中,一般会出现下面四个节/节:

+
    +
  • .text:包含了程序的指令;
  • +
  • .data:包含了程序中初始化过的全局变量,这些全局变量的值需要在程序开始执行之前就初始化掉;
  • +
  • .bss:包含了程序中未初始化的全局变量;
  • +
  • .rodata:包含了程序中的只读数据/常量,比如字符串常量,这些数值在程序执行过程中不能修改。
  • +
+
+

img.png

+
+

When linking multiple object files, the linker groups information from sections with the same name and places them together into a single section on the executable file. For example, when linking multiple object files, the contents of the .text sections from all object files are grouped together and placed sequentially on the executable file on a single section that is also called .text. The following figure shows the layout of an RV32I executable file that was generated by the riscv64-unknown-elf-ld tool, and is encoded using the Executable and Linking Format. This file contains three sections: the .data, the .rodata, and the .text sections. The contents of section .text are mapped to addresses 8000 to 8007, while the contents of section .data are mapped to addresses 800d to 8011.

+
+
+

当链接不同的文件的时候,连接器会将相同名字的节合并到可执行文件的一个节之中。比如,当链接多个目标文件的时候,所有的 .text 节都会被顺序地合并到一个叫 .text 的节之中。默认情况下,GNU 汇编器会将所有的信息都放到 .text 节之中。如果想要将信息放到其他节,可以使用 .section secname 指令,这个指令会告诉汇编器将接下来的信息放到叫 secname 的节之中。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
    .section .data
+x:  .word 10
+    .section .text
+update_x:
+    la t1, x
+    sw a0, 0(t1)
+    ret
+
+    .section .data
+y:  .word 12
+    .section .text
+update_y:
+    la t1, y
+    sw a0, 0(t1)
+    ret
+
+

这里的第二行包含了一个标签 x: 和一个 .word 指令,它们一起使用可以声明一个全局变量 x,并且初始化为 10。这个全局变量会被放到 .data 节之中。接下来的指令将下面的内容存回 .text 节之中。连接器通过不同节的分块与重定位,避免了将指令与数据混在一起的冲突。

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/RISC-V/RISC-V/index.html b/System/RISC-V/RISC-V/index.html new file mode 100644 index 0000000..229fc54 --- /dev/null +++ b/System/RISC-V/RISC-V/index.html @@ -0,0 +1,1819 @@ + + + + + + + + + + + + + + + + + + + + + + + + + RISC-V - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

RISC-V

+
+

约 426 个字 3 行代码 预计阅读时间 1 分钟

+
+
+

Info

+
+

RISC-V Principles

+
    +
  • Simplicity favors regularity.
  • +
  • Smaller is faster.
  • +
  • Separated into multiple specifications
  • +
  • ISA support is given by RV + word-width + extensions, such as RV32I means RISC-V with 32-bit word width and integer base instruction set.
  • +
+

User-Level ISA

+

User-Level ISA defines the normal instructions needed for computation:

+
    +
  • A mandatory base integer ISA RV32I/RV32E/RV64I
  • +
  • I for basic Integer instructions, including ALU(only with addition and subtraction), Branches and Jumps, Loads and Stores.
  • +
  • Standard Extensions:
  • +
  • M for Integer Multiplication and Division.
  • +
  • A for Atomic Instructions.
  • +
  • F for Single-Precision Floating-Point.
  • +
  • D for Double-Precision Floating-Point.
  • +
  • C for Compressed Instructions (16-bit).
  • +
  • V for Vector Operations.
  • +
  • Q for Quad-Precision Floating-Point.
  • +
  • Zicsr for Control and Status Registers.
  • +
  • Zifencei for FENCE.I Instruction.
  • +
  • G/IMAFDZicsr_Zifencei for General Purpose, i.e. integer base and four standard extensions.
  • +
+

Components

+

Any assembly programs are encoded as plain text files and contain four main components:

+
    +
  • Comments
  • +
  • Labels
  • +
  • Assembly Instructions
  • +
  • Assembly Directives
  • +
+

Addressing Architecture

+

A Load/Store Architecture is an instruction set architecture that requires values to be loaded/stored explicitly from/to memory before operating on them. In other words, to read/write a value from/to memory, the software must execute a load/store instruction.

+

The RISC-V ISA is a Load/Store Architecture. Hence, to perform operations (e.g. arithmetic operations), on data stored on memory, it requires the data to be first retrieved from memory into a register by executing a load instruction. As an example, let us consider the following assembly code, which loads a value from memory, multiply it by two, and stores the result on memory.

+
1
+2
+3
lw  a5, 0(a0)     # load the value at address a0 into register a5
+add a6, a5, a5    # multiply the value in a5 by 2 and store the result
+sw  a6, 0(a1)     # store the value in a6 at address a1
+
+

Toolchain

+

The following toolchain is included in the binutils-riscv64-unknown-elf package:

+
    +
  • riscv64-unknown-elf-as: a version of the GNU Assembler that generates code for RISC-V ISAs.
      +
    • -march=rv32i: specify the target ISA as RV32I.
    • +
    • -mabi=ilp32: specify the target ABI as ILP32.
    • +
    • example: riscv64-unknown-elf-as -march=RV32I -mabi=ilp32 hello.o -o hello.s
    • +
    +
  • +
  • riscv64-unknown-elf-ld: a version of the GNU linker that links object files into an executable file.
      +
    • -m elf32lriscv: specify the object file format as ELF32.
    • +
    +
  • +
  • riscv64-unknown-elf-objdump: a version of the GNU objdump that displays information about object files.
      +
    • -D or --disassemble-all: disassemble the contents of a binary file.
    • +
    • example: riscv64-unknown-elf-ld -m elf32lricsv trunk.o -o trunk.x && riscv64-unknown-elf-objdump -D trunk,x
    • +
    • -r or --reloc: inspect the contents of the relocation table on the file.
    • +
    +
  • +
  • riscv64-unknown-elf-nm: a version of the GNU nm that inspects the symbol table of an object file.
      +
    • example: riscv64-unknown-elf-nm trunk.o
    • +
    +
  • +
  • riscv64-unknown-elf-readelf: inspect the ELF header of an executable file.
      +
    • -h or --file-header: display the ELF file header.
    • +
    +
  • +
+

Supplement

+
    +
  • File format to encode object files:
      +
    • ELF (Executable and Linkable Format) is frequently used in Linux-based systems.
    • +
    • PE (Portable Executable) is used in Windows-based systems.
    • +
    +
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/TDAAC/TDAAC/index.html b/System/TDAAC/TDAAC/index.html new file mode 100644 index 0000000..09e92f4 --- /dev/null +++ b/System/TDAAC/TDAAC/index.html @@ -0,0 +1,1425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + The Datacenter as a Computer - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

The Datacenter as a Computer

+
+

约 5 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/images/img-CSAPP/image2-1.png b/System/images/img-CSAPP/image2-1.png new file mode 100644 index 0000000..92dc517 Binary files /dev/null and b/System/images/img-CSAPP/image2-1.png differ diff --git a/System/images/img-CSAPP/image3-1.png b/System/images/img-CSAPP/image3-1.png new file mode 100644 index 0000000..a5a5954 Binary files /dev/null and b/System/images/img-CSAPP/image3-1.png differ diff --git a/System/images/img-RISC-V/img.png b/System/images/img-RISC-V/img.png new file mode 100644 index 0000000..b67ef54 Binary files /dev/null and b/System/images/img-RISC-V/img.png differ diff --git a/System/images/img-Verilog/5.png b/System/images/img-Verilog/5.png new file mode 100644 index 0000000..dc8a89e Binary files /dev/null and b/System/images/img-Verilog/5.png differ diff --git a/System/images/img-Verilog/7.png b/System/images/img-Verilog/7.png new file mode 100644 index 0000000..6579287 Binary files /dev/null and b/System/images/img-Verilog/7.png differ diff --git a/System/images/img-Verilog/mux2to1.png b/System/images/img-Verilog/mux2to1.png new file mode 100644 index 0000000..c24837f Binary files /dev/null and b/System/images/img-Verilog/mux2to1.png differ diff --git a/System/index.html b/System/index.html new file mode 100644 index 0000000..7a8552e --- /dev/null +++ b/System/index.html @@ -0,0 +1,1374 @@ + + + + + + + + + + + + + + + + + + + + + + + + + 计算机系统相关 - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+ +
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System/x86 Assembly/x86/index.html b/System/x86 Assembly/x86/index.html new file mode 100644 index 0000000..43bb38c --- /dev/null +++ b/System/x86 Assembly/x86/index.html @@ -0,0 +1,1551 @@ + + + + + + + + + + + + + + + + + + + + + + + + + x86 Assembly - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

x86 Assembly

+
+

约 2 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Varia/Booklist/index.html b/Varia/Booklist/index.html new file mode 100644 index 0000000..064a947 --- /dev/null +++ b/Varia/Booklist/index.html @@ -0,0 +1,1134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Booklist - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Booklist

+
+

约 112 个字

+
+

Computer Science

+
    +
  • 《Computer System: A Programmer's Perspective》 Randal E. Bryant, David R. O'Hallaron 著
  • +
+

Math

+
    +
  • +

    《数学分析》 梅加强 著

    +
  • +
  • +

    《数学分析讲义》 陈天权 著

    +
  • +
  • +

    《Real And Complex Analysis》 Walter Rudin 著

    +
  • +
+

Literature

+
    +
  • 《雪国》 川端康成 著
  • +
+

Varia

+

Philosophy

+
    +
  • +

    《哲学导论》 王德峰 著

    +
  • +
  • +

    《西方现代思想讲义》 刘擎 著

    +
  • +
+

History

+
    +
  • +

    《The Western Heritage》

    +
  • +
  • +

    《枫丹白露宫 千年法国史》 让·弗朗索瓦·埃贝尔、蒂埃里·萨尔芒 著

    +
  • +
+

Society

+
    +
  • 《基本收入》 盖伊·斯坦丁 著
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Varia/Envs/index.html b/Varia/Envs/index.html new file mode 100644 index 0000000..5e22a80 --- /dev/null +++ b/Varia/Envs/index.html @@ -0,0 +1,1463 @@ + + + + + + + + + + + + + + + + + + + + + + + Environment Configuration - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Environment Configuration Record

+
+

约 407 个字 159 行代码 预计阅读时间 3 分钟

+
+
+

Info

+

为了有效缓解重装系统之后配环境的痛苦,我决定在这里写下我的环境配置纪实。

+

什么?配环境不痛苦?那你给我配。

+
+

脚本

+

忍不了了!所以写了个配环境的脚本!

+
+Makefile +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
install:
+sudo apt update
+sudo apt install python3 pip autoconf automake gcc g++ flex bison ccache help2man libtool gtkwave perl-doc
+sudo apt install build-essential gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu qemu-user gdb-multiarch pkg-config device-tree-compiler
+sudo apt install npm nodejs zsh llvm llvm-dev libreadline-dev
+download: install
+git clone https://git.zju.edu.cn/zju-sys/sys1/sys1-sp24.git
+git submodule update --init sys1-sp24/repo/riscv-isa-cosim
+git submodule update --init sys1-sp24/repo/riscv-pk
+git submodule update --init sys1-sp24/repo/riscv-openocd
+git submodule update --init sys1-sp24/repo/sys-project
+git submodule update --init sys1-sp24/repo/verilator
+cd sys1-sp24/repo/sys-project && git checkout other
+cd sys1-sp24/repo && make verilator
+cd sys1-sp24/repo && make spike
+cd sys1-sp24/repo && sudo make pk
+cd sys1-sp24/repo && make openocd
+cd /usr/local && sudo mkdir riscv64-unknown-elf && sudo mkdir riscv64-unknown-elf/bin && sudo cp riscv64-linux-gnu/bin/pk riscv64-unknown-elf/bin
+cd ~ && mkdir package
+cd ~/package && wget https://github.com/neovim/neovim/releases/download/v0.9.5/nvim-linux64.tar.gz
+$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
+cd ~/package && tar xzvf nvim-linux64.tar.gz
+cd ~ && sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
+cd ~ && git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/half-life
+
+
+

WSL

+

安装

+

我不说了,假定所有人都会。

+

删除本版本的 WSL:wsl --unregister Ubuntu-20.04 后边跟的是版本号,使用 wsl --list 就能看见了。

+

zsh

+

安装 zsh 并设置为默认 shell: +

1
+2
+3
sudo apt install zsh
+cat /etc/shells
+chsh -s /bin/zsh
+

+

使用 oh-my-zsh 美化 zsh: +

1
+2
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
+git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/half-life
+

+

使用 vim 打开 ~/.zshrc,修改 ZSH_THEMEZSH_THEME="half-life": +

1
+2
vim ~/.zshrc
+ZSH_THEME="half-life"       // 这步是在 vim 里边写入的
+

+

配置插件: +

1
+2
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
+git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting 
+

+

还要修改 ~/.zshrc,在 plugins 里边加入 zsh-autosuggestionszsh-syntax-highlighting: +

plugins=(git zsh-autosuggestions zsh-syntax-highlighting z)
+

+

vim

+

原版的 vim 不太好看,而且功能也有限,虽然现在不太用 vim 了,但是还是好看一点比较好,这里选择安装 lunarvim:

+

安装步骤大概分几步:安装 lunarvim 的所有依赖,改环境变量,安装 lunarvim,改环境变量。环境变量千万别改错,改回去稍微费点劲。

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
wget https://github.com/neovim/neovim/releases/download/v0.9.5/nvim-linux64.tar.gz
+tar xzvf nvim-linux64.tar.gz
+vim ~/.zshrc
+export PATH=$PATH:~/nvim-linux64/bin    // 这步是在 vim 里边写入的
+source ~/.zshrc
+sudo apt install pip npm nodejs ripgrep
+LV_BRANCH='release-1.3/neovim-0.9' bash <(curl -s https://raw.githubusercontent.com/LunarVim/LunarVim/release-1.3/neovim-0.9/utils/installer/install.sh)
+nvim ~/.zshrc
+export PATH=$PATH:~/.local/bin          // 这步是在 vim 里边写入的
+source ~/.zshrc
+
+

开始享受 lunarvim 吧!

+

计算机系统相关

+

首先需要安装依赖: +

sudo apt-get install git perl python3 make autoconf g++ flex bison ccache autoconf automake libtool help2man
+

+

其实就是按照系统 I 的文档开抄:

+
1
+2
+3
+4
+5
+6
cd sys1-sp24/repo
+git submodule update --init verilator riscv-isa-cosim riscv-openocd risv-pk
+sudo make verilator
+sudo make spike
+sudo make pk
+sudo make openocd
+
+

说是使用 git submodule,其实就是 git clone https://github.com/verilator/verilator.git

+
+makefile 的内容 +

makefile 的内容放在下边:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
DIR_BUILD       := $(CURDIR)/build
+DIR_PATCH       := $(CURDIR)/patch
+DIR_UPSTREAM    := $(CURDIR)/sys-project
+
+# compile for the ip folder
+SPIKE_DIR       := $(CURDIR)/riscv-isa-cosim
+SPIKE_SRC       := $(shell find $(SPIKE_DIR) -name "*.cc" -o -name "*.h" -o -name "*.c")
+SPIKE_LIB       := $(addprefix $(SPIKE_BUILD)/,libcosim.a libriscv.a libdisasm.a libsoftfloat.a libfesvr.a libfdt.a)
+SPIKE_INCLUDE   := $(SPIKE_DIR) $(SPIKE_DIR)/cosim $(SPIKE_DIR)/fdt $(SPIKE_DIR)/fesvr \
+                   $(SPIKE_DIR)/riscv $(SPIKE_DIR)/softfloat $(SPIKE_BUILD)
+IP_BUILD        := $(DIR_BUILD)/ip
+DIR_COSIM_IP    := $(DIR_UPSTREAM)/ip
+
+export LD_LIBRARY_PATH=$(IP_BUILD)
+$(IP_BUILD)/patch:
+    mkdir -p $(IP_BUILD)
+    cd $(SPIKE_DIR) ; git apply $(DIR_PATCH)/riscv-isa-cosim/*
+    touch $(IP_BUILD)/patch
+
+$(IP_BUILD)/Makefile:
+    mkdir -p $(IP_BUILD)
+    cd $(IP_BUILD); $(SPIKE_DIR)/configure --prefix=$(DIR_COSIM_IP)
+
+ip_gen:$(SPIKE_SRC) $(IP_BUILD)/Makefile $(IP_BUILD)/patch
+    mkdir -p $(DIR_COSIM_IP)
+    make -C $(IP_BUILD) -j$(shell nproc) $(notdir $(SPIKE_LIB))
+    make -C $(IP_BUILD) install
+
+#compiler for verilator
+VLT_DIR     := $(CURDIR)/verilator
+VLT_BUILD   := $(DIR_BUILD)/verilator
+$(VLT_BUILD)/Makefile:
+    mkdir -p $(VLT_BUILD)
+    cd $(VLT_DIR); autoconf
+    cd $(VLT_BUILD); $(VLT_DIR)/configure 
+
+verilator:$(VLT_BUILD)/Makefile $(VLT_DIR)
+    make -C $(VLT_BUILD) -j$(shell nproc)
+    sudo make -C $(VLT_BUILD) install
+    verilator --version
+
+#compiler for opensbi
+OPENSBI_DIR     :=  $(CURDIR)/opensbi
+OPENSBI_BUILD   :=  $(DIR_BUILD)/opensbi
+FW_JUMP_BUILD   :=  $(OPENSBI_BUILD)/platform/generic/firmware/fw_jump.bin $(OPENSBI_BUILD)/platform/generic/firmware/fw_jump.elf
+FW_JUMP         :=  $(DIR_UPSTREAM)/spike/fw_jump.bin $(DIR_UPSTREAM)/spike/fw_jump.elf
+
+$(OPENSBI_BUILD)/patch:
+    mkdir -p $(OPENSBI_BUILD)
+    cd $(OPENSBI_DIR); git apply $(DIR_PATCH)/opensbi/*
+    touch $(OPENSBI_BUILD)/patch
+
+$(FW_JUMP_BUILD):$(OPENSBI_SRC) $(OPENSBI_BUILD)/patch
+    make -C $(OPENSBI_DIR) O=$(OPENSBI_BUILD) \
+        CROSS_COMPILE=riscv64-linux-gnu- \
+        PLATFORM=generic
+
+$(FW_JUMP):$(FW_JUMP_BUILD)
+    cp $(FW_JUMP_BUILD) $(DIR_UPSTREAM)/spike/
+
+fw_jump:$(FW_JUMP)
+
+#compiler for spike
+SPIKE_BUILD := $(DIR_BUILD)/spike
+
+spike:$(SPIKE_DIR)
+    mkdir -p $(SPIKE_BUILD)
+    cd $(SPIKE_BUILD) ; $(SPIKE_DIR)/configure
+    make -C $(SPIKE_BUILD) -j$(shell nproc)
+    sudo make -C $(SPIKE_BUILD) install
+
+#compiler for openocd
+OPENOCD_DIR     := $(CURDIR)/riscv-openocd
+OPENOCD_BUILD   := $(DIR_BUILD)/openocd
+
+openocd:$(OPENOCD_DIR)
+    mkdir -p $(OPENOCD_BUILD)
+    cd $(OPENOCD_DIR); ./bootstrap;
+    cd $(OPENOCD_BUILD); $(OPENOCD_DIR)/configure
+    make -C $(OPENOCD_BUILD) -j$(shell nproc)
+    sudo make -C $(OPENOCD_BUILD) install
+    openocd --version
+
+PK_DIR  :=  $(CURDIR)/riscv-pk
+PK_BUILD:=  $(DIR_BUILD)/riscv-pk
+
+pk:$(PK_DIR)
+    mkdir -p $(PK_BUILD)
+    cd $(PK_BUILD); $(PK_DIR)/configure --host=riscv64-linux-gnu
+    cd $(PK_BUILD); make -j$(nproc)
+    cd $(PK_BUILD); make install
+
+
+

gcc 版本切换

+

首先添加 ppa 源:

+
1
+2
+3
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
+sudo -E add-apt-repository ppa:ubuntu-toolchain-r/test
+sudo apt-get update
+
+

下面利用 update-alternatives 进行 gcc 版本切换:

+
1
+2
+3
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 70 --slave /usr/bin/g++ g++ /usr/bin/g++-13
+sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 60 --slave /usr/bin/g++ g++ /usr/bin/g++-11
+sudo update-alternatives --config gcc
+
+

之后按照提示选择 gcc 版本即可。

+

添加不了就拉倒,手动装就好了,但是可能用不了几个版本了,因为这样默认的 gcc 就是 gcc-13 了,但是仍然不建议手动编译安装,因为会出现坑爹的情况。

+
1
+2
+3
+4
+5
+6
+7
+8
+9
mkdir package && cd package
+wget http://ftp.gnu.org/gnu/gcc/gcc-13.1.0/gcc-13.1.0.tar.gz
+tar xf gcc-13.1.0.tar.gz
+cd gcc-13.1.0/
+./contrib/download_prerequisites
+mkdir build && cd build
+../configure -enable-checking=release -enable-languages=c,c++ -disable-multilib
+sudo make -j8           // 给我编译半小时!
+sudo make install
+
+

Rust

+
1
+2
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
+. "$HOME/.cargo/env"
+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Varia/Learning Plan/index.html b/Varia/Learning Plan/index.html new file mode 100644 index 0000000..b6c7e7c --- /dev/null +++ b/Varia/Learning Plan/index.html @@ -0,0 +1,920 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Learning Plan - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Learning Plan

+
+

约 44 个字

+
+
+

Abstract

+

挖坑时间到!这真的只是我对我的学习期望而已,想学不代表一定会学(x

+

当然,我是一定会奋力学的!

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Varia/Tools/index.html b/Varia/Tools/index.html new file mode 100644 index 0000000..17a30d5 --- /dev/null +++ b/Varia/Tools/index.html @@ -0,0 +1,823 @@ + + + + + + + + + + + + + + + + + + + + + Tools Using Record - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Tools Using Record

+
+

约 4 个字

+
+

1. IDA

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Varia/Typst/index.html b/Varia/Typst/index.html new file mode 100644 index 0000000..770a5e4 --- /dev/null +++ b/Varia/Typst/index.html @@ -0,0 +1,907 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Typst Learning Report - V1CeVersa's Notebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Typst Learning Report

+ +
+

约 0 个字

+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000..1cf13b9 Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/images/pdf.svg b/assets/images/pdf.svg new file mode 100644 index 0000000..a44518f --- /dev/null +++ b/assets/images/pdf.svg @@ -0,0 +1,149 @@ + + + + + PDF file icon + + + + + + + + + + image/svg+xml + + PDF file icon + 08/10/2018 + + + Adobe Systems + + + + + CMetalCore + + + Fuente del texto "PDF": +Franklin Gothic Medium Cond + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/javascripts/bundle.ad660dcc.min.js b/assets/javascripts/bundle.ad660dcc.min.js new file mode 100644 index 0000000..0ffc046 --- /dev/null +++ b/assets/javascripts/bundle.ad660dcc.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Fi=Object.create;var gr=Object.defineProperty;var ji=Object.getOwnPropertyDescriptor;var Wi=Object.getOwnPropertyNames,Dt=Object.getOwnPropertySymbols,Ui=Object.getPrototypeOf,xr=Object.prototype.hasOwnProperty,no=Object.prototype.propertyIsEnumerable;var oo=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,R=(e,t)=>{for(var r in t||(t={}))xr.call(t,r)&&oo(e,r,t[r]);if(Dt)for(var r of Dt(t))no.call(t,r)&&oo(e,r,t[r]);return e};var io=(e,t)=>{var r={};for(var o in e)xr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Dt)for(var o of Dt(e))t.indexOf(o)<0&&no.call(e,o)&&(r[o]=e[o]);return r};var yr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Di=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Wi(t))!xr.call(e,n)&&n!==r&&gr(e,n,{get:()=>t[n],enumerable:!(o=ji(t,n))||o.enumerable});return e};var Vt=(e,t,r)=>(r=e!=null?Fi(Ui(e)):{},Di(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var ao=(e,t,r)=>new Promise((o,n)=>{var i=p=>{try{s(r.next(p))}catch(c){n(c)}},a=p=>{try{s(r.throw(p))}catch(c){n(c)}},s=p=>p.done?o(p.value):Promise.resolve(p.value).then(i,a);s((r=r.apply(e,t)).next())});var co=yr((Er,so)=>{(function(e,t){typeof Er=="object"&&typeof so!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Er,function(){"use strict";function e(r){var o=!0,n=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(H){return!!(H&&H!==document&&H.nodeName!=="HTML"&&H.nodeName!=="BODY"&&"classList"in H&&"contains"in H.classList)}function p(H){var mt=H.type,ze=H.tagName;return!!(ze==="INPUT"&&a[mt]&&!H.readOnly||ze==="TEXTAREA"&&!H.readOnly||H.isContentEditable)}function c(H){H.classList.contains("focus-visible")||(H.classList.add("focus-visible"),H.setAttribute("data-focus-visible-added",""))}function l(H){H.hasAttribute("data-focus-visible-added")&&(H.classList.remove("focus-visible"),H.removeAttribute("data-focus-visible-added"))}function f(H){H.metaKey||H.altKey||H.ctrlKey||(s(r.activeElement)&&c(r.activeElement),o=!0)}function u(H){o=!1}function h(H){s(H.target)&&(o||p(H.target))&&c(H.target)}function w(H){s(H.target)&&(H.target.classList.contains("focus-visible")||H.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(H.target))}function A(H){document.visibilityState==="hidden"&&(n&&(o=!0),te())}function te(){document.addEventListener("mousemove",J),document.addEventListener("mousedown",J),document.addEventListener("mouseup",J),document.addEventListener("pointermove",J),document.addEventListener("pointerdown",J),document.addEventListener("pointerup",J),document.addEventListener("touchmove",J),document.addEventListener("touchstart",J),document.addEventListener("touchend",J)}function ie(){document.removeEventListener("mousemove",J),document.removeEventListener("mousedown",J),document.removeEventListener("mouseup",J),document.removeEventListener("pointermove",J),document.removeEventListener("pointerdown",J),document.removeEventListener("pointerup",J),document.removeEventListener("touchmove",J),document.removeEventListener("touchstart",J),document.removeEventListener("touchend",J)}function J(H){H.target.nodeName&&H.target.nodeName.toLowerCase()==="html"||(o=!1,ie())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",A,!0),te(),r.addEventListener("focus",h,!0),r.addEventListener("blur",w,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var Yr=yr((Rt,Kr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Rt=="object"&&typeof Kr=="object"?Kr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Rt=="object"?Rt.ClipboardJS=r():t.ClipboardJS=r()})(Rt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Ii}});var a=i(279),s=i.n(a),p=i(370),c=i.n(p),l=i(817),f=i.n(l);function u(V){try{return document.execCommand(V)}catch(_){return!1}}var h=function(_){var O=f()(_);return u("cut"),O},w=h;function A(V){var _=document.documentElement.getAttribute("dir")==="rtl",O=document.createElement("textarea");O.style.fontSize="12pt",O.style.border="0",O.style.padding="0",O.style.margin="0",O.style.position="absolute",O.style[_?"right":"left"]="-9999px";var j=window.pageYOffset||document.documentElement.scrollTop;return O.style.top="".concat(j,"px"),O.setAttribute("readonly",""),O.value=V,O}var te=function(_,O){var j=A(_);O.container.appendChild(j);var D=f()(j);return u("copy"),j.remove(),D},ie=function(_){var O=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},j="";return typeof _=="string"?j=te(_,O):_ instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(_==null?void 0:_.type)?j=te(_.value,O):(j=f()(_),u("copy")),j},J=ie;function H(V){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?H=function(O){return typeof O}:H=function(O){return O&&typeof Symbol=="function"&&O.constructor===Symbol&&O!==Symbol.prototype?"symbol":typeof O},H(V)}var mt=function(){var _=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},O=_.action,j=O===void 0?"copy":O,D=_.container,Y=_.target,ke=_.text;if(j!=="copy"&&j!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Y!==void 0)if(Y&&H(Y)==="object"&&Y.nodeType===1){if(j==="copy"&&Y.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(j==="cut"&&(Y.hasAttribute("readonly")||Y.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(ke)return J(ke,{container:D});if(Y)return j==="cut"?w(Y):J(Y,{container:D})},ze=mt;function Ie(V){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Ie=function(O){return typeof O}:Ie=function(O){return O&&typeof Symbol=="function"&&O.constructor===Symbol&&O!==Symbol.prototype?"symbol":typeof O},Ie(V)}function _i(V,_){if(!(V instanceof _))throw new TypeError("Cannot call a class as a function")}function ro(V,_){for(var O=0;O<_.length;O++){var j=_[O];j.enumerable=j.enumerable||!1,j.configurable=!0,"value"in j&&(j.writable=!0),Object.defineProperty(V,j.key,j)}}function Ai(V,_,O){return _&&ro(V.prototype,_),O&&ro(V,O),V}function Ci(V,_){if(typeof _!="function"&&_!==null)throw new TypeError("Super expression must either be null or a function");V.prototype=Object.create(_&&_.prototype,{constructor:{value:V,writable:!0,configurable:!0}}),_&&br(V,_)}function br(V,_){return br=Object.setPrototypeOf||function(j,D){return j.__proto__=D,j},br(V,_)}function Hi(V){var _=Pi();return function(){var j=Wt(V),D;if(_){var Y=Wt(this).constructor;D=Reflect.construct(j,arguments,Y)}else D=j.apply(this,arguments);return ki(this,D)}}function ki(V,_){return _&&(Ie(_)==="object"||typeof _=="function")?_:$i(V)}function $i(V){if(V===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return V}function Pi(){if(typeof Reflect=="undefined"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(V){return!1}}function Wt(V){return Wt=Object.setPrototypeOf?Object.getPrototypeOf:function(O){return O.__proto__||Object.getPrototypeOf(O)},Wt(V)}function vr(V,_){var O="data-clipboard-".concat(V);if(_.hasAttribute(O))return _.getAttribute(O)}var Ri=function(V){Ci(O,V);var _=Hi(O);function O(j,D){var Y;return _i(this,O),Y=_.call(this),Y.resolveOptions(D),Y.listenClick(j),Y}return Ai(O,[{key:"resolveOptions",value:function(){var D=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof D.action=="function"?D.action:this.defaultAction,this.target=typeof D.target=="function"?D.target:this.defaultTarget,this.text=typeof D.text=="function"?D.text:this.defaultText,this.container=Ie(D.container)==="object"?D.container:document.body}},{key:"listenClick",value:function(D){var Y=this;this.listener=c()(D,"click",function(ke){return Y.onClick(ke)})}},{key:"onClick",value:function(D){var Y=D.delegateTarget||D.currentTarget,ke=this.action(Y)||"copy",Ut=ze({action:ke,container:this.container,target:this.target(Y),text:this.text(Y)});this.emit(Ut?"success":"error",{action:ke,text:Ut,trigger:Y,clearSelection:function(){Y&&Y.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(D){return vr("action",D)}},{key:"defaultTarget",value:function(D){var Y=vr("target",D);if(Y)return document.querySelector(Y)}},{key:"defaultText",value:function(D){return vr("text",D)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(D){var Y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return J(D,Y)}},{key:"cut",value:function(D){return w(D)}},{key:"isSupported",value:function(){var D=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Y=typeof D=="string"?[D]:D,ke=!!document.queryCommandSupported;return Y.forEach(function(Ut){ke=ke&&!!document.queryCommandSupported(Ut)}),ke}}]),O}(s()),Ii=Ri},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,p){for(;s&&s.nodeType!==n;){if(typeof s.matches=="function"&&s.matches(p))return s;s=s.parentNode}}o.exports=a},438:function(o,n,i){var a=i(828);function s(l,f,u,h,w){var A=c.apply(this,arguments);return l.addEventListener(u,A,w),{destroy:function(){l.removeEventListener(u,A,w)}}}function p(l,f,u,h,w){return typeof l.addEventListener=="function"?s.apply(null,arguments):typeof u=="function"?s.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(A){return s(A,f,u,h,w)}))}function c(l,f,u,h){return function(w){w.delegateTarget=a(w.target,f),w.delegateTarget&&h.call(l,w)}}o.exports=p},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(o,n,i){var a=i(879),s=i(438);function p(u,h,w){if(!u&&!h&&!w)throw new Error("Missing required arguments");if(!a.string(h))throw new TypeError("Second argument must be a String");if(!a.fn(w))throw new TypeError("Third argument must be a Function");if(a.node(u))return c(u,h,w);if(a.nodeList(u))return l(u,h,w);if(a.string(u))return f(u,h,w);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(u,h,w){return u.addEventListener(h,w),{destroy:function(){u.removeEventListener(h,w)}}}function l(u,h,w){return Array.prototype.forEach.call(u,function(A){A.addEventListener(h,w)}),{destroy:function(){Array.prototype.forEach.call(u,function(A){A.removeEventListener(h,w)})}}}function f(u,h,w){return s(document.body,u,h,w)}o.exports=p},817:function(o){function n(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var p=window.getSelection(),c=document.createRange();c.selectNodeContents(i),p.removeAllRanges(),p.addRange(c),a=p.toString()}return a}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,a,s){var p=this.e||(this.e={});return(p[i]||(p[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var p=this;function c(){p.off(i,c),a.apply(s,arguments)}return c._=a,this.on(i,c,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),p=0,c=s.length;for(p;p{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var ts=/["'&<>]/;ei.exports=rs;function rs(e){var t=""+e,r=ts.exec(t);if(!r)return t;var o,n="",i=0,a=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function N(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],a;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(s){a={error:s}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(a)throw a.error}}return i}function q(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||s(u,h)})})}function s(u,h){try{p(o[u](h))}catch(w){f(i[0][3],w)}}function p(u){u.value instanceof nt?Promise.resolve(u.value.v).then(c,l):f(i[0][2],u)}function c(u){s("next",u)}function l(u){s("throw",u)}function f(u,h){u(h),i.shift(),i.length&&s(i[0][0],i[0][1])}}function mo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof de=="function"?de(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(a){return new Promise(function(s,p){a=e[i](a),n(s,p,a.done,a.value)})}}function n(i,a,s,p){Promise.resolve(p).then(function(c){i({value:c,done:s})},a)}}function k(e){return typeof e=="function"}function ft(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var zt=ft(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function qe(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Fe=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=de(a),p=s.next();!p.done;p=s.next()){var c=p.value;c.remove(this)}}catch(A){t={error:A}}finally{try{p&&!p.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var l=this.initialTeardown;if(k(l))try{l()}catch(A){i=A instanceof zt?A.errors:[A]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=de(f),h=u.next();!h.done;h=u.next()){var w=h.value;try{fo(w)}catch(A){i=i!=null?i:[],A instanceof zt?i=q(q([],N(i)),N(A.errors)):i.push(A)}}}catch(A){o={error:A}}finally{try{h&&!h.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new zt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)fo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&qe(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&qe(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Tr=Fe.EMPTY;function qt(e){return e instanceof Fe||e&&"closed"in e&&k(e.remove)&&k(e.add)&&k(e.unsubscribe)}function fo(e){k(e)?e():e.unsubscribe()}var $e={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var ut={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,a=n.isStopped,s=n.observers;return i||a?Tr:(this.currentObservers=null,s.push(r),new Fe(function(){o.currentObservers=null,qe(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,a=o.isStopped;n?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,o){return new Eo(r,o)},t}(F);var Eo=function(e){re(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:Tr},t}(g);var _r=function(e){re(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(g);var Lt={now:function(){return(Lt.delegate||Date).now()},delegate:void 0};var _t=function(e){re(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=Lt);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,a=o._infiniteTimeWindow,s=o._timestampProvider,p=o._windowTime;n||(i.push(r),!a&&i.push(s.now()+p)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,a=n._buffer,s=a.slice(),p=0;p0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(vt);var So=function(e){re(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(gt);var Hr=new So(To);var Oo=function(e){re(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=bt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var a=r.actions;o!=null&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==o&&(bt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(vt);var Mo=function(e){re(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(gt);var me=new Mo(Oo);var M=new F(function(e){return e.complete()});function Yt(e){return e&&k(e.schedule)}function kr(e){return e[e.length-1]}function Xe(e){return k(kr(e))?e.pop():void 0}function He(e){return Yt(kr(e))?e.pop():void 0}function Bt(e,t){return typeof kr(e)=="number"?e.pop():t}var xt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Gt(e){return k(e==null?void 0:e.then)}function Jt(e){return k(e[ht])}function Xt(e){return Symbol.asyncIterator&&k(e==null?void 0:e[Symbol.asyncIterator])}function Zt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Gi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var er=Gi();function tr(e){return k(e==null?void 0:e[er])}function rr(e){return lo(this,arguments,function(){var r,o,n,i;return Nt(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,nt(r.read())];case 3:return o=a.sent(),n=o.value,i=o.done,i?[4,nt(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,nt(n)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function or(e){return k(e==null?void 0:e.getReader)}function W(e){if(e instanceof F)return e;if(e!=null){if(Jt(e))return Ji(e);if(xt(e))return Xi(e);if(Gt(e))return Zi(e);if(Xt(e))return Lo(e);if(tr(e))return ea(e);if(or(e))return ta(e)}throw Zt(e)}function Ji(e){return new F(function(t){var r=e[ht]();if(k(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Xi(e){return new F(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?b(function(n,i){return e(n,i,o)}):le,Te(1),r?Be(t):zo(function(){return new ir}))}}function Fr(e){return e<=0?function(){return M}:y(function(t,r){var o=[];t.subscribe(T(r,function(n){o.push(n),e=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new g}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,p=s===void 0?!0:s;return function(c){var l,f,u,h=0,w=!1,A=!1,te=function(){f==null||f.unsubscribe(),f=void 0},ie=function(){te(),l=u=void 0,w=A=!1},J=function(){var H=l;ie(),H==null||H.unsubscribe()};return y(function(H,mt){h++,!A&&!w&&te();var ze=u=u!=null?u:r();mt.add(function(){h--,h===0&&!A&&!w&&(f=Wr(J,p))}),ze.subscribe(mt),!l&&h>0&&(l=new at({next:function(Ie){return ze.next(Ie)},error:function(Ie){A=!0,te(),f=Wr(ie,n,Ie),ze.error(Ie)},complete:function(){w=!0,te(),f=Wr(ie,a),ze.complete()}}),W(H).subscribe(l))})(c)}}function Wr(e,t){for(var r=[],o=2;oe.next(document)),e}function $(e,t=document){return Array.from(t.querySelectorAll(e))}function P(e,t=document){let r=fe(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function fe(e,t=document){return t.querySelector(e)||void 0}function Re(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var xa=S(d(document.body,"focusin"),d(document.body,"focusout")).pipe(_e(1),Q(void 0),m(()=>Re()||document.body),B(1));function et(e){return xa.pipe(m(t=>e.contains(t)),K())}function kt(e,t){return C(()=>S(d(e,"mouseenter").pipe(m(()=>!0)),d(e,"mouseleave").pipe(m(()=>!1))).pipe(t?Ht(r=>Me(+!r*t)):le,Q(e.matches(":hover"))))}function Bo(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Bo(e,r)}function x(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)Bo(o,n);return o}function sr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function wt(e){let t=x("script",{src:e});return C(()=>(document.head.appendChild(t),S(d(t,"load"),d(t,"error").pipe(v(()=>$r(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),L(()=>document.head.removeChild(t)),Te(1))))}var Go=new g,ya=C(()=>typeof ResizeObserver=="undefined"?wt("https://unpkg.com/resize-observer-polyfill"):I(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>Go.next(t)))),v(e=>S(Ke,I(e)).pipe(L(()=>e.disconnect()))),B(1));function ce(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ge(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return ya.pipe(E(r=>r.observe(t)),v(r=>Go.pipe(b(o=>o.target===t),L(()=>r.unobserve(t)))),m(()=>ce(e)),Q(ce(e)))}function Tt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function cr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function Jo(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function Ue(e){return{x:e.offsetLeft,y:e.offsetTop}}function Xo(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function Zo(e){return S(d(window,"load"),d(window,"resize")).pipe(Le(0,me),m(()=>Ue(e)),Q(Ue(e)))}function pr(e){return{x:e.scrollLeft,y:e.scrollTop}}function De(e){return S(d(e,"scroll"),d(window,"scroll"),d(window,"resize")).pipe(Le(0,me),m(()=>pr(e)),Q(pr(e)))}var en=new g,Ea=C(()=>I(new IntersectionObserver(e=>{for(let t of e)en.next(t)},{threshold:0}))).pipe(v(e=>S(Ke,I(e)).pipe(L(()=>e.disconnect()))),B(1));function tt(e){return Ea.pipe(E(t=>t.observe(e)),v(t=>en.pipe(b(({target:r})=>r===e),L(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function tn(e,t=16){return De(e).pipe(m(({y:r})=>{let o=ce(e),n=Tt(e);return r>=n.height-o.height-t}),K())}var lr={drawer:P("[data-md-toggle=drawer]"),search:P("[data-md-toggle=search]")};function rn(e){return lr[e].checked}function Je(e,t){lr[e].checked!==t&&lr[e].click()}function Ve(e){let t=lr[e];return d(t,"change").pipe(m(()=>t.checked),Q(t.checked))}function wa(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ta(){return S(d(window,"compositionstart").pipe(m(()=>!0)),d(window,"compositionend").pipe(m(()=>!1))).pipe(Q(!1))}function on(){let e=d(window,"keydown").pipe(b(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:rn("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),b(({mode:t,type:r})=>{if(t==="global"){let o=Re();if(typeof o!="undefined")return!wa(o,r)}return!0}),pe());return Ta().pipe(v(t=>t?M:e))}function xe(){return new URL(location.href)}function pt(e,t=!1){if(G("navigation.instant")&&!t){let r=x("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function nn(){return new g}function an(){return location.hash.slice(1)}function sn(e){let t=x("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Sa(e){return S(d(window,"hashchange"),e).pipe(m(an),Q(an()),b(t=>t.length>0),B(1))}function cn(e){return Sa(e).pipe(m(t=>fe(`[id="${t}"]`)),b(t=>typeof t!="undefined"))}function $t(e){let t=matchMedia(e);return ar(r=>t.addListener(()=>r(t.matches))).pipe(Q(t.matches))}function pn(){let e=matchMedia("print");return S(d(window,"beforeprint").pipe(m(()=>!0)),d(window,"afterprint").pipe(m(()=>!1))).pipe(Q(e.matches))}function Nr(e,t){return e.pipe(v(r=>r?t():M))}function zr(e,t){return new F(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let a=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+a*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function Ne(e,t){return zr(e,t).pipe(v(r=>r.text()),m(r=>JSON.parse(r)),B(1))}function ln(e,t){let r=new DOMParser;return zr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),B(1))}function mn(e,t){let r=new DOMParser;return zr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),B(1))}function fn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function un(){return S(d(window,"scroll",{passive:!0}),d(window,"resize",{passive:!0})).pipe(m(fn),Q(fn()))}function dn(){return{width:innerWidth,height:innerHeight}}function hn(){return d(window,"resize",{passive:!0}).pipe(m(dn),Q(dn()))}function bn(){return z([un(),hn()]).pipe(m(([e,t])=>({offset:e,size:t})),B(1))}function mr(e,{viewport$:t,header$:r}){let o=t.pipe(Z("size")),n=z([o,r]).pipe(m(()=>Ue(e)));return z([r,t,n]).pipe(m(([{height:i},{offset:a,size:s},{x:p,y:c}])=>({offset:{x:a.x-p,y:a.y-c+i},size:s})))}function Oa(e){return d(e,"message",t=>t.data)}function Ma(e){let t=new g;return t.subscribe(r=>e.postMessage(r)),t}function vn(e,t=new Worker(e)){let r=Oa(t),o=Ma(t),n=new g;n.subscribe(o);let i=o.pipe(X(),ne(!0));return n.pipe(X(),Pe(r.pipe(U(i))),pe())}var La=P("#__config"),St=JSON.parse(La.textContent);St.base=`${new URL(St.base,xe())}`;function ye(){return St}function G(e){return St.features.includes(e)}function Ee(e,t){return typeof t!="undefined"?St.translations[e].replace("#",t.toString()):St.translations[e]}function Se(e,t=document){return P(`[data-md-component=${e}]`,t)}function ae(e,t=document){return $(`[data-md-component=${e}]`,t)}function _a(e){let t=P(".md-typeset > :first-child",e);return d(t,"click",{once:!0}).pipe(m(()=>P(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function gn(e){if(!G("announce.dismiss")||!e.childElementCount)return M;if(!e.hidden){let t=P(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return C(()=>{let t=new g;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),_a(e).pipe(E(r=>t.next(r)),L(()=>t.complete()),m(r=>R({ref:e},r)))})}function Aa(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function xn(e,t){let r=new g;return r.subscribe(({hidden:o})=>{e.hidden=o}),Aa(e,t).pipe(E(o=>r.next(o)),L(()=>r.complete()),m(o=>R({ref:e},o)))}function Pt(e,t){return t==="inline"?x("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"})):x("div",{class:"md-tooltip",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"}))}function yn(...e){return x("div",{class:"md-tooltip2",role:"tooltip"},x("div",{class:"md-tooltip2__inner md-typeset"},e))}function En(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return x("aside",{class:"md-annotation",tabIndex:0},Pt(t),x("a",{href:r,class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}else return x("aside",{class:"md-annotation",tabIndex:0},Pt(t),x("span",{class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}function wn(e){return x("button",{class:"md-clipboard md-icon",title:Ee("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}function qr(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(p=>!e.terms[p]).reduce((p,c)=>[...p,x("del",null,c)," "],[]).slice(0,-1),i=ye(),a=new URL(e.location,i.base);G("search.highlight")&&a.searchParams.set("h",Object.entries(e.terms).filter(([,p])=>p).reduce((p,[c])=>`${p} ${c}`.trim(),""));let{tags:s}=ye();return x("a",{href:`${a}`,class:"md-search-result__link",tabIndex:-1},x("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&x("div",{class:"md-search-result__icon md-icon"}),r>0&&x("h1",null,e.title),r<=0&&x("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(p=>{let c=s?p in s?`md-tag-icon md-tag--${s[p]}`:"md-tag-icon":"";return x("span",{class:`md-tag ${c}`},p)}),o>0&&n.length>0&&x("p",{class:"md-search-result__terms"},Ee("search.result.term.missing"),": ",...n)))}function Tn(e){let t=e[0].score,r=[...e],o=ye(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),a=r.findIndex(l=>l.scoreqr(l,1)),...p.length?[x("details",{class:"md-search-result__more"},x("summary",{tabIndex:-1},x("div",null,p.length>0&&p.length===1?Ee("search.result.more.one"):Ee("search.result.more.other",p.length))),...p.map(l=>qr(l,1)))]:[]];return x("li",{class:"md-search-result__item"},c)}function Sn(e){return x("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>x("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?sr(r):r)))}function Qr(e){let t=`tabbed-control tabbed-control--${e}`;return x("div",{class:t,hidden:!0},x("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function On(e){return x("div",{class:"md-typeset__scrollwrap"},x("div",{class:"md-typeset__table"},e))}function Ca(e){var o;let t=ye(),r=new URL(`../${e.version}/`,t.base);return x("li",{class:"md-version__item"},x("a",{href:`${r}`,class:"md-version__link"},e.title,((o=t.version)==null?void 0:o.alias)&&e.aliases.length>0&&x("span",{class:"md-version__alias"},e.aliases[0])))}function Mn(e,t){var o;let r=ye();return e=e.filter(n=>{var i;return!((i=n.properties)!=null&&i.hidden)}),x("div",{class:"md-version"},x("button",{class:"md-version__current","aria-label":Ee("select.version")},t.title,((o=r.version)==null?void 0:o.alias)&&t.aliases.length>0&&x("span",{class:"md-version__alias"},t.aliases[0])),x("ul",{class:"md-version__list"},e.map(Ca)))}var Ha=0;function ka(e){let t=z([et(e),kt(e)]).pipe(m(([o,n])=>o||n),K()),r=C(()=>Jo(e)).pipe(oe(De),ct(1),m(()=>Xo(e)));return t.pipe(Ae(o=>o),v(()=>z([t,r])),m(([o,n])=>({active:o,offset:n})),pe())}function $a(e,t){let{content$:r,viewport$:o}=t,n=`__tooltip2_${Ha++}`;return C(()=>{let i=new g,a=new _r(!1);i.pipe(X(),ne(!1)).subscribe(a);let s=a.pipe(Ht(c=>Me(+!c*250,Hr)),K(),v(c=>c?r:M),E(c=>c.id=n),pe());z([i.pipe(m(({active:c})=>c)),s.pipe(v(c=>kt(c,250)),Q(!1))]).pipe(m(c=>c.some(l=>l))).subscribe(a);let p=a.pipe(b(c=>c),ee(s,o),m(([c,l,{size:f}])=>{let u=e.getBoundingClientRect(),h=u.width/2;if(l.role==="tooltip")return{x:h,y:8+u.height};if(u.y>=f.height/2){let{height:w}=ce(l);return{x:h,y:-16-w}}else return{x:h,y:16+u.height}}));return z([s,i,p]).subscribe(([c,{offset:l},f])=>{c.style.setProperty("--md-tooltip-host-x",`${l.x}px`),c.style.setProperty("--md-tooltip-host-y",`${l.y}px`),c.style.setProperty("--md-tooltip-x",`${f.x}px`),c.style.setProperty("--md-tooltip-y",`${f.y}px`),c.classList.toggle("md-tooltip2--top",f.y<0),c.classList.toggle("md-tooltip2--bottom",f.y>=0)}),a.pipe(b(c=>c),ee(s,(c,l)=>l),b(c=>c.role==="tooltip")).subscribe(c=>{let l=ce(P(":scope > *",c));c.style.setProperty("--md-tooltip-width",`${l.width}px`),c.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(K(),be(me),ee(s)).subscribe(([c,l])=>{l.classList.toggle("md-tooltip2--active",c)}),z([a.pipe(b(c=>c)),s]).subscribe(([c,l])=>{l.role==="dialog"?(e.setAttribute("aria-controls",n),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",n)}),a.pipe(b(c=>!c)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),ka(e).pipe(E(c=>i.next(c)),L(()=>i.complete()),m(c=>R({ref:e},c)))})}function lt(e,{viewport$:t},r=document.body){return $a(e,{content$:new F(o=>{let n=e.title,i=yn(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t})}function Pa(e,t){let r=C(()=>z([Zo(e),De(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:a,height:s}=ce(e);return{x:o-i.x+a/2,y:n-i.y+s/2}}));return et(e).pipe(v(o=>r.pipe(m(n=>({active:o,offset:n})),Te(+!o||1/0))))}function Ln(e,t,{target$:r}){let[o,n]=Array.from(e.children);return C(()=>{let i=new g,a=i.pipe(X(),ne(!0));return i.subscribe({next({offset:s}){e.style.setProperty("--md-tooltip-x",`${s.x}px`),e.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),tt(e).pipe(U(a)).subscribe(s=>{e.toggleAttribute("data-md-visible",s)}),S(i.pipe(b(({active:s})=>s)),i.pipe(_e(250),b(({active:s})=>!s))).subscribe({next({active:s}){s?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(Le(16,me)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(ct(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?e.style.setProperty("--md-tooltip-0",`${-s}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),d(n,"click").pipe(U(a),b(s=>!(s.metaKey||s.ctrlKey))).subscribe(s=>{s.stopPropagation(),s.preventDefault()}),d(n,"mousedown").pipe(U(a),ee(i)).subscribe(([s,{active:p}])=>{var c;if(s.button!==0||s.metaKey||s.ctrlKey)s.preventDefault();else if(p){s.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(c=Re())==null||c.blur()}}),r.pipe(U(a),b(s=>s===o),Ge(125)).subscribe(()=>e.focus()),Pa(e,t).pipe(E(s=>i.next(s)),L(()=>i.complete()),m(s=>R({ref:e},s)))})}function Ra(e){return e.tagName==="CODE"?$(".c, .c1, .cm",e):[e]}function Ia(e){let t=[];for(let r of Ra(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let a;for(;a=/(\(\d+\))(!)?/.exec(i.textContent);){let[,s,p]=a;if(typeof p=="undefined"){let c=i.splitText(a.index);i=c.splitText(s.length),t.push(c)}else{i.textContent=s,t.push(i);break}}}}return t}function _n(e,t){t.append(...Array.from(e.childNodes))}function fr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,a=new Map;for(let s of Ia(t)){let[,p]=s.textContent.match(/\((\d+)\)/);fe(`:scope > li:nth-child(${p})`,e)&&(a.set(p,En(p,i)),s.replaceWith(a.get(p)))}return a.size===0?M:C(()=>{let s=new g,p=s.pipe(X(),ne(!0)),c=[];for(let[l,f]of a)c.push([P(".md-typeset",f),P(`:scope > li:nth-child(${l})`,e)]);return o.pipe(U(p)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of c)l?_n(f,u):_n(u,f)}),S(...[...a].map(([,l])=>Ln(l,t,{target$:r}))).pipe(L(()=>s.complete()),pe())})}function An(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return An(t)}}function Cn(e,t){return C(()=>{let r=An(e);return typeof r!="undefined"?fr(r,e,t):M})}var Hn=Vt(Yr());var Fa=0;function kn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return kn(t)}}function ja(e){return ge(e).pipe(m(({width:t})=>({scrollable:Tt(e).width>t})),Z("scrollable"))}function $n(e,t){let{matches:r}=matchMedia("(hover)"),o=C(()=>{let n=new g,i=n.pipe(Fr(1));n.subscribe(({scrollable:c})=>{c&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let a=[];if(Hn.default.isSupported()&&(e.closest(".copy")||G("content.code.copy")&&!e.closest(".no-copy"))){let c=e.closest("pre");c.id=`__code_${Fa++}`;let l=wn(c.id);c.insertBefore(l,e),G("content.tooltips")&&a.push(lt(l,{viewport$}))}let s=e.closest(".highlight");if(s instanceof HTMLElement){let c=kn(s);if(typeof c!="undefined"&&(s.classList.contains("annotate")||G("content.code.annotate"))){let l=fr(c,e,t);a.push(ge(s).pipe(U(i),m(({width:f,height:u})=>f&&u),K(),v(f=>f?l:M)))}}return $(":scope > span[id]",e).length&&e.classList.add("md-code__content"),ja(e).pipe(E(c=>n.next(c)),L(()=>n.complete()),m(c=>R({ref:e},c)),Pe(...a))});return G("content.lazy")?tt(e).pipe(b(n=>n),Te(1),v(()=>o)):o}function Wa(e,{target$:t,print$:r}){let o=!0;return S(t.pipe(m(n=>n.closest("details:not([open])")),b(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(b(n=>n||!o),E(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function Pn(e,t){return C(()=>{let r=new g;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),Wa(e,t).pipe(E(o=>r.next(o)),L(()=>r.complete()),m(o=>R({ref:e},o)))})}var Rn=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var Br,Da=0;function Va(){return typeof mermaid=="undefined"||mermaid instanceof Element?wt("https://unpkg.com/mermaid@10/dist/mermaid.min.js"):I(void 0)}function In(e){return e.classList.remove("mermaid"),Br||(Br=Va().pipe(E(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Rn,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),B(1))),Br.subscribe(()=>ao(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${Da++}`,r=x("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),a=r.attachShadow({mode:"closed"});a.innerHTML=n,e.replaceWith(r),i==null||i(a)})),Br.pipe(m(()=>({ref:e})))}var Fn=x("table");function jn(e){return e.replaceWith(Fn),Fn.replaceWith(On(e)),I({ref:e})}function Na(e){let t=e.find(r=>r.checked)||e[0];return S(...e.map(r=>d(r,"change").pipe(m(()=>P(`label[for="${r.id}"]`))))).pipe(Q(P(`label[for="${t.id}"]`)),m(r=>({active:r})))}function Wn(e,{viewport$:t,target$:r}){let o=P(".tabbed-labels",e),n=$(":scope > input",e),i=Qr("prev");e.append(i);let a=Qr("next");return e.append(a),C(()=>{let s=new g,p=s.pipe(X(),ne(!0));z([s,ge(e),tt(e)]).pipe(U(p),Le(1,me)).subscribe({next([{active:c},l]){let f=Ue(c),{width:u}=ce(c);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let h=pr(o);(f.xh.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),z([De(o),ge(o)]).pipe(U(p)).subscribe(([c,l])=>{let f=Tt(o);i.hidden=c.x<16,a.hidden=c.x>f.width-l.width-16}),S(d(i,"click").pipe(m(()=>-1)),d(a,"click").pipe(m(()=>1))).pipe(U(p)).subscribe(c=>{let{width:l}=ce(o);o.scrollBy({left:l*c,behavior:"smooth"})}),r.pipe(U(p),b(c=>n.includes(c))).subscribe(c=>c.click()),o.classList.add("tabbed-labels--linked");for(let c of n){let l=P(`label[for="${c.id}"]`);l.replaceChildren(x("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),d(l.firstElementChild,"click").pipe(U(p),b(f=>!(f.metaKey||f.ctrlKey)),E(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return G("content.tabs.link")&&s.pipe(Ce(1),ee(t)).subscribe(([{active:c},{offset:l}])=>{let f=c.innerText.trim();if(c.hasAttribute("data-md-switching"))c.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let w of $("[data-tabs]"))for(let A of $(":scope > input",w)){let te=P(`label[for="${A.id}"]`);if(te!==c&&te.innerText.trim()===f){te.setAttribute("data-md-switching",""),A.click();break}}window.scrollTo({top:e.offsetTop-u});let h=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...h])])}}),s.pipe(U(p)).subscribe(()=>{for(let c of $("audio, video",e))c.pause()}),Na(n).pipe(E(c=>s.next(c)),L(()=>s.complete()),m(c=>R({ref:e},c)))}).pipe(Qe(se))}function Un(e,{viewport$:t,target$:r,print$:o}){return S(...$(".annotate:not(.highlight)",e).map(n=>Cn(n,{target$:r,print$:o})),...$("pre:not(.mermaid) > code",e).map(n=>$n(n,{target$:r,print$:o})),...$("pre.mermaid",e).map(n=>In(n)),...$("table:not([class])",e).map(n=>jn(n)),...$("details",e).map(n=>Pn(n,{target$:r,print$:o})),...$("[data-tabs]",e).map(n=>Wn(n,{viewport$:t,target$:r})),...$("[title]",e).filter(()=>G("content.tooltips")).map(n=>lt(n,{viewport$:t})))}function za(e,{alert$:t}){return t.pipe(v(r=>S(I(!0),I(!1).pipe(Ge(2e3))).pipe(m(o=>({message:r,active:o})))))}function Dn(e,t){let r=P(".md-typeset",e);return C(()=>{let o=new g;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),za(e,t).pipe(E(n=>o.next(n)),L(()=>o.complete()),m(n=>R({ref:e},n)))})}var qa=0;function Qa(e,t){document.body.append(e);let{width:r}=ce(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=cr(t),n=typeof o!="undefined"?De(o):I({x:0,y:0}),i=S(et(t),kt(t)).pipe(K());return z([i,n]).pipe(m(([a,s])=>{let{x:p,y:c}=Ue(t),l=ce(t),f=t.closest("table");return f&&t.parentElement&&(p+=f.offsetLeft+t.parentElement.offsetLeft,c+=f.offsetTop+t.parentElement.offsetTop),{active:a,offset:{x:p-s.x+l.width/2-r/2,y:c-s.y+l.height+8}}}))}function Vn(e){let t=e.title;if(!t.length)return M;let r=`__tooltip_${qa++}`,o=Pt(r,"inline"),n=P(".md-typeset",o);return n.innerHTML=t,C(()=>{let i=new g;return i.subscribe({next({offset:a}){o.style.setProperty("--md-tooltip-x",`${a.x}px`),o.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),S(i.pipe(b(({active:a})=>a)),i.pipe(_e(250),b(({active:a})=>!a))).subscribe({next({active:a}){a?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(Le(16,me)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(ct(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?o.style.setProperty("--md-tooltip-0",`${-a}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),Qa(o,e).pipe(E(a=>i.next(a)),L(()=>i.complete()),m(a=>R({ref:e},a)))}).pipe(Qe(se))}function Ka({viewport$:e}){if(!G("header.autohide"))return I(!1);let t=e.pipe(m(({offset:{y:n}})=>n),Ye(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),K()),o=Ve("search");return z([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),K(),v(n=>n?r:I(!1)),Q(!1))}function Nn(e,t){return C(()=>z([ge(e),Ka(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),K((r,o)=>r.height===o.height&&r.hidden===o.hidden),B(1))}function zn(e,{header$:t,main$:r}){return C(()=>{let o=new g,n=o.pipe(X(),ne(!0));o.pipe(Z("active"),We(t)).subscribe(([{active:a},{hidden:s}])=>{e.classList.toggle("md-header--shadow",a&&!s),e.hidden=s});let i=ue($("[title]",e)).pipe(b(()=>G("content.tooltips")),oe(a=>Vn(a)));return r.subscribe(o),t.pipe(U(n),m(a=>R({ref:e},a)),Pe(i.pipe(U(n))))})}function Ya(e,{viewport$:t,header$:r}){return mr(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=ce(e);return{active:o>=n}}),Z("active"))}function qn(e,t){return C(()=>{let r=new g;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=fe(".md-content h1");return typeof o=="undefined"?M:Ya(o,t).pipe(E(n=>r.next(n)),L(()=>r.complete()),m(n=>R({ref:e},n)))})}function Qn(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),K()),n=o.pipe(v(()=>ge(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),Z("bottom"))));return z([o,n,t]).pipe(m(([i,{top:a,bottom:s},{offset:{y:p},size:{height:c}}])=>(c=Math.max(0,c-Math.max(0,a-p,i)-Math.max(0,c+p-s)),{offset:a-i,height:c,active:a-i<=p})),K((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function Ba(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return I(...e).pipe(oe(o=>d(o,"change").pipe(m(()=>o))),Q(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),B(1))}function Kn(e){let t=$("input",e),r=x("meta",{name:"theme-color"});document.head.appendChild(r);let o=x("meta",{name:"color-scheme"});document.head.appendChild(o);let n=$t("(prefers-color-scheme: light)");return C(()=>{let i=new g;return i.subscribe(a=>{if(document.body.setAttribute("data-md-color-switching",""),a.color.media==="(prefers-color-scheme)"){let s=matchMedia("(prefers-color-scheme: light)"),p=document.querySelector(s.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");a.color.scheme=p.getAttribute("data-md-color-scheme"),a.color.primary=p.getAttribute("data-md-color-primary"),a.color.accent=p.getAttribute("data-md-color-accent")}for(let[s,p]of Object.entries(a.color))document.body.setAttribute(`data-md-color-${s}`,p);for(let s=0;sa.key==="Enter"),ee(i,(a,s)=>s)).subscribe(({index:a})=>{a=(a+1)%t.length,t[a].click(),t[a].focus()}),i.pipe(m(()=>{let a=Se("header"),s=window.getComputedStyle(a);return o.content=s.colorScheme,s.backgroundColor.match(/\d+/g).map(p=>(+p).toString(16).padStart(2,"0")).join("")})).subscribe(a=>r.content=`#${a}`),i.pipe(be(se)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),Ba(t).pipe(U(n.pipe(Ce(1))),st(),E(a=>i.next(a)),L(()=>i.complete()),m(a=>R({ref:e},a)))})}function Yn(e,{progress$:t}){return C(()=>{let r=new g;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(E(o=>r.next({value:o})),L(()=>r.complete()),m(o=>({ref:e,value:o})))})}var Gr=Vt(Yr());function Ga(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function Bn({alert$:e}){Gr.default.isSupported()&&new F(t=>{new Gr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||Ga(P(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(E(t=>{t.trigger.focus()}),m(()=>Ee("clipboard.copied"))).subscribe(e)}function Gn(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function Ja(e,t){let r=new Map;for(let o of $("url",e)){let n=P("loc",o),i=[Gn(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let a of $("[rel=alternate]",o)){let s=a.getAttribute("href");s!=null&&i.push(Gn(new URL(s),t))}}return r}function ur(e){return mn(new URL("sitemap.xml",e)).pipe(m(t=>Ja(t,new URL(e))),ve(()=>I(new Map)))}function Xa(e,t){if(!(e.target instanceof Element))return M;let r=e.target.closest("a");if(r===null)return M;if(r.target||e.metaKey||e.ctrlKey)return M;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),I(new URL(r.href))):M}function Jn(e){let t=new Map;for(let r of $(":scope > *",e.head))t.set(r.outerHTML,r);return t}function Xn(e){for(let t of $("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return I(e)}function Za(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...G("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=fe(o),i=fe(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=Jn(document);for(let[o,n]of Jn(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Se("container");return je($("script",r)).pipe(v(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new F(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),M}),X(),ne(document))}function Zn({location$:e,viewport$:t,progress$:r}){let o=ye();if(location.protocol==="file:")return M;let n=ur(o.base);I(document).subscribe(Xn);let i=d(document.body,"click").pipe(We(n),v(([p,c])=>Xa(p,c)),pe()),a=d(window,"popstate").pipe(m(xe),pe());i.pipe(ee(t)).subscribe(([p,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",p)}),S(i,a).subscribe(e);let s=e.pipe(Z("pathname"),v(p=>ln(p,{progress$:r}).pipe(ve(()=>(pt(p,!0),M)))),v(Xn),v(Za),pe());return S(s.pipe(ee(e,(p,c)=>c)),s.pipe(v(()=>e),Z("pathname"),v(()=>e),Z("hash")),e.pipe(K((p,c)=>p.pathname===c.pathname&&p.hash===c.hash),v(()=>i),E(()=>history.back()))).subscribe(p=>{var c,l;history.state!==null||!p.hash?window.scrollTo(0,(l=(c=history.state)==null?void 0:c.y)!=null?l:0):(history.scrollRestoration="auto",sn(p.hash),history.scrollRestoration="manual")}),e.subscribe(()=>{history.scrollRestoration="manual"}),d(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),t.pipe(Z("offset"),_e(100)).subscribe(({offset:p})=>{history.replaceState(p,"")}),s}var ri=Vt(ti());function oi(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,a)=>`${i}${a}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(0,ri.default)(a).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function It(e){return e.type===1}function dr(e){return e.type===3}function ni(e,t){let r=vn(e);return S(I(location.protocol!=="file:"),Ve("search")).pipe(Ae(o=>o),v(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:G("search.suggest")}}})),r}function ii({document$:e}){let t=ye(),r=Ne(new URL("../versions.json",t.base)).pipe(ve(()=>M)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:a,aliases:s})=>a===i||s.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),v(n=>d(document.body,"click").pipe(b(i=>!i.metaKey&&!i.ctrlKey),ee(o),v(([i,a])=>{if(i.target instanceof Element){let s=i.target.closest("a");if(s&&!s.target&&n.has(s.href)){let p=s.href;return!i.target.closest(".md-version")&&n.get(p)===a?M:(i.preventDefault(),I(p))}}return M}),v(i=>ur(new URL(i)).pipe(m(a=>{let p=xe().href.replace(t.base,i);return a.has(p.split("#")[0])?new URL(p):new URL(i)})))))).subscribe(n=>pt(n,!0)),z([r,o]).subscribe(([n,i])=>{P(".md-header__topic").appendChild(Mn(n,i))}),e.pipe(v(()=>o)).subscribe(n=>{var a;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let s=((a=t.version)==null?void 0:a.default)||"latest";Array.isArray(s)||(s=[s]);e:for(let p of s)for(let c of n.aliases.concat(n.version))if(new RegExp(p,"i").test(c)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let s of ae("outdated"))s.hidden=!1})}function ns(e,{worker$:t}){let{searchParams:r}=xe();r.has("q")&&(Je("search",!0),e.value=r.get("q"),e.focus(),Ve("search").pipe(Ae(i=>!i)).subscribe(()=>{let i=xe();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=et(e),n=S(t.pipe(Ae(It)),d(e,"keyup"),o).pipe(m(()=>e.value),K());return z([n,o]).pipe(m(([i,a])=>({value:i,focus:a})),B(1))}function ai(e,{worker$:t}){let r=new g,o=r.pipe(X(),ne(!0));z([t.pipe(Ae(It)),r],(i,a)=>a).pipe(Z("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(Z("focus")).subscribe(({focus:i})=>{i&&Je("search",i)}),d(e.form,"reset").pipe(U(o)).subscribe(()=>e.focus());let n=P("header [for=__search]");return d(n,"click").subscribe(()=>e.focus()),ns(e,{worker$:t}).pipe(E(i=>r.next(i)),L(()=>r.complete()),m(i=>R({ref:e},i)),B(1))}function si(e,{worker$:t,query$:r}){let o=new g,n=tn(e.parentElement).pipe(b(Boolean)),i=e.parentElement,a=P(":scope > :first-child",e),s=P(":scope > :last-child",e);Ve("search").subscribe(l=>s.setAttribute("role",l?"list":"presentation")),o.pipe(ee(r),Ur(t.pipe(Ae(It)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:a.textContent=f.length?Ee("search.result.none"):Ee("search.result.placeholder");break;case 1:a.textContent=Ee("search.result.one");break;default:let u=sr(l.length);a.textContent=Ee("search.result.other",u)}});let p=o.pipe(E(()=>s.innerHTML=""),v(({items:l})=>S(I(...l.slice(0,10)),I(...l.slice(10)).pipe(Ye(4),Vr(n),v(([f])=>f)))),m(Tn),pe());return p.subscribe(l=>s.appendChild(l)),p.pipe(oe(l=>{let f=fe("details",l);return typeof f=="undefined"?M:d(f,"toggle").pipe(U(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(b(dr),m(({data:l})=>l)).pipe(E(l=>o.next(l)),L(()=>o.complete()),m(l=>R({ref:e},l)))}function is(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=xe();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function ci(e,t){let r=new g,o=r.pipe(X(),ne(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),d(e,"click").pipe(U(o)).subscribe(n=>n.preventDefault()),is(e,t).pipe(E(n=>r.next(n)),L(()=>r.complete()),m(n=>R({ref:e},n)))}function pi(e,{worker$:t,keyboard$:r}){let o=new g,n=Se("search-query"),i=S(d(n,"keydown"),d(n,"focus")).pipe(be(se),m(()=>n.value),K());return o.pipe(We(i),m(([{suggest:s},p])=>{let c=p.split(/([\s-]+)/);if(s!=null&&s.length&&c[c.length-1]){let l=s[s.length-1];l.startsWith(c[c.length-1])&&(c[c.length-1]=l)}else c.length=0;return c})).subscribe(s=>e.innerHTML=s.join("").replace(/\s/g," ")),r.pipe(b(({mode:s})=>s==="search")).subscribe(s=>{switch(s.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(b(dr),m(({data:s})=>s)).pipe(E(s=>o.next(s)),L(()=>o.complete()),m(()=>({ref:e})))}function li(e,{index$:t,keyboard$:r}){let o=ye();try{let n=ni(o.search,t),i=Se("search-query",e),a=Se("search-result",e);d(e,"click").pipe(b(({target:p})=>p instanceof Element&&!!p.closest("a"))).subscribe(()=>Je("search",!1)),r.pipe(b(({mode:p})=>p==="search")).subscribe(p=>{let c=Re();switch(p.type){case"Enter":if(c===i){let l=new Map;for(let f of $(":first-child [href]",a)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,h])=>h-u);f.click()}p.claim()}break;case"Escape":case"Tab":Je("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof c=="undefined")i.focus();else{let l=[i,...$(":not(details) > [href], summary, details[open] [href]",a)],f=Math.max(0,(Math.max(0,l.indexOf(c))+l.length+(p.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}p.claim();break;default:i!==Re()&&i.focus()}}),r.pipe(b(({mode:p})=>p==="global")).subscribe(p=>{switch(p.type){case"f":case"s":case"/":i.focus(),i.select(),p.claim();break}});let s=ai(i,{worker$:n});return S(s,si(a,{worker$:n,query$:s})).pipe(Pe(...ae("search-share",e).map(p=>ci(p,{query$:s})),...ae("search-suggest",e).map(p=>pi(p,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,Ke}}function mi(e,{index$:t,location$:r}){return z([t,r.pipe(Q(xe()),b(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>oi(o.config)(n.searchParams.get("h"))),m(o=>{var a;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let s=i.nextNode();s;s=i.nextNode())if((a=s.parentElement)!=null&&a.offsetHeight){let p=s.textContent,c=o(p);c.length>p.length&&n.set(s,c)}for(let[s,p]of n){let{childNodes:c}=x("span",null,p);s.replaceWith(...Array.from(c))}return{ref:e,nodes:n}}))}function as(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return z([r,t]).pipe(m(([{offset:i,height:a},{offset:{y:s}}])=>(a=a+Math.min(n,Math.max(0,s-i))-n,{height:a,locked:s>=i+n})),K((i,a)=>i.height===a.height&&i.locked===a.locked))}function Jr(e,o){var n=o,{header$:t}=n,r=io(n,["header$"]);let i=P(".md-sidebar__scrollwrap",e),{y:a}=Ue(i);return C(()=>{let s=new g,p=s.pipe(X(),ne(!0)),c=s.pipe(Le(0,me));return c.pipe(ee(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*a}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),c.pipe(Ae()).subscribe(()=>{for(let l of $(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:h}=ce(f);f.scrollTo({top:u-h/2})}}}),ue($("label[tabindex]",e)).pipe(oe(l=>d(l,"click").pipe(be(se),m(()=>l),U(p)))).subscribe(l=>{let f=P(`[id="${l.htmlFor}"]`);P(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),as(e,r).pipe(E(l=>s.next(l)),L(()=>s.complete()),m(l=>R({ref:e},l)))})}function fi(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return Ct(Ne(`${r}/releases/latest`).pipe(ve(()=>M),m(o=>({version:o.tag_name})),Be({})),Ne(r).pipe(ve(()=>M),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),Be({}))).pipe(m(([o,n])=>R(R({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return Ne(r).pipe(m(o=>({repositories:o.public_repos})),Be({}))}}function ui(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return Ne(r).pipe(ve(()=>M),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),Be({}))}function di(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return fi(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return ui(r,o)}return M}var ss;function cs(e){return ss||(ss=C(()=>{let t=__md_get("__source",sessionStorage);if(t)return I(t);if(ae("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return M}return di(e.href).pipe(E(o=>__md_set("__source",o,sessionStorage)))}).pipe(ve(()=>M),b(t=>Object.keys(t).length>0),m(t=>({facts:t})),B(1)))}function hi(e){let t=P(":scope > :last-child",e);return C(()=>{let r=new g;return r.subscribe(({facts:o})=>{t.appendChild(Sn(o)),t.classList.add("md-source__repository--active")}),cs(e).pipe(E(o=>r.next(o)),L(()=>r.complete()),m(o=>R({ref:e},o)))})}function ps(e,{viewport$:t,header$:r}){return ge(document.body).pipe(v(()=>mr(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),Z("hidden"))}function bi(e,t){return C(()=>{let r=new g;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(G("navigation.tabs.sticky")?I({hidden:!1}):ps(e,t)).pipe(E(o=>r.next(o)),L(()=>r.complete()),m(o=>R({ref:e},o)))})}function ls(e,{viewport$:t,header$:r}){let o=new Map,n=$(".md-nav__link",e);for(let s of n){let p=decodeURIComponent(s.hash.substring(1)),c=fe(`[id="${p}"]`);typeof c!="undefined"&&o.set(s,c)}let i=r.pipe(Z("height"),m(({height:s})=>{let p=Se("main"),c=P(":scope > :first-child",p);return s+.8*(c.offsetTop-p.offsetTop)}),pe());return ge(document.body).pipe(Z("height"),v(s=>C(()=>{let p=[];return I([...o].reduce((c,[l,f])=>{for(;p.length&&o.get(p[p.length-1]).tagName>=f.tagName;)p.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let h=f.offsetParent;for(;h;h=h.offsetParent)u+=h.offsetTop;return c.set([...p=[...p,l]].reverse(),u)},new Map))}).pipe(m(p=>new Map([...p].sort(([,c],[,l])=>c-l))),We(i),v(([p,c])=>t.pipe(jr(([l,f],{offset:{y:u},size:h})=>{let w=u+h.height>=Math.floor(s.height);for(;f.length;){let[,A]=f[0];if(A-c=u&&!w)f=[l.pop(),...f];else break}return[l,f]},[[],[...p]]),K((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([s,p])=>({prev:s.map(([c])=>c),next:p.map(([c])=>c)})),Q({prev:[],next:[]}),Ye(2,1),m(([s,p])=>s.prev.length{let i=new g,a=i.pipe(X(),ne(!0));if(i.subscribe(({prev:s,next:p})=>{for(let[c]of p)c.classList.remove("md-nav__link--passed"),c.classList.remove("md-nav__link--active");for(let[c,[l]]of s.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",c===s.length-1)}),G("toc.follow")){let s=S(t.pipe(_e(1),m(()=>{})),t.pipe(_e(250),m(()=>"smooth")));i.pipe(b(({prev:p})=>p.length>0),We(o.pipe(be(se))),ee(s)).subscribe(([[{prev:p}],c])=>{let[l]=p[p.length-1];if(l.offsetHeight){let f=cr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:h}=ce(f);f.scrollTo({top:u-h/2,behavior:c})}}})}return G("navigation.tracking")&&t.pipe(U(a),Z("offset"),_e(250),Ce(1),U(n.pipe(Ce(1))),st({delay:250}),ee(i)).subscribe(([,{prev:s}])=>{let p=xe(),c=s[s.length-1];if(c&&c.length){let[l]=c,{hash:f}=new URL(l.href);p.hash!==f&&(p.hash=f,history.replaceState({},"",`${p}`))}else p.hash="",history.replaceState({},"",`${p}`)}),ls(e,{viewport$:t,header$:r}).pipe(E(s=>i.next(s)),L(()=>i.complete()),m(s=>R({ref:e},s)))})}function ms(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:a}})=>a),Ye(2,1),m(([a,s])=>a>s&&s>0),K()),i=r.pipe(m(({active:a})=>a));return z([i,n]).pipe(m(([a,s])=>!(a&&s)),K(),U(o.pipe(Ce(1))),ne(!0),st({delay:250}),m(a=>({hidden:a})))}function gi(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new g,a=i.pipe(X(),ne(!0));return i.subscribe({next({hidden:s}){e.hidden=s,s?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(U(a),Z("height")).subscribe(({height:s})=>{e.style.top=`${s+16}px`}),d(e,"click").subscribe(s=>{s.preventDefault(),window.scrollTo({top:0})}),ms(e,{viewport$:t,main$:o,target$:n}).pipe(E(s=>i.next(s)),L(()=>i.complete()),m(s=>R({ref:e},s)))}function xi({document$:e,viewport$:t}){e.pipe(v(()=>$(".md-ellipsis")),oe(r=>tt(r).pipe(U(e.pipe(Ce(1))),b(o=>o),m(()=>r),Te(1))),b(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,lt(n,{viewport$:t}).pipe(U(e.pipe(Ce(1))),L(()=>n.removeAttribute("title")))})).subscribe(),e.pipe(v(()=>$(".md-status")),oe(r=>lt(r,{viewport$:t}))).subscribe()}function yi({document$:e,tablet$:t}){e.pipe(v(()=>$(".md-toggle--indeterminate")),E(r=>{r.indeterminate=!0,r.checked=!1}),oe(r=>d(r,"change").pipe(Dr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),ee(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function fs(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Ei({document$:e}){e.pipe(v(()=>$("[data-md-scrollfix]")),E(t=>t.removeAttribute("data-md-scrollfix")),b(fs),oe(t=>d(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function wi({viewport$:e,tablet$:t}){z([Ve("search"),t]).pipe(m(([r,o])=>r&&!o),v(r=>I(r).pipe(Ge(r?400:100))),ee(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function us(){return location.protocol==="file:"?wt(`${new URL("search/search_index.js",Xr.base)}`).pipe(m(()=>__index),B(1)):Ne(new URL("search/search_index.json",Xr.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var ot=Yo(),jt=nn(),Ot=cn(jt),Zr=on(),Oe=bn(),hr=$t("(min-width: 960px)"),Si=$t("(min-width: 1220px)"),Oi=pn(),Xr=ye(),Mi=document.forms.namedItem("search")?us():Ke,eo=new g;Bn({alert$:eo});var to=new g;G("navigation.instant")&&Zn({location$:jt,viewport$:Oe,progress$:to}).subscribe(ot);var Ti;((Ti=Xr.version)==null?void 0:Ti.provider)==="mike"&&ii({document$:ot});S(jt,Ot).pipe(Ge(125)).subscribe(()=>{Je("drawer",!1),Je("search",!1)});Zr.pipe(b(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=fe("link[rel=prev]");typeof t!="undefined"&&pt(t);break;case"n":case".":let r=fe("link[rel=next]");typeof r!="undefined"&&pt(r);break;case"Enter":let o=Re();o instanceof HTMLLabelElement&&o.click()}});xi({viewport$:Oe,document$:ot});yi({document$:ot,tablet$:hr});Ei({document$:ot});wi({viewport$:Oe,tablet$:hr});var rt=Nn(Se("header"),{viewport$:Oe}),Ft=ot.pipe(m(()=>Se("main")),v(e=>Qn(e,{viewport$:Oe,header$:rt})),B(1)),ds=S(...ae("consent").map(e=>xn(e,{target$:Ot})),...ae("dialog").map(e=>Dn(e,{alert$:eo})),...ae("header").map(e=>zn(e,{viewport$:Oe,header$:rt,main$:Ft})),...ae("palette").map(e=>Kn(e)),...ae("progress").map(e=>Yn(e,{progress$:to})),...ae("search").map(e=>li(e,{index$:Mi,keyboard$:Zr})),...ae("source").map(e=>hi(e))),hs=C(()=>S(...ae("announce").map(e=>gn(e)),...ae("content").map(e=>Un(e,{viewport$:Oe,target$:Ot,print$:Oi})),...ae("content").map(e=>G("search.highlight")?mi(e,{index$:Mi,location$:jt}):M),...ae("header-title").map(e=>qn(e,{viewport$:Oe,header$:rt})),...ae("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Nr(Si,()=>Jr(e,{viewport$:Oe,header$:rt,main$:Ft})):Nr(hr,()=>Jr(e,{viewport$:Oe,header$:rt,main$:Ft}))),...ae("tabs").map(e=>bi(e,{viewport$:Oe,header$:rt})),...ae("toc").map(e=>vi(e,{viewport$:Oe,header$:rt,main$:Ft,target$:Ot})),...ae("top").map(e=>gi(e,{viewport$:Oe,header$:rt,main$:Ft,target$:Ot})))),Li=ot.pipe(v(()=>hs),Pe(ds),B(1));Li.subscribe();window.document$=ot;window.location$=jt;window.target$=Ot;window.keyboard$=Zr;window.viewport$=Oe;window.tablet$=hr;window.screen$=Si;window.print$=Oi;window.alert$=eo;window.progress$=to;window.component$=Li;})(); +//# sourceMappingURL=bundle.ad660dcc.min.js.map + diff --git a/assets/javascripts/bundle.ad660dcc.min.js.map b/assets/javascripts/bundle.ad660dcc.min.js.map new file mode 100644 index 0000000..6d61170 --- /dev/null +++ b/assets/javascripts/bundle.ad660dcc.min.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/clipboard/dist/clipboard.js", "node_modules/escape-html/index.js", "src/templates/assets/javascripts/bundle.ts", "node_modules/rxjs/node_modules/tslib/tslib.es6.js", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/BehaviorSubject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/QueueAction.ts", "node_modules/rxjs/src/internal/scheduler/QueueScheduler.ts", "node_modules/rxjs/src/internal/scheduler/queue.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/EmptyError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/debounce.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/throwIfEmpty.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/first.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/templates/assets/javascripts/browser/document/index.ts", "src/templates/assets/javascripts/browser/element/_/index.ts", "src/templates/assets/javascripts/browser/element/focus/index.ts", "src/templates/assets/javascripts/browser/element/hover/index.ts", "src/templates/assets/javascripts/utilities/h/index.ts", "src/templates/assets/javascripts/utilities/round/index.ts", "src/templates/assets/javascripts/browser/script/index.ts", "src/templates/assets/javascripts/browser/element/size/_/index.ts", "src/templates/assets/javascripts/browser/element/size/content/index.ts", "src/templates/assets/javascripts/browser/element/offset/_/index.ts", "src/templates/assets/javascripts/browser/element/offset/content/index.ts", "src/templates/assets/javascripts/browser/element/visibility/index.ts", "src/templates/assets/javascripts/browser/toggle/index.ts", "src/templates/assets/javascripts/browser/keyboard/index.ts", "src/templates/assets/javascripts/browser/location/_/index.ts", "src/templates/assets/javascripts/browser/location/hash/index.ts", "src/templates/assets/javascripts/browser/media/index.ts", "src/templates/assets/javascripts/browser/request/index.ts", "src/templates/assets/javascripts/browser/viewport/offset/index.ts", "src/templates/assets/javascripts/browser/viewport/size/index.ts", "src/templates/assets/javascripts/browser/viewport/_/index.ts", "src/templates/assets/javascripts/browser/viewport/at/index.ts", "src/templates/assets/javascripts/browser/worker/index.ts", "src/templates/assets/javascripts/_/index.ts", "src/templates/assets/javascripts/components/_/index.ts", "src/templates/assets/javascripts/components/announce/index.ts", "src/templates/assets/javascripts/components/consent/index.ts", "src/templates/assets/javascripts/templates/tooltip/index.tsx", "src/templates/assets/javascripts/templates/annotation/index.tsx", "src/templates/assets/javascripts/templates/clipboard/index.tsx", "src/templates/assets/javascripts/templates/search/index.tsx", "src/templates/assets/javascripts/templates/source/index.tsx", "src/templates/assets/javascripts/templates/tabbed/index.tsx", "src/templates/assets/javascripts/templates/table/index.tsx", "src/templates/assets/javascripts/templates/version/index.tsx", "src/templates/assets/javascripts/components/tooltip2/index.ts", "src/templates/assets/javascripts/components/content/annotation/_/index.ts", "src/templates/assets/javascripts/components/content/annotation/list/index.ts", "src/templates/assets/javascripts/components/content/annotation/block/index.ts", "src/templates/assets/javascripts/components/content/code/_/index.ts", "src/templates/assets/javascripts/components/content/details/index.ts", "src/templates/assets/javascripts/components/content/mermaid/index.css", "src/templates/assets/javascripts/components/content/mermaid/index.ts", "src/templates/assets/javascripts/components/content/table/index.ts", "src/templates/assets/javascripts/components/content/tabs/index.ts", "src/templates/assets/javascripts/components/content/_/index.ts", "src/templates/assets/javascripts/components/dialog/index.ts", "src/templates/assets/javascripts/components/tooltip/index.ts", "src/templates/assets/javascripts/components/header/_/index.ts", "src/templates/assets/javascripts/components/header/title/index.ts", "src/templates/assets/javascripts/components/main/index.ts", "src/templates/assets/javascripts/components/palette/index.ts", "src/templates/assets/javascripts/components/progress/index.ts", "src/templates/assets/javascripts/integrations/clipboard/index.ts", "src/templates/assets/javascripts/integrations/sitemap/index.ts", "src/templates/assets/javascripts/integrations/instant/index.ts", "src/templates/assets/javascripts/integrations/search/highlighter/index.ts", "src/templates/assets/javascripts/integrations/search/worker/message/index.ts", "src/templates/assets/javascripts/integrations/search/worker/_/index.ts", "src/templates/assets/javascripts/integrations/version/index.ts", "src/templates/assets/javascripts/components/search/query/index.ts", "src/templates/assets/javascripts/components/search/result/index.ts", "src/templates/assets/javascripts/components/search/share/index.ts", "src/templates/assets/javascripts/components/search/suggest/index.ts", "src/templates/assets/javascripts/components/search/_/index.ts", "src/templates/assets/javascripts/components/search/highlight/index.ts", "src/templates/assets/javascripts/components/sidebar/index.ts", "src/templates/assets/javascripts/components/source/facts/github/index.ts", "src/templates/assets/javascripts/components/source/facts/gitlab/index.ts", "src/templates/assets/javascripts/components/source/facts/_/index.ts", "src/templates/assets/javascripts/components/source/_/index.ts", "src/templates/assets/javascripts/components/tabs/index.ts", "src/templates/assets/javascripts/components/toc/index.ts", "src/templates/assets/javascripts/components/top/index.ts", "src/templates/assets/javascripts/patches/ellipsis/index.ts", "src/templates/assets/javascripts/patches/indeterminate/index.ts", "src/templates/assets/javascripts/patches/scrollfix/index.ts", "src/templates/assets/javascripts/patches/scrolllock/index.ts", "src/templates/assets/javascripts/polyfills/index.ts"], + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*\n * Copyright (c) 2016-2024 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getActiveElement,\n getOptionalElement,\n requestJSON,\n setLocation,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchScript,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountAnnounce,\n mountBackToTop,\n mountConsent,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountProgress,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantNavigation,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchEllipsis,\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Functions - @todo refactor\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @returns Search index observable\n */\nfunction fetchSearchIndex(): Observable {\n if (location.protocol === \"file:\") {\n return watchScript(\n `${new URL(\"search/search_index.js\", config.base)}`\n )\n .pipe(\n // @ts-ignore - @todo fix typings\n map(() => __index),\n shareReplay(1)\n )\n } else {\n return requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget(location$)\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? fetchSearchIndex()\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up progress indicator */\nconst progress$ = new Subject()\n\n/* Set up instant navigation, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantNavigation({ location$, viewport$, progress$ })\n .subscribe(document$)\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector({ document$ })\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"link[rel=prev]\")\n if (typeof prev !== \"undefined\")\n setLocation(prev)\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"link[rel=next]\")\n if (typeof next !== \"undefined\")\n setLocation(next)\n break\n\n /* Expand navigation, see https://bit.ly/3ZjG5io */\n case \"Enter\":\n const active = getActiveElement()\n if (active instanceof HTMLLabelElement)\n active.click()\n }\n })\n\n/* Set up patches */\npatchEllipsis({ viewport$, document$ })\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Consent */\n ...getComponentElements(\"consent\")\n .map(el => mountConsent(el, { target$ })),\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Progress bar */\n ...getComponentElements(\"progress\")\n .map(el => mountProgress(el, { progress$ })),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Announcement bar */\n ...getComponentElements(\"announce\")\n .map(el => mountAnnounce(el)),\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { viewport$, target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, {\n viewport$, header$, main$, target$\n })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.progress$ = progress$ /* Progress indicator subject */\nwindow.component$ = component$ /* Component observable */\n", "/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n", "/**\n * Returns true if the object is a function.\n * @param value The value to check\n */\nexport function isFunction(value: any): value is (...args: any[]) => any {\n return typeof value === 'function';\n}\n", "/**\n * Used to create Error subclasses until the community moves away from ES5.\n *\n * This is because compiling from TypeScript down to ES5 has issues with subclassing Errors\n * as well as other built-in types: https://github.com/Microsoft/TypeScript/issues/12123\n *\n * @param createImpl A factory function to create the actual constructor implementation. The returned\n * function should be a named function that calls `_super` internally.\n */\nexport function createErrorClass(createImpl: (_super: any) => any): T {\n const _super = (instance: any) => {\n Error.call(instance);\n instance.stack = new Error().stack;\n };\n\n const ctorFunc = createImpl(_super);\n ctorFunc.prototype = Object.create(Error.prototype);\n ctorFunc.prototype.constructor = ctorFunc;\n return ctorFunc;\n}\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface UnsubscriptionError extends Error {\n readonly errors: any[];\n}\n\nexport interface UnsubscriptionErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (errors: any[]): UnsubscriptionError;\n}\n\n/**\n * An error thrown when one or more errors have occurred during the\n * `unsubscribe` of a {@link Subscription}.\n */\nexport const UnsubscriptionError: UnsubscriptionErrorCtor = createErrorClass(\n (_super) =>\n function UnsubscriptionErrorImpl(this: any, errors: (Error | string)[]) {\n _super(this);\n this.message = errors\n ? `${errors.length} errors occurred during unsubscription:\n${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\\n ')}`\n : '';\n this.name = 'UnsubscriptionError';\n this.errors = errors;\n }\n);\n", "/**\n * Removes an item from an array, mutating it.\n * @param arr The array to remove the item from\n * @param item The item to remove\n */\nexport function arrRemove(arr: T[] | undefined | null, item: T) {\n if (arr) {\n const index = arr.indexOf(item);\n 0 <= index && arr.splice(index, 1);\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { UnsubscriptionError } from './util/UnsubscriptionError';\nimport { SubscriptionLike, TeardownLogic, Unsubscribable } from './types';\nimport { arrRemove } from './util/arrRemove';\n\n/**\n * Represents a disposable resource, such as the execution of an Observable. A\n * Subscription has one important method, `unsubscribe`, that takes no argument\n * and just disposes the resource held by the subscription.\n *\n * Additionally, subscriptions may be grouped together through the `add()`\n * method, which will attach a child Subscription to the current Subscription.\n * When a Subscription is unsubscribed, all its children (and its grandchildren)\n * will be unsubscribed as well.\n *\n * @class Subscription\n */\nexport class Subscription implements SubscriptionLike {\n /** @nocollapse */\n public static EMPTY = (() => {\n const empty = new Subscription();\n empty.closed = true;\n return empty;\n })();\n\n /**\n * A flag to indicate whether this Subscription has already been unsubscribed.\n */\n public closed = false;\n\n private _parentage: Subscription[] | Subscription | null = null;\n\n /**\n * The list of registered finalizers to execute upon unsubscription. Adding and removing from this\n * list occurs in the {@link #add} and {@link #remove} methods.\n */\n private _finalizers: Exclude[] | null = null;\n\n /**\n * @param initialTeardown A function executed first as part of the finalization\n * process that is kicked off when {@link #unsubscribe} is called.\n */\n constructor(private initialTeardown?: () => void) {}\n\n /**\n * Disposes the resources held by the subscription. May, for instance, cancel\n * an ongoing Observable execution or cancel any other type of work that\n * started when the Subscription was created.\n * @return {void}\n */\n unsubscribe(): void {\n let errors: any[] | undefined;\n\n if (!this.closed) {\n this.closed = true;\n\n // Remove this from it's parents.\n const { _parentage } = this;\n if (_parentage) {\n this._parentage = null;\n if (Array.isArray(_parentage)) {\n for (const parent of _parentage) {\n parent.remove(this);\n }\n } else {\n _parentage.remove(this);\n }\n }\n\n const { initialTeardown: initialFinalizer } = this;\n if (isFunction(initialFinalizer)) {\n try {\n initialFinalizer();\n } catch (e) {\n errors = e instanceof UnsubscriptionError ? e.errors : [e];\n }\n }\n\n const { _finalizers } = this;\n if (_finalizers) {\n this._finalizers = null;\n for (const finalizer of _finalizers) {\n try {\n execFinalizer(finalizer);\n } catch (err) {\n errors = errors ?? [];\n if (err instanceof UnsubscriptionError) {\n errors = [...errors, ...err.errors];\n } else {\n errors.push(err);\n }\n }\n }\n }\n\n if (errors) {\n throw new UnsubscriptionError(errors);\n }\n }\n }\n\n /**\n * Adds a finalizer to this subscription, so that finalization will be unsubscribed/called\n * when this subscription is unsubscribed. If this subscription is already {@link #closed},\n * because it has already been unsubscribed, then whatever finalizer is passed to it\n * will automatically be executed (unless the finalizer itself is also a closed subscription).\n *\n * Closed Subscriptions cannot be added as finalizers to any subscription. Adding a closed\n * subscription to a any subscription will result in no operation. (A noop).\n *\n * Adding a subscription to itself, or adding `null` or `undefined` will not perform any\n * operation at all. (A noop).\n *\n * `Subscription` instances that are added to this instance will automatically remove themselves\n * if they are unsubscribed. Functions and {@link Unsubscribable} objects that you wish to remove\n * will need to be removed manually with {@link #remove}\n *\n * @param teardown The finalization logic to add to this subscription.\n */\n add(teardown: TeardownLogic): void {\n // Only add the finalizer if it's not undefined\n // and don't add a subscription to itself.\n if (teardown && teardown !== this) {\n if (this.closed) {\n // If this subscription is already closed,\n // execute whatever finalizer is handed to it automatically.\n execFinalizer(teardown);\n } else {\n if (teardown instanceof Subscription) {\n // We don't add closed subscriptions, and we don't add the same subscription\n // twice. Subscription unsubscribe is idempotent.\n if (teardown.closed || teardown._hasParent(this)) {\n return;\n }\n teardown._addParent(this);\n }\n (this._finalizers = this._finalizers ?? []).push(teardown);\n }\n }\n }\n\n /**\n * Checks to see if a this subscription already has a particular parent.\n * This will signal that this subscription has already been added to the parent in question.\n * @param parent the parent to check for\n */\n private _hasParent(parent: Subscription) {\n const { _parentage } = this;\n return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));\n }\n\n /**\n * Adds a parent to this subscription so it can be removed from the parent if it\n * unsubscribes on it's own.\n *\n * NOTE: THIS ASSUMES THAT {@link _hasParent} HAS ALREADY BEEN CHECKED.\n * @param parent The parent subscription to add\n */\n private _addParent(parent: Subscription) {\n const { _parentage } = this;\n this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;\n }\n\n /**\n * Called on a child when it is removed via {@link #remove}.\n * @param parent The parent to remove\n */\n private _removeParent(parent: Subscription) {\n const { _parentage } = this;\n if (_parentage === parent) {\n this._parentage = null;\n } else if (Array.isArray(_parentage)) {\n arrRemove(_parentage, parent);\n }\n }\n\n /**\n * Removes a finalizer from this subscription that was previously added with the {@link #add} method.\n *\n * Note that `Subscription` instances, when unsubscribed, will automatically remove themselves\n * from every other `Subscription` they have been added to. This means that using the `remove` method\n * is not a common thing and should be used thoughtfully.\n *\n * If you add the same finalizer instance of a function or an unsubscribable object to a `Subscription` instance\n * more than once, you will need to call `remove` the same number of times to remove all instances.\n *\n * All finalizer instances are removed to free up memory upon unsubscription.\n *\n * @param teardown The finalizer to remove from this subscription\n */\n remove(teardown: Exclude): void {\n const { _finalizers } = this;\n _finalizers && arrRemove(_finalizers, teardown);\n\n if (teardown instanceof Subscription) {\n teardown._removeParent(this);\n }\n }\n}\n\nexport const EMPTY_SUBSCRIPTION = Subscription.EMPTY;\n\nexport function isSubscription(value: any): value is Subscription {\n return (\n value instanceof Subscription ||\n (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe))\n );\n}\n\nfunction execFinalizer(finalizer: Unsubscribable | (() => void)) {\n if (isFunction(finalizer)) {\n finalizer();\n } else {\n finalizer.unsubscribe();\n }\n}\n", "import { Subscriber } from './Subscriber';\nimport { ObservableNotification } from './types';\n\n/**\n * The {@link GlobalConfig} object for RxJS. It is used to configure things\n * like how to react on unhandled errors.\n */\nexport const config: GlobalConfig = {\n onUnhandledError: null,\n onStoppedNotification: null,\n Promise: undefined,\n useDeprecatedSynchronousErrorHandling: false,\n useDeprecatedNextContext: false,\n};\n\n/**\n * The global configuration object for RxJS, used to configure things\n * like how to react on unhandled errors. Accessible via {@link config}\n * object.\n */\nexport interface GlobalConfig {\n /**\n * A registration point for unhandled errors from RxJS. These are errors that\n * cannot were not handled by consuming code in the usual subscription path. For\n * example, if you have this configured, and you subscribe to an observable without\n * providing an error handler, errors from that subscription will end up here. This\n * will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onUnhandledError: ((err: any) => void) | null;\n\n /**\n * A registration point for notifications that cannot be sent to subscribers because they\n * have completed, errored or have been explicitly unsubscribed. By default, next, complete\n * and error notifications sent to stopped subscribers are noops. However, sometimes callers\n * might want a different behavior. For example, with sources that attempt to report errors\n * to stopped subscribers, a caller can configure RxJS to throw an unhandled error instead.\n * This will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onStoppedNotification: ((notification: ObservableNotification, subscriber: Subscriber) => void) | null;\n\n /**\n * The promise constructor used by default for {@link Observable#toPromise toPromise} and {@link Observable#forEach forEach}\n * methods.\n *\n * @deprecated As of version 8, RxJS will no longer support this sort of injection of a\n * Promise constructor. If you need a Promise implementation other than native promises,\n * please polyfill/patch Promise as you see appropriate. Will be removed in v8.\n */\n Promise?: PromiseConstructorLike;\n\n /**\n * If true, turns on synchronous error rethrowing, which is a deprecated behavior\n * in v6 and higher. This behavior enables bad patterns like wrapping a subscribe\n * call in a try/catch block. It also enables producer interference, a nasty bug\n * where a multicast can be broken for all observers by a downstream consumer with\n * an unhandled error. DO NOT USE THIS FLAG UNLESS IT'S NEEDED TO BUY TIME\n * FOR MIGRATION REASONS.\n *\n * @deprecated As of version 8, RxJS will no longer support synchronous throwing\n * of unhandled errors. All errors will be thrown on a separate call stack to prevent bad\n * behaviors described above. Will be removed in v8.\n */\n useDeprecatedSynchronousErrorHandling: boolean;\n\n /**\n * If true, enables an as-of-yet undocumented feature from v5: The ability to access\n * `unsubscribe()` via `this` context in `next` functions created in observers passed\n * to `subscribe`.\n *\n * This is being removed because the performance was severely problematic, and it could also cause\n * issues when types other than POJOs are passed to subscribe as subscribers, as they will likely have\n * their `this` context overwritten.\n *\n * @deprecated As of version 8, RxJS will no longer support altering the\n * context of next functions provided as part of an observer to Subscribe. Instead,\n * you will have access to a subscription or a signal or token that will allow you to do things like\n * unsubscribe and test closed status. Will be removed in v8.\n */\n useDeprecatedNextContext: boolean;\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetTimeoutFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearTimeoutFunction = (handle: TimerHandle) => void;\n\ninterface TimeoutProvider {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n delegate:\n | {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n }\n | undefined;\n}\n\nexport const timeoutProvider: TimeoutProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setTimeout(handler: () => void, timeout?: number, ...args) {\n const { delegate } = timeoutProvider;\n if (delegate?.setTimeout) {\n return delegate.setTimeout(handler, timeout, ...args);\n }\n return setTimeout(handler, timeout, ...args);\n },\n clearTimeout(handle) {\n const { delegate } = timeoutProvider;\n return (delegate?.clearTimeout || clearTimeout)(handle as any);\n },\n delegate: undefined,\n};\n", "import { config } from '../config';\nimport { timeoutProvider } from '../scheduler/timeoutProvider';\n\n/**\n * Handles an error on another job either with the user-configured {@link onUnhandledError},\n * or by throwing it on that new job so it can be picked up by `window.onerror`, `process.on('error')`, etc.\n *\n * This should be called whenever there is an error that is out-of-band with the subscription\n * or when an error hits a terminal boundary of the subscription and no error handler was provided.\n *\n * @param err the error to report\n */\nexport function reportUnhandledError(err: any) {\n timeoutProvider.setTimeout(() => {\n const { onUnhandledError } = config;\n if (onUnhandledError) {\n // Execute the user-configured error handler.\n onUnhandledError(err);\n } else {\n // Throw so it is picked up by the runtime's uncaught error mechanism.\n throw err;\n }\n });\n}\n", "/* tslint:disable:no-empty */\nexport function noop() { }\n", "import { CompleteNotification, NextNotification, ErrorNotification } from './types';\n\n/**\n * A completion object optimized for memory use and created to be the\n * same \"shape\" as other notifications in v8.\n * @internal\n */\nexport const COMPLETE_NOTIFICATION = (() => createNotification('C', undefined, undefined) as CompleteNotification)();\n\n/**\n * Internal use only. Creates an optimized error notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function errorNotification(error: any): ErrorNotification {\n return createNotification('E', undefined, error) as any;\n}\n\n/**\n * Internal use only. Creates an optimized next notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function nextNotification(value: T) {\n return createNotification('N', value, undefined) as NextNotification;\n}\n\n/**\n * Ensures that all notifications created internally have the same \"shape\" in v8.\n *\n * TODO: This is only exported to support a crazy legacy test in `groupBy`.\n * @internal\n */\nexport function createNotification(kind: 'N' | 'E' | 'C', value: any, error: any) {\n return {\n kind,\n value,\n error,\n };\n}\n", "import { config } from '../config';\n\nlet context: { errorThrown: boolean; error: any } | null = null;\n\n/**\n * Handles dealing with errors for super-gross mode. Creates a context, in which\n * any synchronously thrown errors will be passed to {@link captureError}. Which\n * will record the error such that it will be rethrown after the call back is complete.\n * TODO: Remove in v8\n * @param cb An immediately executed function.\n */\nexport function errorContext(cb: () => void) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n const isRoot = !context;\n if (isRoot) {\n context = { errorThrown: false, error: null };\n }\n cb();\n if (isRoot) {\n const { errorThrown, error } = context!;\n context = null;\n if (errorThrown) {\n throw error;\n }\n }\n } else {\n // This is the general non-deprecated path for everyone that\n // isn't crazy enough to use super-gross mode (useDeprecatedSynchronousErrorHandling)\n cb();\n }\n}\n\n/**\n * Captures errors only in super-gross mode.\n * @param err the error to capture\n */\nexport function captureError(err: any) {\n if (config.useDeprecatedSynchronousErrorHandling && context) {\n context.errorThrown = true;\n context.error = err;\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { Observer, ObservableNotification } from './types';\nimport { isSubscription, Subscription } from './Subscription';\nimport { config } from './config';\nimport { reportUnhandledError } from './util/reportUnhandledError';\nimport { noop } from './util/noop';\nimport { nextNotification, errorNotification, COMPLETE_NOTIFICATION } from './NotificationFactories';\nimport { timeoutProvider } from './scheduler/timeoutProvider';\nimport { captureError } from './util/errorContext';\n\n/**\n * Implements the {@link Observer} interface and extends the\n * {@link Subscription} class. While the {@link Observer} is the public API for\n * consuming the values of an {@link Observable}, all Observers get converted to\n * a Subscriber, in order to provide Subscription-like capabilities such as\n * `unsubscribe`. Subscriber is a common type in RxJS, and crucial for\n * implementing operators, but it is rarely used as a public API.\n *\n * @class Subscriber\n */\nexport class Subscriber extends Subscription implements Observer {\n /**\n * A static factory for a Subscriber, given a (potentially partial) definition\n * of an Observer.\n * @param next The `next` callback of an Observer.\n * @param error The `error` callback of an\n * Observer.\n * @param complete The `complete` callback of an\n * Observer.\n * @return A Subscriber wrapping the (partially defined)\n * Observer represented by the given arguments.\n * @nocollapse\n * @deprecated Do not use. Will be removed in v8. There is no replacement for this\n * method, and there is no reason to be creating instances of `Subscriber` directly.\n * If you have a specific use case, please file an issue.\n */\n static create(next?: (x?: T) => void, error?: (e?: any) => void, complete?: () => void): Subscriber {\n return new SafeSubscriber(next, error, complete);\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected isStopped: boolean = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected destination: Subscriber | Observer; // this `any` is the escape hatch to erase extra type param (e.g. R)\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * There is no reason to directly create an instance of Subscriber. This type is exported for typings reasons.\n */\n constructor(destination?: Subscriber | Observer) {\n super();\n if (destination) {\n this.destination = destination;\n // Automatically chain subscriptions together here.\n // if destination is a Subscription, then it is a Subscriber.\n if (isSubscription(destination)) {\n destination.add(this);\n }\n } else {\n this.destination = EMPTY_OBSERVER;\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `next` from\n * the Observable, with a value. The Observable may call this method 0 or more\n * times.\n * @param {T} [value] The `next` value.\n * @return {void}\n */\n next(value?: T): void {\n if (this.isStopped) {\n handleStoppedNotification(nextNotification(value), this);\n } else {\n this._next(value!);\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `error` from\n * the Observable, with an attached `Error`. Notifies the Observer that\n * the Observable has experienced an error condition.\n * @param {any} [err] The `error` exception.\n * @return {void}\n */\n error(err?: any): void {\n if (this.isStopped) {\n handleStoppedNotification(errorNotification(err), this);\n } else {\n this.isStopped = true;\n this._error(err);\n }\n }\n\n /**\n * The {@link Observer} callback to receive a valueless notification of type\n * `complete` from the Observable. Notifies the Observer that the Observable\n * has finished sending push-based notifications.\n * @return {void}\n */\n complete(): void {\n if (this.isStopped) {\n handleStoppedNotification(COMPLETE_NOTIFICATION, this);\n } else {\n this.isStopped = true;\n this._complete();\n }\n }\n\n unsubscribe(): void {\n if (!this.closed) {\n this.isStopped = true;\n super.unsubscribe();\n this.destination = null!;\n }\n }\n\n protected _next(value: T): void {\n this.destination.next(value);\n }\n\n protected _error(err: any): void {\n try {\n this.destination.error(err);\n } finally {\n this.unsubscribe();\n }\n }\n\n protected _complete(): void {\n try {\n this.destination.complete();\n } finally {\n this.unsubscribe();\n }\n }\n}\n\n/**\n * This bind is captured here because we want to be able to have\n * compatibility with monoid libraries that tend to use a method named\n * `bind`. In particular, a library called Monio requires this.\n */\nconst _bind = Function.prototype.bind;\n\nfunction bind any>(fn: Fn, thisArg: any): Fn {\n return _bind.call(fn, thisArg);\n}\n\n/**\n * Internal optimization only, DO NOT EXPOSE.\n * @internal\n */\nclass ConsumerObserver implements Observer {\n constructor(private partialObserver: Partial>) {}\n\n next(value: T): void {\n const { partialObserver } = this;\n if (partialObserver.next) {\n try {\n partialObserver.next(value);\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n\n error(err: any): void {\n const { partialObserver } = this;\n if (partialObserver.error) {\n try {\n partialObserver.error(err);\n } catch (error) {\n handleUnhandledError(error);\n }\n } else {\n handleUnhandledError(err);\n }\n }\n\n complete(): void {\n const { partialObserver } = this;\n if (partialObserver.complete) {\n try {\n partialObserver.complete();\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n}\n\nexport class SafeSubscriber extends Subscriber {\n constructor(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((e?: any) => void) | null,\n complete?: (() => void) | null\n ) {\n super();\n\n let partialObserver: Partial>;\n if (isFunction(observerOrNext) || !observerOrNext) {\n // The first argument is a function, not an observer. The next\n // two arguments *could* be observers, or they could be empty.\n partialObserver = {\n next: (observerOrNext ?? undefined) as (((value: T) => void) | undefined),\n error: error ?? undefined,\n complete: complete ?? undefined,\n };\n } else {\n // The first argument is a partial observer.\n let context: any;\n if (this && config.useDeprecatedNextContext) {\n // This is a deprecated path that made `this.unsubscribe()` available in\n // next handler functions passed to subscribe. This only exists behind a flag\n // now, as it is *very* slow.\n context = Object.create(observerOrNext);\n context.unsubscribe = () => this.unsubscribe();\n partialObserver = {\n next: observerOrNext.next && bind(observerOrNext.next, context),\n error: observerOrNext.error && bind(observerOrNext.error, context),\n complete: observerOrNext.complete && bind(observerOrNext.complete, context),\n };\n } else {\n // The \"normal\" path. Just use the partial observer directly.\n partialObserver = observerOrNext;\n }\n }\n\n // Wrap the partial observer to ensure it's a full observer, and\n // make sure proper error handling is accounted for.\n this.destination = new ConsumerObserver(partialObserver);\n }\n}\n\nfunction handleUnhandledError(error: any) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n captureError(error);\n } else {\n // Ideal path, we report this as an unhandled error,\n // which is thrown on a new call stack.\n reportUnhandledError(error);\n }\n}\n\n/**\n * An error handler used when no error handler was supplied\n * to the SafeSubscriber -- meaning no error handler was supplied\n * do the `subscribe` call on our observable.\n * @param err The error to handle\n */\nfunction defaultErrorHandler(err: any) {\n throw err;\n}\n\n/**\n * A handler for notifications that cannot be sent to a stopped subscriber.\n * @param notification The notification being sent\n * @param subscriber The stopped subscriber\n */\nfunction handleStoppedNotification(notification: ObservableNotification, subscriber: Subscriber) {\n const { onStoppedNotification } = config;\n onStoppedNotification && timeoutProvider.setTimeout(() => onStoppedNotification(notification, subscriber));\n}\n\n/**\n * The observer used as a stub for subscriptions where the user did not\n * pass any arguments to `subscribe`. Comes with the default error handling\n * behavior.\n */\nexport const EMPTY_OBSERVER: Readonly> & { closed: true } = {\n closed: true,\n next: noop,\n error: defaultErrorHandler,\n complete: noop,\n};\n", "/**\n * Symbol.observable or a string \"@@observable\". Used for interop\n *\n * @deprecated We will no longer be exporting this symbol in upcoming versions of RxJS.\n * Instead polyfill and use Symbol.observable directly *or* use https://www.npmjs.com/package/symbol-observable\n */\nexport const observable: string | symbol = (() => (typeof Symbol === 'function' && Symbol.observable) || '@@observable')();\n", "/**\n * This function takes one parameter and just returns it. Simply put,\n * this is like `(x: T): T => x`.\n *\n * ## Examples\n *\n * This is useful in some cases when using things like `mergeMap`\n *\n * ```ts\n * import { interval, take, map, range, mergeMap, identity } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(5));\n *\n * const result$ = source$.pipe(\n * map(i => range(i)),\n * mergeMap(identity) // same as mergeMap(x => x)\n * );\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * Or when you want to selectively apply an operator\n *\n * ```ts\n * import { interval, take, identity } from 'rxjs';\n *\n * const shouldLimit = () => Math.random() < 0.5;\n *\n * const source$ = interval(1000);\n *\n * const result$ = source$.pipe(shouldLimit() ? take(5) : identity);\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * @param x Any value that is returned by this function\n * @returns The value passed as the first parameter to this function\n */\nexport function identity(x: T): T {\n return x;\n}\n", "import { identity } from './identity';\nimport { UnaryFunction } from '../types';\n\nexport function pipe(): typeof identity;\nexport function pipe(fn1: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction,\n ...fns: UnaryFunction[]\n): UnaryFunction;\n\n/**\n * pipe() can be called on one or more functions, each of which can take one argument (\"UnaryFunction\")\n * and uses it to return a value.\n * It returns a function that takes one argument, passes it to the first UnaryFunction, and then\n * passes the result to the next one, passes that result to the next one, and so on. \n */\nexport function pipe(...fns: Array>): UnaryFunction {\n return pipeFromArray(fns);\n}\n\n/** @internal */\nexport function pipeFromArray(fns: Array>): UnaryFunction {\n if (fns.length === 0) {\n return identity as UnaryFunction;\n }\n\n if (fns.length === 1) {\n return fns[0];\n }\n\n return function piped(input: T): R {\n return fns.reduce((prev: any, fn: UnaryFunction) => fn(prev), input as any);\n };\n}\n", "import { Operator } from './Operator';\nimport { SafeSubscriber, Subscriber } from './Subscriber';\nimport { isSubscription, Subscription } from './Subscription';\nimport { TeardownLogic, OperatorFunction, Subscribable, Observer } from './types';\nimport { observable as Symbol_observable } from './symbol/observable';\nimport { pipeFromArray } from './util/pipe';\nimport { config } from './config';\nimport { isFunction } from './util/isFunction';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A representation of any set of values over any amount of time. This is the most basic building block\n * of RxJS.\n *\n * @class Observable\n */\nexport class Observable implements Subscribable {\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n source: Observable | undefined;\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n operator: Operator | undefined;\n\n /**\n * @constructor\n * @param {Function} subscribe the function that is called when the Observable is\n * initially subscribed to. This function is given a Subscriber, to which new values\n * can be `next`ed, or an `error` method can be called to raise an error, or\n * `complete` can be called to notify of a successful completion.\n */\n constructor(subscribe?: (this: Observable, subscriber: Subscriber) => TeardownLogic) {\n if (subscribe) {\n this._subscribe = subscribe;\n }\n }\n\n // HACK: Since TypeScript inherits static properties too, we have to\n // fight against TypeScript here so Subject can have a different static create signature\n /**\n * Creates a new Observable by calling the Observable constructor\n * @owner Observable\n * @method create\n * @param {Function} subscribe? the subscriber function to be passed to the Observable constructor\n * @return {Observable} a new observable\n * @nocollapse\n * @deprecated Use `new Observable()` instead. Will be removed in v8.\n */\n static create: (...args: any[]) => any = (subscribe?: (subscriber: Subscriber) => TeardownLogic) => {\n return new Observable(subscribe);\n };\n\n /**\n * Creates a new Observable, with this Observable instance as the source, and the passed\n * operator defined as the new observable's operator.\n * @method lift\n * @param operator the operator defining the operation to take on the observable\n * @return a new observable with the Operator applied\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * If you have implemented an operator using `lift`, it is recommended that you create an\n * operator by simply returning `new Observable()` directly. See \"Creating new operators from\n * scratch\" section here: https://rxjs.dev/guide/operators\n */\n lift(operator?: Operator): Observable {\n const observable = new Observable();\n observable.source = this;\n observable.operator = operator;\n return observable;\n }\n\n subscribe(observerOrNext?: Partial> | ((value: T) => void)): Subscription;\n /** @deprecated Instead of passing separate callback arguments, use an observer argument. Signatures taking separate callback arguments will be removed in v8. Details: https://rxjs.dev/deprecations/subscribe-arguments */\n subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;\n /**\n * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.\n *\n * Use it when you have all these Observables, but still nothing is happening.\n *\n * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It\n * might be for example a function that you passed to Observable's constructor, but most of the time it is\n * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means\n * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often\n * the thought.\n *\n * Apart from starting the execution of an Observable, this method allows you to listen for values\n * that an Observable emits, as well as for when it completes or errors. You can achieve this in two\n * of the following ways.\n *\n * The first way is creating an object that implements {@link Observer} interface. It should have methods\n * defined by that interface, but note that it should be just a regular JavaScript object, which you can create\n * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular, do\n * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also\n * that your object does not have to implement all methods. If you find yourself creating a method that doesn't\n * do anything, you can simply omit it. Note however, if the `error` method is not provided and an error happens,\n * it will be thrown asynchronously. Errors thrown asynchronously cannot be caught using `try`/`catch`. Instead,\n * use the {@link onUnhandledError} configuration option or use a runtime handler (like `window.onerror` or\n * `process.on('error)`) to be notified of unhandled errors. Because of this, it's recommended that you provide\n * an `error` method to avoid missing thrown errors.\n *\n * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.\n * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent\n * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of an Observer,\n * if you do not need to listen for something, you can omit a function by passing `undefined` or `null`,\n * since `subscribe` recognizes these functions by where they were placed in function call. When it comes\n * to the `error` function, as with an Observer, if not provided, errors emitted by an Observable will be thrown asynchronously.\n *\n * You can, however, subscribe with no parameters at all. This may be the case where you're not interested in terminal events\n * and you also handled emissions internally by using operators (e.g. using `tap`).\n *\n * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.\n * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean\n * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback\n * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.\n *\n * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.\n * It is an Observable itself that decides when these functions will be called. For example {@link of}\n * by default emits all its values synchronously. Always check documentation for how given Observable\n * will behave when subscribed and if its default behavior can be modified with a `scheduler`.\n *\n * #### Examples\n *\n * Subscribe with an {@link guide/observer Observer}\n *\n * ```ts\n * import { of } from 'rxjs';\n *\n * const sumObserver = {\n * sum: 0,\n * next(value) {\n * console.log('Adding: ' + value);\n * this.sum = this.sum + value;\n * },\n * error() {\n * // We actually could just remove this method,\n * // since we do not really care about errors right now.\n * },\n * complete() {\n * console.log('Sum equals: ' + this.sum);\n * }\n * };\n *\n * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.\n * .subscribe(sumObserver);\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Subscribe with functions ({@link deprecations/subscribe-arguments deprecated})\n *\n * ```ts\n * import { of } from 'rxjs'\n *\n * let sum = 0;\n *\n * of(1, 2, 3).subscribe(\n * value => {\n * console.log('Adding: ' + value);\n * sum = sum + value;\n * },\n * undefined,\n * () => console.log('Sum equals: ' + sum)\n * );\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Cancel a subscription\n *\n * ```ts\n * import { interval } from 'rxjs';\n *\n * const subscription = interval(1000).subscribe({\n * next(num) {\n * console.log(num)\n * },\n * complete() {\n * // Will not be called, even when cancelling subscription.\n * console.log('completed!');\n * }\n * });\n *\n * setTimeout(() => {\n * subscription.unsubscribe();\n * console.log('unsubscribed!');\n * }, 2500);\n *\n * // Logs:\n * // 0 after 1s\n * // 1 after 2s\n * // 'unsubscribed!' after 2.5s\n * ```\n *\n * @param {Observer|Function} observerOrNext (optional) Either an observer with methods to be called,\n * or the first of three possible handlers, which is the handler for each value emitted from the subscribed\n * Observable.\n * @param {Function} error (optional) A handler for a terminal event resulting from an error. If no error handler is provided,\n * the error will be thrown asynchronously as unhandled.\n * @param {Function} complete (optional) A handler for a terminal event resulting from successful completion.\n * @return {Subscription} a subscription reference to the registered handlers\n * @method subscribe\n */\n subscribe(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((error: any) => void) | null,\n complete?: (() => void) | null\n ): Subscription {\n const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);\n\n errorContext(() => {\n const { operator, source } = this;\n subscriber.add(\n operator\n ? // We're dealing with a subscription in the\n // operator chain to one of our lifted operators.\n operator.call(subscriber, source)\n : source\n ? // If `source` has a value, but `operator` does not, something that\n // had intimate knowledge of our API, like our `Subject`, must have\n // set it. We're going to just call `_subscribe` directly.\n this._subscribe(subscriber)\n : // In all other cases, we're likely wrapping a user-provided initializer\n // function, so we need to catch errors and handle them appropriately.\n this._trySubscribe(subscriber)\n );\n });\n\n return subscriber;\n }\n\n /** @internal */\n protected _trySubscribe(sink: Subscriber): TeardownLogic {\n try {\n return this._subscribe(sink);\n } catch (err) {\n // We don't need to return anything in this case,\n // because it's just going to try to `add()` to a subscription\n // above.\n sink.error(err);\n }\n }\n\n /**\n * Used as a NON-CANCELLABLE means of subscribing to an observable, for use with\n * APIs that expect promises, like `async/await`. You cannot unsubscribe from this.\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * #### Example\n *\n * ```ts\n * import { interval, take } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(4));\n *\n * async function getTotal() {\n * let total = 0;\n *\n * await source$.forEach(value => {\n * total += value;\n * console.log('observable -> ' + value);\n * });\n *\n * return total;\n * }\n *\n * getTotal().then(\n * total => console.log('Total: ' + total)\n * );\n *\n * // Expected:\n * // 'observable -> 0'\n * // 'observable -> 1'\n * // 'observable -> 2'\n * // 'observable -> 3'\n * // 'Total: 6'\n * ```\n *\n * @param next a handler for each value emitted by the observable\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n */\n forEach(next: (value: T) => void): Promise;\n\n /**\n * @param next a handler for each value emitted by the observable\n * @param promiseCtor a constructor function used to instantiate the Promise\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n * @deprecated Passing a Promise constructor will no longer be available\n * in upcoming versions of RxJS. This is because it adds weight to the library, for very\n * little benefit. If you need this functionality, it is recommended that you either\n * polyfill Promise, or you create an adapter to convert the returned native promise\n * to whatever promise implementation you wanted. Will be removed in v8.\n */\n forEach(next: (value: T) => void, promiseCtor: PromiseConstructorLike): Promise;\n\n forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n const subscriber = new SafeSubscriber({\n next: (value) => {\n try {\n next(value);\n } catch (err) {\n reject(err);\n subscriber.unsubscribe();\n }\n },\n error: reject,\n complete: resolve,\n });\n this.subscribe(subscriber);\n }) as Promise;\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): TeardownLogic {\n return this.source?.subscribe(subscriber);\n }\n\n /**\n * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable\n * @method Symbol.observable\n * @return {Observable} this instance of the observable\n */\n [Symbol_observable]() {\n return this;\n }\n\n /* tslint:disable:max-line-length */\n pipe(): Observable;\n pipe(op1: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction,\n ...operations: OperatorFunction[]\n ): Observable;\n /* tslint:enable:max-line-length */\n\n /**\n * Used to stitch together functional operators into a chain.\n * @method pipe\n * @return {Observable} the Observable result of all of the operators having\n * been called in the order they were passed in.\n *\n * ## Example\n *\n * ```ts\n * import { interval, filter, map, scan } from 'rxjs';\n *\n * interval(1000)\n * .pipe(\n * filter(x => x % 2 === 0),\n * map(x => x + x),\n * scan((acc, x) => acc + x)\n * )\n * .subscribe(x => console.log(x));\n * ```\n */\n pipe(...operations: OperatorFunction[]): Observable {\n return pipeFromArray(operations)(this);\n }\n\n /* tslint:disable:max-line-length */\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: typeof Promise): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: PromiseConstructorLike): Promise;\n /* tslint:enable:max-line-length */\n\n /**\n * Subscribe to this Observable and get a Promise resolving on\n * `complete` with the last emission (if any).\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * @method toPromise\n * @param [promiseCtor] a constructor function used to instantiate\n * the Promise\n * @return A Promise that resolves with the last value emit, or\n * rejects on an error. If there were no emissions, Promise\n * resolves with undefined.\n * @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise\n */\n toPromise(promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n let value: T | undefined;\n this.subscribe(\n (x: T) => (value = x),\n (err: any) => reject(err),\n () => resolve(value)\n );\n }) as Promise;\n }\n}\n\n/**\n * Decides between a passed promise constructor from consuming code,\n * A default configured promise constructor, and the native promise\n * constructor and returns it. If nothing can be found, it will throw\n * an error.\n * @param promiseCtor The optional promise constructor to passed by consuming code\n */\nfunction getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {\n return promiseCtor ?? config.Promise ?? Promise;\n}\n\nfunction isObserver(value: any): value is Observer {\n return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);\n}\n\nfunction isSubscriber(value: any): value is Subscriber {\n return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));\n}\n", "import { Observable } from '../Observable';\nimport { Subscriber } from '../Subscriber';\nimport { OperatorFunction } from '../types';\nimport { isFunction } from './isFunction';\n\n/**\n * Used to determine if an object is an Observable with a lift function.\n */\nexport function hasLift(source: any): source is { lift: InstanceType['lift'] } {\n return isFunction(source?.lift);\n}\n\n/**\n * Creates an `OperatorFunction`. Used to define operators throughout the library in a concise way.\n * @param init The logic to connect the liftedSource to the subscriber at the moment of subscription.\n */\nexport function operate(\n init: (liftedSource: Observable, subscriber: Subscriber) => (() => void) | void\n): OperatorFunction {\n return (source: Observable) => {\n if (hasLift(source)) {\n return source.lift(function (this: Subscriber, liftedSource: Observable) {\n try {\n return init(liftedSource, this);\n } catch (err) {\n this.error(err);\n }\n });\n }\n throw new TypeError('Unable to lift unknown Observable type');\n };\n}\n", "import { Subscriber } from '../Subscriber';\n\n/**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional teardown logic here. This will only be called on teardown if the\n * subscriber itself is not already closed. This is called after all other teardown logic is executed.\n */\nexport function createOperatorSubscriber(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n onFinalize?: () => void\n): Subscriber {\n return new OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize);\n}\n\n/**\n * A generic helper for allowing operators to be created with a Subscriber and\n * use closures to capture necessary state from the operator function itself.\n */\nexport class OperatorSubscriber extends Subscriber {\n /**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional finalization logic here. This will only be called on finalization if the\n * subscriber itself is not already closed. This is called after all other finalization logic is executed.\n * @param shouldUnsubscribe An optional check to see if an unsubscribe call should truly unsubscribe.\n * NOTE: This currently **ONLY** exists to support the strange behavior of {@link groupBy}, where unsubscription\n * to the resulting observable does not actually disconnect from the source if there are active subscriptions\n * to any grouped observable. (DO NOT EXPOSE OR USE EXTERNALLY!!!)\n */\n constructor(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n private onFinalize?: () => void,\n private shouldUnsubscribe?: () => boolean\n ) {\n // It's important - for performance reasons - that all of this class's\n // members are initialized and that they are always initialized in the same\n // order. This will ensure that all OperatorSubscriber instances have the\n // same hidden class in V8. This, in turn, will help keep the number of\n // hidden classes involved in property accesses within the base class as\n // low as possible. If the number of hidden classes involved exceeds four,\n // the property accesses will become megamorphic and performance penalties\n // will be incurred - i.e. inline caches won't be used.\n //\n // The reasons for ensuring all instances have the same hidden class are\n // further discussed in this blog post from Benedikt Meurer:\n // https://benediktmeurer.de/2018/03/23/impact-of-polymorphism-on-component-based-frameworks-like-react/\n super(destination);\n this._next = onNext\n ? function (this: OperatorSubscriber, value: T) {\n try {\n onNext(value);\n } catch (err) {\n destination.error(err);\n }\n }\n : super._next;\n this._error = onError\n ? function (this: OperatorSubscriber, err: any) {\n try {\n onError(err);\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._error;\n this._complete = onComplete\n ? function (this: OperatorSubscriber) {\n try {\n onComplete();\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._complete;\n }\n\n unsubscribe() {\n if (!this.shouldUnsubscribe || this.shouldUnsubscribe()) {\n const { closed } = this;\n super.unsubscribe();\n // Execute additional teardown if we have any and we didn't already do so.\n !closed && this.onFinalize?.();\n }\n }\n}\n", "import { Subscription } from '../Subscription';\n\ninterface AnimationFrameProvider {\n schedule(callback: FrameRequestCallback): Subscription;\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n delegate:\n | {\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n }\n | undefined;\n}\n\nexport const animationFrameProvider: AnimationFrameProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n schedule(callback) {\n let request = requestAnimationFrame;\n let cancel: typeof cancelAnimationFrame | undefined = cancelAnimationFrame;\n const { delegate } = animationFrameProvider;\n if (delegate) {\n request = delegate.requestAnimationFrame;\n cancel = delegate.cancelAnimationFrame;\n }\n const handle = request((timestamp) => {\n // Clear the cancel function. The request has been fulfilled, so\n // attempting to cancel the request upon unsubscription would be\n // pointless.\n cancel = undefined;\n callback(timestamp);\n });\n return new Subscription(() => cancel?.(handle));\n },\n requestAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.requestAnimationFrame || requestAnimationFrame)(...args);\n },\n cancelAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.cancelAnimationFrame || cancelAnimationFrame)(...args);\n },\n delegate: undefined,\n};\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface ObjectUnsubscribedError extends Error {}\n\nexport interface ObjectUnsubscribedErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (): ObjectUnsubscribedError;\n}\n\n/**\n * An error thrown when an action is invalid because the object has been\n * unsubscribed.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n *\n * @class ObjectUnsubscribedError\n */\nexport const ObjectUnsubscribedError: ObjectUnsubscribedErrorCtor = createErrorClass(\n (_super) =>\n function ObjectUnsubscribedErrorImpl(this: any) {\n _super(this);\n this.name = 'ObjectUnsubscribedError';\n this.message = 'object unsubscribed';\n }\n);\n", "import { Operator } from './Operator';\nimport { Observable } from './Observable';\nimport { Subscriber } from './Subscriber';\nimport { Subscription, EMPTY_SUBSCRIPTION } from './Subscription';\nimport { Observer, SubscriptionLike, TeardownLogic } from './types';\nimport { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';\nimport { arrRemove } from './util/arrRemove';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A Subject is a special type of Observable that allows values to be\n * multicasted to many Observers. Subjects are like EventEmitters.\n *\n * Every Subject is an Observable and an Observer. You can subscribe to a\n * Subject, and you can call next to feed values as well as error and complete.\n */\nexport class Subject extends Observable implements SubscriptionLike {\n closed = false;\n\n private currentObservers: Observer[] | null = null;\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n observers: Observer[] = [];\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n isStopped = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n hasError = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n thrownError: any = null;\n\n /**\n * Creates a \"subject\" by basically gluing an observer to an observable.\n *\n * @nocollapse\n * @deprecated Recommended you do not use. Will be removed at some point in the future. Plans for replacement still under discussion.\n */\n static create: (...args: any[]) => any = (destination: Observer, source: Observable): AnonymousSubject => {\n return new AnonymousSubject(destination, source);\n };\n\n constructor() {\n // NOTE: This must be here to obscure Observable's constructor.\n super();\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n lift(operator: Operator): Observable {\n const subject = new AnonymousSubject(this, this);\n subject.operator = operator as any;\n return subject as any;\n }\n\n /** @internal */\n protected _throwIfClosed() {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n }\n\n next(value: T) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n if (!this.currentObservers) {\n this.currentObservers = Array.from(this.observers);\n }\n for (const observer of this.currentObservers) {\n observer.next(value);\n }\n }\n });\n }\n\n error(err: any) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.hasError = this.isStopped = true;\n this.thrownError = err;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.error(err);\n }\n }\n });\n }\n\n complete() {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.isStopped = true;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.complete();\n }\n }\n });\n }\n\n unsubscribe() {\n this.isStopped = this.closed = true;\n this.observers = this.currentObservers = null!;\n }\n\n get observed() {\n return this.observers?.length > 0;\n }\n\n /** @internal */\n protected _trySubscribe(subscriber: Subscriber): TeardownLogic {\n this._throwIfClosed();\n return super._trySubscribe(subscriber);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._checkFinalizedStatuses(subscriber);\n return this._innerSubscribe(subscriber);\n }\n\n /** @internal */\n protected _innerSubscribe(subscriber: Subscriber) {\n const { hasError, isStopped, observers } = this;\n if (hasError || isStopped) {\n return EMPTY_SUBSCRIPTION;\n }\n this.currentObservers = null;\n observers.push(subscriber);\n return new Subscription(() => {\n this.currentObservers = null;\n arrRemove(observers, subscriber);\n });\n }\n\n /** @internal */\n protected _checkFinalizedStatuses(subscriber: Subscriber) {\n const { hasError, thrownError, isStopped } = this;\n if (hasError) {\n subscriber.error(thrownError);\n } else if (isStopped) {\n subscriber.complete();\n }\n }\n\n /**\n * Creates a new Observable with this Subject as the source. You can do this\n * to create custom Observer-side logic of the Subject and conceal it from\n * code that uses the Observable.\n * @return {Observable} Observable that the Subject casts to\n */\n asObservable(): Observable {\n const observable: any = new Observable();\n observable.source = this;\n return observable;\n }\n}\n\n/**\n * @class AnonymousSubject\n */\nexport class AnonymousSubject extends Subject {\n constructor(\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n public destination?: Observer,\n source?: Observable\n ) {\n super();\n this.source = source;\n }\n\n next(value: T) {\n this.destination?.next?.(value);\n }\n\n error(err: any) {\n this.destination?.error?.(err);\n }\n\n complete() {\n this.destination?.complete?.();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n return this.source?.subscribe(subscriber) ?? EMPTY_SUBSCRIPTION;\n }\n}\n", "import { Subject } from './Subject';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\n\n/**\n * A variant of Subject that requires an initial value and emits its current\n * value whenever it is subscribed to.\n *\n * @class BehaviorSubject\n */\nexport class BehaviorSubject extends Subject {\n constructor(private _value: T) {\n super();\n }\n\n get value(): T {\n return this.getValue();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n const subscription = super._subscribe(subscriber);\n !subscription.closed && subscriber.next(this._value);\n return subscription;\n }\n\n getValue(): T {\n const { hasError, thrownError, _value } = this;\n if (hasError) {\n throw thrownError;\n }\n this._throwIfClosed();\n return _value;\n }\n\n next(value: T): void {\n super.next((this._value = value));\n }\n}\n", "import { TimestampProvider } from '../types';\n\ninterface DateTimestampProvider extends TimestampProvider {\n delegate: TimestampProvider | undefined;\n}\n\nexport const dateTimestampProvider: DateTimestampProvider = {\n now() {\n // Use the variable rather than `this` so that the function can be called\n // without being bound to the provider.\n return (dateTimestampProvider.delegate || Date).now();\n },\n delegate: undefined,\n};\n", "import { Subject } from './Subject';\nimport { TimestampProvider } from './types';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * A variant of {@link Subject} that \"replays\" old values to new subscribers by emitting them when they first subscribe.\n *\n * `ReplaySubject` has an internal buffer that will store a specified number of values that it has observed. Like `Subject`,\n * `ReplaySubject` \"observes\" values by having them passed to its `next` method. When it observes a value, it will store that\n * value for a time determined by the configuration of the `ReplaySubject`, as passed to its constructor.\n *\n * When a new subscriber subscribes to the `ReplaySubject` instance, it will synchronously emit all values in its buffer in\n * a First-In-First-Out (FIFO) manner. The `ReplaySubject` will also complete, if it has observed completion; and it will\n * error if it has observed an error.\n *\n * There are two main configuration items to be concerned with:\n *\n * 1. `bufferSize` - This will determine how many items are stored in the buffer, defaults to infinite.\n * 2. `windowTime` - The amount of time to hold a value in the buffer before removing it from the buffer.\n *\n * Both configurations may exist simultaneously. So if you would like to buffer a maximum of 3 values, as long as the values\n * are less than 2 seconds old, you could do so with a `new ReplaySubject(3, 2000)`.\n *\n * ### Differences with BehaviorSubject\n *\n * `BehaviorSubject` is similar to `new ReplaySubject(1)`, with a couple of exceptions:\n *\n * 1. `BehaviorSubject` comes \"primed\" with a single value upon construction.\n * 2. `ReplaySubject` will replay values, even after observing an error, where `BehaviorSubject` will not.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n * @see {@link shareReplay}\n */\nexport class ReplaySubject extends Subject {\n private _buffer: (T | number)[] = [];\n private _infiniteTimeWindow = true;\n\n /**\n * @param bufferSize The size of the buffer to replay on subscription\n * @param windowTime The amount of time the buffered items will stay buffered\n * @param timestampProvider An object with a `now()` method that provides the current timestamp. This is used to\n * calculate the amount of time something has been buffered.\n */\n constructor(\n private _bufferSize = Infinity,\n private _windowTime = Infinity,\n private _timestampProvider: TimestampProvider = dateTimestampProvider\n ) {\n super();\n this._infiniteTimeWindow = _windowTime === Infinity;\n this._bufferSize = Math.max(1, _bufferSize);\n this._windowTime = Math.max(1, _windowTime);\n }\n\n next(value: T): void {\n const { isStopped, _buffer, _infiniteTimeWindow, _timestampProvider, _windowTime } = this;\n if (!isStopped) {\n _buffer.push(value);\n !_infiniteTimeWindow && _buffer.push(_timestampProvider.now() + _windowTime);\n }\n this._trimBuffer();\n super.next(value);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._trimBuffer();\n\n const subscription = this._innerSubscribe(subscriber);\n\n const { _infiniteTimeWindow, _buffer } = this;\n // We use a copy here, so reentrant code does not mutate our array while we're\n // emitting it to a new subscriber.\n const copy = _buffer.slice();\n for (let i = 0; i < copy.length && !subscriber.closed; i += _infiniteTimeWindow ? 1 : 2) {\n subscriber.next(copy[i] as T);\n }\n\n this._checkFinalizedStatuses(subscriber);\n\n return subscription;\n }\n\n private _trimBuffer() {\n const { _bufferSize, _timestampProvider, _buffer, _infiniteTimeWindow } = this;\n // If we don't have an infinite buffer size, and we're over the length,\n // use splice to truncate the old buffer values off. Note that we have to\n // double the size for instances where we're not using an infinite time window\n // because we're storing the values and the timestamps in the same array.\n const adjustedBufferSize = (_infiniteTimeWindow ? 1 : 2) * _bufferSize;\n _bufferSize < Infinity && adjustedBufferSize < _buffer.length && _buffer.splice(0, _buffer.length - adjustedBufferSize);\n\n // Now, if we're not in an infinite time window, remove all values where the time is\n // older than what is allowed.\n if (!_infiniteTimeWindow) {\n const now = _timestampProvider.now();\n let last = 0;\n // Search the array for the first timestamp that isn't expired and\n // truncate the buffer up to that point.\n for (let i = 1; i < _buffer.length && (_buffer[i] as number) <= now; i += 2) {\n last = i;\n }\n last && _buffer.splice(0, last + 1);\n }\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Subscription } from '../Subscription';\nimport { SchedulerAction } from '../types';\n\n/**\n * A unit of work to be executed in a `scheduler`. An action is typically\n * created from within a {@link SchedulerLike} and an RxJS user does not need to concern\n * themselves about creating and manipulating an Action.\n *\n * ```ts\n * class Action extends Subscription {\n * new (scheduler: Scheduler, work: (state?: T) => void);\n * schedule(state?: T, delay: number = 0): Subscription;\n * }\n * ```\n *\n * @class Action\n */\nexport class Action extends Subscription {\n constructor(scheduler: Scheduler, work: (this: SchedulerAction, state?: T) => void) {\n super();\n }\n /**\n * Schedules this action on its parent {@link SchedulerLike} for execution. May be passed\n * some context object, `state`. May happen at some point in the future,\n * according to the `delay` parameter, if specified.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler.\n * @return {void}\n */\n public schedule(state?: T, delay: number = 0): Subscription {\n return this;\n }\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetIntervalFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearIntervalFunction = (handle: TimerHandle) => void;\n\ninterface IntervalProvider {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n delegate:\n | {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n }\n | undefined;\n}\n\nexport const intervalProvider: IntervalProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setInterval(handler: () => void, timeout?: number, ...args) {\n const { delegate } = intervalProvider;\n if (delegate?.setInterval) {\n return delegate.setInterval(handler, timeout, ...args);\n }\n return setInterval(handler, timeout, ...args);\n },\n clearInterval(handle) {\n const { delegate } = intervalProvider;\n return (delegate?.clearInterval || clearInterval)(handle as any);\n },\n delegate: undefined,\n};\n", "import { Action } from './Action';\nimport { SchedulerAction } from '../types';\nimport { Subscription } from '../Subscription';\nimport { AsyncScheduler } from './AsyncScheduler';\nimport { intervalProvider } from './intervalProvider';\nimport { arrRemove } from '../util/arrRemove';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncAction extends Action {\n public id: TimerHandle | undefined;\n public state?: T;\n // @ts-ignore: Property has no initializer and is not definitely assigned\n public delay: number;\n protected pending: boolean = false;\n\n constructor(protected scheduler: AsyncScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (this.closed) {\n return this;\n }\n\n // Always replace the current state with the new state.\n this.state = state;\n\n const id = this.id;\n const scheduler = this.scheduler;\n\n //\n // Important implementation note:\n //\n // Actions only execute once by default, unless rescheduled from within the\n // scheduled callback. This allows us to implement single and repeat\n // actions via the same code path, without adding API surface area, as well\n // as mimic traditional recursion but across asynchronous boundaries.\n //\n // However, JS runtimes and timers distinguish between intervals achieved by\n // serial `setTimeout` calls vs. a single `setInterval` call. An interval of\n // serial `setTimeout` calls can be individually delayed, which delays\n // scheduling the next `setTimeout`, and so on. `setInterval` attempts to\n // guarantee the interval callback will be invoked more precisely to the\n // interval period, regardless of load.\n //\n // Therefore, we use `setInterval` to schedule single and repeat actions.\n // If the action reschedules itself with the same delay, the interval is not\n // canceled. If the action doesn't reschedule, or reschedules with a\n // different delay, the interval will be canceled after scheduled callback\n // execution.\n //\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, delay);\n }\n\n // Set the pending flag indicating that this action has been scheduled, or\n // has recursively rescheduled itself.\n this.pending = true;\n\n this.delay = delay;\n // If this action has already an async Id, don't request a new one.\n this.id = this.id ?? this.requestAsyncId(scheduler, this.id, delay);\n\n return this;\n }\n\n protected requestAsyncId(scheduler: AsyncScheduler, _id?: TimerHandle, delay: number = 0): TimerHandle {\n return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);\n }\n\n protected recycleAsyncId(_scheduler: AsyncScheduler, id?: TimerHandle, delay: number | null = 0): TimerHandle | undefined {\n // If this action is rescheduled with the same delay time, don't clear the interval id.\n if (delay != null && this.delay === delay && this.pending === false) {\n return id;\n }\n // Otherwise, if the action's delay time is different from the current delay,\n // or the action has been rescheduled before it's executed, clear the interval id\n if (id != null) {\n intervalProvider.clearInterval(id);\n }\n\n return undefined;\n }\n\n /**\n * Immediately executes this action and the `work` it contains.\n * @return {any}\n */\n public execute(state: T, delay: number): any {\n if (this.closed) {\n return new Error('executing a cancelled action');\n }\n\n this.pending = false;\n const error = this._execute(state, delay);\n if (error) {\n return error;\n } else if (this.pending === false && this.id != null) {\n // Dequeue if the action didn't reschedule itself. Don't call\n // unsubscribe(), because the action could reschedule later.\n // For example:\n // ```\n // scheduler.schedule(function doWork(counter) {\n // /* ... I'm a busy worker bee ... */\n // var originalAction = this;\n // /* wait 100ms before rescheduling the action */\n // setTimeout(function () {\n // originalAction.schedule(counter + 1);\n // }, 100);\n // }, 1000);\n // ```\n this.id = this.recycleAsyncId(this.scheduler, this.id, null);\n }\n }\n\n protected _execute(state: T, _delay: number): any {\n let errored: boolean = false;\n let errorValue: any;\n try {\n this.work(state);\n } catch (e) {\n errored = true;\n // HACK: Since code elsewhere is relying on the \"truthiness\" of the\n // return here, we can't have it return \"\" or 0 or false.\n // TODO: Clean this up when we refactor schedulers mid-version-8 or so.\n errorValue = e ? e : new Error('Scheduled action threw falsy error');\n }\n if (errored) {\n this.unsubscribe();\n return errorValue;\n }\n }\n\n unsubscribe() {\n if (!this.closed) {\n const { id, scheduler } = this;\n const { actions } = scheduler;\n\n this.work = this.state = this.scheduler = null!;\n this.pending = false;\n\n arrRemove(actions, this);\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, null);\n }\n\n this.delay = null!;\n super.unsubscribe();\n }\n }\n}\n", "import { Action } from './scheduler/Action';\nimport { Subscription } from './Subscription';\nimport { SchedulerLike, SchedulerAction } from './types';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * An execution context and a data structure to order tasks and schedule their\n * execution. Provides a notion of (potentially virtual) time, through the\n * `now()` getter method.\n *\n * Each unit of work in a Scheduler is called an `Action`.\n *\n * ```ts\n * class Scheduler {\n * now(): number;\n * schedule(work, delay?, state?): Subscription;\n * }\n * ```\n *\n * @class Scheduler\n * @deprecated Scheduler is an internal implementation detail of RxJS, and\n * should not be used directly. Rather, create your own class and implement\n * {@link SchedulerLike}. Will be made internal in v8.\n */\nexport class Scheduler implements SchedulerLike {\n public static now: () => number = dateTimestampProvider.now;\n\n constructor(private schedulerActionCtor: typeof Action, now: () => number = Scheduler.now) {\n this.now = now;\n }\n\n /**\n * A getter method that returns a number representing the current time\n * (at the time this function was called) according to the scheduler's own\n * internal clock.\n * @return {number} A number that represents the current time. May or may not\n * have a relation to wall-clock time. May or may not refer to a time unit\n * (e.g. milliseconds).\n */\n public now: () => number;\n\n /**\n * Schedules a function, `work`, for execution. May happen at some point in\n * the future, according to the `delay` parameter, if specified. May be passed\n * some context object, `state`, which will be passed to the `work` function.\n *\n * The given arguments will be processed an stored as an Action object in a\n * queue of actions.\n *\n * @param {function(state: ?T): ?Subscription} work A function representing a\n * task, or some unit of work to be executed by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler itself.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @return {Subscription} A subscription in order to be able to unsubscribe\n * the scheduled work.\n */\n public schedule(work: (this: SchedulerAction, state?: T) => void, delay: number = 0, state?: T): Subscription {\n return new this.schedulerActionCtor(this, work).schedule(state, delay);\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Action } from './Action';\nimport { AsyncAction } from './AsyncAction';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncScheduler extends Scheduler {\n public actions: Array> = [];\n /**\n * A flag to indicate whether the Scheduler is currently executing a batch of\n * queued actions.\n * @type {boolean}\n * @internal\n */\n public _active: boolean = false;\n /**\n * An internal ID used to track the latest asynchronous task such as those\n * coming from `setTimeout`, `setInterval`, `requestAnimationFrame`, and\n * others.\n * @type {any}\n * @internal\n */\n public _scheduled: TimerHandle | undefined;\n\n constructor(SchedulerAction: typeof Action, now: () => number = Scheduler.now) {\n super(SchedulerAction, now);\n }\n\n public flush(action: AsyncAction): void {\n const { actions } = this;\n\n if (this._active) {\n actions.push(action);\n return;\n }\n\n let error: any;\n this._active = true;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions.shift()!)); // exhaust the scheduler queue\n\n this._active = false;\n\n if (error) {\n while ((action = actions.shift()!)) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\n/**\n *\n * Async Scheduler\n *\n * Schedule task as if you used setTimeout(task, duration)\n *\n * `async` scheduler schedules tasks asynchronously, by putting them on the JavaScript\n * event loop queue. It is best used to delay tasks in time or to schedule tasks repeating\n * in intervals.\n *\n * If you just want to \"defer\" task, that is to perform it right after currently\n * executing synchronous code ends (commonly achieved by `setTimeout(deferredTask, 0)`),\n * better choice will be the {@link asapScheduler} scheduler.\n *\n * ## Examples\n * Use async scheduler to delay task\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * const task = () => console.log('it works!');\n *\n * asyncScheduler.schedule(task, 2000);\n *\n * // After 2 seconds logs:\n * // \"it works!\"\n * ```\n *\n * Use async scheduler to repeat task in intervals\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * function task(state) {\n * console.log(state);\n * this.schedule(state + 1, 1000); // `this` references currently executing Action,\n * // which we reschedule with new state and delay\n * }\n *\n * asyncScheduler.schedule(task, 3000, 0);\n *\n * // Logs:\n * // 0 after 3s\n * // 1 after 4s\n * // 2 after 5s\n * // 3 after 6s\n * ```\n */\n\nexport const asyncScheduler = new AsyncScheduler(AsyncAction);\n\n/**\n * @deprecated Renamed to {@link asyncScheduler}. Will be removed in v8.\n */\nexport const async = asyncScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { Subscription } from '../Subscription';\nimport { QueueScheduler } from './QueueScheduler';\nimport { SchedulerAction } from '../types';\nimport { TimerHandle } from './timerHandle';\n\nexport class QueueAction extends AsyncAction {\n constructor(protected scheduler: QueueScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (delay > 0) {\n return super.schedule(state, delay);\n }\n this.delay = delay;\n this.state = state;\n this.scheduler.flush(this);\n return this;\n }\n\n public execute(state: T, delay: number): any {\n return delay > 0 || this.closed ? super.execute(state, delay) : this._execute(state, delay);\n }\n\n protected requestAsyncId(scheduler: QueueScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n\n if ((delay != null && delay > 0) || (delay == null && this.delay > 0)) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n\n // Otherwise flush the scheduler starting with this action.\n scheduler.flush(this);\n\n // HACK: In the past, this was returning `void`. However, `void` isn't a valid\n // `TimerHandle`, and generally the return value here isn't really used. So the\n // compromise is to return `0` which is both \"falsy\" and a valid `TimerHandle`,\n // as opposed to refactoring every other instanceo of `requestAsyncId`.\n return 0;\n }\n}\n", "import { AsyncScheduler } from './AsyncScheduler';\n\nexport class QueueScheduler extends AsyncScheduler {\n}\n", "import { QueueAction } from './QueueAction';\nimport { QueueScheduler } from './QueueScheduler';\n\n/**\n *\n * Queue Scheduler\n *\n * Put every next task on a queue, instead of executing it immediately\n *\n * `queue` scheduler, when used with delay, behaves the same as {@link asyncScheduler} scheduler.\n *\n * When used without delay, it schedules given task synchronously - executes it right when\n * it is scheduled. However when called recursively, that is when inside the scheduled task,\n * another task is scheduled with queue scheduler, instead of executing immediately as well,\n * that task will be put on a queue and wait for current one to finish.\n *\n * This means that when you execute task with `queue` scheduler, you are sure it will end\n * before any other task scheduled with that scheduler will start.\n *\n * ## Examples\n * Schedule recursively first, then do something\n * ```ts\n * import { queueScheduler } from 'rxjs';\n *\n * queueScheduler.schedule(() => {\n * queueScheduler.schedule(() => console.log('second')); // will not happen now, but will be put on a queue\n *\n * console.log('first');\n * });\n *\n * // Logs:\n * // \"first\"\n * // \"second\"\n * ```\n *\n * Reschedule itself recursively\n * ```ts\n * import { queueScheduler } from 'rxjs';\n *\n * queueScheduler.schedule(function(state) {\n * if (state !== 0) {\n * console.log('before', state);\n * this.schedule(state - 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * console.log('after', state);\n * }\n * }, 0, 3);\n *\n * // In scheduler that runs recursively, you would expect:\n * // \"before\", 3\n * // \"before\", 2\n * // \"before\", 1\n * // \"after\", 1\n * // \"after\", 2\n * // \"after\", 3\n *\n * // But with queue it logs:\n * // \"before\", 3\n * // \"after\", 3\n * // \"before\", 2\n * // \"after\", 2\n * // \"before\", 1\n * // \"after\", 1\n * ```\n */\n\nexport const queueScheduler = new QueueScheduler(QueueAction);\n\n/**\n * @deprecated Renamed to {@link queueScheduler}. Will be removed in v8.\n */\nexport const queue = queueScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\nimport { SchedulerAction } from '../types';\nimport { animationFrameProvider } from './animationFrameProvider';\nimport { TimerHandle } from './timerHandle';\n\nexport class AnimationFrameAction extends AsyncAction {\n constructor(protected scheduler: AnimationFrameScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n protected requestAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay is greater than 0, request as an async action.\n if (delay !== null && delay > 0) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n // Push the action to the end of the scheduler queue.\n scheduler.actions.push(this);\n // If an animation frame has already been requested, don't request another\n // one. If an animation frame hasn't been requested yet, request one. Return\n // the current animation frame request id.\n return scheduler._scheduled || (scheduler._scheduled = animationFrameProvider.requestAnimationFrame(() => scheduler.flush(undefined)));\n }\n\n protected recycleAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle | undefined {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n if (delay != null ? delay > 0 : this.delay > 0) {\n return super.recycleAsyncId(scheduler, id, delay);\n }\n // If the scheduler queue has no remaining actions with the same async id,\n // cancel the requested animation frame and set the scheduled flag to\n // undefined so the next AnimationFrameAction will request its own.\n const { actions } = scheduler;\n if (id != null && actions[actions.length - 1]?.id !== id) {\n animationFrameProvider.cancelAnimationFrame(id as number);\n scheduler._scheduled = undefined;\n }\n // Return undefined so the action knows to request a new async id if it's rescheduled.\n return undefined;\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\nexport class AnimationFrameScheduler extends AsyncScheduler {\n public flush(action?: AsyncAction): void {\n this._active = true;\n // The async id that effects a call to flush is stored in _scheduled.\n // Before executing an action, it's necessary to check the action's async\n // id to determine whether it's supposed to be executed in the current\n // flush.\n // Previous implementations of this method used a count to determine this,\n // but that was unsound, as actions that are unsubscribed - i.e. cancelled -\n // are removed from the actions array and that can shift actions that are\n // scheduled to be executed in a subsequent flush into positions at which\n // they are executed within the current flush.\n const flushId = this._scheduled;\n this._scheduled = undefined;\n\n const { actions } = this;\n let error: any;\n action = action || actions.shift()!;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions[0]) && action.id === flushId && actions.shift());\n\n this._active = false;\n\n if (error) {\n while ((action = actions[0]) && action.id === flushId && actions.shift()) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AnimationFrameAction } from './AnimationFrameAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\n\n/**\n *\n * Animation Frame Scheduler\n *\n * Perform task when `window.requestAnimationFrame` would fire\n *\n * When `animationFrame` scheduler is used with delay, it will fall back to {@link asyncScheduler} scheduler\n * behaviour.\n *\n * Without delay, `animationFrame` scheduler can be used to create smooth browser animations.\n * It makes sure scheduled task will happen just before next browser content repaint,\n * thus performing animations as efficiently as possible.\n *\n * ## Example\n * Schedule div height animation\n * ```ts\n * // html:
\n * import { animationFrameScheduler } from 'rxjs';\n *\n * const div = document.querySelector('div');\n *\n * animationFrameScheduler.schedule(function(height) {\n * div.style.height = height + \"px\";\n *\n * this.schedule(height + 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * }, 0, 0);\n *\n * // You will see a div element growing in height\n * ```\n */\n\nexport const animationFrameScheduler = new AnimationFrameScheduler(AnimationFrameAction);\n\n/**\n * @deprecated Renamed to {@link animationFrameScheduler}. Will be removed in v8.\n */\nexport const animationFrame = animationFrameScheduler;\n", "import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\n\n/**\n * A simple Observable that emits no items to the Observer and immediately\n * emits a complete notification.\n *\n * Just emits 'complete', and nothing else.\n *\n * ![](empty.png)\n *\n * A simple Observable that only emits the complete notification. It can be used\n * for composing with other Observables, such as in a {@link mergeMap}.\n *\n * ## Examples\n *\n * Log complete notification\n *\n * ```ts\n * import { EMPTY } from 'rxjs';\n *\n * EMPTY.subscribe({\n * next: () => console.log('Next'),\n * complete: () => console.log('Complete!')\n * });\n *\n * // Outputs\n * // Complete!\n * ```\n *\n * Emit the number 7, then complete\n *\n * ```ts\n * import { EMPTY, startWith } from 'rxjs';\n *\n * const result = EMPTY.pipe(startWith(7));\n * result.subscribe(x => console.log(x));\n *\n * // Outputs\n * // 7\n * ```\n *\n * Map and flatten only odd numbers to the sequence `'a'`, `'b'`, `'c'`\n *\n * ```ts\n * import { interval, mergeMap, of, EMPTY } from 'rxjs';\n *\n * const interval$ = interval(1000);\n * const result = interval$.pipe(\n * mergeMap(x => x % 2 === 1 ? of('a', 'b', 'c') : EMPTY),\n * );\n * result.subscribe(x => console.log(x));\n *\n * // Results in the following to the console:\n * // x is equal to the count on the interval, e.g. (0, 1, 2, 3, ...)\n * // x will occur every 1000ms\n * // if x % 2 is equal to 1, print a, b, c (each on its own)\n * // if x % 2 is not equal to 1, nothing will be output\n * ```\n *\n * @see {@link Observable}\n * @see {@link NEVER}\n * @see {@link of}\n * @see {@link throwError}\n */\nexport const EMPTY = new Observable((subscriber) => subscriber.complete());\n\n/**\n * @param scheduler A {@link SchedulerLike} to use for scheduling\n * the emission of the complete notification.\n * @deprecated Replaced with the {@link EMPTY} constant or {@link scheduled} (e.g. `scheduled([], scheduler)`). Will be removed in v8.\n */\nexport function empty(scheduler?: SchedulerLike) {\n return scheduler ? emptyScheduled(scheduler) : EMPTY;\n}\n\nfunction emptyScheduled(scheduler: SchedulerLike) {\n return new Observable((subscriber) => scheduler.schedule(() => subscriber.complete()));\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport function isScheduler(value: any): value is SchedulerLike {\n return value && isFunction(value.schedule);\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\nimport { isScheduler } from './isScheduler';\n\nfunction last(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function popResultSelector(args: any[]): ((...args: unknown[]) => unknown) | undefined {\n return isFunction(last(args)) ? args.pop() : undefined;\n}\n\nexport function popScheduler(args: any[]): SchedulerLike | undefined {\n return isScheduler(last(args)) ? args.pop() : undefined;\n}\n\nexport function popNumber(args: any[], defaultValue: number): number {\n return typeof last(args) === 'number' ? args.pop()! : defaultValue;\n}\n", "export const isArrayLike = ((x: any): x is ArrayLike => x && typeof x.length === 'number' && typeof x !== 'function');", "import { isFunction } from \"./isFunction\";\n\n/**\n * Tests to see if the object is \"thennable\".\n * @param value the object to test\n */\nexport function isPromise(value: any): value is PromiseLike {\n return isFunction(value?.then);\n}\n", "import { InteropObservable } from '../types';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being Observable (but not necessary an Rx Observable) */\nexport function isInteropObservable(input: any): input is InteropObservable {\n return isFunction(input[Symbol_observable]);\n}\n", "import { isFunction } from './isFunction';\n\nexport function isAsyncIterable(obj: any): obj is AsyncIterable {\n return Symbol.asyncIterator && isFunction(obj?.[Symbol.asyncIterator]);\n}\n", "/**\n * Creates the TypeError to throw if an invalid object is passed to `from` or `scheduled`.\n * @param input The object that was passed.\n */\nexport function createInvalidObservableTypeError(input: any) {\n // TODO: We should create error codes that can be looked up, so this can be less verbose.\n return new TypeError(\n `You provided ${\n input !== null && typeof input === 'object' ? 'an invalid object' : `'${input}'`\n } where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`\n );\n}\n", "export function getSymbolIterator(): symbol {\n if (typeof Symbol !== 'function' || !Symbol.iterator) {\n return '@@iterator' as any;\n }\n\n return Symbol.iterator;\n}\n\nexport const iterator = getSymbolIterator();\n", "import { iterator as Symbol_iterator } from '../symbol/iterator';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being an Iterable */\nexport function isIterable(input: any): input is Iterable {\n return isFunction(input?.[Symbol_iterator]);\n}\n", "import { ReadableStreamLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport async function* readableStreamLikeToAsyncGenerator(readableStream: ReadableStreamLike): AsyncGenerator {\n const reader = readableStream.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n return;\n }\n yield value!;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function isReadableStreamLike(obj: any): obj is ReadableStreamLike {\n // We don't want to use instanceof checks because they would return\n // false for instances from another Realm, like an