Skip to content

Commit 0e2d31c

Browse files
authored
Merge pull request #204 from CodaFi/an-ownership-model
Remove dependence on self in ArrowOf and IsoOf
2 parents 287dd1a + 44642d8 commit 0e2d31c

File tree

3 files changed

+113
-18
lines changed

3 files changed

+113
-18
lines changed

Sources/Modifiers.swift

+22-18
Original file line numberDiff line numberDiff line change
@@ -516,14 +516,15 @@ fileprivate final class ArrowOfImpl<T : Hashable & CoArbitrary, U : Arbitrary> :
516516
}
517517

518518
convenience init(_ arr : @escaping (T) -> U) {
519-
self.init(Dictionary(), { (_ : T) -> U in return undefined() })
519+
var table = [T:U]()
520+
self.init(table, { (_ : T) -> U in return undefined() })
520521

521-
self.arr = { [unowned self] x in
522-
if let v = self.table[x] {
522+
self.arr = { x in
523+
if let v = table[x] {
523524
return v
524525
}
525526
let y = arr(x)
526-
self.table[x] = y
527+
table[x] = y
527528
return y
528529
}
529530
}
@@ -564,24 +565,25 @@ fileprivate final class IsoOfImpl<T : Hashable & CoArbitrary & Arbitrary, U : Eq
564565
}
565566

566567
convenience init(_ embed : @escaping (T) -> U, _ project : @escaping (U) -> T) {
567-
self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() })
568+
var table = [T:U]()
569+
self.init(table, { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() })
568570

