1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
|
# Understanding Bitwise Operations in Python
This guide explains bitwise operations with a focus on the expression `(uuid_int >> 80) & 0xFFFFFFFFFFFF`. We'll break down each operation, provide examples with visualization, and explore practical applications.
## Table of Contents
1. [Basic Concepts](#basic-concepts)
2. [Bitwise Operators](#bitwise-operators)
3. [Breaking Down Our Example](#breaking-down-our-example)
4. [Step-by-Step Execution](#step-by-step-execution)
5. [Common Use Cases](#common-use-cases)
## Basic Concepts
### Bits and Binary
A bit is the most basic unit of information in computing, representing either 0 or 1. Multiple bits form binary numbers:
```
Decimal: 13
Binary: 00001101
↑↑↑↑↑↑↑↑
87654321 (bit positions)
```
### Hexadecimal Notation
Hexadecimal (base 16) uses 0-9 and A-F to represent 16 values:
```
Decimal: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Hexadecimal: 0 1 2 3 4 5 6 7 8 9 A B C D E F
```
Example: `0xFF` = 255 decimal = `11111111` binary
## Bitwise Operators
### Bitwise AND (`&`)
Compares each bit position; results in 1 only if both bits are 1.
```
1101 (13)
& 1010 (10)
----
1000 (8)
```
Example:
```python
a = 13 # 1101 in binary
b = 10 # 1010 in binary
result = a & b
print(f"{a} & {b} = {result}") # Output: 13 & 10 = 8
```
### Bitwise OR (`|`)
Compares each bit position; results in 1 if either bit is 1.
```
1101 (13)
| 1010 (10)
----
1111 (15)
```
Example:
```python
a = 13 # 1101 in binary
b = 10 # 1010 in binary
result = a | b
print(f"{a} | {b} = {result}") # Output: 13 | 10 = 15
```
### Bitwise XOR (`^`)
Compares each bit position; results in 1 only if exactly one bit is 1.
```
1101 (13)
^ 1010 (10)
----
0111 (7)
```
Example:
```python
a = 13 # 1101 in binary
b = 10 # 1010 in binary
result = a ^ b
print(f"{a} ^ {b} = {result}") # Output: 13 ^ 10 = 7
```
### Bitwise NOT (`~`)
Inverts all bits (0 becomes 1, 1 becomes 0).
```
~ 1101 (13)
----
0010 (-14 in two's complement)
```
Example:
```python
a = 13 # 1101 in binary
result = ~a
print(f"~{a} = {result}") # Output: ~13 = -14
```
Note: In Python, NOT operates using two's complement, so ~n = -n-1
### Bitwise Left Shift (`<<`)
Shifts bits to the left by a specified number of positions, filling with 0s on the right.
```
13 << 2:
Before: 00001101 (13)
After: 00110100 (52)
```
Example:
```python
a = 13
shift = 2
result = a << shift
print(f"{a} << {shift} = {result}") # Output: 13 << 2 = 52
```
### Bitwise Right Shift (`>>`)
Shifts bits to the right by a specified number of positions.
```
13 >> 2:
Before: 00001101 (13)
After: 00000011 (3)
```
Example:
```python
a = 13
shift = 2
result = a >> shift
print(f"{a} >> {shift} = {result}") # Output: 13 >> 2 = 3
```
## Breaking Down Our Example
Let's analyze: `(uuid_int >> 80) & 0xFFFFFFFFFFFF`
This expression:
1. Takes a UUID integer value
2. Shifts it right by 80 bits
3. Performs a bitwise AND with `0xFFFFFFFFFFFF` (a 48-bit mask with all 1s)
## Step-by-Step Execution
### Example with a Sample UUID
Let's work with UUID: `123e4567-e89b-12d3-a456-426614174000`
As an integer: `0x123e4567e89b12d3a456426614174000`
#### Step 1: Understanding the Structure
This UUID integer in binary is 128 bits long:
```
UUID Integer:
0001 0010 0011 1110 0100 0101 0110 0111 1110 1000 1001 1011 0001 0010 1101 0011 1010 0100 0101 0110 0100 0010 0110 0110 0001 0100 0001 0111 0100 0000 0000 0000
```
#### Step 2: Right Shift by 80
`uuid_int >> 80` shifts all bits 80 positions to the right:
```
Before shift (simplified view of most significant bits):
0001 0010 0011 1110 0100 0101 0110 0111 1110 1000 1001 1011 0001 0010 1101 0011...
After shift (80 bits from right removed):
...0000 0000 0001 0010 0011 1110 0100 0101 0110 0111 1110 1000 1001 1011 0001 0010
```
Result: `0x123e4567e89b`
#### Step 3: Bitwise AND with Mask
The mask `0xFFFFFFFFFFFF` is 48 bits of all 1s:
```
Shifted value: 0000 0000 0001 0010 0011 1110 0100 0101 0110 0111 1110 1000 1001 1011 0001 0010
Mask: 0000 0000 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
Result: 0000 0000 0001 0010 0011 1110 0100 0101 0110 0111 1110 1000 1001 1011 0001 0010
```
The mask preserves the 48 least significant bits of the shifted value.
Final result: `0x123e4567e89b`
### Understanding Bit Shifting in Depth
Bit shifting is a fundamental operation that moves bits left or right within a binary representation:
#### Right Shift (`>>`)
- **Definition**: Moves all bits to the right by the specified number of positions
- **Effect**: Divides the number by 2^n (where n is the shift amount)
- **Lost Information**: Bits shifted beyond the right edge are discarded
- **Padding**: Most significant bits are filled with 0s (logical shift) or the sign bit (arithmetic shift)
**Visual Example**:
```
Decimal 173 (10101101 in binary) right-shifted by 3:
Before: 10101101
After: 00010101 (equals decimal 21)
↑↑↑ ← New 0s inserted on the left
```
Right shift by 80 bits effectively divides the uuid_int by 2^80, extracting only the higher bit positions.
### Masking Operations Explained
Bit masking uses bitwise AND to selectively filter bits:
#### Bitwise AND Mask
- **Purpose**: Keeps only the bits you want, zeros out the rest
- **Creation**: Set 1s in positions to keep, 0s in positions to clear
- **Formula**: `result = value & mask`
- **Common Masks**:
- `0xFF`: Preserve only the lowest 8 bits
- `0xFFFFFFFFFFFF`: Preserve 48 bits (as in our example)
- `0x01`: Check if the least significant bit is set
**Mask Patterns**:
```
Keep lower 4 bits: 0000 1111 (0x0F)
Keep upper 4 bits: 1111 0000 (0xF0)
Keep specific bits: 0101 0101 (0x55)
```
### Why Use `0xFFFFFFFFFFFF` in Our Example?
The 48-bit mask (`0xFFFFFFFFFFFF`) serves a specific purpose:
1. **Size Limitation**: Ensures the result doesn't exceed 48 bits (6 bytes)
2. **Data Integrity**: Removes any potential higher bits that might exist after the shift
3. **Standardization**: Forces the result into a consistent bit-length format
4. **UUID Structure**: Targets specific segments of the UUID structure
This technique combines shifting and masking to precisely extract 48 bits from a specific position in the 128-bit UUID.
### Code Demonstration:
```python
# Example with the UUID: 123e4567-e89b-12d3-a456-426614174000
uuid_int = 0x123e4567e89b12d3a456426614174000
print(f"Original UUID integer: {uuid_int}")
print(f"Hexadecimal: 0x{uuid_int:032x}")
# Step 1: Right shift by 80
shifted = uuid_int >> 80
print(f"\nAfter shifting right by 80 bits: {shifted}")
print(f"Hexadecimal: 0x{shifted:x}")
# Step 2: Apply the mask with bitwise AND
mask = 0xFFFFFFFFFFFF
result = shifted & mask
print(f"\nMask: 0x{mask:x}")
print(f"After applying the mask: {result}")
print(f"Hexadecimal: 0x{result:x}")
```
Output:
```
Original UUID integer: 24197857161011715162171839636988778528768
Hexadecimal: 0x123e4567e89b12d3a456426614174000
After shifting right by 80 bits: 81985529216411
Hexadecimal: 0x123e4567e89b
Mask: 0xffffffffffff
After applying the mask: 81985529216411
Hexadecimal: 0x123e4567e89b
```
## Common Use Cases
1. **Extracting Fields from UUIDs**: As in our example, isolating specific bit fields
- Example: Getting timestamp components from time-based UUIDs
- Example: Extracting node identifiers from MAC address-based UUIDs
2. **Mask Operations**: Selectively preserving or clearing bits
- Clearing specific flags: `status &= ~FLAG_BITS`
- Setting specific flags: `status |= FLAG_BITS`
- Toggling specific flags: `status ^= FLAG_BITS`
- Checking if flags are set: `if (status & FLAG_BITS) == FLAG_BITS`
3. **Efficient Division/Multiplication**: Using shifts for powers of 2
4. **Flag Manipulation**: Setting, checking, and clearing flags in a single integer
5. **Low-Level Memory Operations**: Direct manipulation of memory contents
## Role-Based Access Control Example
Bitwise operations provide an elegant way to implement role-based access control systems. Here's a practical example demonstrating how to define, assign, and check user roles:
### Defining Roles Using Bit Flags
Each role is assigned a power of 2 so each bit position represents a distinct role:
```python
# Role definitions (each role is a distinct bit)
NOT_LOGGED_IN = 0 # 00000000
USER = 1 # 00000001
EDITOR = 2 # 00000010
ADMIN = 4 # 00000100
SUPER_ADMIN = 8 # 00001000
```
### Assigning Multiple Roles
Combining roles is achieved with the bitwise OR (`|`) operator:
```python
# User with multiple roles (both USER and EDITOR permissions)
user_roles = USER | EDITOR # 00000011 (decimal 3)
# Admin with all permissions
admin_roles = USER | EDITOR | ADMIN | SUPER_ADMIN # 00001111 (decimal 15)
```
### Checking for Roles
Testing for specific roles uses the bitwise AND (`&`) operator:
```python
def has_role(user_roles, role):
"""Check if the user has a specific role."""
return (user_roles & role) == role
def check_access(user_roles):
"""Demonstrate role checking."""
if user_roles == NOT_LOGGED_IN:
print("Not logged in - access denied")
elif has_role(user_roles, ADMIN):
print("Admin access granted - full control")
elif has_role(user_roles, EDITOR):
print("Editor access granted - can edit content")
elif has_role(user_roles, USER):
print("User access granted - can view content")
else:
print("Unknown role configuration")
# Example usage
regular_user = USER # Just a regular user
content_editor = USER | EDITOR # User with editor privileges
site_admin = USER | EDITOR | ADMIN # User with admin privileges
check_access(regular_user) # Output: User access granted - can view content
check_access(content_editor) # Output: Editor access granted - can edit content
check_access(site_admin) # Output: Admin access granted - full control
```
### Adding and Removing Roles
Dynamically modify permissions without affecting other roles:
```python
# Granting a role (using bitwise OR)
def grant_role(user_roles, role):
return user_roles | role
# Revoking a role (using bitwise AND with complement)
def revoke_role(user_roles, role):
return user_roles & ~role
# Example: Promote a regular user to editor
user_roles = USER
print(f"Initial roles: {user_roles:08b}") # 00000001
user_roles = grant_role(user_roles, EDITOR)
print(f"After promotion: {user_roles:08b}") # 00000011
# Example: Revoke editor role
user_roles = revoke_role(user_roles, EDITOR)
print(f"After demotion: {user_roles:08b}") # 00000001
```
### Benefits of Bitwise Role Management
1. **Storage Efficiency**: Represents multiple roles in a single integer
2. **Performance**: Role checking is a simple bitwise operation
3. **Flexibility**: Easily add or remove roles without affecting others
4. **Scalability**: Supports up to 32 or 64 distinct roles (depending on integer size)
5. **Compatibility**: Works well with database storage and API transmission
This pattern is commonly used in:
- Operating system permission systems (read, write, execute)
- Web application authorization frameworks
- Database access control mechanisms
- Game development (character attributes, status effects)
|