wgjcv
(William James)
1
I am developing my first project with Swift. Yesterday I attempted to add protocols ExpressibleByStringLiteral, ExpressibleByIntegerLiteral to a numerical class. I could get the changes to compile but could not get an object to instantiate with them and would get a fatal error when I ran the project. I could not even get the debugger to break in the two inits. Then I happen to discover the issue. If I instantiate an object of this class by any init method that are not one of these two protocols then the protocols will work fine from then on. In other words I can't use either of these two protocols first to instantiate an object of the class. Both protocol inits work perfectly when they are eventually called.
Is this a bug or am I missing something to enable the protocols? It looks like both of these protocols are depending on the fact that any instance of the class exists and has been instantiated.
Example:
This code segment works:
// all variables are APMInt
ll = APMInt(I64: 20) // instantiation that doesn't use protocol ExpressibleByStringLiteralor or ExpressibleByIntegerLiteral
ii = 3
jj = 4
print(ii * jj)
ii = "99"
jj = "88"
print (ii - jj)
kk = ii * jj
This code fails:
// all variables are APMInt
ii = 3
jj = 4
print(ii * jj)
ii = "99"
jj = "88"
print (ii - jj)
kk = ii * jj
Result:
Thread 1: EXC_BAD_ACCESS (code=2, address=0x7fff5965dea8) on line with print(ii * jj) because the objects ii and jj are garbage since they did not really go through their inits
Nevin
2
Please post the code for APMInt, including the initializers for the protocols.
Also, when you post code on this forum, please put triple back-ticks (```) on the lines before and after it, so it shows up formatted properly.
wgjcv
(William James)
3
Okay, the below is a stub of the class showing the inits and protocols. Not executable without a lot of the other code.
//
// APMInt_Class.swift
//
import Foundation
let apmint_base_bits: Int = 30
let apmint_base: Int = 1 << apmint_base_bits
let apmint_lo_mask: Int = apmint_base - 1
let apmint_hi_mask: Int = ~apmint_lo_mask
// APInt Constants
let ZERO: APMInt = APMInt(I64: 0)
let ONE: APMInt = APMInt(I64: 1)
let TWO: APMInt = APMInt(I64: 2)
let THREE: APMInt = APMInt(I64: 3)
let MINUSONE: APMInt = APMInt(I64: -1)
// used to capture math errors
var apmint_error_status: Int = 0
var apmint_error_messages: [String] = [ ""
, "Divide by Zero"
, "Mod by Zero"
, "Bad Bit Number"
, "Square Root of Negative"]
extension APMInt: CustomStringConvertible {
public var description: String {
return self.to_string()
}
}
class APMInt: ExpressibleByStringLiteral, ExpressibleByIntegerLiteral {
var sign: Int // -1 for negative, 0 or zero, 1 for positive
var words: [Int]
public required init(integerLiteral:Int) {
if integerLiteral == 0 {
self.sign = 0
self.words = [0]
return
}
var input: Int
if integerLiteral < 0 {
input = -integerLiteral
self.sign = -1
} else {
input = integerLiteral
self.sign = 1
}
if input <= apmint_lo_mask {
self.words = [input]
} else {
self.words = [input & apmint_lo_mask] + [input >> apmint_base_bits]
}
}
public required init(stringLiteral:String){
var result = APMInt(I64: 0)
var digit_found: Bool = false
var sign: Int = 1
for chars in stringLiteral.utf8 {
if chars > 47 && chars < 58 {
digit_found = true
result = (result * 10) + Int(chars - 48)
} else if chars == 45 { // minus sign
sign = -1
} else if chars == 43 { // plus sign
sign = 1
}
}
if digit_found == false || result.sign == 0 {
self.sign = 0
self.words = [0]
} else {
self.sign = sign
self.words = result.words
}
}
// init from Int
init (I64: Int) {
if I64 == 0 {
self.sign = 0
self.words = [0]
return
}
var input: Int
if I64 < 0 {
input = -I64
self.sign = -1
} else {
input = I64
self.sign = 1
}
if input <= apmint_lo_mask {
self.words = [input]
} else {
self.words = [input & apmint_lo_mask] + [input >> apmint_base_bits]
}
}
// init from string
required init (Text: String) {
var result = APMInt(I64: 0)
var digit_found: Bool = false
var sign: Int = 1
for chars in Text.utf8 {
if chars > 47 && chars < 58 {
digit_found = true
result = (result * 10) + Int(chars - 48)
} else if chars == 45 { // minus sign
sign = -1
} else if chars == 43 { // plus sign
sign = 1
}
}
if digit_found == false || result.sign == 0 {
self.sign = 0
self.words = [0]
} else {
self.sign = sign
self.words = result.words
}
}
func to_string() -> String {
if self.words.count == 0 || self.sign == 0 {return "0"}
var out_string: String = ""
var temp: APMInt = self.abs()
var digit: Int
while temp.sign != 0 {
digit = temp % 10
do { temp = temp / 10}
out_string = String(UnicodeScalar(UInt8(digit + 48))) + out_string
}
if self.sign == -1 {
out_string = "-" + out_string
}
return out_string
}
}