Skip to content

Commit 0eeb827

Browse files
author
Max Moiseev
committed
[integers] arithmetic and failable inits
1 parent 987773f commit 0eeb827

File tree

1 file changed

+65
-21
lines changed

1 file changed

+65
-21
lines changed

test/Prototypes/Integers.swift.gyb

Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -134,18 +134,24 @@ public func _log(_ message: @autoclosure () -> String) {
134134
//===--- Arithmetic -------------------------------------------------------===//
135135
//===----------------------------------------------------------------------===//
136136

137-
/// Arithmetic protocol declares methods backing binary arithmetic operators,
138-
/// such as `+`, `-` and `*`; and their mutating counterparts. These methods
139-
/// operate on arguments of the same type.
137+
/// Declares methods backing binary arithmetic operators, such as `+`, `-` and
138+
/// `*`; and their mutating counterparts.
140139
///
141-
/// Both mutating and non-mutating operations are declared in the protocol, but
142-
/// only the mutating ones are required. Should conforming type omit
143-
/// non-mutating implementations, they will be provided by a protocol extension.
144-
/// Implementation in that case will copy `self`, perform a mutating operation
145-
/// on it and return the resulting value.
140+
/// It provides a suitable basis for arithmetic on scalars such as integers and
141+
/// floating point numbers.
142+
///
143+
/// Both mutating and non-mutating operations are declared in the protocol,
144+
/// however only the mutating ones are required, as non-mutating are provided
145+
/// by the protocol extension.
146146
public protocol Arithmetic : Equatable, IntegerLiteralConvertible {
147-
/// Initialize to zero
148-
init()
147+
// Since `Arithmetic` extends `IntegerLiteralConvertible` it is logical for
148+
// it to be initializable from instances of `Integer` as well as from integer
149+
// literals. Failable exact initializers from other `Arithmetic` types should
150+
// be defined on child protocols.
151+
152+
/// Initializes to the value of `source` if it is representable exactly,
153+
/// returns `nil` otherwise.
154+
init?<T : Integer>(exactly source: T)
149155

150156
% for x in binaryArithmetic['Arithmetic']:
151157
// defaulted using an in-place counterpart, but can be used as an
@@ -157,6 +163,13 @@ public protocol Arithmetic : Equatable, IntegerLiteralConvertible {
157163
% end
158164
}
159165

166+
extension Arithmetic {
167+
@_transparent
168+
public init() {
169+
self = 0
170+
}
171+
}
172+
160173
% for Protocol in binaryArithmetic:
161174
extension ${Protocol} {
162175
% for x in binaryArithmetic[Protocol]:
@@ -176,13 +189,17 @@ extension ${Protocol} {
176189
/// The only method of this protocol has the default implementation in an
177190
/// extension, that uses a parameterless initializer and subtraction.
178191
public protocol SignedArithmetic : Arithmetic {
179-
func negate() -> Self
192+
func negated() -> Self
193+
mutating func negate()
180194
}
181195

182196
extension SignedArithmetic {
183-
public func negate() -> Self {
197+
public func negated() -> Self {
184198
return Self() - self
185199
}
200+
public mutating func negate() {
201+
self = negated()
202+
}
186203
}
187204

188205
% for Protocol in binaryArithmetic:
@@ -202,7 +219,7 @@ public func ${x.operator}= <T: ${Protocol}>(lhs: inout T, rhs: T) {
202219

203220
@_transparent
204221
public prefix func -<T: SignedArithmetic>(x: T) -> T {
205-
return x.negate()
222+
return x.negated()
206223
}
207224

208225
//===----------------------------------------------------------------------===//
@@ -234,7 +251,7 @@ public typealias UWord = UInt${word_bits}
234251
/// `Self` respectively
235252
public protocol Integer : ${IntegerBase} {
236253

237-
// FIXME(compiler limitation): Ideally, this constraint would just be :
254+
// FIXME(ABI): Ideally, this constraint would just be :
238255
// Integer. Until we get recursive protocol requirements, that isn't
239256
// possible.
240257

@@ -263,6 +280,10 @@ public protocol Integer : ${IntegerBase} {
263280
func isEqual(to rhs: Self) -> Bool
264281
func isLess(than rhs: Self) -> Bool
265282

283+
/// Creates an instance of `Self` that has the exact value of `source`,
284+
/// returns `nil` otherwise.
285+
init?<T : FloatingPoint>(exactly source: T)
286+
266287
/// Creates an instance of `Self` from the value of any other `Integer`,
267288
/// trapping if value of `source` cannot be represented by `Self`.
268289
init<T : Integer>(_ source: T)
@@ -311,6 +332,10 @@ public protocol Integer : ${IntegerBase} {
311332
}
312333

313334
extension Integer {
335+
public init?<T : FloatingPoint>(exactly source: T) {
336+
fatalError()
337+
}
338+
314339
public var countRepresentedWords: Word {
315340
return (self.bitWidth + ${word_bits} - 1) / ${word_bits}
316341
}
@@ -598,11 +623,6 @@ extension FixedWidthInteger {
598623
}
599624
% end
600625

601-
@_transparent
602-
public init() {
603-
self = 0
604-
}
605-
606626
@_transparent
607627
public init<T : Integer>(extendingOrTruncating source: T) {
608628
if Self.bitWidth <= ${word_bits} {
@@ -689,6 +709,17 @@ extension UnsignedInteger where Self : FixedWidthInteger {
689709
self.init(extendingOrTruncating: source)
690710
}
691711

712+
@_transparent
713+
public init?<T : Integer>(exactly source: T) {
714+
_assertCond(
715+
source >= 0, "negative value \(source) not representable by \(Self.self)")
716+
let requiredBits = source.signBitIndex + 1
717+
if requiredBits > Self.bitWidth {
718+
return nil
719+
}
720+
self.init(extendingOrTruncating: source)
721+
}
722+
692723
@_transparent
693724
public static var max: Self {
694725
return ~0
@@ -730,6 +761,15 @@ extension SignedInteger where Self : FixedWidthInteger {
730761
self.init(extendingOrTruncating: source)
731762
}
732763

764+
@_transparent
765+
public init?<T : Integer>(exactly source: T) {
766+
let requiredBits = source.signBitIndex + (source >= 0 ? 2 : 1)
767+
if requiredBits > Self.bitWidth {
768+
return nil
769+
}
770+
self.init(extendingOrTruncating: source)
771+
}
772+
733773
@_transparent
734774
public static var max: Self {
735775
return ~min
@@ -974,6 +1014,10 @@ public struct DoubleWidth<
9741014
fatalError()
9751015
}
9761016

1017+
public init?<T : Arithmetic>(exactly source: T) {
1018+
fatalError()
1019+
}
1020+
9771021
public init<T : Integer>(extendingOrTruncating source: T) {
9781022
fatalError()
9791023
}
@@ -1129,9 +1173,9 @@ public struct DoubleWidth<
11291173

11301174
//===--- Int128/UInt128 ---------------------------------------------------===//
11311175

1132-
% for Self in ['Int129', 'UInt129']:
1176+
% for Self in ['Int128_', 'UInt128_']:
11331177
% signed = 'U' not in Self
1134-
% Half = Self[:-3] + '64'
1178+
% Half = Self[:-4] + '64'
11351179
% Unsigned = 'Signed' if signed else 'Unsigned'
11361180
% u = 's' if signed else 'u'
11371181
% U = 'U' if signed else ''

0 commit comments

Comments
 (0)