569-
self.embed = { [unowned self] t in
570-
if let v = self.table[t] {
571+
self.embed = { t in
572+
if let v = table[t] {
571573
return v
572574
}
573575
let y = embed(t)
574-
self.table[t] = y
576+
table[t] = y
575577
return y
576578
}
577579

578-
self.project = { [unowned self] u in
579-
let ts = self.table.filter { $1 == u }.map { $0.0 }
580-
if let k = ts.first, let _ = self.table[k] {
580+
self.project = { u in
581+
let ts = table.filter { $1 == u }.map { $0.0 }
582+
if let k = ts.first, let _ = table[k] {
581583
return k
582584
}
583585
let y = project(u)
584-
self.table[y] = u
586+
table[y] = u
585587
return y
586588
}
587589
}
@@ -601,17 +603,19 @@ fileprivate final class IsoOfImpl<T : Hashable & CoArbitrary & Arbitrary, U : Eq
601603
static func shrink(_ f : IsoOfImpl<T, U>) -> [IsoOfImpl<T, U>] {
602604
return f.table.flatMap { (x, y) in
603605
return Zip2Sequence(_sequence1: T.shrink(x), _sequence2: U.shrink(y)).map({ (y1 , y2) -> IsoOfImpl<T, U> in
604-
return IsoOfImpl<T, U>({ (z : T) -> U in
605-
if x == z {
606-
return y2
607-
}
608-
return f.embed(z)
606+
return IsoOfImpl<T, U>(
607+
{ (z : T) -> U in
608+
if x == z {
609+
return y2
610+
}
611+
return f.embed(z)
609612
}, { (z : U) -> T in
610613
if y == z {
611614
return y1
612615
}
613616
return f.project(z)
614-
})
617+
}
618+
)
615619
})
616620
}
617621
}

SwiftCheck.xcodeproj/project.pbxproj

+8
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@
9696
826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; };
9797
826D818C1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; };
9898
826D818D1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; };
99+
828B7C8A1DEF58CF0066A994 /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828B7C861DEF575C0066A994 /* FormatterSpec.swift */; };
100+
828B7C8B1DEF58D00066A994 /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828B7C861DEF575C0066A994 /* FormatterSpec.swift */; };
101+
828B7C8C1DEF58D10066A994 /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828B7C861DEF575C0066A994 /* FormatterSpec.swift */; };
99102
82BA08CF1D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; };
100103
82BA08D01D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; };
101104
82BA08D11D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; };
@@ -192,6 +195,7 @@
192195
826D81561C953D070022266C /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Witness.swift; path = Sources/Witness.swift; sourceTree = SOURCE_ROOT; };
193196
826D81571C953D070022266C /* WitnessedArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WitnessedArbitrary.swift; path = Sources/WitnessedArbitrary.swift; sourceTree = SOURCE_ROOT; };
194197
826D81C61C953D350022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/Info.plist; sourceTree = SOURCE_ROOT; };
198+
828B7C861DEF575C0066A994 /* FormatterSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FormatterSpec.swift; path = Tests/SwiftCheckTests/FormatterSpec.swift; sourceTree = SOURCE_ROOT; };
195199
82BA08CE1D6FFBD20068D32F /* Compose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Compose.swift; path = Sources/Compose.swift; sourceTree = SOURCE_ROOT; };
196200
844FCC8D198B320500EB242A /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; };
197201
844FCC98198B320500EB242A /* SwiftCheckTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCheckTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -317,6 +321,7 @@
317321
825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */,
318322
825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */,
319323
825C9AD31D8EE86E003313E1 /* FailureSpec.swift */,
324+
828B7C861DEF575C0066A994 /* FormatterSpec.swift */,
320325
825C9AD41D8EE86E003313E1 /* GenSpec.swift */,
321326
825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */,
322327
825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */,
@@ -649,6 +654,7 @@
649654
825C9AE31D8EE86E003313E1 /* ComplexSpec.swift in Sources */,
650655
825C9AE01D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */,
651656
825C9AF21D8EE86E003313E1 /* ModifierSpec.swift in Sources */,
657+
828B7C8C1DEF58D10066A994 /* FormatterSpec.swift in Sources */,
652658
825C9AF81D8EE86E003313E1 /* PropertySpec.swift in Sources */,
653659
825C9AFE1D8EE86E003313E1 /* ReplaySpec.swift in Sources */,
654660
);
@@ -694,6 +700,7 @@
694700
825C9AE11D8EE86E003313E1 /* ComplexSpec.swift in Sources */,
695701
825C9ADE1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */,
696702
825C9AF01D8EE86E003313E1 /* ModifierSpec.swift in Sources */,
703+
828B7C8A1DEF58CF0066A994 /* FormatterSpec.swift in Sources */,
697704
825C9AF61D8EE86E003313E1 /* PropertySpec.swift in Sources */,
698705
825C9AFC1D8EE86E003313E1 /* ReplaySpec.swift in Sources */,
699706
);
@@ -739,6 +746,7 @@
739746
825C9AE21D8EE86E003313E1 /* ComplexSpec.swift in Sources */,
740747
825C9ADF1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */,
741748
825C9AF11D8EE86E003313E1 /* ModifierSpec.swift in Sources */,
749+
828B7C8B1DEF58D00066A994 /* FormatterSpec.swift in Sources */,
742750
825C9AF71D8EE86E003313E1 /* PropertySpec.swift in Sources */,
743751
825C9AFD1D8EE86E003313E1 /* ReplaySpec.swift in Sources */,
744752
);
+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
//
2+
// FormatterSpec.swift
3+
// SwiftCheck
4+
//
5+
// Created by Robert Widmann on 11/30/16.
6+
// Copyright © 2016 Typelift. All rights reserved.
7+
//
8+
// Spec due to broomburgo (https://github.com/broomburgo) meant to test lifetime
9+
// issues in ArrowOf and IsoOf
10+
11+
import SwiftCheck
12+
import XCTest
13+
14+
struct Formatter<Value> {
15+
let lengthLimit : UInt
16+
let makeString : (Value) -> String
17+
let makeValue : (String) -> Value
18+
19+
init(lengthLimit : UInt, makeString : @escaping (Value) -> String, makeValue : @escaping (String) -> Value) {
20+
self.lengthLimit = lengthLimit
21+
self.makeString = makeString
22+
self.makeValue = makeValue
23+
}
24+
25+
func format(_ value : Value) -> String {
26+
let formatted = makeString(value)
27+
let maxIndex = formatted.index(formatted.startIndex, offsetBy: String.IndexDistance(lengthLimit))
28+
if maxIndex >= formatted.endIndex {
29+
return formatted
30+
} else {
31+
return formatted.substring(to: maxIndex)
32+
}
33+
}
34+
35+
func unFormat(_ string : String) -> Value {
36+
let value = makeValue(string)
37+
return value
38+
}
39+
}
40+
41+
struct ArbitraryFormatter<Value : Arbitrary & CoArbitrary & Hashable> : Arbitrary {
42+
private let formatter : Formatter<Value>
43+
init(_ formatter : Formatter<Value>) {
44+
self.formatter = formatter
45+
}
46+
47+
var get : Formatter<Value> {
48+
return formatter
49+
}
50+
51+
static var arbitrary : Gen<ArbitraryFormatter<Value>> {
52+
return Gen.one(of: [
53+
Gen<(UInt, ArrowOf<Value, String>, ArrowOf<String, Value>)>
54+
.zip(UInt.arbitrary, ArrowOf<Value,String>.arbitrary, ArrowOf<String,Value>.arbitrary)
55+
.map { Formatter<Value>(lengthLimit: $0, makeString: $1.getArrow, makeValue: $2.getArrow) }
56+
.map(ArbitraryFormatter.init),
57+
Gen<(UInt, IsoOf<Value, String>)>
58+
.zip(UInt.arbitrary, IsoOf<Value, String>.arbitrary)
59+
.map { Formatter<Value>(lengthLimit: $0, makeString: $1.getTo, makeValue: $1.getFrom) }
60+
.map(ArbitraryFormatter.init)
61+
])
62+
}
63+
}
64+
65+
class FormatterSpec : XCTestCase {
66+
func testAlwaysCorrectLength() {
67+
property(
68+
"Any formatted string is shorter or equal than the provided length"
69+
) <- forAll { (x: Int, af: ArbitraryFormatter<Int>) in
70+
let formatter = af.get
71+
let string = formatter.format(x)
72+
_ = formatter.unFormat(string)
73+
return string.distance(from: string.startIndex, to: string.endIndex) <= String.IndexDistance(formatter.lengthLimit)
74+
}
75+
}
76+
77+
78+
#if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS))
79+
static var allTests = testCase([
80+
("testAlwaysCorrectLength", testAlwaysCorrectLength),
81+
])
82+
#endif
83+
}

0 commit comments

Comments
 (0)