Skip to content

Instantly share code, notes, and snippets.

@yalesov
Last active June 9, 2022 14:48
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yalesov/70452ce01cd4bf4ceda93fa2f9c8dfc5 to your computer and use it in GitHub Desktop.
Save yalesov/70452ce01cd4bf4ceda93fa2f9c8dfc5 to your computer and use it in GitHub Desktop.
Ruby bitwise flag manipulation
# ===== #
# 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