2016-04-16 4 views
5

Wykonuję operacje bitowe w stylu Swift, które to kody są pierwotnie napisane w Objective-C/C. Używam UnsafeMutablePointer do określenia początkowego indeksu adresu pamięci i użycia UnsafeMutableBufferPointer do uzyskiwania dostępu do elementu w zasięgu.Testowanie nie powiodło się po konwersji kodów z Objective-C na Swift

Można uzyskać dostęp do oryginalnego pliku Objective-C 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)") 
    } 
} 

Może ktoś poprowadzi mnie dlaczego drugi testcase nie ale wersja objective-c Pass?

Edytuj: Jak wspomniała @vacawama: Jeśli złamiesz testGetNextSet na 2 testy, obydwa przekaż.

Edit2: Kiedy uruchomić testy z xctool i testy, które wzywające BitArray „s nextSet() padnie podczas biegu.

+0

Jak '' .to32' .toInt' i wdrażane? – vacawama

+0

@vacawama Jest to rozszerzenie Int # public var to32: Int32 {return Int32 (truncatingBitPattern: self)} ' –

+0

Ta instrukcja jest kłopotliwa:' return n - Int ((UInt ((i << 1)) >> 31)). "Jeśli" i' jest ujemny, to się zawiesi. – vacawama

Odpowiedz

3

Objective-C wersja 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); 
} 

Przy tłumaczeniu numberOfTrailingZeros, zmieniłeś wartości zwracanej z Int32 do Int. To dobrze, ale ostatnia linia funkcji nie działa poprawnie podczas tłumaczenia.

W numberOfTrailingZeros wymienić to:

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

z tym:

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

oddanych do UInt32 usuwa wszystkie jednakże dolny 32 bitów. Od czasu przesyłania do UInt nie usuwałeś tych bitów. Aby to się stało, konieczne jest użycie bitPattern.

+0

Wygląda na to, że 'XCTAssertEqual nie powiodło się: (" Opcjonalne (34) ") nie jest równe (" Opcjonalne (32) "), które pokazuje 34 razy. –

+0

Działa to dla mnie, jeśli testuję na urządzeniu 64-bitowym (iPhone 5S i nowsze). Czy możesz zaktualizować swoje pytanie, aby pokazać cały twój kod (w tym implementacje '.toInt',' .to32' i reszty implementacji 'BitArray'.) Być może zrobiłem to inaczej – vacawama

+0

Właśnie przesłałem przykładowe repo [tutaj ] (https://github.com/wongzigii/SwiftBit), proszę sprawdź więcej informacji –

0

W końcu dowiedziałem się, że startIdx wystarczy zainicjować po przydzieleniu.

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

Albo użyć calloc z kodem tylko jedna linia:

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

Ponadto, używam lazy var odroczyć inicjalizacji UnsafeMutableBufferPointer aż nieruchomość jest użyty po raz pierwszy.

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

Z drugiej strony, nie zapomnij deinit:

deinit { 
    startIdx.destroy() 
    startIdx.dealloc(bitsLength * sizeof(Int32)) 
} 
Powiązane problemy