Can I use memory after pointer deinitialization? - swift

Can I use memory after pointer deinitialization?
e.g.
let q = UnsafeMutablePointer<Float>.allocate(capacity: 1)
q.pointee = 123.125
let bq = UnsafeRawBufferPointer(start: q.deinitialize(count: 1), count: 4) // (*)
for i in bq.reversed() {
print(String(i, radix: 16), terminator: " ")
}
q.deallocate()
print()
It's my core solution of this task: https://pl.spoj.com/problems/PP0504D/
Problem in the task is simple: Write a function which show representation of machine bytes of Float value.
float2bytes(123.125) prints 42 f6 40 0
But that is not the crux of the problem.
I'm not deeply in pointers. My doubt is: May I use memory after deinitialization which is points by another pointer (this memory is NOT deallocated)? What does deinitialization really mean?
let p = UnsafeMutablePointer<Int>.allocate(capacity: 1)
p.initialize(to: 7)
print(p.pointee)
p.initialize(to: 9)
p.deinitialize(count: 1)
// something may crash the memory in this place?
print(p.pointee)
p.deallocate()
Anyone can show me the code that causes the crash after deinicialize(count:) ?

Pointers are not deinitialized. Memory is. When you call q.deinitialize(count: 1), you have deinitialized the memory pointed to by q. It is invalid to then read deinitialized memory. It'll almost certainly "work" because this is a trivial type (a float), but it's not valid.
Memory has more states than "allocated" and "deallocated." It also needs to be bound and initialized. When you call deinitialize, the memory is put back into the uninitialized state (but still bound), but it must be reinitialized before reading.
For the full details, see Safely manage pointers in Swift from WWDC 2020.
For the specific case you're describing, you don't need memory management. You can ask the system for the bytes of a value directly:
let value: Float = 123.125
withUnsafeBytes(of: value) { q in
for i in q.reversed() {
print(String(i, radix: 16), terminator: " ")
}
}
(I understand you may have some other problem you're solving. But this is how you'd do what you've described.)
To your second example, you probably would never see a crash from that (since Float is trivial). But its behavior is undefined. Once you invoke undefined behavior, you may be very surprised at the optimizations the compiler is allowed to apply. This could, for example, print nothing, or print some constant value. Or it could crash (probably not, but it could). Or it could work perfectly, but still be wrong.

While #RobNapier's answer is certainly correct, you can also access the “raw bits” of a Float using its bitPattern property:
let f: Float = 123.125
let bits = f.bitPattern
You can then chop up the bits into bytes:
let bytesLittleEndian = stride(from: 0, to: UInt32.bitWidth, by: 8)
.map { UInt8(truncatingIfNeeded: bits >> $0) }
let bytesBigEndian = stride(from: 0, to: UInt32.bitWidth, by: 8)
.reversed()
.map { UInt8(truncatingIfNeeded: bits >> $0) }

Thanks to Rob Napier for this explenation. When I didn't know the pointers yet, I solved the problem like this:
import Foundation
let k = Int(readLine()!)!
for _ in 1...k {
let n = String(Float(readLine()!
.trimmingCharacters(in: .whitespaces))!
.bitPattern, radix: 16)
let f = ((n + repeatElement("0", count: 8 - n.count))
.reduce("") {
"\($0)" + "\(($0.count + 1) % 3 == 0 ? "'" : "")" + "\($1)"
} as String)
.split(separator: "'")
.map {
$0 == "00" ? "0" : $0
}
.reduce("") {
"\($0)\($1) "
}
print(f)
}
But now I'm wondering how to write UI Test for the code
//file
import Foundation
let k = Float(readLine()!)!
print(k)

Related

What does the reduce(_:_:) function do in Swift? [duplicate]

This question already has answers here:
What is the reduce() function doing, in Swift
(4 answers)
Closed 9 months ago.
Here is a piece of code I don't understand. This code uses swift's reduce(::) function along with the closure which I am having trouble to understand. What are the values set in maxVerticalPipCount and maxHorizontalPipCount? Are they 5 and 2 respectively?
let pipsPerRowForRank = [[0], [1], [1,1], [1,1,1], [2,2], [2,1,2],
[2,2,2], [2,1,2,2], [2,2,2,2], [2,2,1,2,2],
[2,2,2,2,2]]
let maxVerticalPipCount = CGFloat(pipsPerRowForRank.reduce(0) { max($1.count, $0) })
let maxHorizontalPipCount = CGFloat(pipsPerRowForRank.reduce(0) { max($1.max() ?? 0, $0) })
By the way, if you’re wondering what precisely reduce does, you can always refer to the source code, where you can see the actual code as well as a nice narrative description in the comments.
But the root of your question is that this code is not entirely obvious. I might suggest that if you’re finding it hard to reason about the code snippet, you can replace the opaque shorthand argument names, $0 and $1, with meaningful names, e.g.:
let verticalMax = pipsPerRowForRank.reduce(0) { previousMax, nextArray in
max(nextArray.count, previousMax)
}
let horizontalMax = pipsPerRowForRank.reduce(0) { previousMax, nextArray in
max(nextArray.max() ?? 0, previousMax)
}
By using argument names that make the functional intent more clear, it often is easier to grok what the code is doing. IMHO, especially when there are multiple arguments, using explicit argument names can make it more clear.
That having been said, I’d probably not use reduce and instead do something like:
let verticalMax = pipsPerRowForRank
.lazy
.map { $0.count }
.max() ?? 0
To my eye, that makes the intent extremely clear, namely that we’re counting how many items are in each sub-array and returning the maximum count.
Likewise, for the horizontal one:
let horizontalMax = pipsPerRowForRank
.lazy
.flatMap { $0 }
.max() ?? 0
Again, I think that’s clear that we’re creating a flat array of the values, and then getting the maximum value.
And, in both cases, we’re using lazy to avoid building interim structures (in case our arrays were very large), but evaluating it as we go along. This improves memory characteristics of the routine and the resulting code is more efficient. Frankly, with an array of arrays this small, lazy isn’t needed, but I include it for your reference.
Bottom line, the goal with functional patterns is not to write code with the fewest keystrokes possible (as there are more concise renditions we could have written), but rather to write efficient code whose intent is as clear as possible with the least amount of cruft. But we should always be able to glance at the code and reason about it quickly. Sometimes if further optimization is needed, we’ll make a conscious decision to sacrifice readability for performance reasons, but that’s not needed here.
This is what the reduce functions do here
var maxVerticalPipCount:CGFloat = 0
for rark in pipsPerRowForRank {
if CGFloat(rark.count) > maxVerticalPipCount {
maxVerticalPipCount = CGFloat(rark.count)
}
}
var maxHorizontalPipCount:CGFloat = 0
for rark in pipsPerRowForRank {
if CGFloat(rark.max() ?? 0) > maxHorizontalPipCount {
maxHorizontalPipCount = CGFloat(rark.max() ?? 0)
}
}
You shouldn't use reduce(::) function for finding the max value. Use max(by:)
function like this
let maxVerticalPipCount = CGFloat(pipsPerRowForRank.max { $0.count < $1.count }?.count ?? 0)
let maxHorizontalPipCount = CGFloat(pipsPerRowForRank.max { ($0.max() ?? 0) < ($1.max() ?? 0) }?.max() ?? 0)
The reduce function loops over every item in a collection, and combines them into one value. Think of it as literally reducing multiple values to one value. [Source]
From Apple Docs
let numbers = [1, 2, 3, 4]
let numberSum = numbers.reduce(0, { x, y in
x + y
})
// numberSum == 10
In your code,
maxVerticalPipCount is iterating through the whole array and finding the max between count of 2nd element and 1st element of each iteration.
maxHorizontalPipCount is finding max of 2nd element's max value and first element.
Try to print each element inside reduce function for better understandings.
let maxVerticalPipCount = pipsPerRowForRank.reduce(0) {
print($0)
return max($1.count, $0)
}
Reduce adds together all the numbers in an array opens a closure and really do whatever you tell it to return.
let pipsPerRowForRank = [[1,1], [2,2,2]]
let maxVerticalPipCount = CGFloat(pipsPerRowForRank.reduce(0) {
max($1.count, $0)})
Here it starts at 0 at reduce(0) and loops through the full array. where it takes the highest value between it's previous value it's in process of calculating and the number of items in the subarray. In the example above the process will be:
maxVerticalPipCount = max(2, 0)
maxVerticalPipCount = max(3, 2)
maxVerticalPipCount = 3
As for the second one
let pipsPerRowForRank = [[1,2], [1,2,3], [1,2,3,4], []]
let maxHorizontalPipCount = CGFloat(pipsPerRowForRank.reduce(0) {
max($1.max() ?? 0, $0)})
Here we instead of checking count of array we check the max value of the nested array, unless it's empty, the it's 0. So here goes this one:
let maxHorizontalPipCount = max(2, 0)
let maxHorizontalPipCount = max(3, 2)
let maxHorizontalPipCount = max(4, 3)
let maxHorizontalPipCount = max(0, 4)
let maxHorizontalPipCount = 4
Example With Swift 5,
enum Errors: Error {
case someError
}
let numbers = [1,2,3,4,5]
let inititalValue = 0
let sum = numbers.reduce(Result.success(inititalValue)) { (result, value) -> Result<Int, Error> in
if let initialValue = try? result.get() {
return .success(value + initialValue)
} else {
return .failure(Errors.someError)
}
}
switch sum {
case .success(let totalSum):
print(totalSum)
case .failure(let error):
print(error)
}

Swift 4 Substring Crash

I'm a little confused about the best practices for Swift 4 string manipulation.
How do you handle the following:
let str = "test"
let start = str.index(str.startIndex, offsetBy: 7)
Thread 1: Fatal error: cannot increment beyond endIndex
Imagine that you do not know the length of the variable 'str' above. And since 'start' is not an optional value, what is the best practice to prevent that crash?
If you use the variation with limitedBy parameter, that will return an optional value:
if let start = str.index(str.startIndex, offsetBy: 7, limitedBy: str.endIndex) {
...
}
That will gracefully detect whether the offset moves the index past the endIndex. Obviously, handle this optional however best in your scenario (if let, guard let, nil coalescing operator, etc.).
Your code doesn't do any range checking:
let str = "test"
let start = str.index(str.startIndex, offsetBy: 7)
Write a function that tests the length of the string first. In fact, you could create an extension on String that lets you use integer subscripts, and returns a Character?:
extension String {
//Allow string[Int] subscripting. WARNING: Slow O(n) performance
subscript(index: Int) -> Character? {
guard index < self.count else { return nil }
return self[self.index(self.startIndex, offsetBy: index)]
}
}
This code:
var str = "test"
print("str[7] = \"\(str[7])\"")
Would display:
str[7] = "nil"
##EDIT:
Be aware, as Alexander pointed out in a comment below, that the subscript extension above has up to O(n) performance (it takes longer and longer as the index value goes up, up to the length of the string.)
If you need to loop through all the characters in a string code like this:
for i in str.count { doSomething(string: str[i]) }
would have O(n^2) (Or n-squared) performance, which is really, really bad. in that case, you should instead first convert the string to an array of characters:
let chars = Array(str.characters)
for i in chars.count { doSomething(string: chars[i]) }
or
for aChar in chars { //do something with aChar }
With that code you pay the O(n) time cost of converting the string to an array of characters once, and then you can do operations on the array of characters with maximum speed. The downside of that approach is that it would more than double the memory requirements.

Swift UnsafeMutablePointer: Must I call deinitialize before deallocate?

Given an instance of UnsafeMutablePointer, what's the point of calling deinitialize(count:) right before deallocate(capacity:)?
Can't you just call deallocate(capacity:)?
I saw this when reading the section "Using Typed Pointers" of the article Unsafe Swift: Using Pointers And Interacting With C on raywenderlich.com.
The article contains the code below, which you can add to a new playground in Xcode.
let count = 2
let stride = MemoryLayout<Int>.stride
let alignment = MemoryLayout<Int>.alignment
let byteCount = stride * count
do {
print("Typed pointers")
let pointer = UnsafeMutablePointer<Int>.allocate(capacity: count)
pointer.initialize(to: 0, count: count)
defer {
pointer.deinitialize(count: count)
pointer.deallocate(capacity: count)
}
pointer.pointee = 42
pointer.advanced(by: 1).pointee = 6
pointer.pointee
pointer.advanced(by: 1).pointee
let bufferPointer = UnsafeBufferPointer(start: pointer, count: count)
for (index, value) in bufferPointer.enumerated() {
print("value \(index): \(value)")
}
}
The article explains below the code, if you keep reading.
Update: as noted by user atrick in the comments below, deinitialization is only required for non-trivial types. That said, including deinitialization is a good way to future proof your code in case you change to something non-trivial. Also, it usually doesn’t cost anything since the compiler will optimize it out.

fatal error with a simple swift program

import UIKit
import Foundation
func randomnumber (low:Int,high:Int )->Int
{
let range = high - (low-1)
return (Int (arc4random()) % range ) + ( low - 1)
}
let answer = randomnumber(low: 0, high: 100)
var turn = 1
while (true)
{
print ("Guess #\(turn): enter a number between 0 and 100")
let userinput = readLine();
if let guess:Int = Int(userinput!)
{
if( guess<answer )
{
print("choose a higher number")
}
if ( guess>answer )
{
print ("choose a smaller number")
}
if( guess==answer)
{
print("wohoo you won")
break;
}
}
}
this code is about a simple game using swift , by having a random number and then putting an input and if this input is bigger than the random number we have to choose smaller number and the opposite if we choose a smaller number and its still not equal to the random number and if it's equal to the random number you win.
this error appears :
fatal error: unexpectedly found nil while unwrapping an Optional value
As Tristan Beaton pointed out, readLine() doesn't work on playground hence your userInput is always nil.
CREATE A COMMAND LINE TOOL APPLICATION
CHOSE SWIFT WHEN YOU SAVE
COPY AN PASTE YOUR CODE
RUN AND PLAY
Also be really careful when you force unwrapping. That's always a crash waiting to happen ;) You can read this tutorial
I have tested this in a Command Line Tool and it worked. Also don't force unwrap optionals since you can just check if they have data without crashing the app.
I have added continue statements within your other if statements. Although it isn't really needed in this case, it is good practice to have it so that any code after the continue doesn't get executed. It just saves a bit of computing power.
import Foundation
func randomnumber(low: Int, high: Int) - >Int {
let range = high - (low-1)
return (Int(arc4random()) % range) + (low - 1)
}
let answer = randomnumber(low: 0, high: 100)
var turn = 1
while (true) {
print("Guess #\(turn): enter a number between 0 and 100")
if let userinput = readLine() {
if let guess:Int = Int(userinput) {
// Putting this here will only increase the guess count if their input in a number.
turn += 1
if guess < answer {
print("choose a higher number")
continue
}
if guess > answer {
print ("choose a smaller number")
continue
}
if guess == answer {
print("wohoo you won")
break
}
}
}
}
This is the console output

access element of fixed length C array in swift

I'm trying to convert some C code to swift.
(Why? - to use CoreMIDI in OS-X in case you asked)
The C code is like this
void printPacketInfo(const MIDIPacket* packet) {
int i;
for (i=0; i<packet->length; i++) {
printf("%d ", packet->data[i]);
}
}
And MIDIPacket is defined like this
struct MIDIPacket
{
MIDITimeStamp timeStamp;
UInt16 length;
Byte data[256];
};
My Swift is like this
func printPacketInfo(packet: UnsafeMutablePointer<MIDIPacket>){
// print some things
print("length", packet.memory.length)
print("time", packet.memory.timeStamp)
print("data[0]", packet.memory.data.1)
for i in 0 ..< packet.memory.length {
print("data", i, packet.memory.data[i])
}
}
But this gives a compiler error
error: type '(UInt8, UInt8, .. cut .. UInt8, UInt8, UInt8)'
has no subscript members
So how can I dereference the I'th element of a fixed size array?
in your case you could try to use something like this ...
// this is tuple with 8 Int values, in your case with 256 Byte (UInt8 ??) values
var t = (1,2,3,4,5,6,7,8)
t.0
t.1
// ....
t.7
func arrayFromTuple<T,R>(tuple:T) -> [R] {
let reflection = Mirror(reflecting: tuple)
var arr : [R] = []
for i in reflection.children {
// better will be to throw an Error if i.value is not R
arr.append(i.value as! R)
}
return arr
}
let arr:[Int] = arrayFromTuple(t)
print(arr) // [1, 2, 3, 4, 5, 6, 7, 8]
...
let t2 = ("alfa","beta","gama")
let arr2:[String] = arrayFromTuple(t2)
arr2[1] // "beta"
This was suggested by https://gist.github.com/jckarter/ec630221890c39e3f8b9
func printPacketInfo(packet: UnsafeMutablePointer<MIDIPacket>){
// print some things
print("length", packet.memory.length)
print("time", packet.memory.timeStamp)
let len = Int(packet.memory.length)
withUnsafePointer(&packet.memory.data) { p in
let p = UnsafeMutablePointer<UInt8>(p)
for i:Int in 0 ..< len {
print(i, p[i])
}
}
}
This is horrible - I hope the compiler turns this nonsense into some good code
The error message is a hint: it shows that MIDIPacket.data is imported not as an array, but as a tuple. (Yes, that's how all fixed length arrays import in Swift.) You seem to have noticed this in the preceding line:
print("data[0]", packet.memory.data.1)
Tuples in Swift are very static, so there isn't a way to dynamically access a tuple element. Thus, in some sense the only "safe" or idiomatic way to print your packet (in the way that you're hinting at) would be 256 lines of code (or up to 256, since the packet's length field tells you when it's safe to stop):
print("data[1]", packet.memory.data.2)
print("data[2]", packet.memory.data.3)
print("data[3]", packet.memory.data.4)
/// ...
print("data[254]", packet.memory.data.255)
print("data[255]", packet.memory.data.256)
Clearly that's not a great solution. Using reflection, per user3441734's answer, is one (cumbersome) alternative. Unsafe memory access, per your own answer (via jckarter), is another (but as the name of the API says, it's "unsafe"). And, of course, you can always work with the packet through (Obj)C.
If you need to do something beyond printing the packet, you can extend the UnsafePointer-based solution to convert it to an array like so:
extension MIDIPacket {
var dataBytes: [UInt8] {
mutating get {
return withUnsafePointer(&data) { tuplePointer in
let elementPointer = UnsafePointer<UInt8>(tuplePointer)
return (0..<Int(length)).map { elementPointer[$0] }
}
}
}
}
Notice that this uses the packet's existing length property to expose an array that has only as many valid bytes as the packet claims to have (rather than filling up the rest of a 256-element array with zeroes). This does allocate memory, however, so it might not be good for the kinds of real-time run conditions you might be using CoreMIDI in.
Should this:
for i in 0 ..< packet.memory.length
Be this?
for i in 0 ..< packet.memory.data.length