Bitwise Calculator — Swift source
Perform AND, OR, XOR, NOT, shifts and rotates on 8/16/32/64-bit values with exact bigint math. Enter operands in binary, octal, decimal or hex and read the result in every base plus a live bit grid. Runs 100% in your browser.
This is the Swift implementation — the same logic the interactive tool runs, in a shareable, citable form.
// =============================================================================
// bitwise.swift — CosmoDev polyglot showcase port of the `bitwise` tool
// -----------------------------------------------------------------------------
// Language : Swift (5.9, standard library only)
// Source: ported from src/lib/bitwise.ts (the canonical, live TypeScript
// lib); mirrors src/tool-sources/bitwise/{python.py,rust.rs}
// License : display source — part of CosmoDev's polyglot tool pages
// (dev.cosmolabs.org). Shown verbatim alongside the JS/TS/Go/Rust/
// Python ports and the other language ports.
// -----------------------------------------------------------------------------
// Pure, deterministic bitwise calculator. Zero deps. Operands are interpreted
// as width-bit two's-complement values: any integer is normalized to the
// half-open range [0, 2^width) before an operation, and every result is masked
// back into that range — so the returned integer is always the unsigned
// bit-pattern of the width-bit result.
//
// Swift note: the TS source uses arbitrary-precision `bigint`. Swift 5.9 has
// no bignum or 128-bit integer, so values live in Int64/UInt64. This stays
// exact for every supported width (8/16/32/64): parsed magnitudes fold
// through two's-complement wrapping (invisible after width-bit
// normalization), and shift/rotate intermediates pre-mask the operand so
// nothing exceeds 64 bits — arithmetically identical to the reference's
// masked bigint shifts. Only literals beyond 2^64-1 diverge from the TS lib
// (thrown as a clean out-of-range), far outside any realistic input.
// =============================================================================
/// Numeric radix used for parsing and formatting.
enum Base {
case bin, oct, dec, hex
/// Positional radix (2/8/10/16).
var radix: UInt64 {
switch self {
case .bin: return 2
case .oct: return 8
case .dec: return 10
case .hex: return 16
}
}
/// Lowercase digit alphabet valid for this base.
var digits: String {
switch self {
case .bin: return "01"
case .oct: return "01234567"
case .dec: return "0123456789"
case .hex: return "0123456789abcdef"
}
}
/// Lowercase name, for error messages that match the TS lib.
var lower: String {
switch self {
case .bin: return "bin"
case .oct: return "oct"
case .dec: return "dec"
case .hex: return "hex"
}
}
}
/// Bit-width of the virtual register (8/16/32/64). `Int` is the natural Swift
/// choice; the library asserts the documented set.
typealias Width = Int
/// Supported bitwise operation. `.not` is unary on `a`; the rest are binary,
/// with `b` as the shift/rotate count for the shift/rotate ops.
enum Op {
case and, or, xor, not, shl, shr, rol, ror
}
/// Parse error: an empty value, an out-of-base digit, or an out-of-range literal.
struct ParseError: Error, CustomStringConvertible {
let message: String
var description: String { message }
}
enum Bitwise {
/// Parse a numeric string in `base` into a signed Int64. Strips 0x/0b/0o
/// prefixes and an optional leading sign. Throws `ParseError` on empty
/// input, any out-of-base digit, or a literal whose magnitude exceeds
/// 2^64-1. The raw signed value is returned (no width normalization);
/// callers fold it into a field via `normalize` / `apply`.
///
/// Magnitudes accumulate as UInt64 (checked with Swift's reporting-
/// overflow arithmetic) and negate by wrapping subtraction, so the full
/// unsigned range (e.g. hex 0xFFFFFFFFFFFFFFFF) round-trips exactly — a
/// wrap of 2^64 is invisible once the value is width-normalized.
static func parse(_ value: String, _ base: Base) throws -> Int64 {
// Trim ASCII whitespace from both ends (stdlib-only; Character
// .isWhitespace covers spaces, tabs, and newlines).
var chars = Substring(value)
while let f = chars.first, f.isWhitespace { chars.removeFirst() }
while let l = chars.last, l.isWhitespace { chars.removeLast() }
let trimmed = String(chars)
guard !trimmed.isEmpty, trimmed != "-" else {
throw ParseError(message: "Empty \(base.lower) value")
}
// Peel off an optional leading '-' so negative literals parse correctly.
let negative = trimmed.hasPrefix("-")
let body = negative ? String(trimmed.dropFirst()) : trimmed
// Strip each base prefix in turn (0x, then 0b, then 0o) from a lowered
// copy — mirrors the reference's chained leading-prefix removal.
// Matching against the lowercased copy keeps "0xFF" valid.
var digits = body.lowercased()
for prefix in ["0x", "0b", "0o"] where digits.hasPrefix(prefix) {
digits.removeFirst(prefix.count)
}
guard !digits.isEmpty else {
throw ParseError(message: "Empty \(base.lower) value")
}
// Horner's method over the digit alphabet, with a checked accumulate:
// an over-wide literal reports a clean error instead of trapping.
let allowed = base.digits
let radix = base.radix
var acc: UInt64 = 0
for ch in digits {
guard let idx = allowed.firstIndex(of: ch) else {
throw ParseError(message: "Invalid digit '\(ch)' for base \(base.lower)")
}
let digit = UInt64(allowed.distance(from: allowed.startIndex, to: idx))
let (mul, o1) = acc.multipliedReportingOverflow(by: radix)
let (add, o2) = mul.addingReportingOverflow(digit)
if o1 || o2 {
throw ParseError(message: "Value out of range for base \(base.lower)")
}
acc = add
}
// Wrapping negate is exact mod 2^64 (two's complement); bitPattern
// reinterprets the result as signed.
let pattern = negative ? 0 &- acc : acc
return Int64(bitPattern: pattern)
}
/// Mask for a `width`-bit field: 2^width - 1. Width 64 is spelled
/// directly because 1 << 64 would trap in UInt64.
static func mask(_ width: Width) -> UInt64 {
width == 64 ? .max : ((1 as UInt64) << width) - 1
}
/// Normalize any signed value to its unsigned width-bit two's-complement
/// value, i.e. into the half-open range [0, 2^width) — e.g. -1 at width 8
/// yields 255. The reference computes ((n % m) + m) % m with m = 2^width
/// on arbitrary-precision ints; casting to UInt64 already yields
/// n mod 2^64 (two's-complement truncation), and ANDing with the width-bit
/// mask reduces that to n mod 2^width — the same canonical value, without
/// materializing 2^64 itself.
static func normalize(_ n: Int64, _ width: Width) -> UInt64 {
UInt64(bitPattern: n) & mask(width)
}
/// Render `n` in `base`, zero-padded to at least `minDigits` digits.
/// Negatives carry a leading '-' and format their magnitude (via wrapping
/// negation on the bit pattern — exact even at Int64.min).
/// `minDigits` corresponds to the `width` parameter of the TS reference
/// (a width-bit binary value needs exactly `width` digits).
///
/// String(_:radix:) produces the lowercase digits of the TS
/// `bigint.toString(radix)` output and renders "0" for zero naturally.
static func format(_ n: Int64, _ base: Base, _ minDigits: Int) -> String {
if n < 0 {
// Wrapping negate yields the true magnitude as a bit pattern.
let mag = 0 &- UInt64(bitPattern: n)
return "-" + String(mag, radix: Int(base.radix)).padding(minDigits)
}
return String(UInt64(bitPattern: n), radix: Int(base.radix)).padding(minDigits)
}
/// Apply a width-bit operation. `a` is the (unary) operand for `.not`;
/// `b` is the second operand for binary ops and the shift/rotate count
/// for shl/shr/rol/ror. Both operands are normalized to width-bit two's
/// complement first; the result is masked to `width` bits.
///
/// For shl/shr we short-circuit when the shift count meets or exceeds the
/// width: every significant bit is shifted out, so the masked result is
/// zero (this also keeps every shift amount below 64 — Swift's `<<`
/// traps on shift counts >= 64). For shl/rol the shifted operand is
/// pre-masked with (mask >> count): the low `width` bits of the true
/// bigint shift are identical, but the intermediate can no longer exceed
/// 64 bits.
static func apply(_ op: Op, _ a: Int64, _ b: Int64, _ width: Width) -> UInt64 {
let m = mask(width)
let x = normalize(a, width)
let y = normalize(b, width)
switch op {
case .and:
return x & y
case .or:
return x | y
case .xor:
return x ^ y
case .not:
return ~x & m
case .shl:
if y >= numericCast(width) {
return 0
}
return (x & (m >> y)) << Int(y) // == (x << y) & m, without trapping
case .shr:
// x is normalized non-negative → logical (zero-filling) shift.
return y >= numericCast(width) ? 0 : x >> Int(y)
case .rol, .ror:
let shift = y % numericCast(width) // rotate amount wraps within width
if shift == 0 {
return x
}
// A right-rotate by `shift` is a left-rotate by (width - shift).
let s = op == .rol ? shift : UInt64(width) - shift
return ((x & (m >> s)) << Int(s)) | (x >> (Int(width) - Int(s)))
}
}
/// Fixed-width binary string of `width` bits (MSB first). Formats the
/// unsigned normalized pattern directly: a width-64 pattern can exceed
/// Int64.max and must not round-trip through the signed path.
static func toBits(_ n: Int64, _ width: Width) -> String {
String(normalize(n, width), radix: 2).padding(width)
}
/// Indices of set bits (LSB = index 0), normalized to `width`, in
/// ascending order. Stops at the highest set bit.
static func flags(_ n: Int64, _ width: Width) -> [Int] {
var v = normalize(n, width)
var out: [Int] = []
var i = 0
while v != 0 {
if v & 1 != 0 {
out.append(i)
}
v >>= 1
i += 1
}
return out
}
}
private extension String {
/// Zero-pad to at least `minDigits` places (String has no padStart).
func padding(_ minDigits: Int) -> String {
count < minDigits ? String(repeating: "0", count: minDigits - count) + self : self
}
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →