Binary operator < cannot be applied to Clong in Swift - swift

I am trying to implement the following code in swift. But my i variable refuse to talk to my MAXADDRS. It says binary operator < cannot be applied to Clong in Swift. If I use CInt the problem goes away, but then I get an error on the variable i when assiginin theAddr = ip_addrs[i]
InitAddresses();
GetIPAddresses();
GetHWAddresses();
var i = CLong()
var deviceIP = NSString()
for (i=0; i < MAXADDRS; ++i)
{
var localHost = 0x7F000001; // 127.0.0.1
var theAddr = CLong()
theAddr = ip_addrs[i]
if (theAddr == 0) {return}
if (theAddr == localHost){continue}
NSLog("Name: %s MAC: %s IP: %s\n", if_names[i], hw_addrs[i], ip_names[i]);
//decided what adapter you want details for
if (strncmp(if_names[i], "en", 2) == 0)
{
NSLog("Adapter en has a IP of %s", ip_names[i]);
}
}
// Do any additional setup after loading the view, typically from a nib.
}
The MAXADDRS it intends to compare relates to the following OBC header
Source files here
http://www.chrisandtennille.com/code/IPAddress.h
http://www.chrisandtennille.com/code/IPAddress.c
My bridging header
#include "IPAddress.h"
#include "IPAddress.c"

#define MAXADDRS 32
is imported to Swift as
public var MAXADDRS: Int32 { get }
On the other hand, CLong is an alias for Int ("The C 'long' type.")
Therefore you need to convert all values to a common type. Since
array subscripting requires an Int index, converting MAXADDRS
to Int might be the easiest solution:
var i = 0 // Int
for (i=0; i < Int(MAXADDRS); ++i) {
}
or more simply:
for i in 0 ..< Int(MAXADDRS) {
}

Related

Getting information about process in Swift

I am trying to get some data about a process in Swift.
I am using this code as a starting point:
pid_t pid = 10000;
rusage_info_current rusage;
if (proc_pid_rusage(pid, RUSAGE_INFO_CURRENT, (void **)&rusage) == 0)
{
cout << rusage.ri_diskio_bytesread << endl;
cout << rusage.ri_diskio_byteswritten << endl;
}
taken from Per Process disk read/write statistics in Mac OS X.
However, I have trouble converting the code above to Swift:
var usage = rusage_info_v3()
if proc_pid_rusage(100, RUSAGE_INFO_CURRENT, &usage) == 0
{
Swift.print("Success")
}
The function prod_pid_rusage expects a parameter of type rusage_info_t?, but I can not instantiate an instance of that type.
Is it possible to use the function in Swift?
Regards,
Sascha
As in C you have to take the address of a rusage_info_current
variable and cast it to the type expected by proc_pid_rusage().
In Swift this is done using withUnsafeMutablePointer()
and withMemoryRebound():
let pid = getpid()
var usage = rusage_info_current()
let result = withUnsafeMutablePointer(to: &usage) {
$0.withMemoryRebound(to: rusage_info_t?.self, capacity: 1) {
proc_pid_rusage(pid, RUSAGE_INFO_CURRENT, $0)
}
}
if result == 0 {
print(usage.ri_diskio_bytesread)
// ...
}
You have to add
#include <libproc.h>
to the bridging header file to make it compile.

Swift Type 'string.index' has no subscript members

I'm currently converting C++ code to Swift and I've gotten stuck on one part. The parameter passed into the function is a string and the area where I'm stuck is when attempting to set a variable based on the second to last character of a string to check for a certain character.
The error shows up on this line:
line[i-1]
I've tried casting this value to an Int but this didn't work:
Int(line[i - 1])
I've also tried to see if the string's startIndex function which takes a Int would work but it didn't:
line.startIndex[i - 1]
Here is the full function:
func scanStringForSpecificCharacters(line: String){
var maxOpen: Int = 0;
var minOpen: Int = 0;
minOpen = 0;
maxOpen = 0;
var i = 0
while i < line.characters.count {
for character in line.characters {
//var c: Character = line[i];
if character == "(" {
maxOpen += 1;
if i == 0 || line[i - 1] != ":" {
minOpen += 1;
}
}
else if character == ")"{
minOpen = max(0,minOpen-1);
if i == 0 || line[i-1] != ":"{
maxOpen -= 1;
}
if maxOpen < 0{
break;
}
}
}
if maxOpen >= 0 && minOpen == 0{
print("YES")
}else{
print("NO")
}
}
}
Strings in Swift aren't indexed collections and instead you can access one of four different views: characters, UTF8, UTF16, or unicodescalars.
This is because Swift supports unicode, where an individual characters may actually be composed of multiple unicode scalars.
Here's a post that really helped me wrap my head around this: https://oleb.net/blog/2016/08/swift-3-strings/
Anyway, to answer you question you'll need to create an index using index(after:), index(before:), or index(_, offsetBy:).
In your case you'd want to do something like this:
line.index(line.endIndex, offsetBy: -2) // second to last character
Also, you'll probably find it easier to iterate directly using a String.Index type rather than Int:
let line = "hello"
var i = line.startIndex
while i < line.endIndex {
print(line[i])
i = line.index(after: i)
}
// prints ->
// h
// e
// l
// l
// o
Working with Strings in Swift was changed several times during it's evolution and it doesn't look like C++ at all. You cannot subscript string to obtain individual characters, you should use index class for that. I recommend you read this article:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html
As already pointed out in the other answers, the compiler error
is caused by the problem that you cannot index a Swift String with
integers.
Another problem in your code is that you have a nested loop which is
probably not intended.
Actually I would try to avoid string indexing at all and only
enumerate the characters, if possible. In your case, you can
easily keep track of the preceding character in a separate variable:
var lastChar: Character = " " // Anything except ":"
for char in line.characters {
if char == "(" {
maxOpen += 1;
if lastChar != ":" {
minOpen += 1;
}
}
// ...
lastChar = char
}
Or, since you only need to know if the preceding character is
a colon:
var lastIsColon = false
for char in string.characters {
if char == "(" {
maxOpen += 1;
if !lastIsColon {
minOpen += 1;
}
}
// ...
lastIsColon = char == ":"
}
Another possible approach is to iterate over the string and a shifted
view of the string in parallel:
for (lastChar, char) in zip([" ".characters, line.characters].joined(), line.characters) {
// ...
}
As others have already explained, trying to index into Swift strings is a pain.
As a minimal change to your code, I would recommend that you just create an array of the characters in your line up front:
let linechars = Array(line.characters)
And then anywhere you need to index into the line, use linechars:
This:
if i == 0 || line[i-1] != ":" {
becomes:
if i == 0 || linechars[i-1] != ":" {

Fix warning "C-style for Statement is deprecated" in Swift 3

I have update Xcode to 7.3 and now I have a warning to the function that I use to create random strings.
I have tried to change the for statement with for (i in 0 ..< len){...} however, the warning became an error.
How can I remove the warning?
static func randomStringWithLength (len : Int) -> NSString {
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let randomString : NSMutableString = NSMutableString(capacity: len)
for (var i=0; i < len; i += 1){ // warning
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
return randomString
}
C-style for loop has been deprecated in Swift 3. You can continue using it for a while, but they will certainly disappear in the future.
You can rewrite your loop to Swift's style:
for i in 0..<len {
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
Since you don't use i at all in the loop's body, you can replace it with:
for _ in 0..<len {
// do stuffs
}
This BLOG saved my life.
INCREMENTING
for i in 0 ..< len {
}
DECREMENTING
for i in (0 ..< len).reverse() {
}
NON-SEQUENTIAL INDEXING
Using where
for i in (0 ..< len) where i % 2 == 0 {
}
Using striding to or through
for i in 0.stride(to: len, by: 2) {
}
in Swift 3 it's been an error
some general replacement was posted and just add
For Swift 3 and need to change the "index"
for var index in stride(from: 0, to: 10, by: 1){}
I've had success with the following. You can use the for loop as follows - note that the for loop is inclusive so you may need to check that len is actually greater than 0:
for i in 0...len - 1 {
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
Or you can use this:
for i in 0 ..< len {
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
BTW it appears XCode 7.x does help you to get there but it's a two step process. First you have to change your increment operator from (say) i++ to i += 1 and then XCode warning helps you modify the loop.

Variadic opIndex Override

Following my previous question, I'm now having trouble overriding opIndex with variadic parameters. I've tried multiple methods (even hack-ish ones) but to no avail.
The code I'm using to generate the identifier string
static string array_decl(D...)(string identifier, D dimensions)
{
static if(dimensions.length == 0)
{
return identifier;
}
else
{
return array_decl(identifier ~ "[" ~ to!(string)(dimensions[0]) ~ "]", dimensions[1..$]);
}
}
What my opIndex override looks like:
T opIndex(D...)(D indices)
{
mixin("return " ~ array_decl("Data", indices) ~ ";");
}
Fails with:
./inheritance.d(81): Error: tuple D is used as a type
./inheritance.d(89): Error: template instance inheritance.array_ident!(int, int, int).array_ident.array_ident!(_param_2, _param_3) error instantiating
./inheritance.d(112): instantiated from here: array_ident!(int, int, int)
./inheritance.d(174): instantiated from here: opIndex!(int, int, int)
./inheritance.d(112): Error: CTFE failed because of previous errors in array_ident
./inheritance.d(112): Error: argument to mixin must be a string, not ("return " ~ array_ident("Data", _param_0, _param_1, _param_2) ~ ";") of type string
The question is how (or is it possible) to implement the opIndex operator for this situation.
I think mixins are the way to go since I only have to generate a string with the format of:
type[index0][index1]...[indexN] Data
for the opIndex overload.
Apparently this is not possible as the tuple passed to opIndex is inaccessible at compile-time. A few solutions I came up with (by Adam D. Ruppe's suggestions):
1. Hard-coding Array Access
Using compile-time conditions to index the array, a bit ugly and the amount of dimensions that can be accessed depends on the amount of conditions implemented.
T opIndex(D...)(D indices)
{
static if(indices.length == 1)
{
return Data[indices[0]];
}
static if(indices.length == 2)
{
return Data[indices[0]][indices[1]];
}
static if(indices.length == 3)
{
return Data[indices[0]][indices[1]][indices[2]];
}
static if(indices.length == 4)
{
return Data[indices[0]][indices[1]][indices[2]][indices[3]];
}
}
2. Pointer(s)
The only other method was to cast the array to a pointer then use offsets. The offset is computed and is then used to index the pointer.
To be able to access the template parameters at run-time:
struct Vector_MultiDim(T, D...)
{
enum dimensions = [D];
static const size_t DimCount = D.length;
... Other members here
}
Function to compute offset (the size of each dimension must be known at run-time):
size_t GetIndex(size_t[] indices)
{
size_t index;
for(size_t i = 0; i < DimCount; i++)
{
size_t factor = 1;
for(size_t j = i + 1; j < DimCount; j++)
{
factor *= dimensions[j];
}
index += indices[i] * factor;
}
return index;
}
opIndex Override:
T opIndex(D...)(D indices)
{
T* arr = cast(T*)Data;
return arr[GetIndex([indices])];
}

How to convert multiple-character numeric format into a readable string in Swift?

I'm trying to convert AudioStreamBasicDescription's mFormatID property, which I get with AudioFileGetGlobalInfo, to a readable string.
In Objective-C it looks like this:
for (int i = 0; i < asbdCount; i++) {
UInt32 format4cc = CFSwapInt32HostToBig(asbds[i].mFormatID);
NSLog(#"mFormatID: %4.4s", (char*)&format4cc);
}
This code is a piece of CAStreamFormatTester from the Learning Core Audio book. asbds is a pointer to AudioStreamBasicDescriptions. How to convert this into Swift?
If asbds is of type UnsafePointer<AudioStreamBasicDescription> or of type [AudioStreamBasicDescription], then I believe this should work:
for i in 0 ..< asbdCount {
var format4cc = CFSwapInt32HostToBig(asbds[i].mFormatID)
withUnsafePointer(&format4cc) { cptr in
println(String(format: "mFormatID: %4.4s", cptr))
}
}