DoxigAlpha

readPackedTwosComplement

Read the value of x from a packed memory buffer. Asserts that buffer is large enough to contain a value of bit-size bit_count at offset bit_offset.

This is equivalent to loading the value of an integer with bit_count bits as if it were a field in packed memory at the provided bit offset.

Function parameters

Parameters

#
x:*Mutable
buffer:[]const u8
bit_offset:usize
bit_count:usize

Used to indicate either limit of a 2s-complement integer.

Types

#
TwosCompIntLimit
Used to indicate either limit of a 2s-complement integer.
Mutable
A arbitrary-precision big integer, with a fixed set of mutable limbs.
Const
A arbitrary-precision big integer, with a fixed set of immutable limbs.
Managed
An arbitrary-precision big integer along with an allocator which manages the memory.

Returns the number of limbs needed to store `scalar`, which must be a

Functions

#
calcLimbLen
Returns the number of limbs needed to store `scalar`, which must be a
calcSetStringLimbCount
Assumes `string_len` doesn't account for minus signs if the number is negative.
calcNonZeroTwosCompLimbCount
Compute the number of limbs required to store a 2s-complement number of `bit_count` bits.
calcTwosCompLimbCount
Compute the number of limbs required to store a 2s-complement number of `bit_count` bits.
addMulLimbWithCarry
a + b * c + *carry, sets carry to the overflow bits
llcmp
Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively for limbs.

Source

Implementation

#
pub fn readPackedTwosComplement(
    x: *Mutable,
    buffer: []const u8,
    bit_offset: usize,
    bit_count: usize,
    endian: Endian,
    signedness: Signedness,
) void {
    if (bit_count == 0) {
        x.limbs[0] = 0;
        x.len = 1;
        x.positive = true;
        return;
    }

    // Check whether the input is negative
    var positive = true;
    if (signedness == .signed) {
        const total_bits = bit_offset + bit_count;
        const last_byte = switch (endian) {
            .little => ((total_bits + 7) / 8) - 1,
            .big => buffer.len - ((total_bits + 7) / 8),
        };

        const sign_bit = @as(u8, 1) << @as(u3, @intCast((total_bits - 1) % 8));
        positive = ((buffer[last_byte] & sign_bit) == 0);
    }

    // Copy all complete limbs
    var carry: u1 = 1;
    var limb_index: usize = 0;
    var bit_index: usize = 0;
    while (limb_index < bit_count / @bitSizeOf(Limb)) : (limb_index += 1) {
        // Read one Limb of bits
        var limb = mem.readPackedInt(Limb, buffer, bit_index + bit_offset, endian);
        bit_index += @bitSizeOf(Limb);

        // 2's complement (bitwise not, then add carry bit)
        if (!positive) {
            const ov = @addWithOverflow(~limb, carry);
            limb = ov[0];
            carry = ov[1];
        }
        x.limbs[limb_index] = limb;
    }

    // Copy the remaining bits
    if (bit_count != bit_index) {
        // Read all remaining bits
        var limb = switch (signedness) {
            .unsigned => mem.readVarPackedInt(Limb, buffer, bit_index + bit_offset, bit_count - bit_index, endian, .unsigned),
            .signed => b: {
                const SLimb = std.meta.Int(.signed, @bitSizeOf(Limb));
                const limb = mem.readVarPackedInt(SLimb, buffer, bit_index + bit_offset, bit_count - bit_index, endian, .signed);
                break :b @as(Limb, @bitCast(limb));
            },
        };

        // 2's complement (bitwise not, then add carry bit)
        if (!positive) {
            const ov = @addWithOverflow(~limb, carry);
            assert(ov[1] == 0);
            limb = ov[0];
        }
        x.limbs[limb_index] = limb;

        limb_index += 1;
    }

    x.positive = positive;
    x.len = limb_index;
    x.normalize(x.len);
}