├── .gitignore
├── Package.swift
├── BinarySearch.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── WorkspaceSettings.xcsettings
├── xcshareddata
│ ├── xcbaselines
│ │ └── 007563E91BFA1AE1000ED5EB.xcbaseline
│ │ │ ├── 81AD72D7-C41B-4703-9EDF-E6AA3DE2BDC8.plist
│ │ │ └── Info.plist
│ └── xcschemes
│ │ └── BinarySearch.xcscheme
├── xcuserdata
│ └── giannif.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
├── .travis.yml
├── Sources
├── BinarySearch.h
├── Info.plist
└── BinarySearch.swift
├── BinarySearchTests
├── Info.plist
├── PerformanceTests.swift
├── BinarySearchRangeTests.swift
├── BinarySearchExtractTests.swift
├── BinarySearchLastTests.swift
├── BinarySearchInsertionIndexForTests.swift
├── BinarySearchTests.swift
├── BinarySearchFirstTests.swift
└── DocumentationTests.swift
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | **/xcuserdata/**
2 | .build
3 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | import PackageDescription
2 | let package = Package(
3 | name: "BinarySearch"
4 | )
5 |
--------------------------------------------------------------------------------
/BinarySearch.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/BinarySearch.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | osx_image: xcode8.2
2 | language: objective-c
3 |
4 | before_install:
5 | - brew update || brew update
6 | - brew outdated xctool || brew upgrade xctool
7 |
8 | script:
9 | - xcodebuild -scheme BinarySearch -destination 'id=22FA2149-1241-469C-BF6D-462D3837DB72'
10 | - xcodebuild test -scheme BinarySearch -destination 'id=22FA2149-1241-469C-BF6D-462D3837DB72'
11 |
--------------------------------------------------------------------------------
/Sources/BinarySearch.h:
--------------------------------------------------------------------------------
1 | //
2 | // BinarySearch.h
3 | // BinarySearch
4 | //
5 | // Created by Gianni Ferullo on 11/16/15.
6 | // Copyright © 2015 Gianni Ferullo. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for BinarySearch.
12 | FOUNDATION_EXPORT double BinarySearchVersionNumber;
13 |
14 | //! Project version string for BinarySearch.
15 | FOUNDATION_EXPORT const unsigned char BinarySearchVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/BinarySearch.xcodeproj/xcshareddata/xcbaselines/007563E91BFA1AE1000ED5EB.xcbaseline/81AD72D7-C41B-4703-9EDF-E6AA3DE2BDC8.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | classNames
6 |
7 | BinarySearchTests
8 |
9 | testExample()
10 |
11 | com.apple.XCTPerformanceMetric_WallClockTime
12 |
13 | baselineAverage
14 | 0.00067972
15 | baselineIntegrationDisplayName
16 | Local Baseline
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/BinarySearch.xcodeproj/xcuserdata/giannif.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | BinarySearch.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 007563DF1BFA1AE1000ED5EB
16 |
17 | primary
18 |
19 |
20 | 007563E91BFA1AE1000ED5EB
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/BinarySearchTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Sources/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.3
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/BinarySearchTests/PerformanceTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PerformanceTests.swift
3 | // BinarySearch
4 | //
5 | // Created by Gianni Ferullo on 11/22/15.
6 | // Copyright © 2015 Gianni Ferullo. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import BinarySearch
11 |
12 | class PerformanceTests: XCTestCase {
13 |
14 | func testFindingClosestValue() {
15 | let test = (0...100000).map {$0}
16 | var numberOfSteps = 0
17 | func counter(_ val1:Int, val2:Int) -> Bool {
18 | numberOfSteps += 1
19 | return val1 == val2
20 | }
21 | guard let result = test.binarySearch(2500, predicate:counter) else {
22 | XCTFail("Didn't find value.")
23 | return
24 | }
25 | XCTAssertEqual(test[result], 2500)
26 | XCTAssertEqual(numberOfSteps, 13)
27 | }
28 |
29 | func testLogN() {
30 | let test = (0...200000).map {$0}
31 | var numberOfSteps = 0
32 | func counter(_ val1:Int, val2:Int) -> Bool {
33 | numberOfSteps += 1
34 | return val1 == val2
35 | }
36 | guard let result = test.binarySearch(2500, predicate:counter) else {
37 | XCTFail("Didn't find value.")
38 | return
39 | }
40 | XCTAssertEqual(test[result], 2500)
41 | XCTAssertEqual(numberOfSteps, 14) // Doubling the input increases the number of steps by 1.
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/BinarySearch.xcodeproj/xcshareddata/xcbaselines/007563E91BFA1AE1000ED5EB.xcbaseline/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | runDestinationsByUUID
6 |
7 | 81AD72D7-C41B-4703-9EDF-E6AA3DE2BDC8
8 |
9 | localComputer
10 |
11 | busSpeedInMHz
12 | 100
13 | cpuCount
14 | 1
15 | cpuKind
16 | Intel Core i7
17 | cpuSpeedInMHz
18 | 1700
19 | logicalCPUCoresPerPackage
20 | 4
21 | modelCode
22 | MacBookAir6,2
23 | physicalCPUCoresPerPackage
24 | 2
25 | platformIdentifier
26 | com.apple.platform.macosx
27 |
28 | targetArchitecture
29 | x86_64
30 | targetDevice
31 |
32 | modelCode
33 | iPhone8,2
34 | platformIdentifier
35 | com.apple.platform.iphonesimulator
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/BinarySearchTests/BinarySearchRangeTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BinarySearchRangeTests.swift
3 | // BinarySearch
4 | //
5 | // Created by Gianni Ferullo on 11/20/15.
6 | // Copyright © 2015 Gianni Ferullo. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import BinarySearch
11 |
12 | class BinarySearchRangeTests: XCTestCase {
13 |
14 | func testFindingClosestValue() {
15 | var test = [0,3,9,10,11,12,13,18]
16 | for input in test {
17 | let result = test.binarySearchRange(input, predicate: {$0 >= $1})
18 | XCTAssertEqual(result?.lowerBound, test.index(of: input))
19 | XCTAssertEqual(result?.upperBound, test.count - 1)
20 | }
21 | for input in test {
22 | let result = test.binarySearchRange(input, predicate: {$0 <= $1})
23 | XCTAssertEqual(result?.lowerBound, 0)
24 | XCTAssertEqual(result?.upperBound, test.index(of: input))
25 | }
26 | let intermediateVals = [1,2,4,5,6,7,8,14,15,16,17]
27 | let expecteStart = [1,1,2,2,2,2,2,7,7,7,7]
28 | for (index, input) in intermediateVals.enumerated() {
29 | let result = test.binarySearchRange(input, predicate: {$0 >= $1})
30 | XCTAssertEqual(result?.lowerBound, expecteStart[index])
31 | XCTAssertEqual(result?.upperBound, test.count - 1)
32 | }
33 | let expectedEnd = [0,0,1,1,1,1,1,6,6,6,6]
34 | for (index, input) in intermediateVals.enumerated() {
35 | let result = test.binarySearchRange(input, predicate: {$0 <= $1})
36 | XCTAssertEqual(result?.lowerBound, 0)
37 | XCTAssertEqual(result?.upperBound, expectedEnd[index])
38 | }
39 |
40 | test = [0,3,9,10,11,12,13]
41 | for input in test {
42 | let result = test.binarySearchRange(input, predicate: {$0 >= $1})
43 | XCTAssertEqual(result?.lowerBound, test.index(of: input))
44 | XCTAssertEqual(result?.upperBound, test.count - 1)
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/BinarySearchTests/BinarySearchExtractTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BinarySearchExtractTest.swift
3 | // BinarySearch
4 | //
5 | // Created by Gianni Ferullo on 11/20/15.
6 | // Copyright © 2015 Gianni Ferullo. All rights reserved.
7 | //
8 |
9 |
10 |
11 | import XCTest
12 | @testable import BinarySearch
13 |
14 | class BinarySearchExtractTests: XCTestCase {
15 |
16 | func testExtract() {
17 | func convertToDict(_ val:Int) -> Dictionary {
18 | return ["testValue": val]
19 | }
20 | let dictArray = (0...10).map(convertToDict)
21 |
22 | var result = dictArray.binarySearch(6, extract:{$0["testValue"]!})
23 | XCTAssertEqual(result, 6)
24 | result = dictArray.binarySearchFirst(6, extract:{$0["testValue"]!})
25 | XCTAssertEqual(result, 6)
26 | result = dictArray.binarySearchLast(6, extract:{$0["testValue"]!})
27 | XCTAssertEqual(result, 6)
28 |
29 | // with predicate >=
30 | result = dictArray.binarySearchLast(6, extract:{$0["testValue"]!}, predicate:{$0>=$1})
31 | XCTAssertEqual(result, 10)
32 | result = dictArray.binarySearchFirst(6, extract:{$0["testValue"]!}, predicate:{$0>=$1})
33 | XCTAssertEqual(result, 6)
34 | var rangeResult = dictArray.binarySearchRange(6, extract:{$0["testValue"]!}, predicate:{$0>=$1})
35 | XCTAssertEqual(rangeResult?.lowerBound, 6)
36 | XCTAssertEqual(rangeResult?.upperBound, 10)
37 |
38 | // with predicate <=
39 | result = dictArray.binarySearchFirst(6, extract:{$0["testValue"]!}, predicate:{$0<=$1})
40 | XCTAssertEqual(result, 0)
41 | result = dictArray.binarySearchLast(6, extract:{$0["testValue"]!}, predicate:{$0<=$1})
42 | XCTAssertEqual(result, 6)
43 | rangeResult = dictArray.binarySearchRange(6, extract:{$0["testValue"]!}, predicate:{$0<=$1})
44 | XCTAssertEqual(rangeResult?.lowerBound, 0)
45 | XCTAssertEqual(rangeResult?.upperBound, 6)
46 |
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/BinarySearchTests/BinarySearchLastTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BinarySearchLast.swift
3 | // BinarySearch
4 | //
5 | // Created by Gianni Ferullo on 11/19/15.
6 | // Copyright © 2015 Gianni Ferullo. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import BinarySearch
11 |
12 | class BinarySearchLastTests: XCTestCase {
13 |
14 | let test = (0...100000).map {$0}
15 |
16 | func testFindingClosestValue() {
17 | let test = [0,3,9,10,11,12,13,18]
18 | var result = test.binarySearchLast(0, predicate: {$0 >= $1})
19 | XCTAssertEqual(test[result!], 18)
20 | result = test.binarySearchLast(5, predicate: {$0 <= $1})
21 | XCTAssertEqual(test[result!], 3)
22 | result = test.binarySearchLast(18, predicate: {$0 <= $1})
23 | XCTAssertEqual(test[result!], 18)
24 | result = test.binarySearchLast(17, predicate: {$0 <= $1})
25 | XCTAssertEqual(test[result!], 13)
26 | for input in 4...9 {
27 | result = test.binarySearchLast(input, predicate: {$0 >= $1})
28 | XCTAssertEqual(test[result!], 18)
29 | }
30 | for input in 4...8 {
31 | result = test.binarySearchLast(input, predicate: {$0 <= $1})
32 | XCTAssertEqual(test[result!], 3)
33 | }
34 | for input in 9...13 {
35 | result = test.binarySearchLast(input, predicate: {$0 <= $1})
36 | XCTAssertEqual(test[result!], input)
37 | }
38 | for input in 13...17 {
39 | result = test.binarySearchLast(input, predicate: {$0 <= $1})
40 | XCTAssertEqual(test[result!], 13)
41 | }
42 | result = test.binarySearchLast(18, predicate: {$0 <= $1})
43 | XCTAssertEqual(test[result!], 18)
44 |
45 | }
46 |
47 | func testPredicateGreaterOrEqualFailSafe() {
48 | let dictArray = [1.0,2.0,Double.nan]
49 | let result = dictArray.binarySearchLast(3.0, predicate:{$0 >= $1})
50 | XCTAssertNil(result)
51 | }
52 |
53 | func testPredicateLessOrEqualFailSafe() {
54 | let dictArray = [1.0,2.0,Double.nan]
55 | let result = dictArray.binarySearchLast(0.0, predicate:{$0 <= $1})
56 | XCTAssertNil(result)
57 | }
58 |
59 | func testPredicateEqualFailSafe() {
60 | let dictArray = [1.0,2.0,Double.nan]
61 | let result = dictArray.binarySearchLast(3.0)
62 | XCTAssertNil(result)
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/BinarySearchTests/BinarySearchInsertionIndexForTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BinarySearchInsertionIndexForTests.swift
3 | // BinarySearch
4 | //
5 | // Created by Gianni Ferullo on 12/17/15.
6 | // Copyright © 2015 Gianni Ferullo. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | //
12 | // BinarySearchInsertionIndexFoTests
13 | // BinarySearch
14 | //
15 | // Created by Gianni Ferullo on 12/17/15.
16 | // Copyright © 2015 Gianni Ferullo. All rights reserved.
17 | //
18 |
19 | import XCTest
20 | @testable import BinarySearch
21 |
22 | class BinarySearchInsertionIndexFoTests: XCTestCase {
23 | let testArray = [0,1,3,4]
24 |
25 | func testExists() {
26 | guard let result = testArray.binarySearchInsertionIndexFor(0) else {
27 | XCTAssert(true, "result is nil")
28 | return
29 | }
30 | XCTFail("result should be nil but it was \(result)")
31 | }
32 |
33 | func testFoundMiddleIndex() {
34 | guard let result = testArray.binarySearchInsertionIndexFor(2) else {
35 | XCTFail("result should be nil")
36 | return
37 | }
38 | XCTAssertEqual(result, 2, "Insertable at 2")
39 | }
40 |
41 | func testFoundBefore() {
42 | guard let result = testArray.binarySearchInsertionIndexFor(-1) else {
43 | XCTFail("result should be nil")
44 | return
45 | }
46 | XCTAssertEqual(result, 0, "Insertable at 0")
47 | }
48 |
49 | func testFoundAfter() {
50 | guard let result = testArray.binarySearchInsertionIndexFor(10) else {
51 | XCTFail("result should be nil")
52 | return
53 | }
54 | XCTAssertEqual(result, testArray.count, "Insertable at \(testArray.count)")
55 | }
56 |
57 | func testEmpty() {
58 | let testArray:[Int] = []
59 | guard let result = testArray.binarySearchInsertionIndexFor(10) else {
60 | XCTFail("result should be nil")
61 | return
62 | }
63 | XCTAssertEqual(result, 0, "Insertable at 0")
64 | }
65 |
66 | func testExtract() {
67 | struct Fruit {
68 | let name:String
69 | }
70 | // An Array of Fruits
71 | let dict = [
72 | Fruit(name:"apple"),
73 | Fruit(name:"banana"),
74 | Fruit(name:"orange")
75 | ]
76 | guard let result = dict.binarySearchInsertionIndexFor("cantaloupe", extract:{$0.name}) else {
77 | XCTFail("Failed to find a dictionary with a testValue of 'bananas'")
78 | return
79 | }
80 | XCTAssertEqual(result, 2, "Insertable at 2")
81 | }
82 |
83 | }
--------------------------------------------------------------------------------
/BinarySearchTests/BinarySearchTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BinarySearchTests.swift
3 | // BinarySearchTests
4 | //
5 | // Created by Gianni Ferullo on 11/16/15.
6 | // Copyright © 2015 Gianni Ferullo. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import BinarySearch
11 | // FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
12 | // Consider refactoring the code to use the non-optional operators.
13 | fileprivate func < (lhs: T?, rhs: T?) -> Bool {
14 | switch (lhs, rhs) {
15 | case let (l?, r?):
16 | return l < r
17 | case (nil, _?):
18 | return true
19 | default:
20 | return false
21 | }
22 | }
23 |
24 | // FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
25 | // Consider refactoring the code to use the non-optional operators.
26 | fileprivate func <= (lhs: T?, rhs: T?) -> Bool {
27 | switch (lhs, rhs) {
28 | case let (l?, r?):
29 | return l <= r
30 | default:
31 | return !(rhs < lhs)
32 | }
33 | }
34 |
35 | // FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
36 | // Consider refactoring the code to use the non-optional operators.
37 | fileprivate func > (lhs: T?, rhs: T?) -> Bool {
38 | switch (lhs, rhs) {
39 | case let (l?, r?):
40 | return l > r
41 | default:
42 | return rhs < lhs
43 | }
44 | }
45 |
46 | // FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
47 | // Consider refactoring the code to use the non-optional operators.
48 | fileprivate func >= (lhs: T?, rhs: T?) -> Bool {
49 | switch (lhs, rhs) {
50 | case let (l?, r?):
51 | return l >= r
52 | default:
53 | return !(lhs < rhs)
54 | }
55 | }
56 |
57 |
58 | class BinarySearchTests: XCTestCase {
59 |
60 | let test = (0...1000).map {$0}
61 |
62 | func testPredicateEqual() {
63 | for find in 0...1000 {
64 | // Find any value less than "find" 0 to 49
65 | let result = test.binarySearch(find, predicate: {$0 == $1})
66 | XCTAssertNotNil(result)
67 | XCTAssertEqual(find, result)
68 | }
69 | }
70 |
71 | func testPredicateLess() {
72 | for find in 1...1000 {
73 | // Find any value less than "find"
74 | let result = test.binarySearch(find, predicate: {$0 < $1})
75 | XCTAssertNotNil(result)
76 | XCTAssert(result < find)
77 | }
78 | }
79 |
80 | func testPredicateLessOrEqual() {
81 | for find in 0...1000 {
82 | // Find any value less or equal than "find"
83 | let result = test.binarySearch(find, predicate: {$0 <= $1})
84 | XCTAssertNotNil(result)
85 | XCTAssert(result <= find)
86 | }
87 | }
88 |
89 | func testPredicateGreater() {
90 | for find in 0...999 {
91 | // Find any value greater than "find"
92 | let result = test.binarySearch(find, predicate: {$0 > $1})
93 | XCTAssertNotNil(result)
94 | XCTAssert(result > find)
95 | }
96 | }
97 |
98 | func testPredicateGreaterOrEqual() {
99 | for find in 0...1000 {
100 | // Find any value greater than "find"
101 | let result = test.binarySearch(find, predicate: {$0 >= $1})
102 | XCTAssertNotNil(result)
103 | XCTAssert(result >= find)
104 | }
105 | }
106 |
107 | func testPredicateGreaterOrEqualFailSafe() {
108 | let dictArray = [1.0,2.0,Double.nan]
109 | let result = dictArray.binarySearch(3.0, predicate:{$0 >= $1})
110 | XCTAssertNil(result)
111 | }
112 |
113 | func testPredicateLessOrEqualFailSafe() {
114 | let dictArray = [1.0,2.0,Double.nan]
115 | let result = dictArray.binarySearch(0.0, predicate:{$0 <= $1})
116 | XCTAssertNil(result)
117 | }
118 |
119 | func testPredicateEqualFailSafe() {
120 | let dictArray = [1.0,2.0,Double.nan]
121 | let result = dictArray.binarySearch(3.0)
122 | XCTAssertNil(result)
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/BinarySearch.xcodeproj/xcshareddata/xcschemes/BinarySearch.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
65 |
71 |
72 |
73 |
74 |
75 |
76 |
82 |
83 |
89 |
90 |
91 |
92 |
94 |
95 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/BinarySearchTests/BinarySearchFirstTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BinarySearchTests.swift
3 | // BinarySearchTests
4 | //
5 | // Created by Gianni Ferullo on 11/16/15.
6 | // Copyright © 2015 Gianni Ferullo. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import BinarySearch
11 | // FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
12 | // Consider refactoring the code to use the non-optional operators.
13 | fileprivate func < (lhs: T?, rhs: T?) -> Bool {
14 | switch (lhs, rhs) {
15 | case let (l?, r?):
16 | return l < r
17 | case (nil, _?):
18 | return true
19 | default:
20 | return false
21 | }
22 | }
23 |
24 | // FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
25 | // Consider refactoring the code to use the non-optional operators.
26 | fileprivate func <= (lhs: T?, rhs: T?) -> Bool {
27 | switch (lhs, rhs) {
28 | case let (l?, r?):
29 | return l <= r
30 | default:
31 | return !(rhs < lhs)
32 | }
33 | }
34 |
35 | // FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
36 | // Consider refactoring the code to use the non-optional operators.
37 | fileprivate func > (lhs: T?, rhs: T?) -> Bool {
38 | switch (lhs, rhs) {
39 | case let (l?, r?):
40 | return l > r
41 | default:
42 | return rhs < lhs
43 | }
44 | }
45 |
46 |
47 | class BinarySearchFirstTests: XCTestCase {
48 |
49 | let test = (0...100000).map {$0}
50 |
51 | func testPredicateEqual() {
52 | for find in 0...1000 {
53 | let result = test.binarySearchFirst(find, predicate: {$0 == $1})
54 | XCTAssertNotNil(result)
55 | XCTAssertEqual(find, result)
56 | }
57 | }
58 |
59 | func testPredicateLess() {
60 | for find in 1...1000 {
61 | // Find any value less than "find"
62 | let result = test.binarySearchFirst(find, predicate: {$0 < $1})
63 | XCTAssertNotNil(result)
64 | XCTAssert(result < find)
65 | }
66 | }
67 |
68 | func testPredicateLessOrEqual() {
69 | for find in 0...1000 {
70 | // Find any value less or equal than "find"
71 | let result = test.binarySearchFirst(find, predicate: {$0 <= $1})
72 | XCTAssertNotNil(result)
73 | XCTAssert(result <= find)
74 | }
75 | }
76 |
77 | func testPredicateGreater() {
78 | for find in 0...999 {
79 | // Find any value greater than "find"
80 | let result = test.binarySearchFirst(find, predicate: {$0 > $1})
81 | XCTAssertNotNil(result)
82 | XCTAssert(result > find)
83 | }
84 | }
85 |
86 | func testFindingClosestValue() {
87 | // Find any value greater than "find"
88 | let test = [0,3,9,10,11,12,13,18]
89 | var result = test.binarySearchFirst(0, predicate: {$0 >= $1})
90 | XCTAssertEqual(test[result!], 0)
91 |
92 | result = test.binarySearchFirst(1, predicate: {$0 >= $1})
93 | XCTAssertEqual(test[result!], 3)
94 | result = test.binarySearchFirst(2, predicate: {$0 >= $1})
95 | XCTAssertEqual(test[result!], 3)
96 | result = test.binarySearchFirst(3, predicate: {$0 >= $1})
97 | XCTAssertEqual(test[result!], 3)
98 | for input in 4...9 {
99 | result = test.binarySearchFirst(input, predicate: {$0 >= $1})
100 | XCTAssertEqual(test[result!], 9)
101 | }
102 | }
103 |
104 | func testPredicateGreaterOrEqual() {
105 | for find in 0...1000 {
106 | // Find any value greater than "find"
107 | let result = test.binarySearchFirst(find, predicate: {$0 >= $1})
108 | XCTAssertNotNil(result)
109 | XCTAssert(result == find)
110 | }
111 | }
112 |
113 | func testPredicateGreaterOrEqualFailSafe() {
114 | let dictArray = [1.0,2.0,Double.nan]
115 | let result = dictArray.binarySearchFirst(3.0, predicate:{$0 >= $1})
116 | XCTAssertNil(result)
117 | }
118 |
119 | func testPredicateLessOrEqualFailSafe() {
120 | let dictArray = [1.0,2.0,Double.nan]
121 | let result = dictArray.binarySearchFirst(0.0, predicate:{$0 <= $1})
122 | XCTAssertNil(result)
123 | }
124 |
125 | func testPredicateEqualFailSafe() {
126 | let dictArray = [1.0,2.0,Double.nan]
127 | let result = dictArray.binarySearchFirst(3.0)
128 | XCTAssertNil(result)
129 | }
130 |
131 |
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/Sources/BinarySearch.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BinarySearch.swift
3 | // BinarySearch
4 | //
5 | // Created by Gianni Ferullo on 11/16/15.
6 | // Copyright © 2015 Gianni Ferullo. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public extension Collection where Index: Strideable {
12 |
13 | func binarySearch(_ find:T,
14 | extract: (Iterator.Element) -> T = {(el) -> T in return el as! T},
15 | predicate: (T,T) -> Bool = {(val1, val2) -> Bool in return val1 == val2}
16 | )-> Index? {
17 | var left = startIndex
18 | var right = endIndex - 1
19 | while (left <= right) {
20 | let mid = index(left, offsetBy: distance(from: left, to: right) / 2)
21 | let currentValue:T = extract(self[mid])
22 | if left == right {
23 | return predicate(currentValue, find) ? left : nil
24 | }
25 | if predicate(currentValue, find) {
26 | return mid
27 | }else if currentValue == find {
28 | return checkLeft(find, mid, extract, predicate) ?? checkRight(find, mid, extract, predicate)
29 | }else if currentValue < find {
30 | left = index(mid, offsetBy: 1)
31 | }else if currentValue > find {
32 | right = index(mid, offsetBy: -1)
33 | }else {
34 | return nil
35 | }
36 | }
37 | return nil
38 | }
39 |
40 | func binarySearchFirst(_ find:T,
41 | extract: (Iterator.Element) -> T = {(el) -> T in return el as! T},
42 | predicate: (T,T) -> Bool = {(val1, val2) -> Bool in return val1 == val2}
43 | )-> Index? {
44 | var left = startIndex
45 | var right = endIndex - 1
46 | while (left <= right) {
47 | let mid = index(left, offsetBy: distance(from: left, to: right) / 2)
48 | let currentValue:T = extract(self[mid])
49 | if left == right {
50 | return predicate(currentValue, find) ? left : nil
51 | }
52 | if predicate(currentValue, find) {
53 | if checkLeft(find, mid, extract, predicate) == nil {
54 | return mid
55 | }
56 | right = index(mid, offsetBy: -1)
57 | }else if currentValue == find {
58 | return checkLeft(find, mid, extract, predicate) ?? checkRight(find, mid, extract, predicate)
59 | }else if currentValue < find {
60 | left = index(mid, offsetBy: 1)
61 | }else if currentValue > find {
62 | right = index(mid, offsetBy: -1)
63 | }else {
64 | return nil
65 | }
66 | }
67 | return nil
68 | }
69 |
70 | func binarySearchLast(_ find:T,
71 | extract: (Iterator.Element) -> T = {(el) -> T in return el as! T},
72 | predicate: (T,T) -> Bool = {(val1, val2) -> Bool in return val1 == val2}
73 | )-> Index? {
74 | var left = startIndex
75 | var right = endIndex - 1
76 | while (left <= right) {
77 | let mid = index(left, offsetBy: distance(from: left, to: right) / 2)
78 | let currentValue:T = extract(self[mid])
79 | if left == right {
80 | return predicate(currentValue, find) ? left : nil
81 | }
82 | if predicate(currentValue, find) {
83 | if checkRight(find, mid, extract, predicate) == nil {
84 | return mid
85 | }
86 | left = index(mid, offsetBy: 1)
87 | }else if currentValue == find {
88 | return checkLeft(find, mid, extract, predicate) ?? checkRight(find, mid, extract, predicate)
89 | }else if currentValue < find {
90 | left = index(mid, offsetBy: 1)
91 | }else if currentValue > find {
92 | right = index(mid, offsetBy: -1)
93 | }else {
94 | return nil
95 | }
96 | }
97 | return nil
98 | }
99 |
100 | func binarySearchRange(_ find:T,
101 | extract: (Iterator.Element) -> T = {(el) -> T in return el as! T},
102 | predicate: (T,T) -> Bool = {(val1, val2) -> Bool in return val1 == val2}
103 | )-> Range? {
104 | if let first = binarySearchFirst(find, extract: extract, predicate: predicate),
105 | let last = binarySearchLast(find, extract: extract, predicate: predicate){
106 | return Range(uncheckedBounds: (lower: first, upper: last))
107 | }
108 | return nil
109 | }
110 |
111 | func binarySearchInsertionIndexFor(_ find:T,
112 | extract: (Iterator.Element) -> T = {(el) -> T in return el as! T}
113 | ) -> Index? {
114 | if let foundIndex = binarySearchLast(find, extract:extract, predicate:{$0 <= $1}) {
115 | let val = extract(self[foundIndex])
116 | if val != find {
117 | return index(foundIndex, offsetBy: 1)
118 | }else{
119 | return nil
120 | }
121 | }else if let first = self.first {
122 | return find < extract(first) ? startIndex : endIndex
123 | }else {
124 | return startIndex
125 | }
126 | }
127 |
128 | private func checkRight(_ find:T, _ mid:Index, _ extract: (Iterator.Element) -> T, _ predicate: (T,T) -> Bool) -> Index?{
129 | if distance(from: mid, to: endIndex) > 0 {
130 | let i = index(mid, offsetBy: 1)
131 | if predicate(extract(self[i]), find) {
132 | return i
133 | }
134 | }
135 | return nil
136 | }
137 |
138 | private func checkLeft(_ find:T, _ mid:Index, _ extract: (Iterator.Element) -> T, _ predicate: (T,T) -> Bool) -> Index?{
139 | if distance(from: startIndex, to: mid) > 0 {
140 | let i = index(mid, offsetBy: -1)
141 | if predicate(extract(self[i]), find) {
142 | return i
143 | }
144 | }
145 | return nil
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/BinarySearchTests/DocumentationTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BinarySearchExtractTest.swift
3 | // BinarySearch
4 | //
5 | // Created by Gianni Ferullo on 11/20/15.
6 | // Copyright © 2015 Gianni Ferullo. All rights reserved.
7 | //
8 |
9 |
10 |
11 | import XCTest
12 | @testable import BinarySearch
13 |
14 | class DocumentationTests: XCTestCase {
15 |
16 | func test() {
17 | let sortedInts = [0,1,2,3,4,5,6,7,8,9,10]
18 | guard let intIndex = sortedInts.binarySearch(6) else {
19 | XCTFail("Failed to find Int 6")
20 | return
21 | }
22 | XCTAssertEqual(intIndex, 6)
23 | XCTAssertEqual(sortedInts[intIndex], 6) // Our values are the same as the indices in this example.
24 |
25 | let fruitsArray = ["apples", "bananas", "oranges"]
26 | guard let fruitIndex = fruitsArray.binarySearch("bananas") else {
27 | XCTFail("Failed to find 'bananas'")
28 | return
29 | }
30 | XCTAssertEqual(fruitIndex, 1)
31 | XCTAssertEqual(fruitsArray[fruitIndex], "bananas")
32 |
33 | let kiwiIndex = fruitsArray.binarySearch("kiwi")
34 | kiwiIndex // nil
35 | XCTAssertNil(kiwiIndex)
36 | }
37 |
38 | func testPredicate() {
39 | let fruitsArray = ["apples", "bananas", "oranges"]
40 | guard let index = fruitsArray.binarySearch("bana", predicate:{$0.hasPrefix($1)}) else {
41 | XCTFail("Failed to find element that begins with 'bana'")
42 | return
43 | }
44 | XCTAssertEqual(index, 1)
45 | XCTAssertEqual(fruitsArray[index], "bananas")
46 | }
47 |
48 | func testExtract() {
49 | struct Fruit {
50 | let name:String
51 | }
52 | // An Array of Fruits
53 | let dict = [
54 | Fruit(name:"apple"),
55 | Fruit(name:"banana"),
56 | Fruit(name:"orange")
57 | ]
58 | guard let index = dict.binarySearch("banana", extract:{$0.name}) else {
59 | XCTFail("Failed to find a dictionary with a testValue of 'bananas'")
60 | return
61 | }
62 | XCTAssertEqual(index, 1)
63 | XCTAssertEqual(dict[index].name, "banana")
64 | }
65 |
66 | func testFullExample() {
67 |
68 | struct Album {
69 | let name:String
70 | let date:TimeInterval
71 | init(_ name:String, _ date:String){
72 | self.name = name
73 | self.date = Album.getDate(date)
74 | }
75 | static func getDate(_ date: String) -> TimeInterval{
76 | let formatter = DateFormatter()
77 | formatter.dateFormat = "yyyy-MM-dd"
78 | return formatter.date(from: date)!.timeIntervalSince1970
79 | }
80 | }
81 |
82 | // An Array of albums, sorted by date
83 | let stonesAlbums = [
84 | Album("Beggars Banquet", "1968-12-06"),
85 | Album("Let It Bleed", "1969-12-05"),
86 | Album("Sticky Fingers", "1971-04-23"),
87 | Album("Exile on Main St.", "1972-05-12"),
88 | Album("Some Girls", "1978-06-9"),
89 | Album("Emotional Rescue", "1980-06-20"),
90 | Album("Tattoo You", "1981-08-24"),
91 | Album("Undercover", "1983-11-07")
92 | ]
93 |
94 | guard let firstStonesAlbumSeventies = stonesAlbums.binarySearchFirst(Album.getDate("1970-01-01"),
95 | // Extract the date value to test with the predicate above
96 | extract: {$0.date},
97 | // We want to find the first value greater than Jan 1, 1970
98 | predicate: {$0 >= $1}) else {
99 | XCTFail("Failed to find a Rolling Stones album after 1970")
100 | return
101 | }
102 | XCTAssertEqual(firstStonesAlbumSeventies, 2)
103 | XCTAssertEqual(stonesAlbums[firstStonesAlbumSeventies].name, "Sticky Fingers")
104 | guard let lastStonesAlbumSixties = stonesAlbums.binarySearchLast(Album.getDate("1970-01-01"),
105 | // Extract the date value to test with the predicate above
106 | extract: {$0.date},
107 | // We want to find the first value greater than Jan 1, 1970
108 | predicate: {$0 <= $1}) else {
109 | XCTFail("Failed to find a Rolling Stones album after 1970")
110 | return
111 | }
112 | XCTAssertEqual(lastStonesAlbumSixties, 1)
113 | XCTAssertEqual(stonesAlbums[lastStonesAlbumSixties].name, "Let It Bleed")
114 | guard let albumSixties = stonesAlbums.binarySearchRange(Album.getDate("1970-01-01"),
115 | // Extract the date value to test with the predicate above
116 | extract: {$0.date},
117 | // We want to find the first value greater than Jan 1, 1970
118 | predicate: {$0 >= $1 && $0 < Album.getDate("1978-01-01")}) else {
119 | XCTFail("Failed to find a Rolling Stones album after 1970")
120 | return
121 | }
122 | XCTAssertEqual(albumSixties.lowerBound, 2)
123 | XCTAssertEqual(albumSixties.upperBound, 3)
124 | }
125 |
126 | func testFirst() {
127 | let sortedArray = [0,5,15,75,100]
128 | func compare(_ val:Int, val2:Int) -> Bool {
129 | return val > 10
130 | }
131 | guard let indexGreaterThanOrEqual = sortedArray.binarySearchFirst(10, predicate: compare) else {
132 | XCTFail("Failed to find an index greater than or equal to 10")
133 | return
134 | }
135 | // Find the first value that's greater than or equal to 10
136 | XCTAssertEqual(indexGreaterThanOrEqual, 2)
137 | XCTAssertEqual(sortedArray[indexGreaterThanOrEqual], 15)
138 |
139 | guard let indexLessThanOrEqual = sortedArray.binarySearchFirst(10, predicate: {$0 <= $1}) else {
140 | XCTFail("Failed to find an index less than or equal to 10")
141 | return
142 | }
143 | XCTAssertEqual(indexLessThanOrEqual, 0)
144 | XCTAssertEqual(sortedArray[indexLessThanOrEqual], 0)
145 | }
146 |
147 | func testLast() {
148 | let sortedArray = [0,5,15,75,100]
149 | guard let indexGreaterThanOrEqual = sortedArray.binarySearchLast(10, predicate: {$0 >= $1}) else {
150 | XCTFail("Failed to find an index greater than or equal to 10")
151 | return
152 | }
153 | // Find the first value that's greater than or equal to 10
154 | XCTAssertEqual(indexGreaterThanOrEqual, 4)
155 | XCTAssertEqual(sortedArray[indexGreaterThanOrEqual], 100)
156 |
157 | guard let indexLessThanOrEqual = sortedArray.binarySearchLast(10, predicate: {$0 <= $1}) else {
158 | XCTFail("Failed to find an index less than or equal to 10")
159 | return
160 | }
161 | XCTAssertEqual(indexLessThanOrEqual, 1)
162 | XCTAssertEqual(sortedArray[indexLessThanOrEqual], 5)
163 | }
164 |
165 | func testRange() {
166 | let sortedArray = [0,5,15,75,100]
167 | guard let range = sortedArray.binarySearchRange(10, predicate:{$0 >= $1}) else {
168 | XCTFail("Failed to find a range of Ints greater than or equal to 10")
169 | return
170 | }
171 | // Find the range of values that's greater than or equal to 10
172 | XCTAssertEqual(range.lowerBound, 2)
173 | XCTAssertEqual(sortedArray[range.lowerBound], 15)
174 | XCTAssertEqual(range.upperBound, 4)
175 | XCTAssertEqual(sortedArray[range.upperBound], 100)
176 |
177 | }
178 |
179 | func testManualRange() {
180 | let sortedArray = [0,5,15,75,100,150]
181 | guard let startIndex = sortedArray.binarySearchFirst(10, predicate:{$0 >= $1}),
182 | let endIndex = sortedArray.binarySearchLast(100, predicate:{$0 <= $1})
183 | else {
184 | XCTFail("Failed to find a range of Ints greater than or equal to 10")
185 | return
186 | }
187 | // Find the range of values that's greater than or equal to 10
188 | XCTAssertEqual(startIndex, 2)
189 | XCTAssertEqual(sortedArray[startIndex], 15)
190 | XCTAssertEqual(endIndex, 4)
191 | XCTAssertEqual(sortedArray[endIndex], 100)
192 | }
193 |
194 | func testInsertionIndexFor() {
195 | guard let foundIndex = [0,5,15,75,100].binarySearchInsertionIndexFor(10) else {
196 | XCTFail("The find should have succeeded")
197 | return
198 | }
199 | // The value 10 would go at the 2nd index
200 | XCTAssertEqual(foundIndex, 2)
201 | guard let foundIndex2 = [0,5,15,75,100].binarySearchInsertionIndexFor(-5) else {
202 | XCTFail("The find should have succeeded")
203 | return
204 | }
205 | // The value -5 would go at the index 0
206 | XCTAssertEqual(foundIndex2, 0)
207 | guard let foundIndex3 = [0,5,15,75,100].binarySearchInsertionIndexFor(500) else {
208 | XCTFail("The find should have succeeded")
209 | return
210 | }
211 | // The value 500 would go at the end index
212 | XCTAssertEqual(foundIndex3, 5)
213 | guard let _ = [0,5,15,75,100].binarySearchInsertionIndexFor(75) else {
214 | XCTAssertTrue(true, "The return value should be nil")
215 | return
216 | }
217 | XCTFail("The foundIndex should have be nil")
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Binary Search Swift Extension
2 | [](https://travis-ci.org/giannif/BinarySearch)
3 | [](https://github.com/Carthage/Carthage)
4 |
5 | Perform a [binary search][wiki] on [Collections][] (e.g. [Array][], [Dictionary][], [Set][]), with a few powerful options such as finding the first or last index in the collection, matching an optional [predicate](#predicate), and the ability to [extract](#extract) values from a collection to avoid having to prepare that collection for a binary search.
6 |
7 | ### Methods
8 | - [binarySearch](#binarySearch) - Find the index of the first element that passes the truth test (predicate). The default predicate is `==`.
9 | - [binarySearchFirst](#binarySearchFirst) - Find the index of the first element in the collection that matches the predicate.
10 | - [binarySearchLast](#binarySearchLast) - Find the index of the last element in the collection that matches the predicate.
11 | - [binarySearchRange](#binarySearchRange) - Find the startIndex and endIndex of elements that match the predicate.
12 | - [binarySearchInsertionIndexFor](#binarySearchInsertionIndexFor) - Find the index that an element would be inserted at.
13 |
14 |
15 | ### Arguments
16 | - `find` _required_ - The value you're looking for
17 | - `predicate` _optional_ - A truth test, e.g. `$0 <= $1`, `$0.hasPrefix($1)`, where `$0` is the value of `find` and `$1` is the current element value. See [more](#predicate).
18 | - `extract` _optional_ - The value to compare, e.g. `$0.someVal`, where `someVal` is the same type as the argument for
19 | `find`. See [more](#extract).
20 |
21 | **Important**
22 | > Running binary search requires sorted data.
23 |
24 | **Important**
25 | > Duplicate values are unsupported.
26 |
27 | ### Performance Benefit
28 | Binary Search runs in O(log n), as opposed to linear search which runs in O(n).
29 | Meaning, if you use linear search, in the worst case scenario, the number of steps to find your value will equal the number of elements.
30 | For binary search, this number is [dramatically lower][wikiPerformance].
31 |
32 | All binary search methods in this extension return an `Index`, or a `Range` for `binarySearchRange`.
33 |
34 |
35 | #### binarySearch
36 |
37 | _In all examples below, assume the tests pass._ The documation code has tests.
38 |
39 | Find an item that is equal to the first argument.
40 |
41 | ```Swift
42 | let sortedInts = [0,1,2,3,4,5,6,7,8,9,10]
43 | guard let intIndex = sortedInts.binarySearch(6) else {
44 | XCTFail("Failed to find Int 6")
45 | return
46 | }
47 | XCTAssertEqual(intIndex, 6)
48 | // In this contrived example, our values are the same as the indices.
49 | XCTAssertEqual(sortedInts[intIndex], 6)
50 | ```
51 |
52 | ```Swift
53 | let fruitsArray = ["apples", "bananas", "oranges"]
54 | guard let fruitIndex = fruitsArray.binarySearch("bananas") else {
55 | XCTFail("Failed to find 'bananas'")
56 | return
57 | }
58 | XCTAssertEqual(fruitIndex, 1)
59 | XCTAssertEqual(fruitsArray[fruitIndex], "bananas")
60 |
61 | let kiwiIndex = fruitsArray.binarySearch("kiwi")
62 | XCTAssertNil(kiwiIndex) // If the search fails the result is nil
63 | ```
64 |
65 | #### Predicate
66 | An optional argument to evaluate truthfulness. The default is `$0 == $1`, where `$0` is the value of `find` and `$1` is the current element value.
67 |
68 |
69 | ```Swift
70 | let fruitsArray = ["apples", "bananas", "oranges"]
71 | guard let index = fruitsArray.binarySearch("bana", predicate:{$0.hasPrefix($1)}) else {
72 | XCTFail("Failed to find element that begins with 'bana'")
73 | return
74 | }
75 | XCTAssertEqual(index, 1)
76 | XCTAssertEqual(fruitsArray[index], "bananas")
77 | ```
78 |
79 |
80 | #### Extract
81 | An optional argument to extract a value. The value must match the type you're searching for,
82 | and the array must be sorted on the property that you're extracting.
83 |
84 | The default is `Generator.Element -> T = {(el) -> T in return el as! T}`
85 |
86 | ```Swift
87 | struct Fruit {
88 | let name:String
89 | }
90 | // An Array of Fruits
91 | let fruits = [
92 | Fruit(name:"apple"),
93 | Fruit(name:"banana"),
94 | Fruit(name:"orange")
95 | ]
96 | guard let index = fruits.binarySearch("banana", extract:{$0.name}) else {
97 | XCTFail("Failed to find a dictionary with a name 'bananas'")
98 | return
99 | }
100 | XCTAssertEqual(index, 1)
101 | XCTAssertEqual(fruits[index].name, "banana")
102 | ```
103 |
104 |
105 | #### binarySearchFirst
106 |
107 | Find the value with the lowest index that meets the predicate.
108 |
109 | ```Swift
110 | let sortedArray = [0,5,15,75,100]
111 | guard let indexGreaterThanOrEqual = sortedArray.binarySearchFirst(10, predicate: {$0 >= $1}) else {
112 | XCTFail("Failed to find an index greater than or equal to 10")
113 | return
114 | }
115 | XCTAssertEqual(indexGreaterThanOrEqual, 2)
116 | XCTAssertEqual(sortedArray[indexGreaterThanOrEqual], 15)
117 |
118 | guard let indexLessThanOrEqual = sortedArray.binarySearchFirst(10, predicate: {$0 <= $1}) else {
119 | XCTFail("Failed to find an index less than or equal to 10")
120 | return
121 | }
122 | XCTAssertEqual(indexLessThanOrEqual, 0)
123 | XCTAssertEqual(sortedArray[indexLessThanOrEqual], 0)
124 | ```
125 |
126 | #### binarySearchLast
127 |
128 | Find the value with the highest index that meets the predicate.
129 | ```Swift
130 | let sortedArray = [0,5,15,75,100]
131 | guard let indexGreaterThanOrEqual = sortedArray.binarySearchLast(10, predicate: {$0 >= $1}) else {
132 | XCTFail("Failed to find an index greater than or equal to 10")
133 | return
134 | }
135 | XCTAssertEqual(indexGreaterThanOrEqual, 4)
136 | XCTAssertEqual(sortedArray[indexGreaterThanOrEqual], 100)
137 |
138 | guard let indexLessThanOrEqual = sortedArray.binarySearchLast(10, predicate: {$0 <= $1}) else {
139 | XCTFail("Failed to find an index less than or equal to 10")
140 | return
141 | }
142 | XCTAssertEqual(indexLessThanOrEqual, 1)
143 | XCTAssertEqual(sortedArray[indexLessThanOrEqual], 5)
144 | ```
145 |
146 |
147 | #### binarySearchRange
148 |
149 | A convenience method that wraps [binarySearchFirst](#binarySearchFirst) and [binarySearchLast](#binarySearchLast)
150 |
151 | ```Swift
152 | let sortedArray = [0,5,15,75,100]
153 | guard let range = sortedArray.binarySearchRange(10, predicate:{$0 >= $1}) else {
154 | XCTFail("Failed to find a range of Ints greater than or equal to 10")
155 | return
156 | }
157 | XCTAssertEqual(range.startIndex, 2)
158 | XCTAssertEqual(sortedArray[range.startIndex], 15)
159 | XCTAssertEqual(range.endIndex, 4)
160 | XCTAssertEqual(sortedArray[range.endIndex], 100)
161 | ```
162 |
163 | If you need to have a different predicate for the start and end, just use the `binarySearchFirst` and `binarySearchLast` methods:
164 |
165 | ```Swift
166 | let sortedArray = [0,5,15,75,100,150]
167 | guard let startIndex = sortedArray.binarySearchFirst(10, predicate:{$0 >= $1}),
168 | endIndex = sortedArray.binarySearchLast(100, predicate:{$0 <= $1})
169 | else {
170 | XCTFail("Failed to find a range of Ints greater than or equal to 10 and less than or equal to 100")
171 | return
172 | }
173 | // Find the range of values that's greater than or equal to 10
174 | XCTAssertEqual(startIndex, 2)
175 | XCTAssertEqual(sortedArray[startIndex], 15)
176 | XCTAssertEqual(endIndex, 4)
177 | XCTAssertEqual(sortedArray[endIndex], 100)
178 | ```
179 |
180 |
181 | #### binarySearchInsertionIndexFor
182 |
183 | Returns the `Index` that an element could be inserted at while maintaing the sort. If the return value is nil, the element already exists in the collection.
184 |
185 | ```Swift
186 | guard let foundIndex = [0,5,15,75,100].binarySearchInsertionIndexFor(10) else {
187 | XCTFail("The find should have succeeded")
188 | return
189 | }
190 | // The value 10 would go at the 2nd index
191 | XCTAssertEqual(foundIndex, 2)
192 | ```
193 | ```Swift
194 | guard let foundIndex = [0,5,15,75,100].binarySearchInsertionIndexFor(-5) else {
195 | XCTFail("The find should have succeeded")
196 | return
197 | }
198 | // The value -5 would go at the start index
199 | XCTAssertEqual(foundIndex, 0)
200 | ```
201 | ```Swift
202 | guard let foundIndex = [0,5,15,75,100].binarySearchInsertionIndexFor(500) else {
203 | XCTFail("The find should have succeeded")
204 | return
205 | }
206 | // The value 500 would go at the end index
207 | XCTAssertEqual(foundIndex, 5)
208 | ```
209 | ```Swift
210 | guard let _ = [0,5,15,75,100].binarySearchInsertionIndexFor(75) else {
211 | XCTAssertTrue(true, "The element already exists")
212 | return
213 | }
214 | XCTFail("The foundIndex should be nil")
215 | ```
216 |
217 | #### Installation
218 |
219 | Copy the BinarySearch.swift file into your project, or use [Carthage][].
220 |
221 | # To Do #
222 | * [ ] What can the predicate contain?
223 | * [ ] Support for duplicate values, or throw an error when they're encountered
224 | * [ ] Clean up tests. Write more tests.
225 | * [x] Carthage support
226 | * [x] Installation instructions
227 | * [x] Run tests on Travis CI
228 |
229 | [wiki]: https://en.wikipedia.org/wiki/Binary_search_algorithm
230 | [wikiPerformance]: https://en.wikipedia.org/wiki/Binary_search_algorithm#Performance "Binary Search Performance"
231 | [Collections]: https://developer.apple.com/library/watchos/documentation/Swift/Reference/Swift_CollectionType_Protocol/index.html
232 | [Array]: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_Array_Structure/
233 | [Set]: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_Set_Structure/
234 | [Dictionary]: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_Dictionary_Structure/
235 | [Carthage]: https://github.com/Carthage/Carthage
236 |
237 |
--------------------------------------------------------------------------------
/BinarySearch.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 002BFDC61BFE44BB00709DC4 /* BinarySearchLastTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 002BFDC51BFE44BB00709DC4 /* BinarySearchLastTests.swift */; };
11 | 002BFDC81BFF696300709DC4 /* BinarySearchRangeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 002BFDC71BFF696300709DC4 /* BinarySearchRangeTests.swift */; };
12 | 002BFDCA1BFF70C600709DC4 /* BinarySearchExtractTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 002BFDC91BFF70C600709DC4 /* BinarySearchExtractTests.swift */; };
13 | 002BFDCC1C00BC1200709DC4 /* DocumentationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 002BFDCB1C00BC1200709DC4 /* DocumentationTests.swift */; };
14 | 007563E41BFA1AE1000ED5EB /* BinarySearch.h in Headers */ = {isa = PBXBuildFile; fileRef = 007563E31BFA1AE1000ED5EB /* BinarySearch.h */; settings = {ATTRIBUTES = (Public, ); }; };
15 | 007563EB1BFA1AE1000ED5EB /* BinarySearch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 007563E01BFA1AE1000ED5EB /* BinarySearch.framework */; };
16 | 007563F01BFA1AE1000ED5EB /* BinarySearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 007563EF1BFA1AE1000ED5EB /* BinarySearchTests.swift */; };
17 | 007563FB1BFA1AF3000ED5EB /* BinarySearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 007563FA1BFA1AF3000ED5EB /* BinarySearch.swift */; };
18 | 00A0B1D61C235F2000FDF27A /* BinarySearchInsertionIndexForTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00A0B1D51C235F2000FDF27A /* BinarySearchInsertionIndexForTests.swift */; };
19 | 00AB63511BFBEF98001514CC /* BinarySearchFirstTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00AB63501BFBEF98001514CC /* BinarySearchFirstTests.swift */; };
20 | 00BAE0A61C0277730090B52D /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00BAE0A51C0277730090B52D /* PerformanceTests.swift */; };
21 | /* End PBXBuildFile section */
22 |
23 | /* Begin PBXContainerItemProxy section */
24 | 007563EC1BFA1AE1000ED5EB /* PBXContainerItemProxy */ = {
25 | isa = PBXContainerItemProxy;
26 | containerPortal = 007563D71BFA1AE1000ED5EB /* Project object */;
27 | proxyType = 1;
28 | remoteGlobalIDString = 007563DF1BFA1AE1000ED5EB;
29 | remoteInfo = BinarySearch;
30 | };
31 | /* End PBXContainerItemProxy section */
32 |
33 | /* Begin PBXFileReference section */
34 | 002BFDC51BFE44BB00709DC4 /* BinarySearchLastTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinarySearchLastTests.swift; sourceTree = ""; };
35 | 002BFDC71BFF696300709DC4 /* BinarySearchRangeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinarySearchRangeTests.swift; sourceTree = ""; };
36 | 002BFDC91BFF70C600709DC4 /* BinarySearchExtractTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinarySearchExtractTests.swift; sourceTree = ""; };
37 | 002BFDCB1C00BC1200709DC4 /* DocumentationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DocumentationTests.swift; sourceTree = ""; };
38 | 007563E01BFA1AE1000ED5EB /* BinarySearch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BinarySearch.framework; sourceTree = BUILT_PRODUCTS_DIR; };
39 | 007563E31BFA1AE1000ED5EB /* BinarySearch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BinarySearch.h; sourceTree = ""; };
40 | 007563E51BFA1AE1000ED5EB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
41 | 007563EA1BFA1AE1000ED5EB /* BinarySearchTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BinarySearchTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
42 | 007563EF1BFA1AE1000ED5EB /* BinarySearchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinarySearchTests.swift; sourceTree = ""; };
43 | 007563F11BFA1AE1000ED5EB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
44 | 007563FA1BFA1AF3000ED5EB /* BinarySearch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinarySearch.swift; sourceTree = ""; };
45 | 00A0B1D51C235F2000FDF27A /* BinarySearchInsertionIndexForTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinarySearchInsertionIndexForTests.swift; sourceTree = ""; };
46 | 00AB63501BFBEF98001514CC /* BinarySearchFirstTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinarySearchFirstTests.swift; sourceTree = ""; };
47 | 00BAE0A51C0277730090B52D /* PerformanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformanceTests.swift; sourceTree = ""; };
48 | /* End PBXFileReference section */
49 |
50 | /* Begin PBXFrameworksBuildPhase section */
51 | 007563DC1BFA1AE1000ED5EB /* Frameworks */ = {
52 | isa = PBXFrameworksBuildPhase;
53 | buildActionMask = 2147483647;
54 | files = (
55 | );
56 | runOnlyForDeploymentPostprocessing = 0;
57 | };
58 | 007563E71BFA1AE1000ED5EB /* Frameworks */ = {
59 | isa = PBXFrameworksBuildPhase;
60 | buildActionMask = 2147483647;
61 | files = (
62 | 007563EB1BFA1AE1000ED5EB /* BinarySearch.framework in Frameworks */,
63 | );
64 | runOnlyForDeploymentPostprocessing = 0;
65 | };
66 | /* End PBXFrameworksBuildPhase section */
67 |
68 | /* Begin PBXGroup section */
69 | 007563D61BFA1AE1000ED5EB = {
70 | isa = PBXGroup;
71 | children = (
72 | 007563E21BFA1AE1000ED5EB /* Sources */,
73 | 007563EE1BFA1AE1000ED5EB /* BinarySearchTests */,
74 | 007563E11BFA1AE1000ED5EB /* Products */,
75 | );
76 | sourceTree = "";
77 | };
78 | 007563E11BFA1AE1000ED5EB /* Products */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 007563E01BFA1AE1000ED5EB /* BinarySearch.framework */,
82 | 007563EA1BFA1AE1000ED5EB /* BinarySearchTests.xctest */,
83 | );
84 | name = Products;
85 | sourceTree = "";
86 | };
87 | 007563E21BFA1AE1000ED5EB /* Sources */ = {
88 | isa = PBXGroup;
89 | children = (
90 | 007563E31BFA1AE1000ED5EB /* BinarySearch.h */,
91 | 007563E51BFA1AE1000ED5EB /* Info.plist */,
92 | 007563FA1BFA1AF3000ED5EB /* BinarySearch.swift */,
93 | );
94 | path = Sources;
95 | sourceTree = "";
96 | };
97 | 007563EE1BFA1AE1000ED5EB /* BinarySearchTests */ = {
98 | isa = PBXGroup;
99 | children = (
100 | 007563EF1BFA1AE1000ED5EB /* BinarySearchTests.swift */,
101 | 00AB63501BFBEF98001514CC /* BinarySearchFirstTests.swift */,
102 | 007563F11BFA1AE1000ED5EB /* Info.plist */,
103 | 002BFDC51BFE44BB00709DC4 /* BinarySearchLastTests.swift */,
104 | 002BFDC71BFF696300709DC4 /* BinarySearchRangeTests.swift */,
105 | 002BFDC91BFF70C600709DC4 /* BinarySearchExtractTests.swift */,
106 | 002BFDCB1C00BC1200709DC4 /* DocumentationTests.swift */,
107 | 00BAE0A51C0277730090B52D /* PerformanceTests.swift */,
108 | 00A0B1D51C235F2000FDF27A /* BinarySearchInsertionIndexForTests.swift */,
109 | );
110 | path = BinarySearchTests;
111 | sourceTree = "";
112 | };
113 | /* End PBXGroup section */
114 |
115 | /* Begin PBXHeadersBuildPhase section */
116 | 007563DD1BFA1AE1000ED5EB /* Headers */ = {
117 | isa = PBXHeadersBuildPhase;
118 | buildActionMask = 2147483647;
119 | files = (
120 | 007563E41BFA1AE1000ED5EB /* BinarySearch.h in Headers */,
121 | );
122 | runOnlyForDeploymentPostprocessing = 0;
123 | };
124 | /* End PBXHeadersBuildPhase section */
125 |
126 | /* Begin PBXNativeTarget section */
127 | 007563DF1BFA1AE1000ED5EB /* BinarySearch */ = {
128 | isa = PBXNativeTarget;
129 | buildConfigurationList = 007563F41BFA1AE1000ED5EB /* Build configuration list for PBXNativeTarget "BinarySearch" */;
130 | buildPhases = (
131 | 007563DB1BFA1AE1000ED5EB /* Sources */,
132 | 007563DC1BFA1AE1000ED5EB /* Frameworks */,
133 | 007563DD1BFA1AE1000ED5EB /* Headers */,
134 | 007563DE1BFA1AE1000ED5EB /* Resources */,
135 | );
136 | buildRules = (
137 | );
138 | dependencies = (
139 | );
140 | name = BinarySearch;
141 | productName = BinarySearch;
142 | productReference = 007563E01BFA1AE1000ED5EB /* BinarySearch.framework */;
143 | productType = "com.apple.product-type.framework";
144 | };
145 | 007563E91BFA1AE1000ED5EB /* BinarySearchTests */ = {
146 | isa = PBXNativeTarget;
147 | buildConfigurationList = 007563F71BFA1AE1000ED5EB /* Build configuration list for PBXNativeTarget "BinarySearchTests" */;
148 | buildPhases = (
149 | 007563E61BFA1AE1000ED5EB /* Sources */,
150 | 007563E71BFA1AE1000ED5EB /* Frameworks */,
151 | 007563E81BFA1AE1000ED5EB /* Resources */,
152 | );
153 | buildRules = (
154 | );
155 | dependencies = (
156 | 007563ED1BFA1AE1000ED5EB /* PBXTargetDependency */,
157 | );
158 | name = BinarySearchTests;
159 | productName = BinarySearchTests;
160 | productReference = 007563EA1BFA1AE1000ED5EB /* BinarySearchTests.xctest */;
161 | productType = "com.apple.product-type.bundle.unit-test";
162 | };
163 | /* End PBXNativeTarget section */
164 |
165 | /* Begin PBXProject section */
166 | 007563D71BFA1AE1000ED5EB /* Project object */ = {
167 | isa = PBXProject;
168 | attributes = {
169 | LastSwiftUpdateCheck = 0710;
170 | LastUpgradeCheck = 0710;
171 | ORGANIZATIONNAME = "Gianni Ferullo";
172 | TargetAttributes = {
173 | 007563DF1BFA1AE1000ED5EB = {
174 | CreatedOnToolsVersion = 7.1;
175 | LastSwiftMigration = 0820;
176 | };
177 | 007563E91BFA1AE1000ED5EB = {
178 | CreatedOnToolsVersion = 7.1;
179 | LastSwiftMigration = 0820;
180 | };
181 | };
182 | };
183 | buildConfigurationList = 007563DA1BFA1AE1000ED5EB /* Build configuration list for PBXProject "BinarySearch" */;
184 | compatibilityVersion = "Xcode 3.2";
185 | developmentRegion = English;
186 | hasScannedForEncodings = 0;
187 | knownRegions = (
188 | en,
189 | );
190 | mainGroup = 007563D61BFA1AE1000ED5EB;
191 | productRefGroup = 007563E11BFA1AE1000ED5EB /* Products */;
192 | projectDirPath = "";
193 | projectRoot = "";
194 | targets = (
195 | 007563DF1BFA1AE1000ED5EB /* BinarySearch */,
196 | 007563E91BFA1AE1000ED5EB /* BinarySearchTests */,
197 | );
198 | };
199 | /* End PBXProject section */
200 |
201 | /* Begin PBXResourcesBuildPhase section */
202 | 007563DE1BFA1AE1000ED5EB /* Resources */ = {
203 | isa = PBXResourcesBuildPhase;
204 | buildActionMask = 2147483647;
205 | files = (
206 | );
207 | runOnlyForDeploymentPostprocessing = 0;
208 | };
209 | 007563E81BFA1AE1000ED5EB /* Resources */ = {
210 | isa = PBXResourcesBuildPhase;
211 | buildActionMask = 2147483647;
212 | files = (
213 | );
214 | runOnlyForDeploymentPostprocessing = 0;
215 | };
216 | /* End PBXResourcesBuildPhase section */
217 |
218 | /* Begin PBXSourcesBuildPhase section */
219 | 007563DB1BFA1AE1000ED5EB /* Sources */ = {
220 | isa = PBXSourcesBuildPhase;
221 | buildActionMask = 2147483647;
222 | files = (
223 | 007563FB1BFA1AF3000ED5EB /* BinarySearch.swift in Sources */,
224 | );
225 | runOnlyForDeploymentPostprocessing = 0;
226 | };
227 | 007563E61BFA1AE1000ED5EB /* Sources */ = {
228 | isa = PBXSourcesBuildPhase;
229 | buildActionMask = 2147483647;
230 | files = (
231 | 00BAE0A61C0277730090B52D /* PerformanceTests.swift in Sources */,
232 | 002BFDCC1C00BC1200709DC4 /* DocumentationTests.swift in Sources */,
233 | 007563F01BFA1AE1000ED5EB /* BinarySearchTests.swift in Sources */,
234 | 00A0B1D61C235F2000FDF27A /* BinarySearchInsertionIndexForTests.swift in Sources */,
235 | 00AB63511BFBEF98001514CC /* BinarySearchFirstTests.swift in Sources */,
236 | 002BFDC81BFF696300709DC4 /* BinarySearchRangeTests.swift in Sources */,
237 | 002BFDC61BFE44BB00709DC4 /* BinarySearchLastTests.swift in Sources */,
238 | 002BFDCA1BFF70C600709DC4 /* BinarySearchExtractTests.swift in Sources */,
239 | );
240 | runOnlyForDeploymentPostprocessing = 0;
241 | };
242 | /* End PBXSourcesBuildPhase section */
243 |
244 | /* Begin PBXTargetDependency section */
245 | 007563ED1BFA1AE1000ED5EB /* PBXTargetDependency */ = {
246 | isa = PBXTargetDependency;
247 | target = 007563DF1BFA1AE1000ED5EB /* BinarySearch */;
248 | targetProxy = 007563EC1BFA1AE1000ED5EB /* PBXContainerItemProxy */;
249 | };
250 | /* End PBXTargetDependency section */
251 |
252 | /* Begin XCBuildConfiguration section */
253 | 007563F21BFA1AE1000ED5EB /* Debug */ = {
254 | isa = XCBuildConfiguration;
255 | buildSettings = {
256 | ALWAYS_SEARCH_USER_PATHS = NO;
257 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
258 | CLANG_CXX_LIBRARY = "libc++";
259 | CLANG_ENABLE_MODULES = YES;
260 | CLANG_ENABLE_OBJC_ARC = YES;
261 | CLANG_WARN_BOOL_CONVERSION = YES;
262 | CLANG_WARN_CONSTANT_CONVERSION = YES;
263 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
264 | CLANG_WARN_EMPTY_BODY = YES;
265 | CLANG_WARN_ENUM_CONVERSION = YES;
266 | CLANG_WARN_INT_CONVERSION = YES;
267 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
268 | CLANG_WARN_UNREACHABLE_CODE = YES;
269 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
270 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
271 | COPY_PHASE_STRIP = NO;
272 | CURRENT_PROJECT_VERSION = 1;
273 | DEBUG_INFORMATION_FORMAT = dwarf;
274 | ENABLE_STRICT_OBJC_MSGSEND = YES;
275 | ENABLE_TESTABILITY = YES;
276 | GCC_C_LANGUAGE_STANDARD = gnu99;
277 | GCC_DYNAMIC_NO_PIC = NO;
278 | GCC_NO_COMMON_BLOCKS = YES;
279 | GCC_OPTIMIZATION_LEVEL = 0;
280 | GCC_PREPROCESSOR_DEFINITIONS = (
281 | "DEBUG=1",
282 | "$(inherited)",
283 | );
284 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
285 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
286 | GCC_WARN_UNDECLARED_SELECTOR = YES;
287 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
288 | GCC_WARN_UNUSED_FUNCTION = YES;
289 | GCC_WARN_UNUSED_VARIABLE = YES;
290 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
291 | MTL_ENABLE_DEBUG_INFO = YES;
292 | ONLY_ACTIVE_ARCH = YES;
293 | SDKROOT = iphoneos;
294 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
295 | TARGETED_DEVICE_FAMILY = "1,2";
296 | VERSIONING_SYSTEM = "apple-generic";
297 | VERSION_INFO_PREFIX = "";
298 | };
299 | name = Debug;
300 | };
301 | 007563F31BFA1AE1000ED5EB /* Release */ = {
302 | isa = XCBuildConfiguration;
303 | buildSettings = {
304 | ALWAYS_SEARCH_USER_PATHS = NO;
305 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
306 | CLANG_CXX_LIBRARY = "libc++";
307 | CLANG_ENABLE_MODULES = YES;
308 | CLANG_ENABLE_OBJC_ARC = YES;
309 | CLANG_WARN_BOOL_CONVERSION = YES;
310 | CLANG_WARN_CONSTANT_CONVERSION = YES;
311 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
312 | CLANG_WARN_EMPTY_BODY = YES;
313 | CLANG_WARN_ENUM_CONVERSION = YES;
314 | CLANG_WARN_INT_CONVERSION = YES;
315 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
316 | CLANG_WARN_UNREACHABLE_CODE = YES;
317 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
318 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
319 | COPY_PHASE_STRIP = NO;
320 | CURRENT_PROJECT_VERSION = 1;
321 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
322 | ENABLE_NS_ASSERTIONS = NO;
323 | ENABLE_STRICT_OBJC_MSGSEND = YES;
324 | GCC_C_LANGUAGE_STANDARD = gnu99;
325 | GCC_NO_COMMON_BLOCKS = YES;
326 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
327 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
328 | GCC_WARN_UNDECLARED_SELECTOR = YES;
329 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
330 | GCC_WARN_UNUSED_FUNCTION = YES;
331 | GCC_WARN_UNUSED_VARIABLE = YES;
332 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
333 | MTL_ENABLE_DEBUG_INFO = NO;
334 | SDKROOT = iphoneos;
335 | TARGETED_DEVICE_FAMILY = "1,2";
336 | VALIDATE_PRODUCT = YES;
337 | VERSIONING_SYSTEM = "apple-generic";
338 | VERSION_INFO_PREFIX = "";
339 | };
340 | name = Release;
341 | };
342 | 007563F51BFA1AE1000ED5EB /* Debug */ = {
343 | isa = XCBuildConfiguration;
344 | buildSettings = {
345 | APPLICATION_EXTENSION_API_ONLY = YES;
346 | CLANG_ENABLE_MODULES = YES;
347 | DEFINES_MODULE = YES;
348 | DYLIB_COMPATIBILITY_VERSION = 1;
349 | DYLIB_CURRENT_VERSION = 1;
350 | DYLIB_INSTALL_NAME_BASE = "@rpath";
351 | INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
352 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
353 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
354 | PRODUCT_BUNDLE_IDENTIFIER = hotsoup.BinarySearch;
355 | PRODUCT_NAME = "$(TARGET_NAME)";
356 | SKIP_INSTALL = YES;
357 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
358 | SWIFT_VERSION = 3.0;
359 | };
360 | name = Debug;
361 | };
362 | 007563F61BFA1AE1000ED5EB /* Release */ = {
363 | isa = XCBuildConfiguration;
364 | buildSettings = {
365 | APPLICATION_EXTENSION_API_ONLY = YES;
366 | CLANG_ENABLE_MODULES = YES;
367 | DEFINES_MODULE = YES;
368 | DYLIB_COMPATIBILITY_VERSION = 1;
369 | DYLIB_CURRENT_VERSION = 1;
370 | DYLIB_INSTALL_NAME_BASE = "@rpath";
371 | INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
372 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
373 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
374 | PRODUCT_BUNDLE_IDENTIFIER = hotsoup.BinarySearch;
375 | PRODUCT_NAME = "$(TARGET_NAME)";
376 | SKIP_INSTALL = YES;
377 | SWIFT_VERSION = 3.0;
378 | };
379 | name = Release;
380 | };
381 | 007563F81BFA1AE1000ED5EB /* Debug */ = {
382 | isa = XCBuildConfiguration;
383 | buildSettings = {
384 | INFOPLIST_FILE = BinarySearchTests/Info.plist;
385 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
386 | PRODUCT_BUNDLE_IDENTIFIER = hotsoup.BinarySearchTests;
387 | PRODUCT_NAME = "$(TARGET_NAME)";
388 | SWIFT_VERSION = 3.0;
389 | };
390 | name = Debug;
391 | };
392 | 007563F91BFA1AE1000ED5EB /* Release */ = {
393 | isa = XCBuildConfiguration;
394 | buildSettings = {
395 | INFOPLIST_FILE = BinarySearchTests/Info.plist;
396 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
397 | PRODUCT_BUNDLE_IDENTIFIER = hotsoup.BinarySearchTests;
398 | PRODUCT_NAME = "$(TARGET_NAME)";
399 | SWIFT_VERSION = 3.0;
400 | };
401 | name = Release;
402 | };
403 | /* End XCBuildConfiguration section */
404 |
405 | /* Begin XCConfigurationList section */
406 | 007563DA1BFA1AE1000ED5EB /* Build configuration list for PBXProject "BinarySearch" */ = {
407 | isa = XCConfigurationList;
408 | buildConfigurations = (
409 | 007563F21BFA1AE1000ED5EB /* Debug */,
410 | 007563F31BFA1AE1000ED5EB /* Release */,
411 | );
412 | defaultConfigurationIsVisible = 0;
413 | defaultConfigurationName = Release;
414 | };
415 | 007563F41BFA1AE1000ED5EB /* Build configuration list for PBXNativeTarget "BinarySearch" */ = {
416 | isa = XCConfigurationList;
417 | buildConfigurations = (
418 | 007563F51BFA1AE1000ED5EB /* Debug */,
419 | 007563F61BFA1AE1000ED5EB /* Release */,
420 | );
421 | defaultConfigurationIsVisible = 0;
422 | defaultConfigurationName = Release;
423 | };
424 | 007563F71BFA1AE1000ED5EB /* Build configuration list for PBXNativeTarget "BinarySearchTests" */ = {
425 | isa = XCConfigurationList;
426 | buildConfigurations = (
427 | 007563F81BFA1AE1000ED5EB /* Debug */,
428 | 007563F91BFA1AE1000ED5EB /* Release */,
429 | );
430 | defaultConfigurationIsVisible = 0;
431 | defaultConfigurationName = Release;
432 | };
433 | /* End XCConfigurationList section */
434 | };
435 | rootObject = 007563D71BFA1AE1000ED5EB /* Project object */;
436 | }
437 |
--------------------------------------------------------------------------------