library-go/utils/bitmap/bitmap.go

173 lines
7.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package usecase
// Bitmap 基礎結構
// Bitmap 是一個位圖結構,使用 byte slice 來表示大量的位bit
// 每個 byte 由 8 個位組成因此可以高效地管理大量的開關狀態true/false
// Bitmap 的優點在於它能節省空間,尤其是在需要大量布爾值的場合。
// 缺點是,如果需要動態擴充 Bitmap 的大小,會導致效率下降,因為需要重新分配和移動內存。
// 因此,最好在初始化時就規劃好所需的位數大小,避免在之後頻繁擴充。
type Bitmap []byte
// MakeBitmapWithBitSize 通過指定的 bit 數創建一個新的 Bitmap。
// 參數 nBits 表示所需的位bit數。
// 如果指定的位數少於 64則默認將 Bitmap 初始化為 64 位(這是最低的限制)。
// 此外位數nBits會被自動調整為 8 的倍數,以適配 byte 的長度(每 8 位為一個 byte
// 返回值是一個 Bitmapbyte slice其大小根據位數確定。
func MakeBitmapWithBitSize(nBits int) Bitmap {
// 如果指定的位數少於 64則設置為 64 位8 個 byte
if nBits < 64 {
nBits = 64
}
// 計算需要的 byte 數,確保每 8 位為一個 byte並調整 nBits 以達到 8 的倍數
return MustBitMap((nBits + 7) / 8)
}
// MustBitMap 根據指定的 byte 數創建一個 Bitmapbyte slice
// 參數 nBytes 表示所需的 byte 數。
// 返回值是一個長度為 nBytes 的 Bitmap。
func MustBitMap(nBytes int) Bitmap {
// 使用 make 函數創建一個 byte slice大小為 nBytes。
return make([]byte, nBytes)
}
// SetTrue 設置指定位置的 bit 為 true1
// 參數 bitPos 是需要設置的位的位置(以 0 為基準的位索引)。
// 這個操作會找到該 bit 所在的 byte然後通過位運算將該位置的 bit 設置為 1。
func (b Bitmap) SetTrue(bitPos uint32) {
// |= 是一種位運算的複合賦值運算符,表示將左邊的變數與右邊的值進行 位或運算bitwise OR並將結果賦值
b[bitPos/8] |= 1 << (bitPos % 8)
}
// SetFalse 設置指定位置的 bit 為 false0
// 參數 bitPos 是需要設置的位的位置(以 0 為基準的位索引)。
// 這個操作會找到該 bit 所在的 byte然後通過位運算將該位置的 bit 設置為 0。
func (b Bitmap) SetFalse(bitPos uint32) {
// 取出對應 byte使用位與和取反運算將對應的 bit 設置為 0
// 假設我們有以下情況:
// • b[1](即 b[bitPos/8])是 10101111十進制 175
// • bitPos = 10也就是我們想清除第 10 位的值。
//
// 操作步驟:
//
// 1. bitPos/8 = 1所以我們要修改 b[1] 這個 byte。
// 2. bitPos % 8 = 2表示我們要清除的位是這個 byte 中的第 3 位(從右數起第 3 位)。
// 3. 1 << (bitPos % 8) = 1 << 2 = 00000100生成位掩碼 00000100。
// 4. 取反:^(1 << 2) = ^00000100 = 11111011這樣的掩碼表示除了第 3 位,其他位都是 1。
// 5. 位與運算10101111 & 11111011 = 10101011結果將第 3 位清除其餘位保持不變。即b[1] 變成了 10101011十進制 171
// &= 是一種 位與運算的複合賦值運算符,表示將左邊的變數與右邊的值進行 位與運算bitwise AND然後將結果賦值給左邊的變數。
b[bitPos/8] &= ^(1 << (bitPos % 8))
}
// IsTrue 檢查指定位置的 bit 是否為 true1
// 參數 bitPos 是要檢查的位的位置(以 0 為基準的位索引)。
// 如果該 bit 是 1則返回 true否則返回 false。
func (b Bitmap) IsTrue(bitPos uint32) bool {
/*
這一行程式碼 b[bitPos/8]&(1<<(bitPos%8)) != 0 是用來檢查 指定位bit 是否為 true1
它的核心是位運算。讓我們逐步拆解並解釋這一行程式碼:
1. 背景知識:
• 位運算 是在二進制層面操作數字。每個 byte 有 8 個位bit所以位圖結構是以 byte 來表示位的集合。
• b 是一個 Bitmap 結構,也就是 []byte即 byte 的切片。
• bitPos 是一個 uint32 類型的變數表示我們想要檢查的位bit在整個位圖中的索引位置
3. 完整流程舉例:
假設:
• b = []byte{0b10101010, 0b01010101} (即二進制表示的兩個 byte分別是 10101010 和 01010101
• bitPos = 10我們要檢查第 10 位是否為 1
操作順序:
1. 計算 bitPos/8 = 10/8 = 1所以我們要檢查的是第二個 byte0b01010101。
2. 計算 bitPos%8 = 10%8 = 2所以我們要檢查的是該 byte 中的第 3 位(從右數起第 3 位)。
3. 位移1 << 2 = 00000100。
4. 位與0b01010101 & 0b00000100 = 0b00000100因為該 byte 的第 3 位是 1結果不等於 0
5. 判斷結果:結果不等於 0因此第 10 位是 1true
4. 總結:
• b[bitPos/8]&(1<<(bitPos%8)) != 0 是一個經典的位操作,用來檢查位圖中某一個位是否為 1。
• bitPos/8 找到對應的 bytebitPos % 8 找到該位在這個 byte 中的具體位置。
• 最後的位與運算和比較用來確定該位的狀態是 true1還是 false0
*/
return b[bitPos/8]&(1<<(bitPos%8)) != 0
}
// Reset 重置 Bitmap使所有的 bit 都設置為 false0
// 這個操作會將整個 Bitmap 的所有 byte 都設置為 0從而達到重置的效果。
func (b Bitmap) Reset() {
// 迭代 Bitmap 中的每個 byte並將其設置為 0
for i := range b {
b[i] = 0
}
}
// ByteSize 返回 Bitmap 的 byte 長度。
// 這個函數返回 Bitmap 目前占用的 byte 數量,該值等於 Bitmap 的長度slice 的長度)。
func (b Bitmap) ByteSize() int {
return len(b)
}
// BitSize 返回 Bitmap 的位bit長度。
// 這個函數通過將 byte 長度乘以 8 來計算 Bitmap 中的總位數。
func (b Bitmap) BitSize() int {
// 每個 byte 包含 8 個 bit因此將 byte 長度乘以 8
return len(b) * 8
}
// Resize 重新調整 Bitmap 的大小,將其擴展為指定的 bit 大小。
// 原來的數據會被保留,新增加的部分位將初始化為 0。
// 參數 newBitSize 是 Bitmap 需要擴展到的位大小。
func (b Bitmap) Resize(newBitSize int) Bitmap {
newByteSize := (newBitSize + 7) / 8
if newByteSize <= len(b) {
// 如果新大小比原大小小或相等,不做任何操作,直接返回原 Bitmap
return b
}
// 創建新的 Bitmap
newBitmap := make([]byte, newByteSize)
// 將原 Bitmap 複製到新 Bitmap 中
copy(newBitmap, b)
// 返回新的 Bitmap
return newBitmap
}
// UpdateFrom 會將傳入的 Bitmap 的值更新到當前 Bitmap 中。
// 如果傳入的 Bitmap 大於當前 Bitmap則當前 Bitmap 會自動擴展並保存新 Bitmap 的數據。
// 如果傳入的 Bitmap 小於當前 Bitmap僅更新前面部分的數據。
func (b Bitmap) UpdateFrom(newBitmap Bitmap) Bitmap {
// 如果 newBitmap 比當前 Bitmap 長,則擴展當前 Bitmap 的大小
if len(newBitmap) > len(b) {
// 創建一個擴展過的 Bitmap
expandedBitmap := make([]byte, len(newBitmap))
copy(expandedBitmap, b) // 將當前 Bitmap 的數據複製到擴展的 Bitmap 中
b = expandedBitmap // 更新當前 Bitmap 的引用
}
return b
}
// SetAllTrue 將 Bitmap 中的所有位設置為 true1
func (b Bitmap) SetAllTrue() Bitmap {
// 將 Bitmap 中的每個 byte 設置為 0xFF表示所有 bit 都為 1
for i := range b {
b[i] = 0xFF
}
return b
}
// SetAllFalse 將 Bitmap 中的所有位設置為 false0
func (b Bitmap) SetAllFalse() Bitmap {
// 將 Bitmap 中的每個 byte 設置為 0表示所有 bit 都為 0
for i := range b {
b[i] = 0
}
return b
}