Last active
June 9, 2022 14:48
-
-
Save yalesov/70452ce01cd4bf4ceda93fa2f9c8dfc5 to your computer and use it in GitHub Desktop.
Ruby bitwise flag manipulation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ===== # | |
# Flags # | |
# ===== # | |
# say, a 1 byte integer | |
# | |
# 0 0 0 0 0 0 0 0 | |
# |- position 0 | |
# |--- position 1 | |
# |----- position 2 | |
# | |
# A bit flag at position 0 (0x01) | |
# 0 0 0 0 0 0 0 1 | |
# |- position 0 = (1 << 0) | |
# | |
# A bit flag at position 1 (0x02) | |
# 0 0 0 0 0 0 1 0 | |
# |--- position 1 = (1 << 1) | |
# | |
# A bit flag at position 2 (0x04) | |
# 0 0 0 0 0 1 0 0 | |
# |----- position 2 = (1 << 2) | |
# | |
# Defined as | |
FLAG_AT_POSITION_0 = (1 << 0) | |
FLAG_AT_POSITION_1 = (1 << 1) | |
FLAG_AT_POSITION_2 = (1 << 2) | |
# etc | |
# personally that looks more logical than | |
FLAG_AT_POSITION_0 = 1 | |
FLAG_AT_POSITION_1 = 2 | |
FLAG_AT_POSITION_2 = 4 | |
# or | |
FLAG_AT_POSITION_0 = 0x01 | |
FLAG_AT_POSITION_1 = 0x02 | |
FLAG_AT_POSITION_2 = 0x04 | |
# because there is a logic sequence from the (1 << 0), (1 << 1), (1 << 2) | |
# but the jump in 1, 2, 4, 8, 16, ... is not obvious | |
# well, the early sequences may be obvious, | |
# but going to later bits, say, the 30th bit in a 4-byte integer... what is 2^30 again? | |
# ==== # | |
# Math # | |
# ==== # | |
# | |
# These being flags, we are only interested in the 0/1 values at positions | |
# | |
# 0 0 1 0 0 1 0 1 (num) | |
# | |
# we want to get the flag at position, say, 1 | |
# bitwise & against (1 << 1) | |
# | |
# 0 0 1 0 0 1 0 1 (num) | |
# & | |
# 0 0 0 0 0 0 1 0 (1 << 1) | |
# = | |
# 0 0 0 0 0 0 0 0 (0, falsy in other languages, no match) | |
num & (1 << 1) # 0, falsy in other languages | |
# we want to get the flag at position, say, 2 | |
# bitwise & against (1 << 2) | |
# | |
# 0 0 1 0 0 1 0 1 (num) | |
# & | |
# 0 0 0 0 0 1 0 0 (1 << 2) | |
# = | |
# 0 0 0 0 0 1 0 0 ((1 << 2), truthy, matched) | |
num & (1 << 2) # truthy | |
(num & (1 << 2)) == (1 << 2) # also valid | |
# ===================== # | |
# Setting bitwise flags # | |
# ===================== # | |
# | |
# These being flags, we are only interested in the 0/1 values at positions | |
# | |
# 0 0 1 0 0 1 0 1 (src) | |
# | |
# we want to set the flag at position, say, 1, to 1 (true) | |
# bitwise | against (1 << 1) | |
# | |
# 0 0 1 0 0 1 0 1 (src) | |
# | | |
# 0 0 0 0 0 0 1 0 (1 << 1) | |
# = | |
# 0 0 1 0 0 1 1 1 | |
src | (1 << 1) # the flag we want | |
# we want to set the flag at position, say, 2, to 0 (false) | |
# bitwise & against the complement of (1 << 2) | |
# | |
# 0 0 1 0 0 1 0 1 (src) | |
# & | |
# 1 1 1 1 1 0 1 1 ~(1 << 2) | |
# = | |
# 0 0 1 0 0 0 0 1 | |
src & ~(1 << 2) # the flag we want | |
# overall, it looks clearer [to me], | |
# about which bit position we are manipulating in the raw data | |
# plus, it gives you ability to write generic manipulation functions | |
# ======================== # | |
# General helper functions # | |
# ======================== # | |
def get_bit(num, pos) # pos: rightmost bit = 0, second-right = 1, etc | |
(num & (1 << pos)) > 0 | |
end | |
def set_bitflag(num, pos, value) # value: the bool flag | |
if value | |
num | (1 << pos) | |
else | |
num & ~(1 << pos) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment