2024-09-04 20:24:31 +00:00
|
|
|
|
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)。
|
|
|
|
|
// 返回值是一個 Bitmap(byte 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 數創建一個 Bitmap(byte slice)。
|
|
|
|
|
// 參數 nBytes 表示所需的 byte 數。
|
|
|
|
|
// 返回值是一個長度為 nBytes 的 Bitmap。
|
|
|
|
|
func MustBitMap(nBytes int) Bitmap {
|
|
|
|
|
// 使用 make 函數創建一個 byte slice,大小為 nBytes。
|
|
|
|
|
return make([]byte, nBytes)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetTrue 設置指定位置的 bit 為 true(1)。
|
|
|
|
|
// 參數 bitPos 是需要設置的位的位置(以 0 為基準的位索引)。
|
|
|
|
|
// 這個操作會找到該 bit 所在的 byte,然後通過位運算將該位置的 bit 設置為 1。
|
|
|
|
|
func (b Bitmap) SetTrue(bitPos uint32) {
|
|
|
|
|
// |= 是一種位運算的複合賦值運算符,表示將左邊的變數與右邊的值進行 位或運算(bitwise OR),並將結果賦值
|
|
|
|
|
b[bitPos/8] |= 1 << (bitPos % 8)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetFalse 設置指定位置的 bit 為 false(0)。
|
|
|
|
|
// 參數 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 是否為 true(1)。
|
|
|
|
|
// 參數 bitPos 是要檢查的位的位置(以 0 為基準的位索引)。
|
|
|
|
|
// 如果該 bit 是 1,則返回 true;否則返回 false。
|
|
|
|
|
func (b Bitmap) IsTrue(bitPos uint32) bool {
|
|
|
|
|
/*
|
|
|
|
|
這一行程式碼 b[bitPos/8]&(1<<(bitPos%8)) != 0 是用來檢查 指定位(bit) 是否為 true(1),
|
|
|
|
|
它的核心是位運算。讓我們逐步拆解並解釋這一行程式碼:
|
|
|
|
|
|
|
|
|
|
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,所以我們要檢查的是第二個 byte:0b01010101。
|
|
|
|
|
2. 計算 bitPos%8 = 10%8 = 2,所以我們要檢查的是該 byte 中的第 3 位(從右數起第 3 位)。
|
|
|
|
|
3. 位移:1 << 2 = 00000100。
|
|
|
|
|
4. 位與:0b01010101 & 0b00000100 = 0b00000100(因為該 byte 的第 3 位是 1,結果不等於 0)。
|
|
|
|
|
5. 判斷結果:結果不等於 0,因此第 10 位是 1(true)。
|
|
|
|
|
|
|
|
|
|
4. 總結:
|
|
|
|
|
|
|
|
|
|
• b[bitPos/8]&(1<<(bitPos%8)) != 0 是一個經典的位操作,用來檢查位圖中某一個位是否為 1。
|
|
|
|
|
• bitPos/8 找到對應的 byte,bitPos % 8 找到該位在這個 byte 中的具體位置。
|
|
|
|
|
• 最後的位與運算和比較用來確定該位的狀態是 true(1)還是 false(0)。
|
|
|
|
|
*/
|
|
|
|
|
return b[bitPos/8]&(1<<(bitPos%8)) != 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reset 重置 Bitmap,使所有的 bit 都設置為 false(0)。
|
|
|
|
|
// 這個操作會將整個 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
|
|
|
|
|
}
|
2024-09-05 03:03:52 +00:00
|
|
|
|
|
|
|
|
|
// SetAllTrue 將 Bitmap 中的所有位設置為 true(1)。
|
|
|
|
|
func (b Bitmap) SetAllTrue() Bitmap {
|
|
|
|
|
// 將 Bitmap 中的每個 byte 設置為 0xFF,表示所有 bit 都為 1
|
|
|
|
|
for i := range b {
|
|
|
|
|
b[i] = 0xFF
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return b
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetAllFalse 將 Bitmap 中的所有位設置為 false(0)。
|
|
|
|
|
func (b Bitmap) SetAllFalse() Bitmap {
|
|
|
|
|
// 將 Bitmap 中的每個 byte 設置為 0,表示所有 bit 都為 0
|
|
|
|
|
for i := range b {
|
|
|
|
|
b[i] = 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return b
|
|
|
|
|
}
|