{"id":22515486,"url":"https://github.com/kylesmith19091/bitmanip","last_synced_at":"2025-03-28T02:20:14.243Z","repository":{"id":124213600,"uuid":"451088555","full_name":"KyleSmith19091/BitManip","owner":"KyleSmith19091","description":"This is a header only library for common bit manipulation and other operations using constexpr and some bit manipulation techniques to provide a low overhead and efficient interface.","archived":false,"fork":false,"pushed_at":"2022-01-23T12:21:08.000Z","size":5,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-02T03:41:29.865Z","etag":null,"topics":["bit-manipulation","bit-tricks","cpp","header-only"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KyleSmith19091.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-23T11:51:10.000Z","updated_at":"2023-01-16T13:40:45.000Z","dependencies_parsed_at":null,"dependency_job_id":"352fc634-3cc2-46da-8005-de3a3f7f403e","html_url":"https://github.com/KyleSmith19091/BitManip","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KyleSmith19091%2FBitManip","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KyleSmith19091%2FBitManip/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KyleSmith19091%2FBitManip/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KyleSmith19091%2FBitManip/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KyleSmith19091","download_url":"https://codeload.github.com/KyleSmith19091/BitManip/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245955440,"owners_count":20699909,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bit-manipulation","bit-tricks","cpp","header-only"],"created_at":"2024-12-07T03:32:45.074Z","updated_at":"2025-03-28T02:20:13.966Z","avatar_url":"https://github.com/KyleSmith19091.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Integer and Character Bit Manipulation\n\nThis is a header only library for common bit manipulation and other operations using constexpr and some bitwise operators to provide a low\noverhead and efficient interface.\n\n## Possible Operations\n### Number Manipulation\n1. isOdd → Check if integer is odd =\u003e O(1)\n\n2. oppositeSigns → Check if two integers have different signs =\u003e O(1)\n\n3. isBitSet → Check if bit is set =\u003e O(1)\n\n4. unsetKBit → Unsets K'th bit =\u003e O(1)\n\n5. setKBit → Sets K'th Bit =\u003e O(1)\n\n6. toggleKBit → Toggles K'th bit =\u003e O(1)\n\n7. unsetRightmostBit → Unsets the rightmost bit =\u003e O(1)\n\n8. isPowerOf2 → Check if number is a power of 2 =\u003e O(1)\n\n9. findOddParity → Check for odd parity =\u003e O(1) (Only works for 32 bit integers)\n\n10. abs → Get the absolute value of given number =\u003e O(1) \n\n11. swap → Swaps two integers =\u003e O(1)\n\n12. getRightmostBitPosTest → Gets the position of the rightmost set bit =\u003e O(n) where n is the number of bits in number(actually constant as function only works with ints)\n\n### Character Manipulation\n1. toLowercase → Converts char to lowercase =\u003e O(1)\n\n2. toUppercase → Converts char to uppercase =\u003e O(1)\n\n3. toggleCharCase → Toggles char case =\u003e O(1)\n\n4. getAlphabeticPos → Gets the alphabetic position of given char =\u003e O(1)\n\n## Discussion\nAll the above functions are implemented using bitwise operators which allows us to certain operations as fast as our computer allows us. They are the most basic of operations and can be simplified to basic circuits on a hardware level.\nThe constexpr functions are also branchless allowing us to take advantage of CPU pipelining and we also don't have to rely on any branch predictions.\n\n### Examples\nThe advantage will be shown at the hand of an example. In this case we will look at the isOdd implementation.\n\n```c++\nconstexpr bool isOdd(const int\u0026 i) noexcept{\n    return i \u0026 1;\n}\n```\nWe are simply checking if the rightmost bit of the integer is a 1, which if set will indicate an odd number\nThis will compile to following x86 assembly(Intel syntax) with no optimization applied using clang(trunk):\n\n```asm\nisOddOptim(int const\u0026): # @isOddOptim(int const\u0026)\n    push rbp ; Push base stack pointer\n    mov rbp, rsp ; Move stack pointer to base pointer\n    mov qword ptr [rbp - 8], rdi ; Move first parameter onto the stack\n    mov rax, qword ptr [rbp - 8] ; Move value from stack to rax register\n    mov eax, dword ptr [rax] ; Move pointer in rax to eax(32-bit register)\n    and eax, 1 ; Perform and operation of eax and 1\n    cmp eax, 0 ; Compare eax with 0\n    setne al ; If lower byte is not 0 then set byte\n    and al, 1 ; And lower byte of eax with 1\n    movzx eax, al ; Move(zero extend) the lower byte into eax\n    pop rbp ; Restore stack\n    ret ; Return from function call\n```\n\nIf we remove the stack alignment operations for fulfilling the C++ ABI and handling the integer reference we are left with: \n\n```asm\nisOddOptim(int const\u0026): # @isOddOptim(int const\u0026)\n    and eax, 1 ; (eax has the value of the first parameter)\n    cmp eax, 0 ; Compare eax with 0\n    setne al ; If lower byte is not 0 then set byte\n    and al, 1 ; And lower byte of eax with 1\n    movzx eax, al ; Move(zero extend) the lower byte into eax\n```\nThe main algorithm on an assembly level consists of 5 instructions.\n\nNow looking at how a typical implementation of this would look without bitwise manipulation:\n\n```c++\nbool isOddBranch(const int\u0026 i) {\n    if(i % 2 != 0) {\n        return true;\n    } else {\n        return false;\n    }\n}\n\nbool isOddTernary(const int\u0026 i) {\n    return i % 2 != 0 ? true : false;\n}\n```\n\n```asm\nisOddBranch(int const\u0026): # @isOddBranch(int const\u0026)\n    push rbp\n    mov rbp, rsp\n    mov qword ptr [rbp - 16], rdi\n    mov rax, qword ptr [rbp - 16]\n    mov eax, dword ptr [rax]\n    mov ecx, 2\n    cdq\n    idiv ecx\n    cmp edx, 0\n    je .LBB1_2\n    mov byte ptr [rbp - 1], 1\n    jmp .LBB1_3\n    .LBB1_2:\n    mov byte ptr [rbp - 1], 0\n    .LBB1_3:\n    mov al, byte ptr [rbp - 1]\n    and al, 1\n    movzx eax, al\n    pop rbp\n    ret\n```\nThe instructions used are much simpler we have a few movs, idiv, jmps and something called cdq. This implementation might be able to leverage some\npipelining using branch prediction strategies if we're checking numbers that are odd due to the way we setup the if statement, but as soon as we run into an even number we flush the pipeline.\nThen we lose a lot of potential work that could have been done.\n\nNow looking at an implementation using a ternary expression:\n\n```asm\nisOddTernary(int const\u0026): # @isOddTernary(int const\u0026)\n    push rbp\n    mov rbp, rsp\n    mov qword ptr [rbp - 8], rdi\n    mov rax, qword ptr [rbp - 8]\n    mov eax, dword ptr [rax]\n    mov edx, eax\n    shr edx, 31\n    mov ecx, eax\n    add ecx, edx\n    and ecx, -2\n    sub eax, ecx\n    setne al\n    neg al\n    and al, 1\n    movzx eax, al\n    pop rbp\n    ret\n```\nThis looks alot beter, we don't have any visible branches because we got some help from the compiler here, but we have a lot of extra operations happening.\n\nSo we can see that the bitwise method is the best of the three. It is however important to know that compilers are very smart and if we apply some optimization flags all three of these implementations compile to exactly the same assembly. \n\n```c++\nisOddOptim(int const\u0026): # @isOddOptim(int const\u0026)\n    mov al, byte ptr [rdi]\n    and al, 1\n    ret\n\nisOddBranch(int const\u0026): # @isOddBranch(int const\u0026)\n    mov al, byte ptr [rdi]\n    and al, 1\n    ret\n\nisOddTernary(int const\u0026): # @isOddTernary(int const\u0026)\n    mov al, byte ptr [rdi]\n    and al, 1\n    ret\n```\n\n## Testing\nTo run the tests written in the Main.cpp, you will need the google test suite installed and available to the compiler that you are using.\n```bash\n$ make\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkylesmith19091%2Fbitmanip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkylesmith19091%2Fbitmanip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkylesmith19091%2Fbitmanip/lists"}