Testcase failed after converting codes from Objective-C to Swift

╄→гoц情女王★ 提交于 2020-01-03 15:16:11

问题


I am doing some bitwise operations in Swift style, which these codes are originally written in Objective-C/C. I use UnsafeMutablePointer to state the beginning index of memory address and use UnsafeMutableBufferPointer for accessing the element within the scope.

You can access the original Objective-C file Here.

public init(size: Int) {
    self.size = size
    self.bitsLength = (size + 31) / 32
    self.startIdx = UnsafeMutablePointer<Int32>.alloc(bitsLength * sizeof(Int32))
    self.bits = UnsafeMutableBufferPointer(start: startIdx, count: bitsLength)
}

/**
 * @param from first bit to check
 * @return index of first bit that is set, starting from the given index, or size if none are set
 *  at or beyond its given index
 */
public func nextSet(from: Int) -> Int {
    if from >= size { return size }
    var bitsOffset = from / 32
    var currentBits: Int32 = bits[bitsOffset]
    currentBits &= ~((1 << (from & 0x1F)) - 1).to32
    while currentBits == 0 {
        if ++bitsOffset == bitsLength {
            return size
        }
        currentBits = bits[bitsOffset]
    }
    let result: Int = bitsOffset * 32 + numberOfTrailingZeros(currentBits).toInt
    return result > size ? size : result
}

func numberOfTrailingZeros(i: Int32) -> Int {
    var i = i
    guard i != 0 else { return 32 }
    var n = 31
    var y: Int32
    y = i << 16
    if y != 0 { n = n - 16; i = y }
    y = i << 8
    if y != 0 { n = n - 8; i = y }
    y = i << 4
    if y != 0 { n = n - 4; i = y }
    y = i << 2
    if y != 0 { n = n - 2; i = y }
    return n - Int((UInt((i << 1)) >> 31))
}

Testcase:

func testGetNextSet1() {
    // Passed
    var bits = BitArray(size: 32)
    for i in 0..<bits.size {
        XCTAssertEqual(32, bits.nextSet(i), "\(i)")
    }
    // Failed
    bits = BitArray(size: 34)
    for i in 0..<bits.size {
        XCTAssertEqual(34, bits.nextSet(i), "\(i)")
    }
}

Can someone guide me why the second testcase fail but the objective-c version pass ?

Edit: As @vacawama mentioned: If you break testGetNextSet into 2 tests, both pass.

Edit2: When I run tests with xctool, and tests which calling BitArray's nextSet() will crash while running.


回答1:


Objective-C version of numberOfTrailingZeros:

// Ported from OpenJDK Integer.numberOfTrailingZeros implementation
- (int32_t)numberOfTrailingZeros:(int32_t)i {
    int32_t y;
    if (i == 0) return 32;
    int32_t n = 31;
    y = i <<16; if (y != 0) { n = n -16; i = y; }
    y = i << 8; if (y != 0) { n = n - 8; i = y; }
    y = i << 4; if (y != 0) { n = n - 4; i = y; }
    y = i << 2; if (y != 0) { n = n - 2; i = y; }
    return n - (int32_t)((uint32_t)(i << 1) >> 31);
}

When translating numberOfTrailingZeros, you changed the return value from Int32 to Int. That is fine, but the last line of the function is not operating properly as you translated it.

In numberOfTrailingZeros, replace this:

return n - Int((UInt((i << 1)) >> 31))

With this:

return n - Int(UInt32(bitPattern: i << 1) >> 31)

The cast to UInt32 removes all but the lower 32 bits. Since you were casting to UInt, you weren't removing those bits. It is necessary to use bitPattern to make this happen.




回答2:


Finally I found out that startIdx just need to be initialized after allocation.

self.startIdx = UnsafeMutablePointer<Int32>.alloc(bitsLength * sizeof(Int32))
self.startIdx.initializeFrom(Array(count: bitsLength, repeatedValue: 0))

Or use calloc with just one line code:

self.startIdx = unsafeBitCast(calloc(bitsLength, sizeof(Int32)), UnsafeMutablePointer<Int32>.self)

Furthermore, I use lazy var to defer the Initialization of UnsafeMutableBufferPointer until the property is first used.

lazy var bits: UnsafeMutableBufferPointer<Int32> = {
   return UnsafeMutableBufferPointer<Int32>(start: self.startIdx, count: self.bitsLength)
}()

On the other hand, don't forget to deinit:

deinit {
    startIdx.destroy()
    startIdx.dealloc(bitsLength * sizeof(Int32))
}


来源:https://stackoverflow.com/questions/36662378/testcase-failed-after-converting-codes-from-objective-c-to-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!