You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
swift-ci opened this issue
Apr 8, 2017
· 4 comments
Labels
bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler in itselffeatureA feature request or implementation
SR-1956withUnsafePointer shouldn't take its argument as inout
Issue Description:
Summary: When bridging to a struct imported from C, getting the address of an
object means the method needs to be mutable, which it should not be.
//------------------------------------------------------------------------------
// Bitset: A set of points on a Go board as a C struct.
const int NumWords = 6;
struct Bitset {
uint64_t bits[NumWords];
};
//------------------------------------------------------------------------------
// PointSet: A set of points on a Go board as a Swift struct. Would like to use
// a Swift array, but that incurs a heap allocation we can't afford.
// BUG: This method should not be 'mutating', but needs to be because can't
// pass the address of bits to UnsafeRawPointer without using &, which
// tells the compiler that 'bits' get mutated. This 'mutating' then
// causes ripple effects throughout the client code.
mutating func contains(_ p: Int) -> Bool {
return testBitRaw(&bits, bit: p)
}
}
//------------------------------------------------------------------------------
// bit functions
typealias Word = UInt64
let BitsPerWord = 64
let Log2of64 = 6
let NumWords = 6
Thanks for the tip about assigning to a local variable. In this case, it looks like the compiler can eliminate the copy, but for larger arrays, that's not the case. See the attached Swift-Mutable-Speed project: accessing through the function that copies to a local variable is many times slower.
The following comment in the Pointer module indicates that this works as expected when passing an array; it should also work when passing something that's not an array, as the idea is to interpret the given memory as an array.
/// An immutable pointer to the elements of an array is implicitly created when
/// you pass the array as an argument. This example uses implicit bridging to
/// pass a pointer to the elements of `numbers` when calling
/// `printInt(atAddress: )`.
///
/// let numbers = [5, 10, 15, 20]
/// printInt(atAddress: numbers)
bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler in itselffeatureA feature request or implementation
Attachment: Download
Environment
Xcode 8.3 (8E162), macOS 10.12.4 (16E195)
Additional Detail from JIRA
md5: 713abe4534ab19d75f4e6cbdf923fbeb
relates to:
withUnsafePointer
shouldn't take its argument asinout
Issue Description:
Summary: When bridging to a struct imported from C, getting the address of an
object means the method needs to be mutable, which it should not be.
//------------------------------------------------------------------------------
// Bitset: A set of points on a Go board as a C struct.
const int NumWords = 6;
struct Bitset {
uint64_t bits[NumWords];
};
//------------------------------------------------------------------------------
// PointSet: A set of points on a Go board as a Swift struct. Would like to use
// a Swift array, but that incurs a heap allocation we can't afford.
struct PointSet {
var bits = Bitset()
mutating func include(_ p: Int) {
setBitRaw(&bits, bit: p)
}
// BUG: This method should not be 'mutating', but needs to be because can't
// pass the address of bits to UnsafeRawPointer without using &, which
// tells the compiler that 'bits' get mutated. This 'mutating' then
// causes ripple effects throughout the client code.
mutating func contains(_ p: Int) -> Bool {
return testBitRaw(&bits, bit: p)
}
}
//------------------------------------------------------------------------------
// bit functions
typealias Word = UInt64
let BitsPerWord = 64
let Log2of64 = 6
let NumWords = 6
func wordWithBit(_ bit: Int) -> Int {
return Int(bit >> Log2of64)
}
func bitInWord(_ bit: Int) -> Word {
return Word(bit) & Word(BitsPerWord-1)
}
func setBitRaw(_ pointer: UnsafeMutableRawPointer, bit: Int) {
let a = pointer.bindMemory(to: Word.self, capacity: NumWords)
a[wordWithBit(bit)] |= (1 << bitInWord(bit))
}
func testBitRaw(_ pointer: UnsafeRawPointer, bit: Int) -> Bool {
let a = pointer.bindMemory(to: Word.self, capacity: NumWords)
return (a[wordWithBit(bit)] & (1 << bitInWord(bit))) != 0
}
See the attached sample project. Would love to find out that there's a less ugly way to do this (without losing performance).
The text was updated successfully, but these errors were encountered: