Yes, that why I did it.
I have managed to get working code based on your input.
// Returns a tuple containing the high and low components to UInt addition
@inline(__always)
func addingFullWidth(_ x: UInt,_ y: UInt) -> (high: UInt, low: UInt) {
let sum = x.addingReportingOverflow(y)
return (sum.overflow ? 1 : 0, sum.partialValue)
}
extension RandomAccessCollection
where Self: MutableCollection,
Self: RangeReplaceableCollection,
Element == UInt,
Index == Int {
// in-place add rhs to self
mutating func Add<R: RandomAccessCollection> (_ rhs: R,_ uselastcarry:Bool = true)
where R.Element == UInt, R.Index == Int {
if self.count == 0 || (self.count == 1 && self.startIndex == 0) {
self = Self(Array(rhs))
return
}
if rhs.count == 0 || (rhs.count == 1 && rhs.startIndex == 0) {
self = Self(Array(self))
return
}
let (sc, rc) = (self.count, rhs.count)
let (si, ri) = (self.startIndex, rhs.startIndex)
let minc = Swift.min(sc, rc)
var rIndex = 0
var carry:UInt = 0
if sc >= rc {
while rIndex < minc {
(carry, self[rIndex + si]) = addingFullWidth(self[rIndex + si], rhs[rIndex + ri], carry)
rIndex += 1
}
if sc == rc {
if carry > 0 && uselastcarry { self.append(1)}
return
}
while carry > 0 && rIndex < rc {
(carry, self[rIndex + si]) = addingFullWidth(self[rIndex + si], carry)
rIndex += 1
}
if carry > 0 && uselastcarry { self.append(1)}
self = Self(Array(self))
return
} else {
var result = Array(rhs)
while rIndex < minc {
(carry, result[rIndex]) = addingFullWidth(result[rIndex], self[rIndex + si], carry)
rIndex += 1
}
while carry > 0 && rIndex < rc {
(carry, result[rIndex]) = addingFullWidth(result[rIndex], carry)
rIndex += 1
}
if carry > 0 && uselastcarry { result.append(1)}
self = Self(result)
return
}
}
}
var u1:[UInt] = [0]
var u2 = u1[1...]
u2.Add(u1)
print(u2)
For simplicity I chose to output self as an array and made the conversions necessary. I could have made the necessary conversions to make self's type remain unchanged but I would have to go this route I think:
if self is Array<UInt> {
// do what's necessary to make self an array
} else {
// do what's necessary to make self a slice
}
I am going to have to ponder the output some. To this point I was trying to solve having two different inputs without thinking the output (sigh, two more options). This just gets worse and worse. No wonder I see developers just avoiding dealing with slices and just always converting to array.
The only thing I have not been able to solve is how to get a pointer to self or rhs in the add function. For sure if self is a slice the compiler simply refuses to cooperate no matter what I tried. The only sure way I know is to pass the pointer as an argument as in previous posts. However that complicates self even more.
Anyhow, I hope this post helps others that find themselves trying to merge array and array.
Next up is to do some benchmarking.