Swift: how add offset to memcpy(...) - ios

How to add offset for array for memcpy(...) invocation?
I have array of String :
var source = ["a","b","c","d"]
var dest = [String](count:n, repeatedValue: "")
memcpy(&dest, source, UInt(2 * sizeof(String))
This copy ["a","b"] to dest. I'ts obvious.
How can i copy ["b", "c"] ?

Do not use memcpy or other low-level "C" operators on objects. That will not work for many reasons.
Use the slice operator:
var source = ["a","b","c","d"]
var dest = Array(source[1...2])
println("dest: \(dest)")
output:
dest: [b, c]
Unicode is handled correctly:
var source = ["🇪🇸", "😂", "a","b","c","d"]
var dest = Array(source[1...2])
println("dest: \(dest)")
output:
dest: [😂, a]

I'm still new to Swift, and use of methods with "Unsafe" in the name still worries me, but I'm fairly sure this is a usable technique for calling memcpy() and specifying an offset for the destination and/or source address. But this only works for byte arrays, i.e., [UInt8]. Definitely not for strings, as explained by #zaph.
public class SystemMisc {
/// Wrapper for the memcpy() method that allows specification of an offset for the destination
/// and/or the source addresses.
///
/// This version for when destination is a normal Swift byte array.
///
/// - Parameters:
/// - destPointer: Address for destination byte array, typically Swift [UInt8].
/// - destOffset: Offset to be added to the destination address, may be zero.
/// - sourcePointer: Address for source byte array, typically Swift [UInt8].
/// - sourceOffset: Offset to be added to the source address, may be zero.
/// - byteLength: Number of bytes to be copied.
public static func memoryCopy(_ destPointer : UnsafeRawPointer, _ destOffset : Int,
_ sourcePointer : UnsafeRawPointer, _ sourceOffset : Int,
_ byteLength : Int) {
memoryCopy(UnsafeMutableRawPointer(mutating: destPointer), destOffset,
sourcePointer, sourceOffset, byteLength)
}
/// Wrapper for the memcpy() method that allows specification of an offset for the destination
/// and/or the source addresses.
///
/// This version for when destination address is already available as an UnsafeMutableRawPointer,
/// for example if caller has used UnsafeMutableRawPointer() to create it or is working with
/// unmanaged memory. The destPointer argument may also be a converted pointer, as done by the
/// above wrapper method.
///
/// - Parameters:
/// - destPointer: Address for destination byte array, see above notes.
/// - destOffset: Offset to be added to the destination address, may be zero.
/// - sourcePointer: Address for source byte array, typically Swift [UInt8].
/// - sourceOffset: Offset to be added to the source address, may be zero.
/// - byteLength: Number of bytes to be copied.
public static func memoryCopy(_ destPointer : UnsafeMutableRawPointer, _ destOffset : Int,
_ sourcePointer : UnsafeRawPointer, _ sourceOffset : Int,
_ byteLength : Int) {
memcpy(destPointer.advanced(by: destOffset),
sourcePointer.advanced(by: sourceOffset),
byteLength)
}
}
And here's some test code:
// Test the memoryCopy() method, using extra UnsafeMutableRawPointer conversion
let destArray1 : [UInt8] = [ 0, 1, 2, 3 ] // Note - doesn't need to be var
let sourceArray1 : [UInt8] = [ 42, 43, 44, 45 ]
SystemMisc.memoryCopy(destArray1, 1, sourceArray1, 1, 2)
assert(destArray1[0] == 0 && destArray1[1] == 43 && destArray1[2] == 44 && destArray1[3] == 3)
// Test the memoryCopy() method, providing UnsafeMutableRawPointer for destination
var destArray2 : [UInt8] = [ 0, 1, 2, 3 ]
let sourceArray2 : [UInt8] = [ 42, 43, 44, 45 ]
let destArray2Pointer = UnsafeMutableRawPointer(&destArray2)
SystemMisc.memoryCopy(destArray2Pointer, 1, sourceArray2, 1, 2)
assert(destArray2[0] == 0 && destArray2[1] == 43 && destArray2[2] == 44 && destArray2[3] == 3)

First of all, there's something none of the writers seem to have understood: an array of object (here String instances) do not store the content but a reference to this object. Therefore UTF-8, UTF-16, whatever has nothing to do with it. What the backing array actually contains is pointers (ie addresses == unsigned integers). Aside from that, unless an array in swift is an actual array in memory, you shouldn't use memcpy on it, even more so if it is backed by an NSArray!
Nonetheless, to answer the original question that seems to be working perfectly and makes me think that in this case the Swift Array is a contiguous zone of memory here is what you should do:
source and dest are pointers to contiguous memory zones: the first object being at the base address, the second #+sizeof(type), the nth element at #+(n-1)*sizeof(type).
All you have to do is specify the write offset for dest, in your particular case 0, and the offset in source, in your case 1.

Related

Swift - Difference between passing variable and passing variable address withUnsafePointer?

recently I was trying to see the address of my variable and I have this question.
var age: Int = 5
withUnsafePointer(to: age) {
print($0) // 0x00007ffee3362750
print($0.pointee) // 5
}
withUnsafePointer(to: &age) {
print($0) // 0x000000010d226330
print($0.pointee) // 5
}
why it shows different memory address and why it shows the same value for the pointee?
var strarr = [1, 2]
withUnsafePointer(to: strarr[0]) {
print("\($0)") // 0x00007ffee3362750
print("\($0.pointee)") // 1
}
withUnsafePointer(to: strarr[1]) {
print("\($0)") // 0x00007ffee3362750
print("\($0.pointee)") // 2
}
withUnsafePointer(to: &strarr[0]) {
print("\($0)") // 0x0000600002755760
print("\($0.pointee)") // 1
}
withUnsafePointer(to: &strarr[1]) {
print("\($0)") // 0x0000600002755768
print("\($0.pointee)") // 2
}
for the array, why it shows the same memory address for index 1 and 2, when I'm not passing the address of the variable and why it shows a different memory address for index 1 and 2 when I'm passing the memory address?
Appreciate your answer and looking forward to understand this
The differences you see come from the fact that you are using two different overloads of withUnsafePointer, I'll list them in the same order you used them:
func withUnsafePointer<T, Result>(to value: T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result
, and
func withUnsafePointer<T, Result>(to value: inout T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result
The difference between the two is the inout qualifier used for the value parameter.
Now, let's try to understand what happens behind the scenes.
First, 0x00007ffee3362750 looks like a stack pointer, while 0x000000010d226330 looks like a heap pointer. Stack addresses start at the top of the allocated memory for the program, and decrease with every function call (and increase when the function returns).
This indicates that the first overload of withUnsafePointer create a temporary writable variable from the one passed as the argument. This is needed as UnsafePointer needs an inout reference to work with, and a regular parameter is readonly.
This means that the implementation of the non-inout overload of withUnsafePointer looks something like this:
func withUnsafePointer<T, Result>(to value: T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result {
var value = value // shadow the argument, create a readwrite location
return try withUnsafePointer(&value, body)
}
Thus, the first call needs to allocate an intermediate memory location, and this is why you see two different addresses, it's because the addresses are not pointing to the same memory location. However, since both memory locations start with the same value, printing the pointee results in identical output.
Now, let's talk about the array example. The behaviour you see has the same cause: stack allocations. What happens is:
program starts executing, stack pointer has value P (random name)
non-inout withUnsafePointer is called, this is a function call, and stack is reserved for the function; stack pointer is P - N
withUnsafePointer creates the temporary writable variable, and executes
withUnsafePointer returns, and frees the stack memory, at this stack pointer gets back to P
second non-inout withUnsafePointer is called, the stack pointer is back to P - N, however since there were no other function calls between the two, the same stack address is reserved for the temporary writable variable, thus the UnsafePointer instance has the same address
Here, even if the UnsafePointer points to the same address, the values at that address are different, corresponding to values of arr[0] and arr[1].
As for the inout calls, the UnsafePointer point to the actual addresses of the items in the array buffer.
This is how you can get different values for the non-inout calls too:
withUnsafePointer(to: strarr[0]) {
print("\($0)")
print("\($0.pointee)")
}
// this adds a nested function call, which also decreases the stack pointer
// resulting in the temporary location not being on the same stack address
func test() {
withUnsafePointer(to: strarr[1]) {
print("\($0)")
print("\($0.pointee)")
}
}
test()

UnsafeMutablePointer to an Array element

var a = [1,2,3]
let ptr1 = UnsafeMutablePointer<Int>(&a[0]) //works fine
let index = 0
let ptr2 = UnsafeMutablePointer<Int>(&a[index]) //compiler throws error
error: cannot invoke initializer for type UnsafeMutablePointer<Int> with an argument list of type (inout Int)
Why the latter one doesn't compile? Is there anything I am missing here?
I wanted to do like a below snippet.
class Holder {
var numbers: [Int] = [1,2,3,4]
var modifier: Modifier
init(index: Int) {
self.modifier = Modifier(UnsafeMutablePointer(&self.numbers) + index)
}
}
class Modifer {
var ptr: UnsafeMutablePointer<Int>
init(_ ptr: UnsafeMutablePointer<Int>) {
self.ptr = ptr
}
func change(to: Int) {
self.ptr.pointee = to
// expected the change to be reflected in numbers array
// but as Rob Napier said it became invalid and throws EXC_BAD_ACCESS
}
}
How can I achieve the above expected result?
Note that neither of these is a valid way to create an UnsafeMutablePointer. Swift is free to deallocate a immediately after the last time it is referenced, so by the time you use these pointers, they may be invalid. The tool you want is a.withUnsafeMutableBufferPointer.
That said, the correct syntax here is:
let ptr2 = UnsafeMutablePointer(&a) + index
Looking at your updated code, there's no way for this to make sense on Array. I think you're assuming that Arrays are reference types. They're value types. There's no way to change a piece of numbers. Any change to it replaces the entire array with a completely different array. Swift has some clever copy-on-write tricks to make this efficient, and in practice it may not actually replace the entire array, but you should program as though it did. You should consider the following line:
array[1] = 2
to be equivalent to:
array = <a new array that is identical, but element 1 has been replaced by 2>
This means that pointers into Array are meaningless outside of very controlled situations (such as inside a withUnsafeMutableBufferPointer block).
What you want is something more like this:
class Holder {
var numbers: [Int] = [1,2,3,4]
private(set) var modifier: ((Int) -> ())! // ! is an artifact of capturing self in init
init(index: Int) {
self.modifier = { [weak self] in self?.numbers[index] = $0 }
}
}
let holder = Holder(index: 2)
holder.numbers // [1, 2, 3, 4]
holder.modifier(0)
holder.numbers // [1, 2, 0, 4]

does swift's string type conform to collection protocol?

In the swift programming language book, it states
You can use the startIndex and endIndex properties and the
index(before:), index(after:), and index(_:offsetBy:) methods on any
type that conforms to the Collection protocol. This includes String,
as shown here, as well as collection types such as Array, Dictionary,
and Set.
However, I have checked the apple documentation on swift's string api, which does not indicate that String type conform to Collection protocol
I must be missing something here, but can't seem to figure it out.
As of Swift 2, String does not conform to Collection, only its various "views"
like characters, utf8, utf16 or unicodeScalars.
(This might again change in the future, compare
String should be a Collection of Characters Again in
String Processing For Swift 4.)
It has startIndex and endIndex properties and index methods though, these
are forwarded to the characters view, as can be seen in
the source code
StringRangeReplaceableCollection.swift.gyb:
extension String {
/// The index type for subscripting a string.
public typealias Index = CharacterView.Index
// ...
/// The position of the first character in a nonempty string.
///
/// In an empty string, `startIndex` is equal to `endIndex`.
public var startIndex: Index { return characters.startIndex }
/// A string's "past the end" position---that is, the position one greater
/// than the last valid subscript argument.
///
/// In an empty string, `endIndex` is equal to `startIndex`.
public var endIndex: Index { return characters.endIndex }
/// Returns the position immediately after the given index.
///
/// - Parameter i: A valid index of the collection. `i` must be less than
/// `endIndex`.
/// - Returns: The index value immediately after `i`.
public func index(after i: Index) -> Index {
return characters.index(after: i)
}
// ...
}
Strings are collections again. This means you can reverse them, loop over them character-by-character, map() and flatMap() them, and more. For example:
let quote = "It is a truth universally acknowledged that new Swift versions bring new features."
let reversed = quote.reversed()
for letter in quote {
print(letter)
}
This change was introduced as part of a broad set of amendments called the String Manifesto.

Swift String from imported unsigned char 2D array

I am using a 3rd party C library in my iOS application, which I am in the process of converting from Objective-C to Swift. I hit an obstacle when attempting to read one of the structs returned by the C library in Swift.
The struct looks similar to this:
typedef unsigned int LibUint;
typedef unsigned char LibUint8;
typedef struct RequestConfiguration_ {
LibUint8 names[30][128];
LibUint numberNames;
LibUint currentName;
} RequestConfiguration;
Which is imported into Swift as a Tuple containing 30 Tuples of 128 LibUint8 values. After a long time of trial and error using nested withUnsafePointer calls, I eventually began searching for solutions to iterating a Tuple in Swift.
What I ended up using is the following functions:
/**
* Perform iterator on every children of the type using reflection
*/
func iterateChildren<T>(reflectable: T, #noescape iterator: (String?, Any) -> Void) {
let mirror = Mirror(reflecting: reflectable)
for i in mirror.children {
iterator(i.label, i.value)
}
}
/**
* Returns a String containing the characters within the Tuple
*/
func libUint8TupleToString<T>(tuple: T) -> String {
var result = [CChar]()
let mirror = Mirror(reflecting: tuple)
for child in mirror.children {
let char = CChar(child.value as! LibUint8)
result.append(char)
// Null reached, skip the rest.
if char == 0 {
break;
}
}
// Always null terminate; faster than checking if last is null.
result.append(CChar(0))
return String.fromCString(result) ?? ""
}
/**
* Returns an array of Strings by decoding characters within the Tuple
*/
func libUint8StringsInTuple<T>(tuple: T, length: Int = 0) -> [String] {
var idx = 0
var strings = [String]()
iterateChildren(tuple) { (label, value) in
guard length > 0 && idx < length else { return }
let str = libUint8TupleToString(value)
strings.append(str)
idx++
}
return strings
}
Usage
func handleConfiguration(config: RequestConfiguration) {
// Declaration types are added for clarity
let names: [String] = libUint8StringsInTuple(config.names, config.numberNames)
let currentName: String = names[config.currentName]
}
My solution uses reflection to iterate the first Tuple, and reflection to iterate the second, because I was getting incorrect strings when using withUnsafePointer for the nested Tuples, which I assume is due to signage. Surely there must be a way to read the C strings in the array, using an UnsafePointer alike withUsafePointer(&struct.cstring) { String.fromCString(UnsafePointer($0)) }.
To be clear, I'm looking for the fastest way to read these C strings in Swift, even if that involves using Reflection.
Here is a possible solution:
func handleConfiguration(var config: RequestConfiguration) {
let numStrings = Int(config.numberNames)
let lenStrings = sizeofValue(config.names.0)
let names = (0 ..< numStrings).map { idx in
withUnsafePointer(&config.names) {
String.fromCString(UnsafePointer<CChar>($0) + idx * lenStrings) ?? ""
}
}
let currentName = names[Int(config.currentName)]
print(names, currentName)
}
It uses the fact that
LibUint8 names[30][128];
are 30*128 contiguous bytes in memory. withUnsafePointer(&config.names)
calls the closure with $0 as a pointer to the start of that
memory location, and
UnsafePointer<CChar>($0) + idx * lenStrings
is a pointer to the start of the idx-th subarray. The above code requires
that each subarray contains a NUL-terminated UTF-8 string.
The solution suggested by Martin R looks good to me and, as far as I can see from my limited testing, does work. However, as Martin pointed out, it requires that the strings be NUL-terminated UTF-8. Here are two more possible approaches. These follow the principle of handling the complexity of C data structures in C instead of dealing with it in Swift. Which of these approaches you choose depends on what specifically you are doing with RequestConfiguration in your app. If you are not comfortable programming in C, then a pure Swift approach, like the one suggested by Martin, might be a better choice.
For the purposes of this discussion, we will assume that the 3rd party C library has the following function for retrieving RequestConfiguration:
const RequestConfiguration * getConfig();
Approach 1: Make the RequestConfiguration object available to your Swift code, but extract names from it using the following C helper function:
const unsigned char * getNameFromConfig(const RequestConfiguration * rc, unsigned int nameIdx)
{
return rc->names[nameIdx];
}
Both this function's signature and the RequestConfiguration type must be available to the Swift code via the bridging header. You can then do something like this in Swift:
var cfg : UnsafePointer<RequestConfiguration> = getConfig()
if let s = String.fromCString(UnsafePointer<CChar>(getNameFromConfig(cfg, cfg.memory.currentName)))
{
print(s)
}
This approach is nice if you need the RequestConfiguration object available to Swift in order to check the number of names in multiple places, for example.
Approach 2: You just need to be able to get the name at a given position. In this case the RequestConfiguration type does not even need to be visible to Swift. You can write a helper C function like this:
const unsigned char * getNameFromConfig1(unsigned int idx)
{
const RequestConfiguration * p = getConfig();
return p->names[idx];
}
and use it in Swift as follows:
if let s = String.fromCString(UnsafePointer<CChar>(getNameFromConfig1(2)))
{
print(s)
}
This will print the name at position 2 (counting from 0). Of course, with this approach you might also want to have C helpers that return the count of names as well as the current name index.
Again, with these 2 approaches it is assumed the strings are NUL-terminated UTF-8. There are other approaches possible, these are just examples.
Also please note that the above assumes that you access RequestConfiguration as read-only. If you also want to modify it and make the changes visible to the 3rd party library C code, then it's a different ballgame.

Type 'String.Index' does not conform protocol 'IntegerLiteralConvertible'

With Beta 3 all worked fine, now I get a strange error, and I have no clue how to fix it. Tried all the solutions for similiar problems.
Here is my code:
if !name.isEmpty {
var splitted: [String] = name.componentsSeparatedByString(" ")
for curPart in splitted {
if !curPart.isEmpty {
acronym += curPart.substringToIndex(1) //Error
}
}
if (acronym as NSString).length > 2 {
acronym = acronym.substringToIndex(2) //Error
}
}
Both marked lines gave me the same error:
Type 'String.Index' does not conform protocol 'IntegerLiteralConvertible'
Can someone help me? Or is Beta 4 bugged?
Thanks!
In beta 4, Swift's String.Index handling changed yet again -- you now can't supply an Int when a String.Index is expected. The way to handle it is by creating the String.Index you need using the advance method:
if !name.isEmpty {
var splitted: [String] = name.componentsSeparatedByString(" ")
for curPart in splitted {
if !curPart.isEmpty {
acronym += curPart.substringToIndex(advance(curPart.startIndex, 1))
}
}
if countElements(acronym) > 2 {
acronym = acronym.substringToIndex(advance(acronym.startIndex, 2))
}
}
This is all based on making sure Unicode strings are handled properly - since different Unicode characters can have different sizes, pure integer indexing would hide the fact that Strings aren't random access.
Swift's notion of string components and iteration has changed in Beta 4. From the guide, we see:
Every instance of Swift’s Character type represents a single extended grapheme cluster. An extended grapheme cluster is a sequence of one or more Unicode scalars that (when combined) produce a single human-readable character.
This has some interesting side effects:
let str1 = "abc"
let str2 = "\u{20DD}def"
countElements(str1) // 3
countElements(str2) // 4
countElements(str1+str2) // 6 ≠ 3+4 !!!
That's because the c and \u{20DD} combine to form c⃝. Also notice that we're using countElements. In order to figure out the length of the string, Swift actually has to iterate through the whole string and figure out where the actual grapheme divisions are, so it takes O(n) time.
We can also see the effect on different encodings:
Array((str1+str2).utf8) // [97, 98, 99, 226, 131, 157, 100, 101, 102]
Array((str1+str2).utf16) // [97, 98, 99, 8413, 100, 101, 102]
Another issue, as your error says, is that String's IndexType is no longer convertible from an integer literal: you can't perform random access on the string by specifying an offset. Instead, you can use startIndex and advance to move forward some distance in the string, for example str[str.startIndex] or str[advance(str.startIndex, distance)].
Or you can define your own helper functions in the meantime:
func at<C: Collection>(c: C, i: C.IndexType.DistanceType) -> C.GeneratorType.Element {
return c[advance(c.startIndex, i)]
}
func take<C: protocol<Collection, Sliceable>>(c: C, n: C.IndexType.DistanceType) -> C.SliceType {
return c[c.startIndex..<advance(c.startIndex, n)]
}
at(str1+str2, 3) // d
take(str1+str2, 2) // ab
Obviously there are some improvements that could (and probably will) be made in future updates. You may want to file a bug with your concerns. In the long run, supporting grapheme clusters correctly was probably a good decision, but it makes string access a little more painful in the meantime.
For Swift 2.0
Using the example above:
curPart.substringToIndex(curPart.startIndex.advancedBy(1))

Resources