Bitmasking

Trick này được gọi là “Bitmasking” aka “bitwise flags” aka “bit flag pattern” aka “flag enumeration“

Thay vì tạo nhiều biến booleans (true/false) độc lập, chúng ta có thể lưu tất cả chúng vào 1 biến integer và thao tác nó bằng bitand

Ưu điểm

  • Compact storage: một số integer có thể biểu diễn nhiều flags
  • Fast checks: bitwise operations cực kì nhanh
  • Flexible combinations: có thể on/off từng flag mộ cách độc lập mà không ảnh hưởng đến các flags khác

Mỗi giá trị (vd: 1 , 2, 4, 8, 16, …) là một lũy thừa của 2 (vd: 20 (bit thứ nhất bật), 21 (bit thứ hai bật),…) tương ứng với một bit duy nhất được bật (1), vì thế chúng ta có thể kết hợp chúng bằng phép cộng (hoặc bitwise OR) và kiểm tra chúng bằng bitwise AND.

const int READ  = 1;    // 00000001   bit 0 bật         
const int WRITE = 2;    // 00000010   bit 1 bật (dịch bit 1 sang trái một vị trí)
const int EXEC   = 4;    // 00000100

// combine
00000001  + 00000010 = 00000011 (decimal 3).

// check
bitand(3, 1) = 1 -->TRUE
// Khi khai báo biến hoặc hàm là static trong struct/class, chúng thuộc về struct/class chứ không thuộc về một đối tượng cụ thể.
// Điều này cho phép gọi trực tiếp Permissions::READ, Permissions::setFlag() mà không cần khởi tạo Permissions permision;
struct Permissions
{
  static const int READ    = 1;
  static const int WRITE   = 2;
  static const int EXEC    = 4;
  static const int DEFAULT = READ + WRITE;

  // Utility functions
  // thêm hoặc xóa flag
  static void setFlag(int& p_mode, int p_flag, bool p_value) 
  {
    if (p_value){
      p_mode |= p_flag;  // Set flag (bitwise OR ensures flag is added)
    } else {
      p_mode &= ~p_flag; // Reset flag (bitwise AND with NOT removes flag)
    }
  }

  // Kiểm tra flag
  static bool isFlagSet(int p_mode, int p_flag)
  {
    return (p_mode & p_flag) == p_flag;
  }

  // in flags
  static string getFlagNames( int p_mode )
  {
    // create a string with " | flag" for each raised bit flag
    string l_result = string( p_mode & READ    ? "|READ" : ""  )
                     .append( p_mode & WRITE   ? "|WRITE"   : ""  )
                     .append( p_mode & EXEC    ? "|EXEC"    : ""  );

    // remove leading " | " if present
    return l_result.empty() ? l_result : l_result.substr(1);
  };
}

int main() {
  int mode = Permissions::DEFAULT;
  cout << "Initial mode: " << mode << endl;

  // add flag
  setFlag(mode, Permissions::EXEC, true);

  // check flag
  if (isFlagSet(mode, Permissions::EXEC)) {
    cout << "Permission::EXEC is set, current mode: "<< mode << endl;
  }

  cout << "Final mode: " << Permissions::getFlagNames(mode) << endl;

  return 0;
}
Initial mode: 3
Permission::EXEC is set, current mode: 7
Final mode: READ|WRITE|EXEC

Xem thêm: https://onlybinh.duckdns.org/enum-struct-class/

Leave a Comment