├── .github
└── workflows
│ ├── linux.yml
│ └── mac.yml
├── .gitignore
├── Configs
├── SortedArray.plist
└── SortedArrayTests.plist
├── LICENSE.txt
├── Package.swift
├── README.md
├── SortedArray.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── xcshareddata
│ ├── xcbaselines
│ └── DD7502791C68FCFC006590AF.xcbaseline
│ │ ├── 28BBA58F-EC4C-4E7A-943A-5B8FD5CC1F33.plist
│ │ └── Info.plist
│ └── xcschemes
│ ├── Performance-Tests-macOS.xcscheme
│ ├── SortedArray-iOS.xcscheme
│ ├── SortedArray-macOS.xcscheme
│ ├── SortedArray-tvOS.xcscheme
│ └── SortedArray-watchOS.xcscheme
├── Sources
└── SortedArray.swift
└── Tests
├── LinuxMain.swift
├── PerformanceTests
└── PerformanceTests.swift
└── UnitTests
├── SortedArrayTests.swift
└── TestHelpers.swift
/.github/workflows/linux.yml:
--------------------------------------------------------------------------------
1 | # GitHub actions documentation:
2 | # https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
3 | #
4 | # List of installed software for GitHub actions:
5 | # https://docs.github.com/en/actions/reference/software-installed-on-github-hosted-runners
6 |
7 | name: SwiftPM Linux
8 | on:
9 | push:
10 | workflow_dispatch:
11 |
12 | jobs:
13 | linux-swiftpm:
14 | name: Build and run tests
15 | runs-on: ubuntu-20.04
16 | # Ubuntu 20.04: Focal
17 | # Ubuntu 18.04: Xenial
18 | container: swift:focal
19 | steps:
20 | - uses: actions/checkout@v2
21 | - name: Print Swift version
22 | run: swift --version
23 | - name: Run tests
24 | run: swift test
25 |
--------------------------------------------------------------------------------
/.github/workflows/mac.yml:
--------------------------------------------------------------------------------
1 | # GitHub actions documentation:
2 | # https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
3 | #
4 | # List of installed software for GitHub actions:
5 | # https://docs.github.com/en/actions/reference/software-installed-on-github-hosted-runners
6 |
7 | name: SwiftPM Mac
8 | on:
9 | push:
10 | workflow_dispatch:
11 |
12 | jobs:
13 | macos-swiftpm:
14 | name: Build and run tests
15 | runs-on: macOS-latest
16 | # Set DEVELOPER_DIR to customize Xcode version
17 | # env:
18 | # DEVELOPER_DIR: /Applications/Xcode_12.app
19 | steps:
20 | - uses: actions/checkout@v2
21 | - name: Print Swift version
22 | run: swift --version
23 | - name: Run SwiftPM tests
24 | run: swift test
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 |
--------------------------------------------------------------------------------
/Configs/SortedArray.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 | 0.6.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2017 Ole Begemann. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Configs/SortedArrayTests.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 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 Ole Begemann
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
19 | OR OTHER DEALINGS IN THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:4.0
2 | import PackageDescription
3 |
4 | /// Provides the `SortedArray` type, an array that keeps its elements
5 | /// sorted according to a given sort predicate.
6 | ///
7 | /// - Author: Ole Begemann
8 | /// - Seealso: https://github.com/ole/SortedArray
9 | /// - Seealso: https://blog/2017/02/sorted-array/
10 | ///
11 | let package = Package(
12 | name: "SortedArray",
13 | products: [
14 | .library(
15 | name: "SortedArray",
16 | targets: ["SortedArray"]),
17 | ],
18 | targets: [
19 | .target(
20 | name: "SortedArray",
21 | dependencies: [],
22 | path: "Sources"),
23 | .testTarget(
24 | name: "UnitTests",
25 | dependencies: ["SortedArray"]),
26 | .testTarget(
27 | name: "PerformanceTests",
28 | dependencies: ["SortedArray"]),
29 | ],
30 | swiftLanguageVersions: [4]
31 | )
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SortedArray
2 |
3 | A sorted array type for Swift 4.0+.
4 |
5 | Provides the `SortedArray` type, an array that keeps its elements sorted according to a given sort predicate.
6 |
7 | Written by Ole Begemann, February 2017.
8 |
9 | For more info, see the [GitHub repo](https://github.com/ole/SortedArray) and my accompanying [blog article](https://oleb.net/blog/2017/02/sorted-array/).
10 |
11 | ## Supported Platforms
12 |
13 | The current release supports Swift 4.0 and up.
14 |
15 | If you need support for older Swift version, here's a list of the latest releases that support specific Swift versions:
16 |
17 | | Swift version | Latest SortedArray release |
18 | | ------------- | -------------------------- |
19 | | 4.x | master |
20 | | 3.x | [0.6.0](https://github.com/ole/SortedArray/releases/tag/0.6.0) |
21 | | 3.0 | [0.4](https://github.com/ole/SortedArray/releases/tag/0.4.0) |
22 |
23 | Since the code has no dependencies other than the Swift standard library (it doesn't even use Foundation), it should work on all platforms where Swift is available.
24 |
25 | I tested it on macOS, iOS, tvOS, and Linux.
26 |
27 | ## Usage
28 |
29 | ### Swift Package Manager
30 |
31 | Add this to your `Package.swift` file:
32 |
33 | ```swift
34 | // Package.swift
35 | import PackageDescription
36 |
37 | let package = Package(
38 | name: "",
39 | dependencies: [
40 | .Package(url: "https://github.com/ole/SortedArray.git", majorVersion: 0)
41 | ]
42 | )
43 | ```
44 |
45 | ### Carthage
46 |
47 | Add this to your `Cartfile`:
48 |
49 | ```
50 | github "ole/SortedArray" ~> 0.7
51 | ```
52 |
53 | Integration via Carthage should work for macOS, iOS, tvOS, and watchOS targets.
54 |
55 | ### Manually
56 |
57 | Clone the repository and add or copy `SortedArray.swift` to your project. It has no dependencies.
58 |
59 | ## Dependencies
60 |
61 | None.
62 |
63 | ## License
64 |
65 | [MIT license](https://github.com/ole/SortedArray/blob/master/LICENSE.txt).
66 |
--------------------------------------------------------------------------------
/SortedArray.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 47;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 52D6D9871BEFF229002C0205 /* SortedArray.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* SortedArray.framework */; };
11 | 52D6D9981BEFF375002C0205 /* SortedArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D6D9961BEFF375002C0205 /* SortedArray.swift */; };
12 | 52D6D9EA1BEFFFA4002C0205 /* SortedArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D6D9961BEFF375002C0205 /* SortedArray.swift */; };
13 | 52D6DA091BF00081002C0205 /* SortedArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D6D9961BEFF375002C0205 /* SortedArray.swift */; };
14 | 52D6DA261BF00118002C0205 /* SortedArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D6D9961BEFF375002C0205 /* SortedArray.swift */; };
15 | 5DB8B87920D7FF5E00D463D6 /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB8B87520D7FF4600D463D6 /* PerformanceTests.swift */; };
16 | 5DB8B87A20D7FF5F00D463D6 /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB8B87520D7FF4600D463D6 /* PerformanceTests.swift */; };
17 | 5DB8B87B20D7FF5F00D463D6 /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB8B87520D7FF4600D463D6 /* PerformanceTests.swift */; };
18 | 5DB8B87C20D7FF6200D463D6 /* SortedArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB8B87720D7FF4600D463D6 /* SortedArrayTests.swift */; };
19 | 5DB8B87D20D7FF6200D463D6 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB8B87820D7FF4600D463D6 /* TestHelpers.swift */; };
20 | 5DB8B87E20D7FF6300D463D6 /* SortedArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB8B87720D7FF4600D463D6 /* SortedArrayTests.swift */; };
21 | 5DB8B87F20D7FF6300D463D6 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB8B87820D7FF4600D463D6 /* TestHelpers.swift */; };
22 | 5DB8B88020D7FF6300D463D6 /* SortedArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB8B87720D7FF4600D463D6 /* SortedArrayTests.swift */; };
23 | 5DB8B88120D7FF6300D463D6 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB8B87820D7FF4600D463D6 /* TestHelpers.swift */; };
24 | DD7502881C68FEDE006590AF /* SortedArray.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6DA0F1BF000BD002C0205 /* SortedArray.framework */; };
25 | DD7502921C690C7A006590AF /* SortedArray.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D9F01BEFFFBE002C0205 /* SortedArray.framework */; };
26 | /* End PBXBuildFile section */
27 |
28 | /* Begin PBXContainerItemProxy section */
29 | 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */ = {
30 | isa = PBXContainerItemProxy;
31 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */;
32 | proxyType = 1;
33 | remoteGlobalIDString = 52D6D97B1BEFF229002C0205;
34 | remoteInfo = SortedArray;
35 | };
36 | DD7502801C68FCFC006590AF /* PBXContainerItemProxy */ = {
37 | isa = PBXContainerItemProxy;
38 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */;
39 | proxyType = 1;
40 | remoteGlobalIDString = 52D6DA0E1BF000BD002C0205;
41 | remoteInfo = "SortedArray-macOS";
42 | };
43 | DD7502931C690C7A006590AF /* PBXContainerItemProxy */ = {
44 | isa = PBXContainerItemProxy;
45 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */;
46 | proxyType = 1;
47 | remoteGlobalIDString = 52D6D9EF1BEFFFBE002C0205;
48 | remoteInfo = "SortedArray-tvOS";
49 | };
50 | /* End PBXContainerItemProxy section */
51 |
52 | /* Begin PBXFileReference section */
53 | 52D6D97C1BEFF229002C0205 /* SortedArray.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SortedArray.framework; sourceTree = BUILT_PRODUCTS_DIR; };
54 | 52D6D9861BEFF229002C0205 /* SortedArray-iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SortedArray-iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
55 | 52D6D9961BEFF375002C0205 /* SortedArray.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SortedArray.swift; path = Sources/SortedArray.swift; sourceTree = ""; };
56 | 52D6D9E21BEFFF6E002C0205 /* SortedArray.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SortedArray.framework; sourceTree = BUILT_PRODUCTS_DIR; };
57 | 52D6D9F01BEFFFBE002C0205 /* SortedArray.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SortedArray.framework; sourceTree = BUILT_PRODUCTS_DIR; };
58 | 52D6DA0F1BF000BD002C0205 /* SortedArray.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SortedArray.framework; sourceTree = BUILT_PRODUCTS_DIR; };
59 | 5D7AAFCC20D71F4200080885 /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; };
60 | 5D7AAFCD20D71F4200080885 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; };
61 | 5D7AAFCE20D71F4200080885 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
62 | 5D7AAFD020D722B100080885 /* travis-build-script.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "travis-build-script.sh"; sourceTree = ""; };
63 | 5D7AAFD120D7231E00080885 /* .travis.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .travis.yml; sourceTree = ""; };
64 | 5DB8B87320D7FF4600D463D6 /* LinuxMain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinuxMain.swift; sourceTree = ""; };
65 | 5DB8B87520D7FF4600D463D6 /* PerformanceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PerformanceTests.swift; sourceTree = ""; };
66 | 5DB8B87720D7FF4600D463D6 /* SortedArrayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SortedArrayTests.swift; sourceTree = ""; };
67 | 5DB8B87820D7FF4600D463D6 /* TestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = ""; };
68 | AD2FAA261CD0B6D800659CF4 /* SortedArray.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = SortedArray.plist; sourceTree = ""; };
69 | AD2FAA281CD0B6E100659CF4 /* SortedArrayTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = SortedArrayTests.plist; sourceTree = ""; };
70 | DD75027A1C68FCFC006590AF /* SortedArray-macOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SortedArray-macOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
71 | DD75028D1C690C7A006590AF /* SortedArray-tvOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SortedArray-tvOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
72 | /* End PBXFileReference section */
73 |
74 | /* Begin PBXFrameworksBuildPhase section */
75 | 52D6D9781BEFF229002C0205 /* Frameworks */ = {
76 | isa = PBXFrameworksBuildPhase;
77 | buildActionMask = 2147483647;
78 | files = (
79 | );
80 | runOnlyForDeploymentPostprocessing = 0;
81 | };
82 | 52D6D9831BEFF229002C0205 /* Frameworks */ = {
83 | isa = PBXFrameworksBuildPhase;
84 | buildActionMask = 2147483647;
85 | files = (
86 | 52D6D9871BEFF229002C0205 /* SortedArray.framework in Frameworks */,
87 | );
88 | runOnlyForDeploymentPostprocessing = 0;
89 | };
90 | 52D6D9DE1BEFFF6E002C0205 /* Frameworks */ = {
91 | isa = PBXFrameworksBuildPhase;
92 | buildActionMask = 2147483647;
93 | files = (
94 | );
95 | runOnlyForDeploymentPostprocessing = 0;
96 | };
97 | 52D6D9EC1BEFFFBE002C0205 /* Frameworks */ = {
98 | isa = PBXFrameworksBuildPhase;
99 | buildActionMask = 2147483647;
100 | files = (
101 | );
102 | runOnlyForDeploymentPostprocessing = 0;
103 | };
104 | 52D6DA0B1BF000BD002C0205 /* Frameworks */ = {
105 | isa = PBXFrameworksBuildPhase;
106 | buildActionMask = 2147483647;
107 | files = (
108 | );
109 | runOnlyForDeploymentPostprocessing = 0;
110 | };
111 | DD7502771C68FCFC006590AF /* Frameworks */ = {
112 | isa = PBXFrameworksBuildPhase;
113 | buildActionMask = 2147483647;
114 | files = (
115 | DD7502881C68FEDE006590AF /* SortedArray.framework in Frameworks */,
116 | );
117 | runOnlyForDeploymentPostprocessing = 0;
118 | };
119 | DD75028A1C690C7A006590AF /* Frameworks */ = {
120 | isa = PBXFrameworksBuildPhase;
121 | buildActionMask = 2147483647;
122 | files = (
123 | DD7502921C690C7A006590AF /* SortedArray.framework in Frameworks */,
124 | );
125 | runOnlyForDeploymentPostprocessing = 0;
126 | };
127 | /* End PBXFrameworksBuildPhase section */
128 |
129 | /* Begin PBXGroup section */
130 | 52D6D9721BEFF229002C0205 = {
131 | isa = PBXGroup;
132 | children = (
133 | 52D6D9961BEFF375002C0205 /* SortedArray.swift */,
134 | 5DB8B87220D7FF4600D463D6 /* Tests */,
135 | 5D7AAFCB20D71F0800080885 /* Other files (not in any target) */,
136 | 5D7AAFCF20D722B100080885 /* scripts */,
137 | 52D6D99C1BEFF38C002C0205 /* Configs */,
138 | 52D6D97D1BEFF229002C0205 /* Products */,
139 | );
140 | sourceTree = "";
141 | };
142 | 52D6D97D1BEFF229002C0205 /* Products */ = {
143 | isa = PBXGroup;
144 | children = (
145 | 52D6D97C1BEFF229002C0205 /* SortedArray.framework */,
146 | 52D6D9861BEFF229002C0205 /* SortedArray-iOS Tests.xctest */,
147 | 52D6D9E21BEFFF6E002C0205 /* SortedArray.framework */,
148 | 52D6D9F01BEFFFBE002C0205 /* SortedArray.framework */,
149 | 52D6DA0F1BF000BD002C0205 /* SortedArray.framework */,
150 | DD75027A1C68FCFC006590AF /* SortedArray-macOS Tests.xctest */,
151 | DD75028D1C690C7A006590AF /* SortedArray-tvOS Tests.xctest */,
152 | );
153 | name = Products;
154 | sourceTree = "";
155 | };
156 | 52D6D99C1BEFF38C002C0205 /* Configs */ = {
157 | isa = PBXGroup;
158 | children = (
159 | DD7502721C68FC1B006590AF /* Frameworks */,
160 | DD7502731C68FC20006590AF /* Tests */,
161 | );
162 | path = Configs;
163 | sourceTree = "";
164 | };
165 | 5D7AAFCB20D71F0800080885 /* Other files (not in any target) */ = {
166 | isa = PBXGroup;
167 | children = (
168 | 5D7AAFCE20D71F4200080885 /* README.md */,
169 | 5D7AAFCC20D71F4200080885 /* LICENSE.txt */,
170 | 5D7AAFCD20D71F4200080885 /* Package.swift */,
171 | 5D7AAFD120D7231E00080885 /* .travis.yml */,
172 | );
173 | name = "Other files (not in any target)";
174 | sourceTree = "";
175 | };
176 | 5D7AAFCF20D722B100080885 /* scripts */ = {
177 | isa = PBXGroup;
178 | children = (
179 | 5D7AAFD020D722B100080885 /* travis-build-script.sh */,
180 | );
181 | path = scripts;
182 | sourceTree = "";
183 | };
184 | 5DB8B87220D7FF4600D463D6 /* Tests */ = {
185 | isa = PBXGroup;
186 | children = (
187 | 5DB8B87320D7FF4600D463D6 /* LinuxMain.swift */,
188 | 5DB8B87420D7FF4600D463D6 /* PerformanceTests */,
189 | 5DB8B87620D7FF4600D463D6 /* UnitTests */,
190 | );
191 | path = Tests;
192 | sourceTree = "";
193 | };
194 | 5DB8B87420D7FF4600D463D6 /* PerformanceTests */ = {
195 | isa = PBXGroup;
196 | children = (
197 | 5DB8B87520D7FF4600D463D6 /* PerformanceTests.swift */,
198 | );
199 | path = PerformanceTests;
200 | sourceTree = "";
201 | };
202 | 5DB8B87620D7FF4600D463D6 /* UnitTests */ = {
203 | isa = PBXGroup;
204 | children = (
205 | 5DB8B87720D7FF4600D463D6 /* SortedArrayTests.swift */,
206 | 5DB8B87820D7FF4600D463D6 /* TestHelpers.swift */,
207 | );
208 | path = UnitTests;
209 | sourceTree = "";
210 | };
211 | DD7502721C68FC1B006590AF /* Frameworks */ = {
212 | isa = PBXGroup;
213 | children = (
214 | AD2FAA261CD0B6D800659CF4 /* SortedArray.plist */,
215 | );
216 | name = Frameworks;
217 | sourceTree = "";
218 | };
219 | DD7502731C68FC20006590AF /* Tests */ = {
220 | isa = PBXGroup;
221 | children = (
222 | AD2FAA281CD0B6E100659CF4 /* SortedArrayTests.plist */,
223 | );
224 | name = Tests;
225 | sourceTree = "";
226 | };
227 | /* End PBXGroup section */
228 |
229 | /* Begin PBXHeadersBuildPhase section */
230 | 52D6D9791BEFF229002C0205 /* Headers */ = {
231 | isa = PBXHeadersBuildPhase;
232 | buildActionMask = 2147483647;
233 | files = (
234 | );
235 | runOnlyForDeploymentPostprocessing = 0;
236 | };
237 | 52D6D9DF1BEFFF6E002C0205 /* Headers */ = {
238 | isa = PBXHeadersBuildPhase;
239 | buildActionMask = 2147483647;
240 | files = (
241 | );
242 | runOnlyForDeploymentPostprocessing = 0;
243 | };
244 | 52D6D9ED1BEFFFBE002C0205 /* Headers */ = {
245 | isa = PBXHeadersBuildPhase;
246 | buildActionMask = 2147483647;
247 | files = (
248 | );
249 | runOnlyForDeploymentPostprocessing = 0;
250 | };
251 | 52D6DA0C1BF000BD002C0205 /* Headers */ = {
252 | isa = PBXHeadersBuildPhase;
253 | buildActionMask = 2147483647;
254 | files = (
255 | );
256 | runOnlyForDeploymentPostprocessing = 0;
257 | };
258 | /* End PBXHeadersBuildPhase section */
259 |
260 | /* Begin PBXNativeTarget section */
261 | 52D6D97B1BEFF229002C0205 /* SortedArray-iOS */ = {
262 | isa = PBXNativeTarget;
263 | buildConfigurationList = 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "SortedArray-iOS" */;
264 | buildPhases = (
265 | 52D6D9771BEFF229002C0205 /* Sources */,
266 | 52D6D9781BEFF229002C0205 /* Frameworks */,
267 | 52D6D9791BEFF229002C0205 /* Headers */,
268 | 52D6D97A1BEFF229002C0205 /* Resources */,
269 | );
270 | buildRules = (
271 | );
272 | dependencies = (
273 | );
274 | name = "SortedArray-iOS";
275 | productName = SortedArray;
276 | productReference = 52D6D97C1BEFF229002C0205 /* SortedArray.framework */;
277 | productType = "com.apple.product-type.framework";
278 | };
279 | 52D6D9851BEFF229002C0205 /* SortedArray-iOS Tests */ = {
280 | isa = PBXNativeTarget;
281 | buildConfigurationList = 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "SortedArray-iOS Tests" */;
282 | buildPhases = (
283 | 52D6D9821BEFF229002C0205 /* Sources */,
284 | 52D6D9831BEFF229002C0205 /* Frameworks */,
285 | 52D6D9841BEFF229002C0205 /* Resources */,
286 | );
287 | buildRules = (
288 | );
289 | dependencies = (
290 | 52D6D9891BEFF229002C0205 /* PBXTargetDependency */,
291 | );
292 | name = "SortedArray-iOS Tests";
293 | productName = SortedArrayTests;
294 | productReference = 52D6D9861BEFF229002C0205 /* SortedArray-iOS Tests.xctest */;
295 | productType = "com.apple.product-type.bundle.unit-test";
296 | };
297 | 52D6D9E11BEFFF6E002C0205 /* SortedArray-watchOS */ = {
298 | isa = PBXNativeTarget;
299 | buildConfigurationList = 52D6D9E71BEFFF6E002C0205 /* Build configuration list for PBXNativeTarget "SortedArray-watchOS" */;
300 | buildPhases = (
301 | 52D6D9DD1BEFFF6E002C0205 /* Sources */,
302 | 52D6D9DE1BEFFF6E002C0205 /* Frameworks */,
303 | 52D6D9DF1BEFFF6E002C0205 /* Headers */,
304 | 52D6D9E01BEFFF6E002C0205 /* Resources */,
305 | );
306 | buildRules = (
307 | );
308 | dependencies = (
309 | );
310 | name = "SortedArray-watchOS";
311 | productName = "SortedArray-watchOS";
312 | productReference = 52D6D9E21BEFFF6E002C0205 /* SortedArray.framework */;
313 | productType = "com.apple.product-type.framework";
314 | };
315 | 52D6D9EF1BEFFFBE002C0205 /* SortedArray-tvOS */ = {
316 | isa = PBXNativeTarget;
317 | buildConfigurationList = 52D6DA011BEFFFBE002C0205 /* Build configuration list for PBXNativeTarget "SortedArray-tvOS" */;
318 | buildPhases = (
319 | 52D6D9EB1BEFFFBE002C0205 /* Sources */,
320 | 52D6D9EC1BEFFFBE002C0205 /* Frameworks */,
321 | 52D6D9ED1BEFFFBE002C0205 /* Headers */,
322 | 52D6D9EE1BEFFFBE002C0205 /* Resources */,
323 | );
324 | buildRules = (
325 | );
326 | dependencies = (
327 | );
328 | name = "SortedArray-tvOS";
329 | productName = "SortedArray-tvOS";
330 | productReference = 52D6D9F01BEFFFBE002C0205 /* SortedArray.framework */;
331 | productType = "com.apple.product-type.framework";
332 | };
333 | 52D6DA0E1BF000BD002C0205 /* SortedArray-macOS */ = {
334 | isa = PBXNativeTarget;
335 | buildConfigurationList = 52D6DA201BF000BD002C0205 /* Build configuration list for PBXNativeTarget "SortedArray-macOS" */;
336 | buildPhases = (
337 | 52D6DA0A1BF000BD002C0205 /* Sources */,
338 | 52D6DA0B1BF000BD002C0205 /* Frameworks */,
339 | 52D6DA0C1BF000BD002C0205 /* Headers */,
340 | 52D6DA0D1BF000BD002C0205 /* Resources */,
341 | );
342 | buildRules = (
343 | );
344 | dependencies = (
345 | );
346 | name = "SortedArray-macOS";
347 | productName = "SortedArray-macOS";
348 | productReference = 52D6DA0F1BF000BD002C0205 /* SortedArray.framework */;
349 | productType = "com.apple.product-type.framework";
350 | };
351 | DD7502791C68FCFC006590AF /* SortedArray-macOS Tests */ = {
352 | isa = PBXNativeTarget;
353 | buildConfigurationList = DD7502821C68FCFC006590AF /* Build configuration list for PBXNativeTarget "SortedArray-macOS Tests" */;
354 | buildPhases = (
355 | DD7502761C68FCFC006590AF /* Sources */,
356 | DD7502771C68FCFC006590AF /* Frameworks */,
357 | DD7502781C68FCFC006590AF /* Resources */,
358 | );
359 | buildRules = (
360 | );
361 | dependencies = (
362 | DD7502811C68FCFC006590AF /* PBXTargetDependency */,
363 | );
364 | name = "SortedArray-macOS Tests";
365 | productName = "SortedArray-OS Tests";
366 | productReference = DD75027A1C68FCFC006590AF /* SortedArray-macOS Tests.xctest */;
367 | productType = "com.apple.product-type.bundle.unit-test";
368 | };
369 | DD75028C1C690C7A006590AF /* SortedArray-tvOS Tests */ = {
370 | isa = PBXNativeTarget;
371 | buildConfigurationList = DD7502951C690C7A006590AF /* Build configuration list for PBXNativeTarget "SortedArray-tvOS Tests" */;
372 | buildPhases = (
373 | DD7502891C690C7A006590AF /* Sources */,
374 | DD75028A1C690C7A006590AF /* Frameworks */,
375 | DD75028B1C690C7A006590AF /* Resources */,
376 | );
377 | buildRules = (
378 | );
379 | dependencies = (
380 | DD7502941C690C7A006590AF /* PBXTargetDependency */,
381 | );
382 | name = "SortedArray-tvOS Tests";
383 | productName = "SortedArray-tvOS Tests";
384 | productReference = DD75028D1C690C7A006590AF /* SortedArray-tvOS Tests.xctest */;
385 | productType = "com.apple.product-type.bundle.unit-test";
386 | };
387 | /* End PBXNativeTarget section */
388 |
389 | /* Begin PBXProject section */
390 | 52D6D9731BEFF229002C0205 /* Project object */ = {
391 | isa = PBXProject;
392 | attributes = {
393 | LastSwiftUpdateCheck = 0720;
394 | LastUpgradeCheck = 1000;
395 | ORGANIZATIONNAME = SortedArray;
396 | TargetAttributes = {
397 | 52D6D97B1BEFF229002C0205 = {
398 | CreatedOnToolsVersion = 7.1;
399 | LastSwiftMigration = 0900;
400 | };
401 | 52D6D9851BEFF229002C0205 = {
402 | CreatedOnToolsVersion = 7.1;
403 | LastSwiftMigration = 0900;
404 | };
405 | 52D6D9E11BEFFF6E002C0205 = {
406 | CreatedOnToolsVersion = 7.1;
407 | LastSwiftMigration = 0900;
408 | };
409 | 52D6D9EF1BEFFFBE002C0205 = {
410 | CreatedOnToolsVersion = 7.1;
411 | LastSwiftMigration = 0900;
412 | };
413 | 52D6DA0E1BF000BD002C0205 = {
414 | CreatedOnToolsVersion = 7.1;
415 | LastSwiftMigration = 0900;
416 | };
417 | DD7502791C68FCFC006590AF = {
418 | CreatedOnToolsVersion = 7.2.1;
419 | LastSwiftMigration = 0900;
420 | };
421 | DD75028C1C690C7A006590AF = {
422 | CreatedOnToolsVersion = 7.2.1;
423 | LastSwiftMigration = 0900;
424 | };
425 | };
426 | };
427 | buildConfigurationList = 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "SortedArray" */;
428 | compatibilityVersion = "Xcode 6.3";
429 | developmentRegion = English;
430 | hasScannedForEncodings = 0;
431 | knownRegions = (
432 | en,
433 | );
434 | mainGroup = 52D6D9721BEFF229002C0205;
435 | productRefGroup = 52D6D97D1BEFF229002C0205 /* Products */;
436 | projectDirPath = "";
437 | projectRoot = "";
438 | targets = (
439 | 52D6D97B1BEFF229002C0205 /* SortedArray-iOS */,
440 | 52D6DA0E1BF000BD002C0205 /* SortedArray-macOS */,
441 | 52D6D9E11BEFFF6E002C0205 /* SortedArray-watchOS */,
442 | 52D6D9EF1BEFFFBE002C0205 /* SortedArray-tvOS */,
443 | 52D6D9851BEFF229002C0205 /* SortedArray-iOS Tests */,
444 | DD7502791C68FCFC006590AF /* SortedArray-macOS Tests */,
445 | DD75028C1C690C7A006590AF /* SortedArray-tvOS Tests */,
446 | );
447 | };
448 | /* End PBXProject section */
449 |
450 | /* Begin PBXResourcesBuildPhase section */
451 | 52D6D97A1BEFF229002C0205 /* Resources */ = {
452 | isa = PBXResourcesBuildPhase;
453 | buildActionMask = 2147483647;
454 | files = (
455 | );
456 | runOnlyForDeploymentPostprocessing = 0;
457 | };
458 | 52D6D9841BEFF229002C0205 /* Resources */ = {
459 | isa = PBXResourcesBuildPhase;
460 | buildActionMask = 2147483647;
461 | files = (
462 | );
463 | runOnlyForDeploymentPostprocessing = 0;
464 | };
465 | 52D6D9E01BEFFF6E002C0205 /* Resources */ = {
466 | isa = PBXResourcesBuildPhase;
467 | buildActionMask = 2147483647;
468 | files = (
469 | );
470 | runOnlyForDeploymentPostprocessing = 0;
471 | };
472 | 52D6D9EE1BEFFFBE002C0205 /* Resources */ = {
473 | isa = PBXResourcesBuildPhase;
474 | buildActionMask = 2147483647;
475 | files = (
476 | );
477 | runOnlyForDeploymentPostprocessing = 0;
478 | };
479 | 52D6DA0D1BF000BD002C0205 /* Resources */ = {
480 | isa = PBXResourcesBuildPhase;
481 | buildActionMask = 2147483647;
482 | files = (
483 | );
484 | runOnlyForDeploymentPostprocessing = 0;
485 | };
486 | DD7502781C68FCFC006590AF /* Resources */ = {
487 | isa = PBXResourcesBuildPhase;
488 | buildActionMask = 2147483647;
489 | files = (
490 | );
491 | runOnlyForDeploymentPostprocessing = 0;
492 | };
493 | DD75028B1C690C7A006590AF /* Resources */ = {
494 | isa = PBXResourcesBuildPhase;
495 | buildActionMask = 2147483647;
496 | files = (
497 | );
498 | runOnlyForDeploymentPostprocessing = 0;
499 | };
500 | /* End PBXResourcesBuildPhase section */
501 |
502 | /* Begin PBXSourcesBuildPhase section */
503 | 52D6D9771BEFF229002C0205 /* Sources */ = {
504 | isa = PBXSourcesBuildPhase;
505 | buildActionMask = 2147483647;
506 | files = (
507 | 52D6D9981BEFF375002C0205 /* SortedArray.swift in Sources */,
508 | );
509 | runOnlyForDeploymentPostprocessing = 0;
510 | };
511 | 52D6D9821BEFF229002C0205 /* Sources */ = {
512 | isa = PBXSourcesBuildPhase;
513 | buildActionMask = 2147483647;
514 | files = (
515 | 5DB8B87C20D7FF6200D463D6 /* SortedArrayTests.swift in Sources */,
516 | 5DB8B87920D7FF5E00D463D6 /* PerformanceTests.swift in Sources */,
517 | 5DB8B87D20D7FF6200D463D6 /* TestHelpers.swift in Sources */,
518 | );
519 | runOnlyForDeploymentPostprocessing = 0;
520 | };
521 | 52D6D9DD1BEFFF6E002C0205 /* Sources */ = {
522 | isa = PBXSourcesBuildPhase;
523 | buildActionMask = 2147483647;
524 | files = (
525 | 52D6D9EA1BEFFFA4002C0205 /* SortedArray.swift in Sources */,
526 | );
527 | runOnlyForDeploymentPostprocessing = 0;
528 | };
529 | 52D6D9EB1BEFFFBE002C0205 /* Sources */ = {
530 | isa = PBXSourcesBuildPhase;
531 | buildActionMask = 2147483647;
532 | files = (
533 | 52D6DA091BF00081002C0205 /* SortedArray.swift in Sources */,
534 | );
535 | runOnlyForDeploymentPostprocessing = 0;
536 | };
537 | 52D6DA0A1BF000BD002C0205 /* Sources */ = {
538 | isa = PBXSourcesBuildPhase;
539 | buildActionMask = 2147483647;
540 | files = (
541 | 52D6DA261BF00118002C0205 /* SortedArray.swift in Sources */,
542 | );
543 | runOnlyForDeploymentPostprocessing = 0;
544 | };
545 | DD7502761C68FCFC006590AF /* Sources */ = {
546 | isa = PBXSourcesBuildPhase;
547 | buildActionMask = 2147483647;
548 | files = (
549 | 5DB8B87E20D7FF6300D463D6 /* SortedArrayTests.swift in Sources */,
550 | 5DB8B87A20D7FF5F00D463D6 /* PerformanceTests.swift in Sources */,
551 | 5DB8B87F20D7FF6300D463D6 /* TestHelpers.swift in Sources */,
552 | );
553 | runOnlyForDeploymentPostprocessing = 0;
554 | };
555 | DD7502891C690C7A006590AF /* Sources */ = {
556 | isa = PBXSourcesBuildPhase;
557 | buildActionMask = 2147483647;
558 | files = (
559 | 5DB8B88020D7FF6300D463D6 /* SortedArrayTests.swift in Sources */,
560 | 5DB8B87B20D7FF5F00D463D6 /* PerformanceTests.swift in Sources */,
561 | 5DB8B88120D7FF6300D463D6 /* TestHelpers.swift in Sources */,
562 | );
563 | runOnlyForDeploymentPostprocessing = 0;
564 | };
565 | /* End PBXSourcesBuildPhase section */
566 |
567 | /* Begin PBXTargetDependency section */
568 | 52D6D9891BEFF229002C0205 /* PBXTargetDependency */ = {
569 | isa = PBXTargetDependency;
570 | target = 52D6D97B1BEFF229002C0205 /* SortedArray-iOS */;
571 | targetProxy = 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */;
572 | };
573 | DD7502811C68FCFC006590AF /* PBXTargetDependency */ = {
574 | isa = PBXTargetDependency;
575 | target = 52D6DA0E1BF000BD002C0205 /* SortedArray-macOS */;
576 | targetProxy = DD7502801C68FCFC006590AF /* PBXContainerItemProxy */;
577 | };
578 | DD7502941C690C7A006590AF /* PBXTargetDependency */ = {
579 | isa = PBXTargetDependency;
580 | target = 52D6D9EF1BEFFFBE002C0205 /* SortedArray-tvOS */;
581 | targetProxy = DD7502931C690C7A006590AF /* PBXContainerItemProxy */;
582 | };
583 | /* End PBXTargetDependency section */
584 |
585 | /* Begin XCBuildConfiguration section */
586 | 52D6D98E1BEFF229002C0205 /* Debug */ = {
587 | isa = XCBuildConfiguration;
588 | buildSettings = {
589 | ALWAYS_SEARCH_USER_PATHS = NO;
590 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
591 | CLANG_CXX_LIBRARY = "libc++";
592 | CLANG_ENABLE_MODULES = YES;
593 | CLANG_ENABLE_OBJC_ARC = YES;
594 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
595 | CLANG_WARN_BOOL_CONVERSION = YES;
596 | CLANG_WARN_COMMA = YES;
597 | CLANG_WARN_CONSTANT_CONVERSION = YES;
598 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
599 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
600 | CLANG_WARN_EMPTY_BODY = YES;
601 | CLANG_WARN_ENUM_CONVERSION = YES;
602 | CLANG_WARN_INFINITE_RECURSION = YES;
603 | CLANG_WARN_INT_CONVERSION = YES;
604 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
605 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
606 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
607 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
608 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
609 | CLANG_WARN_STRICT_PROTOTYPES = YES;
610 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
611 | CLANG_WARN_UNREACHABLE_CODE = YES;
612 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
613 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
614 | COPY_PHASE_STRIP = NO;
615 | CURRENT_PROJECT_VERSION = 1;
616 | DEBUG_INFORMATION_FORMAT = dwarf;
617 | ENABLE_STRICT_OBJC_MSGSEND = YES;
618 | ENABLE_TESTABILITY = YES;
619 | GCC_C_LANGUAGE_STANDARD = gnu99;
620 | GCC_DYNAMIC_NO_PIC = NO;
621 | GCC_NO_COMMON_BLOCKS = YES;
622 | GCC_OPTIMIZATION_LEVEL = 0;
623 | GCC_PREPROCESSOR_DEFINITIONS = (
624 | "DEBUG=1",
625 | "$(inherited)",
626 | );
627 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
628 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
629 | GCC_WARN_UNDECLARED_SELECTOR = YES;
630 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
631 | GCC_WARN_UNUSED_FUNCTION = YES;
632 | GCC_WARN_UNUSED_VARIABLE = YES;
633 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
634 | MTL_ENABLE_DEBUG_INFO = YES;
635 | ONLY_ACTIVE_ARCH = YES;
636 | SDKROOT = iphoneos;
637 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
638 | SWIFT_VERSION = 4.0;
639 | TARGETED_DEVICE_FAMILY = "1,2";
640 | VERSIONING_SYSTEM = "apple-generic";
641 | VERSION_INFO_PREFIX = "";
642 | };
643 | name = Debug;
644 | };
645 | 52D6D98F1BEFF229002C0205 /* Release */ = {
646 | isa = XCBuildConfiguration;
647 | buildSettings = {
648 | ALWAYS_SEARCH_USER_PATHS = NO;
649 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
650 | CLANG_CXX_LIBRARY = "libc++";
651 | CLANG_ENABLE_MODULES = YES;
652 | CLANG_ENABLE_OBJC_ARC = YES;
653 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
654 | CLANG_WARN_BOOL_CONVERSION = YES;
655 | CLANG_WARN_COMMA = YES;
656 | CLANG_WARN_CONSTANT_CONVERSION = YES;
657 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
658 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
659 | CLANG_WARN_EMPTY_BODY = YES;
660 | CLANG_WARN_ENUM_CONVERSION = YES;
661 | CLANG_WARN_INFINITE_RECURSION = YES;
662 | CLANG_WARN_INT_CONVERSION = YES;
663 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
664 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
665 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
666 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
667 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
668 | CLANG_WARN_STRICT_PROTOTYPES = YES;
669 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
670 | CLANG_WARN_UNREACHABLE_CODE = YES;
671 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
672 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
673 | COPY_PHASE_STRIP = NO;
674 | CURRENT_PROJECT_VERSION = 1;
675 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
676 | ENABLE_NS_ASSERTIONS = NO;
677 | ENABLE_STRICT_OBJC_MSGSEND = YES;
678 | GCC_C_LANGUAGE_STANDARD = gnu99;
679 | GCC_NO_COMMON_BLOCKS = YES;
680 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
681 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
682 | GCC_WARN_UNDECLARED_SELECTOR = YES;
683 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
684 | GCC_WARN_UNUSED_FUNCTION = YES;
685 | GCC_WARN_UNUSED_VARIABLE = YES;
686 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
687 | MTL_ENABLE_DEBUG_INFO = NO;
688 | SDKROOT = iphoneos;
689 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
690 | SWIFT_VERSION = 4.0;
691 | TARGETED_DEVICE_FAMILY = "1,2";
692 | VALIDATE_PRODUCT = YES;
693 | VERSIONING_SYSTEM = "apple-generic";
694 | VERSION_INFO_PREFIX = "";
695 | };
696 | name = Release;
697 | };
698 | 52D6D9911BEFF229002C0205 /* Debug */ = {
699 | isa = XCBuildConfiguration;
700 | buildSettings = {
701 | APPLICATION_EXTENSION_API_ONLY = YES;
702 | CLANG_ENABLE_MODULES = YES;
703 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
704 | DEFINES_MODULE = YES;
705 | DYLIB_COMPATIBILITY_VERSION = 1;
706 | DYLIB_CURRENT_VERSION = 1;
707 | DYLIB_INSTALL_NAME_BASE = "@rpath";
708 | INFOPLIST_FILE = Configs/SortedArray.plist;
709 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
710 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
711 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
712 | ONLY_ACTIVE_ARCH = NO;
713 | PRODUCT_BUNDLE_IDENTIFIER = "com.olebegemann.SortedArray-iOS";
714 | PRODUCT_NAME = SortedArray;
715 | SKIP_INSTALL = YES;
716 | };
717 | name = Debug;
718 | };
719 | 52D6D9921BEFF229002C0205 /* Release */ = {
720 | isa = XCBuildConfiguration;
721 | buildSettings = {
722 | APPLICATION_EXTENSION_API_ONLY = YES;
723 | CLANG_ENABLE_MODULES = YES;
724 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
725 | DEFINES_MODULE = YES;
726 | DYLIB_COMPATIBILITY_VERSION = 1;
727 | DYLIB_CURRENT_VERSION = 1;
728 | DYLIB_INSTALL_NAME_BASE = "@rpath";
729 | INFOPLIST_FILE = Configs/SortedArray.plist;
730 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
731 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
732 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
733 | PRODUCT_BUNDLE_IDENTIFIER = "com.olebegemann.SortedArray-iOS";
734 | PRODUCT_NAME = SortedArray;
735 | SKIP_INSTALL = YES;
736 | };
737 | name = Release;
738 | };
739 | 52D6D9941BEFF229002C0205 /* Debug */ = {
740 | isa = XCBuildConfiguration;
741 | buildSettings = {
742 | CLANG_ENABLE_MODULES = YES;
743 | INFOPLIST_FILE = Configs/SortedArrayTests.plist;
744 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
745 | PRODUCT_BUNDLE_IDENTIFIER = "com.SortedArray.SortedArray-iOS-Tests";
746 | PRODUCT_NAME = "$(TARGET_NAME)";
747 | };
748 | name = Debug;
749 | };
750 | 52D6D9951BEFF229002C0205 /* Release */ = {
751 | isa = XCBuildConfiguration;
752 | buildSettings = {
753 | CLANG_ENABLE_MODULES = YES;
754 | INFOPLIST_FILE = Configs/SortedArrayTests.plist;
755 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
756 | PRODUCT_BUNDLE_IDENTIFIER = "com.SortedArray.SortedArray-iOS-Tests";
757 | PRODUCT_NAME = "$(TARGET_NAME)";
758 | };
759 | name = Release;
760 | };
761 | 52D6D9E81BEFFF6E002C0205 /* Debug */ = {
762 | isa = XCBuildConfiguration;
763 | buildSettings = {
764 | APPLICATION_EXTENSION_API_ONLY = YES;
765 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
766 | DEFINES_MODULE = YES;
767 | DYLIB_COMPATIBILITY_VERSION = 1;
768 | DYLIB_CURRENT_VERSION = 1;
769 | DYLIB_INSTALL_NAME_BASE = "@rpath";
770 | INFOPLIST_FILE = Configs/SortedArray.plist;
771 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
772 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
773 | PRODUCT_BUNDLE_IDENTIFIER = "com.olebegemann.SortedArray-watchOS";
774 | PRODUCT_NAME = SortedArray;
775 | SDKROOT = watchos;
776 | SKIP_INSTALL = YES;
777 | TARGETED_DEVICE_FAMILY = 4;
778 | WATCHOS_DEPLOYMENT_TARGET = 2.0;
779 | };
780 | name = Debug;
781 | };
782 | 52D6D9E91BEFFF6E002C0205 /* Release */ = {
783 | isa = XCBuildConfiguration;
784 | buildSettings = {
785 | APPLICATION_EXTENSION_API_ONLY = YES;
786 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
787 | DEFINES_MODULE = YES;
788 | DYLIB_COMPATIBILITY_VERSION = 1;
789 | DYLIB_CURRENT_VERSION = 1;
790 | DYLIB_INSTALL_NAME_BASE = "@rpath";
791 | INFOPLIST_FILE = Configs/SortedArray.plist;
792 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
793 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
794 | PRODUCT_BUNDLE_IDENTIFIER = "com.olebegemann.SortedArray-watchOS";
795 | PRODUCT_NAME = SortedArray;
796 | SDKROOT = watchos;
797 | SKIP_INSTALL = YES;
798 | TARGETED_DEVICE_FAMILY = 4;
799 | WATCHOS_DEPLOYMENT_TARGET = 2.0;
800 | };
801 | name = Release;
802 | };
803 | 52D6DA021BEFFFBE002C0205 /* Debug */ = {
804 | isa = XCBuildConfiguration;
805 | buildSettings = {
806 | APPLICATION_EXTENSION_API_ONLY = YES;
807 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
808 | DEFINES_MODULE = YES;
809 | DYLIB_COMPATIBILITY_VERSION = 1;
810 | DYLIB_CURRENT_VERSION = 1;
811 | DYLIB_INSTALL_NAME_BASE = "@rpath";
812 | INFOPLIST_FILE = Configs/SortedArray.plist;
813 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
814 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
815 | PRODUCT_BUNDLE_IDENTIFIER = "com.olebegemann.SortedArray-tvOS";
816 | PRODUCT_NAME = SortedArray;
817 | SDKROOT = appletvos;
818 | SKIP_INSTALL = YES;
819 | TARGETED_DEVICE_FAMILY = 3;
820 | TVOS_DEPLOYMENT_TARGET = 9.0;
821 | };
822 | name = Debug;
823 | };
824 | 52D6DA031BEFFFBE002C0205 /* Release */ = {
825 | isa = XCBuildConfiguration;
826 | buildSettings = {
827 | APPLICATION_EXTENSION_API_ONLY = YES;
828 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
829 | DEFINES_MODULE = YES;
830 | DYLIB_COMPATIBILITY_VERSION = 1;
831 | DYLIB_CURRENT_VERSION = 1;
832 | DYLIB_INSTALL_NAME_BASE = "@rpath";
833 | INFOPLIST_FILE = Configs/SortedArray.plist;
834 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
835 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
836 | PRODUCT_BUNDLE_IDENTIFIER = "com.olebegemann.SortedArray-tvOS";
837 | PRODUCT_NAME = SortedArray;
838 | SDKROOT = appletvos;
839 | SKIP_INSTALL = YES;
840 | TARGETED_DEVICE_FAMILY = 3;
841 | TVOS_DEPLOYMENT_TARGET = 9.0;
842 | };
843 | name = Release;
844 | };
845 | 52D6DA211BF000BD002C0205 /* Debug */ = {
846 | isa = XCBuildConfiguration;
847 | buildSettings = {
848 | APPLICATION_EXTENSION_API_ONLY = YES;
849 | CODE_SIGN_IDENTITY = "-";
850 | COMBINE_HIDPI_IMAGES = YES;
851 | DEFINES_MODULE = YES;
852 | DYLIB_COMPATIBILITY_VERSION = 1;
853 | DYLIB_CURRENT_VERSION = 1;
854 | DYLIB_INSTALL_NAME_BASE = "@rpath";
855 | FRAMEWORK_VERSION = A;
856 | INFOPLIST_FILE = Configs/SortedArray.plist;
857 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
858 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
859 | MACOSX_DEPLOYMENT_TARGET = 10.10;
860 | PRODUCT_BUNDLE_IDENTIFIER = "com.olebegemann.SortedArray-macOS";
861 | PRODUCT_NAME = SortedArray;
862 | SDKROOT = macosx;
863 | SKIP_INSTALL = YES;
864 | };
865 | name = Debug;
866 | };
867 | 52D6DA221BF000BD002C0205 /* Release */ = {
868 | isa = XCBuildConfiguration;
869 | buildSettings = {
870 | APPLICATION_EXTENSION_API_ONLY = YES;
871 | CODE_SIGN_IDENTITY = "-";
872 | COMBINE_HIDPI_IMAGES = YES;
873 | DEFINES_MODULE = YES;
874 | DYLIB_COMPATIBILITY_VERSION = 1;
875 | DYLIB_CURRENT_VERSION = 1;
876 | DYLIB_INSTALL_NAME_BASE = "@rpath";
877 | FRAMEWORK_VERSION = A;
878 | INFOPLIST_FILE = Configs/SortedArray.plist;
879 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
880 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
881 | MACOSX_DEPLOYMENT_TARGET = 10.10;
882 | PRODUCT_BUNDLE_IDENTIFIER = "com.olebegemann.SortedArray-macOS";
883 | PRODUCT_NAME = SortedArray;
884 | SDKROOT = macosx;
885 | SKIP_INSTALL = YES;
886 | };
887 | name = Release;
888 | };
889 | DD7502831C68FCFC006590AF /* Debug */ = {
890 | isa = XCBuildConfiguration;
891 | buildSettings = {
892 | CODE_SIGN_IDENTITY = "-";
893 | COMBINE_HIDPI_IMAGES = YES;
894 | INFOPLIST_FILE = Configs/SortedArrayTests.plist;
895 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
896 | MACOSX_DEPLOYMENT_TARGET = 10.11;
897 | PRODUCT_BUNDLE_IDENTIFIER = "com.SortedArray.SortedArray-macOS-Tests";
898 | PRODUCT_NAME = "$(TARGET_NAME)";
899 | SDKROOT = macosx;
900 | };
901 | name = Debug;
902 | };
903 | DD7502841C68FCFC006590AF /* Release */ = {
904 | isa = XCBuildConfiguration;
905 | buildSettings = {
906 | CODE_SIGN_IDENTITY = "-";
907 | COMBINE_HIDPI_IMAGES = YES;
908 | INFOPLIST_FILE = Configs/SortedArrayTests.plist;
909 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
910 | MACOSX_DEPLOYMENT_TARGET = 10.11;
911 | PRODUCT_BUNDLE_IDENTIFIER = "com.SortedArray.SortedArray-macOS-Tests";
912 | PRODUCT_NAME = "$(TARGET_NAME)";
913 | SDKROOT = macosx;
914 | };
915 | name = Release;
916 | };
917 | DD7502961C690C7A006590AF /* Debug */ = {
918 | isa = XCBuildConfiguration;
919 | buildSettings = {
920 | INFOPLIST_FILE = Configs/SortedArrayTests.plist;
921 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
922 | PRODUCT_BUNDLE_IDENTIFIER = "com.SortedArray.SortedArray-tvOS-Tests";
923 | PRODUCT_NAME = "$(TARGET_NAME)";
924 | SDKROOT = appletvos;
925 | TVOS_DEPLOYMENT_TARGET = 9.1;
926 | };
927 | name = Debug;
928 | };
929 | DD7502971C690C7A006590AF /* Release */ = {
930 | isa = XCBuildConfiguration;
931 | buildSettings = {
932 | INFOPLIST_FILE = Configs/SortedArrayTests.plist;
933 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
934 | PRODUCT_BUNDLE_IDENTIFIER = "com.SortedArray.SortedArray-tvOS-Tests";
935 | PRODUCT_NAME = "$(TARGET_NAME)";
936 | SDKROOT = appletvos;
937 | TVOS_DEPLOYMENT_TARGET = 9.1;
938 | };
939 | name = Release;
940 | };
941 | /* End XCBuildConfiguration section */
942 |
943 | /* Begin XCConfigurationList section */
944 | 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "SortedArray" */ = {
945 | isa = XCConfigurationList;
946 | buildConfigurations = (
947 | 52D6D98E1BEFF229002C0205 /* Debug */,
948 | 52D6D98F1BEFF229002C0205 /* Release */,
949 | );
950 | defaultConfigurationIsVisible = 0;
951 | defaultConfigurationName = Release;
952 | };
953 | 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "SortedArray-iOS" */ = {
954 | isa = XCConfigurationList;
955 | buildConfigurations = (
956 | 52D6D9911BEFF229002C0205 /* Debug */,
957 | 52D6D9921BEFF229002C0205 /* Release */,
958 | );
959 | defaultConfigurationIsVisible = 0;
960 | defaultConfigurationName = Release;
961 | };
962 | 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "SortedArray-iOS Tests" */ = {
963 | isa = XCConfigurationList;
964 | buildConfigurations = (
965 | 52D6D9941BEFF229002C0205 /* Debug */,
966 | 52D6D9951BEFF229002C0205 /* Release */,
967 | );
968 | defaultConfigurationIsVisible = 0;
969 | defaultConfigurationName = Release;
970 | };
971 | 52D6D9E71BEFFF6E002C0205 /* Build configuration list for PBXNativeTarget "SortedArray-watchOS" */ = {
972 | isa = XCConfigurationList;
973 | buildConfigurations = (
974 | 52D6D9E81BEFFF6E002C0205 /* Debug */,
975 | 52D6D9E91BEFFF6E002C0205 /* Release */,
976 | );
977 | defaultConfigurationIsVisible = 0;
978 | defaultConfigurationName = Release;
979 | };
980 | 52D6DA011BEFFFBE002C0205 /* Build configuration list for PBXNativeTarget "SortedArray-tvOS" */ = {
981 | isa = XCConfigurationList;
982 | buildConfigurations = (
983 | 52D6DA021BEFFFBE002C0205 /* Debug */,
984 | 52D6DA031BEFFFBE002C0205 /* Release */,
985 | );
986 | defaultConfigurationIsVisible = 0;
987 | defaultConfigurationName = Release;
988 | };
989 | 52D6DA201BF000BD002C0205 /* Build configuration list for PBXNativeTarget "SortedArray-macOS" */ = {
990 | isa = XCConfigurationList;
991 | buildConfigurations = (
992 | 52D6DA211BF000BD002C0205 /* Debug */,
993 | 52D6DA221BF000BD002C0205 /* Release */,
994 | );
995 | defaultConfigurationIsVisible = 0;
996 | defaultConfigurationName = Release;
997 | };
998 | DD7502821C68FCFC006590AF /* Build configuration list for PBXNativeTarget "SortedArray-macOS Tests" */ = {
999 | isa = XCConfigurationList;
1000 | buildConfigurations = (
1001 | DD7502831C68FCFC006590AF /* Debug */,
1002 | DD7502841C68FCFC006590AF /* Release */,
1003 | );
1004 | defaultConfigurationIsVisible = 0;
1005 | defaultConfigurationName = Release;
1006 | };
1007 | DD7502951C690C7A006590AF /* Build configuration list for PBXNativeTarget "SortedArray-tvOS Tests" */ = {
1008 | isa = XCConfigurationList;
1009 | buildConfigurations = (
1010 | DD7502961C690C7A006590AF /* Debug */,
1011 | DD7502971C690C7A006590AF /* Release */,
1012 | );
1013 | defaultConfigurationIsVisible = 0;
1014 | defaultConfigurationName = Release;
1015 | };
1016 | /* End XCConfigurationList section */
1017 | };
1018 | rootObject = 52D6D9731BEFF229002C0205 /* Project object */;
1019 | }
1020 |
--------------------------------------------------------------------------------
/SortedArray.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SortedArray.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SortedArray.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/SortedArray.xcodeproj/xcshareddata/xcbaselines/DD7502791C68FCFC006590AF.xcbaseline/28BBA58F-EC4C-4E7A-943A-5B8FD5CC1F33.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | classNames
6 |
7 | PerformanceTests
8 |
9 | testPerformanceOfIndexOf()
10 |
11 | com.apple.XCTPerformanceMetric_WallClockTime
12 |
13 | baselineAverage
14 | 7.1619e-05
15 | baselineIntegrationDisplayName
16 | 18. Jun 2018 at 17:12:56
17 |
18 |
19 | testPerformanceOfIndexOfObject()
20 |
21 | com.apple.XCTPerformanceMetric_WallClockTime
22 |
23 | baselineAverage
24 | 9.9912e-05
25 | baselineIntegrationDisplayName
26 | 18. Jun 2018 at 17:12:56
27 |
28 |
29 | testPerformanceOfIndexOfObjectInRange()
30 |
31 | com.apple.XCTPerformanceMetric_WallClockTime
32 |
33 | baselineAverage
34 | 2.2075e-05
35 | baselineIntegrationDisplayName
36 | 18. Jun 2018 at 17:12:56
37 |
38 |
39 | testPerformanceOfLastIndexOf()
40 |
41 | com.apple.XCTPerformanceMetric_WallClockTime
42 |
43 | baselineAverage
44 | 7.4486e-05
45 | baselineIntegrationDisplayName
46 | 18. Jun 2018 at 17:12:56
47 |
48 |
49 | testPerformanceOfLastIndexOfObject()
50 |
51 | com.apple.XCTPerformanceMetric_WallClockTime
52 |
53 | baselineAverage
54 | 5.5835e-05
55 | baselineIntegrationDisplayName
56 | 18. Jun 2018 at 17:12:56
57 |
58 |
59 | testPerformanceOfLastIndexOfObjectInRange()
60 |
61 | com.apple.XCTPerformanceMetric_WallClockTime
62 |
63 | baselineAverage
64 | 1.1141e-05
65 | baselineIntegrationDisplayName
66 | 18. Jun 2018 at 17:12:56
67 |
68 |
69 |
70 | SortedArrayTests
71 |
72 | testIndexOfPerformance()
73 |
74 | com.apple.XCTPerformanceMetric_WallClockTime
75 |
76 | baselineAverage
77 | 0.32278
78 | baselineIntegrationDisplayName
79 | Local Baseline
80 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/SortedArray.xcodeproj/xcshareddata/xcbaselines/DD7502791C68FCFC006590AF.xcbaseline/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | runDestinationsByUUID
6 |
7 | 28BBA58F-EC4C-4E7A-943A-5B8FD5CC1F33
8 |
9 | localComputer
10 |
11 | busSpeedInMHz
12 | 100
13 | cpuCount
14 | 1
15 | cpuKind
16 | Intel Core i7
17 | cpuSpeedInMHz
18 | 2600
19 | logicalCPUCoresPerPackage
20 | 8
21 | modelCode
22 | MacBookPro11,2
23 | physicalCPUCoresPerPackage
24 | 4
25 | platformIdentifier
26 | com.apple.platform.macosx
27 |
28 | targetArchitecture
29 | x86_64
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/SortedArray.xcodeproj/xcshareddata/xcschemes/Performance-Tests-macOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
35 |
41 |
42 |
43 |
45 |
46 |
47 |
48 |
49 |
50 |
56 |
57 |
58 |
59 |
60 |
61 |
71 |
72 |
78 |
79 |
80 |
81 |
82 |
83 |
89 |
90 |
96 |
97 |
98 |
99 |
101 |
102 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/SortedArray.xcodeproj/xcshareddata/xcschemes/SortedArray-iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
36 |
42 |
43 |
44 |
46 |
47 |
48 |
49 |
50 |
51 |
57 |
58 |
59 |
60 |
61 |
62 |
72 |
73 |
79 |
80 |
81 |
82 |
83 |
84 |
90 |
91 |
97 |
98 |
99 |
100 |
102 |
103 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/SortedArray.xcodeproj/xcshareddata/xcschemes/SortedArray-macOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
36 |
42 |
43 |
44 |
46 |
47 |
48 |
49 |
50 |
51 |
57 |
58 |
59 |
60 |
61 |
62 |
72 |
73 |
79 |
80 |
81 |
82 |
83 |
84 |
90 |
91 |
97 |
98 |
99 |
100 |
102 |
103 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/SortedArray.xcodeproj/xcshareddata/xcschemes/SortedArray-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
36 |
42 |
43 |
44 |
46 |
47 |
48 |
49 |
50 |
51 |
57 |
58 |
59 |
60 |
61 |
62 |
72 |
73 |
79 |
80 |
81 |
82 |
83 |
84 |
90 |
91 |
97 |
98 |
99 |
100 |
102 |
103 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/SortedArray.xcodeproj/xcshareddata/xcschemes/SortedArray-watchOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
71 |
72 |
73 |
74 |
76 |
77 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/Sources/SortedArray.swift:
--------------------------------------------------------------------------------
1 | import Foundation // Needed for ComparisonResult (used privately)
2 |
3 | /// An array that keeps its elements sorted at all times.
4 | public struct SortedArray {
5 | /// The backing store
6 | fileprivate var _elements: [Element]
7 |
8 | public typealias Comparator = (A, A) -> Bool
9 |
10 | /// The predicate that determines the array's sort order.
11 | fileprivate let areInIncreasingOrder: Comparator
12 |
13 | /// Initializes an empty array.
14 | ///
15 | /// - Parameter areInIncreasingOrder: The comparison predicate the array should use to sort its elements.
16 | public init(areInIncreasingOrder: @escaping Comparator) {
17 | self._elements = []
18 | self.areInIncreasingOrder = areInIncreasingOrder
19 | }
20 |
21 | /// Initializes the array with a sequence of unsorted elements and a comparison predicate.
22 | public init(unsorted: S, areInIncreasingOrder: @escaping Comparator) where S.Element == Element {
23 | let sorted = unsorted.sorted(by: areInIncreasingOrder)
24 | self._elements = sorted
25 | self.areInIncreasingOrder = areInIncreasingOrder
26 | }
27 |
28 | /// Initializes the array with a sequence that is already sorted according to the given comparison predicate.
29 | ///
30 | /// This is faster than `init(unsorted:areInIncreasingOrder:)` because the elements don't have to sorted again.
31 | ///
32 | /// - Precondition: `sorted` is sorted according to the given comparison predicate. If you violate this condition, the behavior is undefined.
33 | public init(sorted: S, areInIncreasingOrder: @escaping Comparator) where S.Element == Element {
34 | self._elements = Array(sorted)
35 | self.areInIncreasingOrder = areInIncreasingOrder
36 | }
37 |
38 | /// Inserts a new element into the array, preserving the sort order.
39 | ///
40 | /// - Returns: the index where the new element was inserted.
41 | /// - Complexity: O(_n_) where _n_ is the size of the array. O(_log n_) if the new
42 | /// element can be appended, i.e. if it is ordered last in the resulting array.
43 | @discardableResult
44 | public mutating func insert(_ newElement: Element) -> Index {
45 | let index = insertionIndex(for: newElement)
46 | // This should be O(1) if the element is to be inserted at the end,
47 | // O(_n) in the worst case (inserted at the front).
48 | _elements.insert(newElement, at: index)
49 | return index
50 | }
51 |
52 | /// Inserts all elements from `elements` into `self`, preserving the sort order.
53 | ///
54 | /// This can be faster than inserting the individual elements one after another because
55 | /// we only need to re-sort once.
56 | ///
57 | /// - Complexity: O(_n * log(n)_) where _n_ is the size of the resulting array.
58 | public mutating func insert(contentsOf newElements: S) where S.Element == Element {
59 | _elements.append(contentsOf: newElements)
60 | _elements.sort(by: areInIncreasingOrder)
61 | }
62 | }
63 |
64 | extension SortedArray where Element: Comparable {
65 | /// Initializes an empty sorted array. Uses `<` as the comparison predicate.
66 | public init() {
67 | self.init(areInIncreasingOrder: <)
68 | }
69 |
70 | /// Initializes the array with a sequence of unsorted elements. Uses `<` as the comparison predicate.
71 | public init(unsorted: S) where S.Element == Element {
72 | self.init(unsorted: unsorted, areInIncreasingOrder: <)
73 | }
74 |
75 | /// Initializes the array with a sequence that is already sorted according to the `<` comparison predicate. Uses `<` as the comparison predicate.
76 | ///
77 | /// This is faster than `init(unsorted:)` because the elements don't have to sorted again.
78 | ///
79 | /// - Precondition: `sorted` is sorted according to the `<` predicate. If you violate this condition, the behavior is undefined.
80 | public init(sorted: S) where S.Element == Element {
81 | self.init(sorted: sorted, areInIncreasingOrder: <)
82 | }
83 | }
84 |
85 | extension SortedArray: RandomAccessCollection {
86 | public typealias Index = Int
87 |
88 | public var startIndex: Index { return _elements.startIndex }
89 | public var endIndex: Index { return _elements.endIndex }
90 |
91 | public func index(after i: Index) -> Index {
92 | return _elements.index(after: i)
93 | }
94 |
95 | public func index(before i: Index) -> Index {
96 | return _elements.index(before: i)
97 | }
98 |
99 | public subscript(position: Index) -> Element {
100 | return _elements[position]
101 | }
102 | }
103 |
104 | extension SortedArray {
105 | /// Like `Sequence.filter(_:)`, but returns a `SortedArray` instead of an `Array`.
106 | /// We can do this efficiently because filtering doesn't change the sort order.
107 | public func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> SortedArray {
108 | let newElements = try _elements.filter(isIncluded)
109 | return SortedArray(sorted: newElements, areInIncreasingOrder: areInIncreasingOrder)
110 | }
111 | }
112 |
113 | extension SortedArray: CustomStringConvertible, CustomDebugStringConvertible {
114 | public var description: String {
115 | return "\(String(describing: _elements)) (sorted)"
116 | }
117 |
118 | public var debugDescription: String {
119 | return " \(String(reflecting: _elements))"
120 | }
121 | }
122 |
123 | // MARK: - Removing elements. This is mostly a reimplementation of part `RangeReplaceableCollection`'s interface. `SortedArray` can't conform to `RangeReplaceableCollection` because some of that protocol's semantics (e.g. `append(_:)` don't fit `SortedArray`'s semantics.
124 | extension SortedArray {
125 | /// Removes and returns the element at the specified position.
126 | ///
127 | /// - Parameter index: The position of the element to remove. `index` must be a valid index of the array.
128 | /// - Returns: The element at the specified index.
129 | /// - Complexity: O(_n_), where _n_ is the length of the array.
130 | @discardableResult
131 | public mutating func remove(at index: Int) -> Element {
132 | return _elements.remove(at: index)
133 | }
134 |
135 | /// Removes the elements in the specified subrange from the array.
136 | ///
137 | /// - Parameter bounds: The range of the array to be removed. The
138 | /// bounds of the range must be valid indices of the array.
139 | ///
140 | /// - Complexity: O(_n_), where _n_ is the length of the array.
141 | public mutating func removeSubrange(_ bounds: Range) {
142 | _elements.removeSubrange(bounds)
143 | }
144 |
145 | /// Removes the elements in the specified subrange from the array.
146 | ///
147 | /// - Parameter bounds: The range of the array to be removed. The
148 | /// bounds of the range must be valid indices of the array.
149 | ///
150 | /// - Complexity: O(_n_), where _n_ is the length of the array.
151 | public mutating func removeSubrange(_ bounds: ClosedRange) {
152 | _elements.removeSubrange(bounds)
153 | }
154 |
155 | // Starting with Swift 4.2, CountableRange and CountableClosedRange are typealiases for
156 | // Range and ClosedRange, so these methods trigger "Invalid redeclaration" errors.
157 | // Compile them only for older compiler versions.
158 | // swift(3.1): Latest version of Swift 3 under the Swift 3 compiler.
159 | // swift(3.2): Swift 4 compiler under Swift 3 mode.
160 | // swift(3.3): Swift 4.1 compiler under Swift 3 mode.
161 | // swift(3.4): Swift 4.2 compiler under Swift 3 mode.
162 | // swift(4.0): Swift 4 compiler
163 | // swift(4.1): Swift 4.1 compiler
164 | // swift(4.1.50): Swift 4.2 compiler in Swift 4 mode
165 | // swift(4.2): Swift 4.2 compiler
166 | #if !swift(>=4.1.50)
167 | /// Removes the elements in the specified subrange from the array.
168 | ///
169 | /// - Parameter bounds: The range of the array to be removed. The
170 | /// bounds of the range must be valid indices of the array.
171 | ///
172 | /// - Complexity: O(_n_), where _n_ is the length of the array.
173 | public mutating func removeSubrange(_ bounds: CountableRange) {
174 | _elements.removeSubrange(bounds)
175 | }
176 |
177 | /// Removes the elements in the specified subrange from the array.
178 | ///
179 | /// - Parameter bounds: The range of the array to be removed. The
180 | /// bounds of the range must be valid indices of the array.
181 | ///
182 | /// - Complexity: O(_n_), where _n_ is the length of the array.
183 | public mutating func removeSubrange(_ bounds: CountableClosedRange) {
184 | _elements.removeSubrange(bounds)
185 | }
186 | #endif
187 |
188 | /// Removes the specified number of elements from the beginning of the
189 | /// array.
190 | ///
191 | /// - Parameter n: The number of elements to remove from the array.
192 | /// `n` must be greater than or equal to zero and must not exceed the
193 | /// number of elements in the array.
194 | ///
195 | /// - Complexity: O(_n_), where _n_ is the length of the array.
196 | public mutating func removeFirst(_ n: Int) {
197 | _elements.removeFirst(n)
198 | }
199 |
200 | /// Removes and returns the first element of the array.
201 | ///
202 | /// - Precondition: The array must not be empty.
203 | /// - Returns: The removed element.
204 | /// - Complexity: O(_n_), where _n_ is the length of the collection.
205 | @discardableResult
206 | public mutating func removeFirst() -> Element {
207 | return _elements.removeFirst()
208 | }
209 |
210 | /// Removes and returns the last element of the array.
211 | ///
212 | /// - Precondition: The collection must not be empty.
213 | /// - Returns: The last element of the collection.
214 | /// - Complexity: O(1)
215 | @discardableResult
216 | public mutating func removeLast() -> Element {
217 | return _elements.removeLast()
218 | }
219 |
220 | /// Removes the given number of elements from the end of the array.
221 | ///
222 | /// - Parameter n: The number of elements to remove. `n` must be greater
223 | /// than or equal to zero, and must be less than or equal to the number of
224 | /// elements in the array.
225 | /// - Complexity: O(1).
226 | public mutating func removeLast(_ n: Int) {
227 | _elements.removeLast(n)
228 | }
229 |
230 | /// Removes all elements from the array.
231 | ///
232 | /// - Parameter keepCapacity: Pass `true` to keep the existing capacity of
233 | /// the array after removing its elements. The default value is `false`.
234 | ///
235 | /// - Complexity: O(_n_), where _n_ is the length of the array.
236 | public mutating func removeAll(keepingCapacity keepCapacity: Bool = true) {
237 | _elements.removeAll(keepingCapacity: keepCapacity)
238 | }
239 |
240 | /// Removes an element from the array. If the array contains multiple
241 | /// instances of `element`, this method only removes the first one.
242 | ///
243 | /// - Complexity: O(_n_), where _n_ is the size of the array.
244 | public mutating func remove(_ element: Element) {
245 | guard let index = index(of: element) else { return }
246 | _elements.remove(at: index)
247 | }
248 | }
249 |
250 | // MARK: - More efficient variants of default implementations or implementations that need fewer constraints than the default implementations.
251 | extension SortedArray {
252 | /// Returns the first index where the specified value appears in the collection.
253 | ///
254 | /// - Complexity: O(_log(n)_), where _n_ is the size of the array.
255 | public func firstIndex(of element: Element) -> Index? {
256 | var range: Range = startIndex ..< endIndex
257 | var match: Index? = nil
258 | while case let .found(m) = search(for: element, in: range) {
259 | // We found a matching element
260 | // Check if its predecessor also matches
261 | if let predecessor = index(m, offsetBy: -1, limitedBy: range.lowerBound),
262 | compare(self[predecessor], element) == .orderedSame
263 | {
264 | // Predecessor matches => continue searching using binary search
265 | match = predecessor
266 | range = range.lowerBound ..< predecessor
267 | }
268 | else {
269 | // We're done
270 | match = m
271 | break
272 | }
273 | }
274 | return match
275 | }
276 |
277 | /// Returns the first index in which an element of the collection satisfies the given predicate.
278 | ///
279 | /// - Requires: The `predicate` must return `false` for elements of the array up to a given point, and `true` for
280 | /// all elements after that point _(the opposite of `lastIndex(where:)`)_.
281 | /// The given point may be before the first element or after the last element; i.e. it is valid to return `true`
282 | /// for all elements or `false` for all elements.
283 | /// For most use-cases, the `predicate` closure will use the form `{ $0 > … }` or `{ $0 >= … }` _(or equivalent,
284 | /// if the SortedArray was initialized with a custom Comparator)_.
285 | ///
286 | /// - Complexity: O(_log(n)_), where _n_ is the size of the array.
287 | public func firstIndex(where predicate: (Element) throws -> Bool) rethrows -> Index? {
288 | var match: Index? = nil
289 | if case let .found(m) = try searchFirst(where: predicate) {
290 | match = m
291 | }
292 | return match
293 | }
294 |
295 | /// Returns the first element of the sequence that satisfies the given predicate.
296 | ///
297 | /// - Requires: The `predicate` must return `false` for elements of the array up to a given point, and `true` for
298 | /// all elements after that point _(the opposite of `last(where:)`)_.
299 | /// The given point may be before the first element or after the last element; i.e. it is valid to return `true`
300 | /// for all elements or `false` for all elements.
301 | /// For most use-cases, the `predicate` closure will use the form `{ $0 > … }` or `{ $0 >= … }` _(or equivalent,
302 | /// if the SortedArray was initialized with a custom Comparator)_.
303 | ///
304 | /// - Complexity: O(_log(n)_), where _n_ is the size of the array.
305 | public func first(where predicate: (Element) throws -> Bool) rethrows -> Element? {
306 | guard let index = try firstIndex(where: predicate) else { return nil }
307 | return self[index]
308 | }
309 |
310 | /// Returns the first index where the specified value appears in the collection.
311 | /// Old name for `firstIndex(of:)`.
312 | /// - Seealso: `firstIndex(of:)`
313 | public func index(of element: Element) -> Index? {
314 | return firstIndex(of: element)
315 | }
316 |
317 | /// Returns a Boolean value indicating whether the sequence contains the given element.
318 | ///
319 | /// - Complexity: O(_log(n)_), where _n_ is the size of the array.
320 | public func contains(_ element: Element) -> Bool {
321 | return anyIndex(of: element) != nil
322 | }
323 |
324 | /// Returns the minimum element in the sequence.
325 | ///
326 | /// - Complexity: O(1).
327 | @warn_unqualified_access
328 | public func min() -> Element? {
329 | return first
330 | }
331 |
332 | /// Returns the maximum element in the sequence.
333 | ///
334 | /// - Complexity: O(1).
335 | @warn_unqualified_access
336 | public func max() -> Element? {
337 | return last
338 | }
339 | }
340 |
341 | // MARK: - APIs that go beyond what's in the stdlib
342 | extension SortedArray {
343 | /// Returns an arbitrary index where the specified value appears in the collection.
344 | /// Like `index(of:)`, but without the guarantee to return the *first* index
345 | /// if the array contains duplicates of the searched element.
346 | ///
347 | /// Can be slightly faster than `index(of:)`.
348 | public func anyIndex(of element: Element) -> Index? {
349 | switch search(for: element) {
350 | case let .found(at: index): return index
351 | case .notFound(insertAt: _): return nil
352 | }
353 | }
354 |
355 | /// Returns the last index where the specified value appears in the collection.
356 | ///
357 | /// - Complexity: O(_log(n)_), where _n_ is the size of the array.
358 | public func lastIndex(of element: Element) -> Index? {
359 | var range: Range = startIndex ..< endIndex
360 | var match: Index? = nil
361 | while case let .found(m) = search(for: element, in: range) {
362 | // We found a matching element
363 | // Check if its successor also matches
364 | let lastValidIndex = index(before: range.upperBound)
365 | if let successor = index(m, offsetBy: 1, limitedBy: lastValidIndex),
366 | compare(self[successor], element) == .orderedSame
367 | {
368 | // Successor matches => continue searching using binary search
369 | match = successor
370 | guard let afterSuccessor = index(successor, offsetBy: 1, limitedBy: lastValidIndex) else {
371 | break
372 | }
373 | range = afterSuccessor ..< range.upperBound
374 | }
375 | else {
376 | // We're done
377 | match = m
378 | break
379 | }
380 | }
381 | return match
382 | }
383 |
384 | /// Returns the index of the last element in the collection that matches the given predicate.
385 | ///
386 | /// - Requires: The `predicate` must return `true` for elements of the array up to a given point, and `false` for
387 | /// all elements after that point _(the opposite of `firstIndex(where:)`)_.
388 | /// The given point may be before the first element or after the last element; i.e. it is valid to return `true`
389 | /// for all elements or `false` for all elements.
390 | /// For most use-cases, the `predicate` closure will use the form `{ $0 < … }` or `{ $0 <= … }` _(or equivalent,
391 | /// if the SortedArray was initialized with a custom Comparator)_.
392 | ///
393 | /// - Complexity: O(_log(n)_), where _n_ is the size of the array.
394 | public func lastIndex(where predicate: (Element) throws -> Bool) rethrows -> Index? {
395 | var match: Index? = nil
396 | if case let .found(m) = try searchLast(where: predicate) {
397 | match = m
398 | }
399 | return match
400 | }
401 |
402 | /// Returns the last element of the sequence that satisfies the given predicate.
403 | ///
404 | /// - Requires: The `predicate` must return `true` for elements of the array up to a given point, and `false` for
405 | /// all elements after that point _(the opposite of `first(where:)`)_.
406 | /// The given point may be before the first element or after the last element; i.e. it is valid to return `true`
407 | /// for all elements or `false` for all elements.
408 | /// For most use-cases, the `predicate` closure will use the form `{ $0 < … }` or `{ $0 <= … }` _(or equivalent,
409 | /// if the SortedArray was initialized with a custom Comparator)_.
410 | ///
411 | /// - Complexity: O(_log(n)_), where _n_ is the size of the array.
412 | public func last(where predicate: (Element) throws -> Bool) rethrows -> Element? {
413 | guard let index = try lastIndex(where: predicate) else { return nil }
414 | return self[index]
415 | }
416 | }
417 |
418 | // MARK: - Converting between a stdlib comparator function and Foundation.ComparisonResult
419 | extension SortedArray {
420 | fileprivate func compare(_ lhs: Element, _ rhs: Element) -> Foundation.ComparisonResult {
421 | if areInIncreasingOrder(lhs, rhs) {
422 | return .orderedAscending
423 | } else if areInIncreasingOrder(rhs, lhs) {
424 | return .orderedDescending
425 | } else {
426 | // If neither element comes before the other, they _must_ be
427 | // equal, per the strict ordering requirement of `areInIncreasingOrder`.
428 | return .orderedSame
429 | }
430 | }
431 | }
432 |
433 | // MARK: - Binary search
434 | extension SortedArray {
435 | /// The index where `newElement` should be inserted to preserve the array's sort order.
436 | fileprivate func insertionIndex(for newElement: Element) -> Index {
437 | switch search(for: newElement) {
438 | case let .found(at: index): return index
439 | case let .notFound(insertAt: index): return index
440 | }
441 | }
442 | }
443 |
444 | fileprivate enum Match {
445 | case found(at: Index)
446 | case notFound(insertAt: Index)
447 | }
448 |
449 | extension Range where Bound == Int {
450 | var middle: Int? {
451 | guard !isEmpty else { return nil }
452 | return lowerBound + count / 2
453 | }
454 | }
455 |
456 | extension SortedArray {
457 | /// Searches the array for `element` using binary search.
458 | ///
459 | /// - Returns: If `element` is in the array, returns `.found(at: index)`
460 | /// where `index` is the index of the element in the array.
461 | /// If `element` is not in the array, returns `.notFound(insertAt: index)`
462 | /// where `index` is the index where the element should be inserted to
463 | /// preserve the sort order.
464 | /// If the array contains multiple elements that are equal to `element`,
465 | /// there is no guarantee which of these is found.
466 | ///
467 | /// - Complexity: O(_log(n)_), where _n_ is the size of the array.
468 | fileprivate func search(for element: Element) -> Match {
469 | return search(for: element, in: startIndex ..< endIndex)
470 | }
471 |
472 | fileprivate func search(for element: Element, in range: Range) -> Match {
473 | guard let middle = range.middle else { return .notFound(insertAt: range.upperBound) }
474 | switch compare(element, self[middle]) {
475 | case .orderedDescending:
476 | return search(for: element, in: index(after: middle).. … }` or `{ $0 >= … }` _(or equivalent,
491 | /// if the SortedArray was initialized with a custom Comparator)_.
492 | ///
493 | /// - Parameter predicate: A closure that returns `false` for elements up to a point; and `true` for all after.
494 | /// - Returns: If `element` is in the array, returns `.found(at: index)`
495 | /// where `index` is the index of the element in the array.
496 | /// If `element` is not in the array, returns `.notFound(insertAt: index)`
497 | /// where `index` is the index where the element should be inserted to
498 | /// preserve the sort order.
499 | /// If the array contains multiple elements that are equal to `element`,
500 | /// there is no guarantee which of these is found.
501 | ///
502 | /// - Complexity: O(_log(n)_), where _n_ is the size of the array.
503 | /// - SeeAlso: http://ruby-doc.org/core-2.6.3/Array.html#method-i-bsearch_index
504 | fileprivate func searchFirst(where predicate: (Element) throws -> Bool) rethrows -> Match {
505 | return try searchFirst(where: predicate, in: startIndex ..< endIndex)
506 | }
507 |
508 | fileprivate func searchFirst(where predicate: (Element) throws -> Bool, in range: Range) rethrows -> Match {
509 | guard let middle = range.middle else { return .notFound(insertAt: range.upperBound) }
510 | if try predicate(self[middle]) {
511 | if middle == 0 {
512 | return .found(at: middle)
513 | } else if !(try predicate(self[index(before: middle)])) {
514 | return .found(at: middle)
515 | } else {
516 | return try searchFirst(where: predicate, in: range.lowerBound ..< middle)
517 | }
518 | } else {
519 | return try searchFirst(where: predicate, in: index(after: middle) ..< range.upperBound)
520 | }
521 | }
522 |
523 | /// Searches the array for the last element matching the `predicate` using binary search.
524 | ///
525 | /// - Requires: The `predicate` must return `true` for elements of the array up to a given point, and `false` for
526 | /// all elements after that point _(the opposite of `searchFirst(where:)`)_.
527 | /// The given point may be before the first element or after the last element; i.e. it is valid to return `true`
528 | /// for all elements or `false` for all elements.
529 | /// For most use-cases, the `predicate` closure will use the form `{ $0 < … }` or `{ $0 <= … }` _(or equivalent,
530 | /// if the SortedArray was initialized with a custom Comparator)_.
531 | ///
532 | /// - Parameter predicate: A closure that returns `false` for elements up to a point; and `true` for all after.
533 | /// - Returns: If `element` is in the array, returns `.found(at: index)`
534 | /// where `index` is the index of the element in the array.
535 | /// If `element` is not in the array, returns `.notFound(insertAt: index)`
536 | /// where `index` is the index where the element should be inserted to
537 | /// preserve the sort order.
538 | /// If the array contains multiple elements that are equal to `element`,
539 | /// there is no guarantee which of these is found.
540 | ///
541 | /// - Complexity: O(_log(n)_), where _n_ is the size of the array.
542 | /// - SeeAlso: http://ruby-doc.org/core-2.6.3/Array.html#method-i-bsearch_index
543 | fileprivate func searchLast(where predicate: (Element) throws -> Bool) rethrows -> Match {
544 | return try searchLast(where: predicate, in: startIndex ..< endIndex)
545 | }
546 |
547 | fileprivate func searchLast(where predicate: (Element) throws -> Bool, in range: Range) rethrows -> Match {
548 | guard let middle = range.middle else { return .notFound(insertAt: range.upperBound) }
549 | if try predicate(self[middle]) {
550 | if middle == range.upperBound - 1 {
551 | return .found(at: middle)
552 | } else if !(try predicate(self[index(after: middle)])) {
553 | return .found(at: middle)
554 | } else {
555 | return try searchLast(where: predicate, in: index(after: middle) ..< range.upperBound)
556 | }
557 | } else {
558 | return try searchLast(where: predicate, in: range.lowerBound ..< middle)
559 | }
560 | }
561 | }
562 |
563 | #if swift(>=4.1)
564 | extension SortedArray: Equatable where Element: Equatable {
565 | public static func == (lhs: SortedArray, rhs: SortedArray) -> Bool {
566 | // Ignore the comparator function for Equatable
567 | return lhs._elements == rhs._elements
568 | }
569 | }
570 | #else
571 | public func == (lhs: SortedArray, rhs: SortedArray) -> Bool {
572 | return lhs._elements == rhs._elements
573 | }
574 |
575 | public func != (lhs: SortedArray, rhs: SortedArray) -> Bool {
576 | return lhs._elements != rhs._elements
577 | }
578 | #endif
579 |
580 | #if swift(>=4.1.50)
581 | extension SortedArray: Hashable where Element: Hashable {
582 | public func hash(into hasher: inout Hasher) {
583 | hasher.combine(_elements)
584 | }
585 | }
586 | #endif
587 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import UnitTests
3 | @testable import PerformanceTests
4 |
5 | XCTMain([
6 | testCase(SortedArrayTests.allTests),
7 | testCase(PerformanceTests.allTests),
8 | ])
9 |
--------------------------------------------------------------------------------
/Tests/PerformanceTests/PerformanceTests.swift:
--------------------------------------------------------------------------------
1 | import SortedArray
2 | import XCTest
3 |
4 | class PerformanceTests: XCTestCase {
5 | func testLinuxTestSuiteIncludesAllTests() {
6 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
7 | let darwinTestCount = PerformanceTests.defaultTestSuite.testCaseCount
8 | let linuxTestCount = PerformanceTests.allTests.count
9 | XCTAssertEqual(linuxTestCount, darwinTestCount, "allTests (used for testing on Linux) is missing \(darwinTestCount - linuxTestCount) tests")
10 | #endif
11 | }
12 |
13 | func testPerformanceOfIndexOf() {
14 | let sourceArray = Array(repeating: 500, count: 1_000_000) + Array(repeating: 40, count: 1_000_000) + Array(repeating: 3, count: 1_000_000)
15 | let sut = SortedArray(unsorted: sourceArray)
16 | measure {
17 | XCTAssertEqual(sut.index(of: 500), 2_000_000)
18 | }
19 | }
20 |
21 | func testPerformanceOfLastIndexOf() {
22 | let sourceArray = Array(repeating: 500, count: 1_000_000) + Array(repeating: 40, count: 1_000_000) + Array(repeating: 3, count: 1_000_000)
23 | let sut = SortedArray(unsorted: sourceArray)
24 | measure {
25 | XCTAssertEqual(sut.lastIndex(of: 3), 999_999)
26 | }
27 | }
28 |
29 | func testPerformanceOfFirstIndexWhere() {
30 | let sourceArray = Array(repeating: 500, count: 1_000_000) + Array(repeating: 40, count: 1_000_000) + Array(repeating: 3, count: 1_000_000)
31 | let sut = SortedArray(unsorted: sourceArray)
32 | measure {
33 | XCTAssertEqual(sut.firstIndex(where: { $0 >= 500 }), 2_000_000)
34 | }
35 | }
36 |
37 | func testPerformanceOfLastIndexWhere() {
38 | let sourceArray = Array(repeating: 500, count: 1_000_000) + Array(repeating: 40, count: 1_000_000) + Array(repeating: 3, count: 1_000_000)
39 | let sut = SortedArray(unsorted: sourceArray)
40 | measure {
41 | XCTAssertEqual(sut.lastIndex(where: { $0 <= 3 }), 999_999)
42 | }
43 | }
44 |
45 | func testPerformanceOfIndexOfObject() {
46 | let sourceArray = Array(repeating: Box(500), count: 1_000_000) + Array(repeating: Box(40), count: 1_000_000) + Array(repeating: Box(3), count: 1_000_000)
47 | let sut = SortedArray(unsorted: sourceArray)
48 | measure {
49 | XCTAssertEqual(sut.index(of: Box(500)), 2_000_000)
50 | }
51 | }
52 |
53 | func testPerformanceOfLastIndexOfObject() {
54 | let sourceArray = Array(repeating: Box(500), count: 1_000_000) + Array(repeating: Box(40), count: 1_000_000) + Array(repeating: Box(3), count: 1_000_000)
55 | let sut = SortedArray(unsorted: sourceArray)
56 | measure {
57 | XCTAssertEqual(sut.lastIndex(of: Box(3)), 999_999)
58 | }
59 | }
60 |
61 | func testPerformanceOfFirstIndexWhereObject() {
62 | let sourceArray = Array(repeating: Box(500), count: 1_000_000) + Array(repeating: Box(40), count: 1_000_000) + Array(repeating: Box(3), count: 1_000_000)
63 | let sut = SortedArray(unsorted: sourceArray)
64 | measure {
65 | XCTAssertEqual(sut.firstIndex(where: { $0 >= Box(500) }), 2_000_000)
66 | }
67 | }
68 |
69 | func testPerformanceOfLastIndexWhereObject() {
70 | let sourceArray = Array(repeating: Box(500), count: 1_000_000) + Array(repeating: Box(40), count: 1_000_000) + Array(repeating: Box(3), count: 1_000_000)
71 | let sut = SortedArray(unsorted: sourceArray)
72 | measure {
73 | XCTAssertEqual(sut.lastIndex(where: { $0 <= Box(3) }), 999_999)
74 | }
75 | }
76 |
77 | func testPerformanceOfIndexOfObjectInRange() {
78 | let sut = SortedArray(sorted: (0..<3_000_000).lazy.map(Box.init))
79 | measure {
80 | XCTAssertEqual(sut.index(of: Box(500)), 500)
81 | }
82 | }
83 |
84 | func testPerformanceOfLastIndexOfObjectInRange() {
85 | let sut = SortedArray(sorted: (0..<3_000_000).lazy.map(Box.init))
86 | XCTAssertEqual(sut.lastIndex(of: Box(1_999_999)), 1_999_999)
87 | measure {
88 | XCTAssertEqual(sut.lastIndex(of: Box(1_999_999)), 1_999_999)
89 | }
90 | }
91 |
92 | func testPerformanceOfFirstIndexWhereObjectInRange() {
93 | let sut = SortedArray(sorted: (0..<3_000_000).lazy.map(Box.init))
94 | measure {
95 | XCTAssertEqual(sut.firstIndex(where: { $0 >= Box(500) }), 500)
96 | }
97 | }
98 |
99 | func testPerformanceOfLastIndexWhereObjectInRange() {
100 | let sut = SortedArray(sorted: (0..<3_000_000).lazy.map(Box.init))
101 | measure {
102 | XCTAssertEqual(sut.lastIndex(where: { $0 <= Box(1_999_999) }), 1_999_999)
103 | }
104 | }
105 | }
106 |
107 | extension PerformanceTests {
108 | static var allTests : [(String, (PerformanceTests) -> () throws -> Void)] {
109 | return [
110 | ("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests),
111 | ("testPerformanceOfIndexOf", testPerformanceOfIndexOf),
112 | ("testPerformanceOfLastIndexOf", testPerformanceOfLastIndexOf),
113 | ("testPerformanceOfFirstIndexWhere", testPerformanceOfFirstIndexWhere),
114 | ("testPerformanceOfLastIndexWhere", testPerformanceOfLastIndexWhere),
115 | ("testPerformanceOfIndexOfObject", testPerformanceOfIndexOfObject),
116 | ("testPerformanceOfLastIndexOfObject", testPerformanceOfLastIndexOfObject),
117 | ("testPerformanceOfFirstIndexWhereObject", testPerformanceOfFirstIndexWhereObject),
118 | ("testPerformanceOfLastIndexWhereObject", testPerformanceOfLastIndexWhereObject),
119 | ("testPerformanceOfIndexOfObjectInRange", testPerformanceOfIndexOfObjectInRange),
120 | ("testPerformanceOfLastIndexOfObjectInRange", testPerformanceOfLastIndexOfObjectInRange),
121 | ("testPerformanceOfFirstIndexWhereObjectInRange", testPerformanceOfFirstIndexWhereObjectInRange),
122 | ("testPerformanceOfLastIndexWhereObjectInRange", testPerformanceOfLastIndexWhereObjectInRange),
123 | ]
124 | }
125 | }
126 |
127 | /// Helper class
128 | class Box: Comparable {
129 | static func ==(lhs: Box, rhs: Box) -> Bool {
130 | return lhs.value == rhs.value
131 | }
132 |
133 | static func <(lhs: Box, rhs: Box) -> Bool {
134 | return lhs.value < rhs.value
135 | }
136 |
137 | let value: T
138 | init(_ value: T) {
139 | self.value = value
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/Tests/UnitTests/SortedArrayTests.swift:
--------------------------------------------------------------------------------
1 | import SortedArray
2 | import XCTest
3 |
4 | class SortedArrayTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | }
8 |
9 | override func tearDown() {
10 | super.tearDown()
11 | }
12 |
13 | func testLinuxTestSuiteIncludesAllTests() {
14 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
15 | let darwinTestCount = SortedArrayTests.defaultTestSuite.testCaseCount
16 | let linuxTestCount = SortedArrayTests.allTests.count
17 | XCTAssertEqual(linuxTestCount, darwinTestCount, "allTests (used for testing on Linux) is missing \(darwinTestCount - linuxTestCount) tests")
18 | #endif
19 | }
20 |
21 | func testInitUnsortedSorts() {
22 | let sut = SortedArray(unsorted: [3,4,2,1], areInIncreasingOrder: <)
23 | assertElementsEqual(sut, [1,2,3,4])
24 | }
25 |
26 | func testInitSortedDoesntResort() {
27 | // Warning: this is not a valid way to create a SortedArray
28 | let sut = SortedArray(sorted: [3,2,1])
29 | assertElementsEqual(Array(sut), [3,2,1])
30 | }
31 |
32 | func testSortedArrayCanUseArbitraryComparisonPredicate() {
33 | struct Person {
34 | var firstName: String
35 | var lastName: String
36 | }
37 | let a = Person(firstName: "A", lastName: "Smith")
38 | let b = Person(firstName: "B", lastName: "Jones")
39 | let c = Person(firstName: "C", lastName: "Lewis")
40 |
41 | var sut = SortedArray { $0.firstName > $1.firstName }
42 | sut.insert(contentsOf: [b,a,c])
43 | assertElementsEqual(sut.map { $0.firstName }, ["C","B","A"])
44 | }
45 |
46 | func testConvenienceInitsUseLessThan() {
47 | let sut = SortedArray(unsorted: ["a","c","b"])
48 | assertElementsEqual(sut, ["a","b","c"])
49 | }
50 |
51 | func testInsertAtBeginningPreservesSortOrder() {
52 | var sut = SortedArray(unsorted: 1...3)
53 | sut.insert(0)
54 | assertElementsEqual(sut, [0,1,2,3])
55 | }
56 |
57 | func testInsertInMiddlePreservesSortOrder() {
58 | var sut = SortedArray(unsorted: 1...5)
59 | sut.insert(4)
60 | assertElementsEqual(sut, [1,2,3,4,4,5])
61 | }
62 |
63 | func testInsertAtEndPreservesSortOrder() {
64 | var sut = SortedArray(unsorted: 1...3)
65 | sut.insert(5)
66 | assertElementsEqual(sut, [1,2,3,5])
67 | }
68 |
69 | func testInsertAtBeginningReturnsInsertionIndex() {
70 | var sut = SortedArray(unsorted: [1,2,3])
71 | let index = sut.insert(0)
72 | XCTAssertEqual(index, 0)
73 | }
74 |
75 | func testInsertInMiddleReturnsInsertionIndex() {
76 | var sut = SortedArray(unsorted: [1,2,3,5])
77 | let index = sut.insert(4)
78 | XCTAssertEqual(index, 3)
79 | }
80 |
81 | func testInsertAtEndReturnsInsertionIndex() {
82 | var sut = SortedArray(unsorted: [1,2,3])
83 | let index = sut.insert(100)
84 | XCTAssertEqual(index, 3)
85 | }
86 |
87 | func testInsertInEmptyArrayReturnsInsertionIndex() {
88 | var sut = SortedArray()
89 | let index = sut.insert(10)
90 | XCTAssertEqual(index, 0)
91 | }
92 |
93 | func testInsertEqualElementReturnsCorrectInsertionIndex() {
94 | var sut = SortedArray(unsorted: [3,1,0,2,1])
95 | let index = sut.insert(1)
96 | XCTAssert(index == 1 || index == 2 || index == 3)
97 | }
98 |
99 | func testInsertContentsOfPreservesSortOrder() {
100 | var sut = SortedArray(unsorted: [10,9,8])
101 | sut.insert(contentsOf: (7...11).reversed())
102 | assertElementsEqual(sut, [7,8,8,9,9,10,10,11])
103 | }
104 |
105 | func testIndexOfFindsElementInMiddle() {
106 | let sut = SortedArray(unsorted: ["a","z","r","k"])
107 | let index = sut.firstIndex(of: "k")
108 | XCTAssertEqual(index, 1)
109 | }
110 |
111 | func testIndexOfFindsFirstElement() {
112 | let sut = SortedArray(sorted: 1..<10)
113 | let index = sut.firstIndex(of: 1)
114 | XCTAssertEqual(index, 0)
115 | }
116 |
117 | func testIndexOfFindsLastElement() {
118 | let sut = SortedArray(sorted: 1..<10)
119 | let index = sut.firstIndex(of: 9)
120 | XCTAssertEqual(index, 8)
121 | }
122 |
123 | func testIndexOfReturnsNilWhenNotFound() {
124 | let sut = SortedArray(unsorted: "Hello World")
125 | let index = sut.firstIndex(of: "h")
126 | XCTAssertNil(index)
127 | }
128 |
129 | func testIndexOfReturnsNilForEmptyArray() {
130 | let sut = SortedArray()
131 | let index = sut.firstIndex(of: 1)
132 | XCTAssertNil(index)
133 | }
134 |
135 | func testIndexOfCanDealWithSingleElementArray() {
136 | let sut = SortedArray(unsorted: [5])
137 | let index = sut.firstIndex(of: 5)
138 | XCTAssertEqual(index, 0)
139 | }
140 |
141 | func testIndexOfFindsFirstIndexOfDuplicateElements1() {
142 | let sut = SortedArray(unsorted: [1,2,3,3,3,3,3,3,3,3,4,5])
143 | let index = sut.firstIndex(of: 3)
144 | XCTAssertEqual(index, 2)
145 | }
146 |
147 | func testIndexOfFindsFirstIndexOfDuplicateElements2() {
148 | let sut = SortedArray(unsorted: [1,4,4,4,4,4,4,4,4,3,2])
149 | let index = sut.firstIndex(of: 4)
150 | XCTAssertEqual(index, 3)
151 | }
152 |
153 | func testIndexOfFindsFirstIndexOfDuplicateElements3() {
154 | let sut = SortedArray(unsorted: String(repeating: "A", count: 10))
155 | let index = sut.firstIndex(of: "A")
156 | XCTAssertEqual(index, 0)
157 | }
158 |
159 | func testIndexOfFindsFirstIndexOfDuplicateElements4() {
160 | let sut = SortedArray(unsorted: Array(repeating: "a", count: 100_000))
161 | let index = sut.firstIndex(of: "a")
162 | XCTAssertEqual(index, 0)
163 | }
164 |
165 | func testIndexOfFindsFirstIndexOfDuplicateElements5() {
166 | let sourceArray = Array(repeating: 5, count: 100_000) + [1,2,6,7,8,9]
167 | let sut = SortedArray(unsorted: sourceArray)
168 | let index = sut.firstIndex(of: 5)
169 | XCTAssertEqual(index, 2)
170 | }
171 |
172 | func testIndexOfExistsAndIsAnAliasForFirstIndexOf() {
173 | let sut = SortedArray(unsorted: [1,2,3,3,3,3,3,3,3,3,4,5])
174 | let index = sut.index(of: 3)
175 | XCTAssertEqual(index, 2)
176 | }
177 |
178 | func testFirstIndexWhereFindsElementInMiddle() {
179 | let sut = SortedArray(unsorted: ["a","z","r","k"])
180 | let index = sut.firstIndex(where: { $0 >= "k" })
181 | XCTAssertEqual(index, 1)
182 | }
183 |
184 | func testFirstIndexWhereFindsFirstElement() {
185 | let sut = SortedArray(sorted: 1..<10)
186 | let index = sut.firstIndex(where: { $0 >= 1 })
187 | XCTAssertEqual(index, 0)
188 | }
189 |
190 | func testFirstIndexWhereFindsLastElement() {
191 | let sut = SortedArray(sorted: 1..<10)
192 | let index = sut.firstIndex(where: { $0 >= 9 })
193 | XCTAssertEqual(index, 8)
194 | }
195 |
196 | func testFirstIndexWhereReturnsNilWhenNotFound() {
197 | let sut = SortedArray(unsorted: "Hello World")
198 | let index = sut.firstIndex(where: { $0 > "z"})
199 | XCTAssertNil(index)
200 | }
201 |
202 | func testFirstIndexWhereReturnsNilForEmptyArray() {
203 | let sut = SortedArray()
204 | let index = sut.firstIndex(where: { $0 >= 1 })
205 | XCTAssertNil(index)
206 | }
207 |
208 | func testFirstIndexWhereCanDealWithSingleElementArray() {
209 | let sut = SortedArray(unsorted: [5])
210 | let index = sut.firstIndex(where: { $0 >= 5 })
211 | XCTAssertEqual(index, 0)
212 | }
213 |
214 | func testFirstIndexWhereFindsFirstIndexOfDuplicateElements1() {
215 | let sut = SortedArray(unsorted: [1,2,3,3,3,3,3,3,3,3,4,5])
216 | let index = sut.firstIndex(where: { $0 >= 3 })
217 | XCTAssertEqual(index, 2)
218 | }
219 |
220 | func testFirstIndexWhereFindsFirstIndexOfDuplicateElements2() {
221 | let sut = SortedArray(unsorted: [1,4,4,4,4,4,4,4,4,3,2])
222 | let index = sut.firstIndex(where: { $0 >= 4 })
223 | XCTAssertEqual(index, 3)
224 | }
225 |
226 | func testFirstIndexWhereFindsFirstIndexOfDuplicateElements3() {
227 | let sut = SortedArray(unsorted: String(repeating: "A", count: 10))
228 | let index = sut.firstIndex(where: { $0 >= "A" })
229 | XCTAssertEqual(index, 0)
230 | }
231 |
232 | func testFirstIndexWhereFindsFirstIndexOfDuplicateElements4() {
233 | let sut = SortedArray(unsorted: Array(repeating: "a", count: 100_000))
234 | let index = sut.firstIndex(where: { $0 >= "a" })
235 | XCTAssertEqual(index, 0)
236 | }
237 |
238 | func testFirstIndexWhereFindsFirstIndexOfDuplicateElements5() {
239 | let sourceArray = Array(repeating: 5, count: 100_000) + [1,2,6,7,8,9]
240 | let sut = SortedArray(unsorted: sourceArray)
241 | let index = sut.firstIndex(where: { $0 >= 5 })
242 | XCTAssertEqual(index, 2)
243 | }
244 |
245 | func testFirstWhereFindsFirstMatchingElement() {
246 | let sut = SortedArray(unsorted: [4, 3, 2, 1])
247 | let last = sut.first(where: { $0 >= 2 })
248 | XCTAssertEqual(last, 2)
249 | }
250 |
251 | func testLastIndexOfFindsElementInMiddle() {
252 | let sut = SortedArray(unsorted: ["a","z","r","k"])
253 | let index = sut.lastIndex(of: "k")
254 | XCTAssertEqual(index, 1)
255 | }
256 |
257 | func testLastIndexOfFindsFirstElement() {
258 | let sut = SortedArray(sorted: 1..<10)
259 | let index = sut.lastIndex(of: 1)
260 | XCTAssertEqual(index, 0)
261 | }
262 |
263 | func testLastIndexOfFindsLastElement() {
264 | let sut = SortedArray(sorted: 1..<10)
265 | let index = sut.lastIndex(of: 9)
266 | XCTAssertEqual(index, 8)
267 | }
268 |
269 | func testLastIndexOfReturnsNilWhenNotFound() {
270 | let sut = SortedArray(unsorted: "Hello World")
271 | let index = sut.lastIndex(of: "h")
272 | XCTAssertNil(index)
273 | }
274 |
275 | func testLastIndexOfReturnsNilForEmptyArray() {
276 | let sut = SortedArray()
277 | let index = sut.lastIndex(of: 1)
278 | XCTAssertNil(index)
279 | }
280 |
281 | func testLastIndexOfCanDealWithSingleElementArray() {
282 | let sut = SortedArray(unsorted: [5])
283 | let index = sut.lastIndex(of: 5)
284 | XCTAssertEqual(index, 0)
285 | }
286 |
287 | func testLastIndexOfFindsLastIndexOfDuplicateElements1() {
288 | let sut = SortedArray(unsorted: [1,2,3,3,3,3,3,3,3,3,4,5])
289 | let index = sut.lastIndex(of: 3)
290 | XCTAssertEqual(index, 9)
291 | }
292 |
293 | func testLastIndexOfFindsLastIndexOfDuplicateElements2() {
294 | let sut = SortedArray(unsorted: [1,4,4,4,4,4,4,4,4,3,2])
295 | let index = sut.lastIndex(of: 4)
296 | XCTAssertEqual(index, 10)
297 | }
298 |
299 | func testLastIndexOfFindsLastIndexOfDuplicateElements3() {
300 | let sut = SortedArray(unsorted: String(repeating: "A", count: 10))
301 | let index = sut.lastIndex(of: "A")
302 | XCTAssertEqual(index, 9)
303 | }
304 |
305 | func testLastIndexWhereFindsElementInMiddle() {
306 | let sut = SortedArray(unsorted: ["a","z","r","k"])
307 | let index = sut.lastIndex(where: { $0 <= "k" })
308 | XCTAssertEqual(index, 1)
309 | }
310 |
311 | func testLastIndexWhereFindsFirstElement() {
312 | let sut = SortedArray(sorted: 1..<10)
313 | let index = sut.lastIndex(where: { $0 <= 1 })
314 | XCTAssertEqual(index, 0)
315 | }
316 |
317 | func testLastIndexWhereFindsLastElement() {
318 | let sut = SortedArray(sorted: 1..<10)
319 | let index = sut.lastIndex(where: { $0 <= 9 })
320 | XCTAssertEqual(index, 8)
321 | }
322 |
323 | func testLastIndexWhereReturnsNilWhenNotFound() {
324 | let sut = SortedArray(unsorted: "Hello World")
325 | let index = sut.lastIndex(where: { $0 < " " })
326 | XCTAssertNil(index)
327 | }
328 |
329 | func testLastIndexWhereReturnsNilForEmptyArray() {
330 | let sut = SortedArray()
331 | let index = sut.lastIndex(where: { $0 <= 1 })
332 | XCTAssertNil(index)
333 | }
334 |
335 | func testLastIndexWhereCanDealWithSingleElementArray() {
336 | let sut = SortedArray(unsorted: [5])
337 | let index = sut.lastIndex(where: { $0 <= 5 })
338 | XCTAssertEqual(index, 0)
339 | }
340 |
341 | func testLastIndexWhereFindsLastIndexOfDuplicateElements1() {
342 | let sut = SortedArray(unsorted: [1,2,3,3,3,3,3,3,3,3,4,5])
343 | let index = sut.lastIndex(where: { $0 <= 3 })
344 | XCTAssertEqual(index, 9)
345 | }
346 |
347 | func testLastIndexWhereFindsLastIndexOfDuplicateElements2() {
348 | let sut = SortedArray(unsorted: [1,4,4,4,4,4,4,4,4,3,2])
349 | let index = sut.lastIndex(where: { $0 <= 4 })
350 | XCTAssertEqual(index, 10)
351 | }
352 |
353 | func testLastIndexWhereFindsLastIndexOfDuplicateElements3() {
354 | let sut = SortedArray(unsorted: String(repeating: "A", count: 10))
355 | let index = sut.lastIndex(where: { $0 <= "A" })
356 | XCTAssertEqual(index, 9)
357 | }
358 |
359 | func testLastWhereFindsLastMatchingElement() {
360 | let sut = SortedArray(unsorted: [4, 3, 2, 1])
361 | let last = sut.last(where: { $0 <= 3 })
362 | XCTAssertEqual(last, 3)
363 | }
364 |
365 | func testsContains() {
366 | let sut = SortedArray(unsorted: "Lorem ipsum")
367 | XCTAssertTrue(sut.contains(" "))
368 | XCTAssertFalse(sut.contains("a"))
369 | }
370 |
371 | func testMin() {
372 | let sut = SortedArray(unsorted: -10...10)
373 | XCTAssertEqual(sut.min(), -10)
374 | }
375 |
376 | func testMax() {
377 | let sut = SortedArray(unsorted: -10...(-1))
378 | XCTAssertEqual(sut.max(), -1)
379 | }
380 |
381 | func testCustomStringConvertible() {
382 | let sut = SortedArray(unsorted: ["a", "c", "b"])
383 | let description = String(describing: sut)
384 | XCTAssertEqual(description, "[\"a\", \"b\", \"c\"] (sorted)")
385 | }
386 |
387 | func testCustomDebugStringConvertible() {
388 | let sut = SortedArray(unsorted: ["a", "c", "b"])
389 | let description = String(reflecting: sut)
390 | XCTAssertEqual(description, " [\"a\", \"b\", \"c\"]")
391 | }
392 |
393 | func testFilter() {
394 | let sut = SortedArray(unsorted: ["a", "b", "c"])
395 | assertElementsEqual(sut.filter { $0 != "a" }, ["b", "c"])
396 | }
397 |
398 | func testRemoveAtIndex() {
399 | var sut = SortedArray(unsorted: [3,4,2,1])
400 | let removedElement = sut.remove(at: 1)
401 | assertElementsEqual(sut, [1,3,4])
402 | XCTAssertEqual(removedElement, 2)
403 | }
404 |
405 | func testRemoveSubrange() {
406 | var sut = SortedArray(unsorted: ["a","d","c","b"])
407 | sut.removeSubrange(2..<4)
408 | assertElementsEqual(sut, ["a","b"])
409 | }
410 |
411 | func testRemoveCountableSubrange() {
412 | var sut = SortedArray(unsorted: ["a","d","c","b"])
413 | let countableRange: CountableRange = 2..<4
414 | sut.removeSubrange(countableRange)
415 | assertElementsEqual(sut, ["a","b"])
416 | }
417 |
418 | func testRemoveFirst() {
419 | var sut = SortedArray(unsorted: [3,4,2,1])
420 | let removedElement = sut.removeFirst()
421 | assertElementsEqual(sut, [2,3,4])
422 | XCTAssertEqual(removedElement, 1)
423 | }
424 |
425 | func testRemoveFirstN() {
426 | var sut = SortedArray(unsorted: [3,4,2,1])
427 | sut.removeFirst(2)
428 | assertElementsEqual(sut, [3,4])
429 | }
430 |
431 | func testRemoveLast() {
432 | var sut = SortedArray(unsorted: [3,4,2,1])
433 | let removedElement = sut.removeLast()
434 | assertElementsEqual(sut, [1,2,3])
435 | XCTAssertEqual(removedElement, 4)
436 | }
437 |
438 | func testRemoveLastN() {
439 | var sut = SortedArray(unsorted: [3,4,2,1])
440 | sut.removeLast(2)
441 | assertElementsEqual(sut, [1,2])
442 | }
443 |
444 | func testRemoveAll() {
445 | var sut = SortedArray(unsorted: ["a","d","c","b"])
446 | sut.removeAll()
447 | assertElementsEqual(sut, [])
448 | }
449 |
450 | func testRemoveElementAtBeginningPreservesSortOrder() {
451 | var sut = SortedArray(unsorted: 1...3)
452 | sut.remove(1)
453 | assertElementsEqual(sut, [2,3])
454 | }
455 |
456 | func testRemoveElementInMiddlePreservesSortOrder() {
457 | var sut = SortedArray(unsorted: 1...5)
458 | sut.remove(4)
459 | assertElementsEqual(sut, [1,2,3,5])
460 | }
461 |
462 | func testRemoveElementAtEndPreservesSortOrder() {
463 | var sut = SortedArray(unsorted: 1...3)
464 | sut.remove(3)
465 | assertElementsEqual(sut, [1,2])
466 | }
467 |
468 | func testIsEquatableInSwift4_1AndHigher() {
469 | #if swift(>=4.1)
470 | let array1 = SortedArray(unsorted: [3,2,1])
471 | let array2 = SortedArray(unsorted: 1...3)
472 | XCTAssertEqual(array1, array2)
473 | #endif
474 | }
475 |
476 | func testComparatorFunctionIsNotRelevantForEquatable() {
477 | #if swift(>=4.1)
478 | let array1 = SortedArray(unsorted: [1,1,1], areInIncreasingOrder: <)
479 | let array2 = SortedArray(unsorted: [1,1,1], areInIncreasingOrder: >)
480 | let array3 = SortedArray(unsorted: [3,2,1,4])
481 | XCTAssertEqual(array1, array2)
482 | XCTAssertNotEqual(array1, array3)
483 | #endif
484 | }
485 |
486 | func testImplementsEqual() {
487 | let sut = SortedArray(unsorted: [3,2,1])
488 | XCTAssertTrue(sut == SortedArray(unsorted: 1...3))
489 | }
490 |
491 | func testImplementsNotEqual() {
492 | let sut = SortedArray(unsorted: 1...3)
493 | XCTAssertTrue(sut != SortedArray(unsorted: 1...4))
494 | }
495 |
496 | func testIsHashableInSwift4_2AndHigher() {
497 | #if swift(>=4.1.50)
498 | let array1 = SortedArray(unsorted: [3,2,1])
499 | let array2 = SortedArray(unsorted: 1...3)
500 | let array3 = SortedArray(unsorted: [3,2,1,4])
501 | XCTAssertEqual(array1.hashValue, array2.hashValue)
502 | XCTAssertNotEqual(array1.hashValue, array3.hashValue)
503 | #endif
504 | }
505 | }
506 |
507 | extension SortedArrayTests {
508 | static var allTests : [(String, (SortedArrayTests) -> () throws -> Void)] {
509 | return [
510 | ("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests),
511 | ("testInitUnsortedSorts", testInitUnsortedSorts),
512 | ("testInitSortedDoesntResort", testInitSortedDoesntResort),
513 | ("testSortedArrayCanUseArbitraryComparisonPredicate", testSortedArrayCanUseArbitraryComparisonPredicate),
514 | ("testConvenienceInitsUseLessThan", testConvenienceInitsUseLessThan),
515 | ("testInsertAtBeginningPreservesSortOrder", testInsertAtBeginningPreservesSortOrder),
516 | ("testInsertInMiddlePreservesSortOrder", testInsertInMiddlePreservesSortOrder),
517 | ("testInsertAtEndPreservesSortOrder", testInsertAtEndPreservesSortOrder),
518 | ("testInsertAtBeginningReturnsInsertionIndex", testInsertAtBeginningReturnsInsertionIndex),
519 | ("testInsertInMiddleReturnsInsertionIndex", testInsertInMiddleReturnsInsertionIndex),
520 | ("testInsertAtEndReturnsInsertionIndex", testInsertAtEndReturnsInsertionIndex),
521 | ("testInsertInEmptyArrayReturnsInsertionIndex", testInsertInEmptyArrayReturnsInsertionIndex),
522 | ("testInsertEqualElementReturnsCorrectInsertionIndex", testInsertEqualElementReturnsCorrectInsertionIndex),
523 | ("testInsertContentsOfPreservesSortOrder", testInsertContentsOfPreservesSortOrder),
524 | ("testIndexOfFindsElementInMiddle", testIndexOfFindsElementInMiddle),
525 | ("testIndexOfFindsFirstElement", testIndexOfFindsFirstElement),
526 | ("testIndexOfFindsLastElement", testIndexOfFindsLastElement),
527 | ("testIndexOfReturnsNilWhenNotFound", testIndexOfReturnsNilWhenNotFound),
528 | ("testIndexOfReturnsNilForEmptyArray", testIndexOfReturnsNilForEmptyArray),
529 | ("testIndexOfCanDealWithSingleElementArray", testIndexOfCanDealWithSingleElementArray),
530 | ("testIndexOfFindsFirstIndexOfDuplicateElements1", testIndexOfFindsFirstIndexOfDuplicateElements1),
531 | ("testIndexOfFindsFirstIndexOfDuplicateElements2", testIndexOfFindsFirstIndexOfDuplicateElements2),
532 | ("testIndexOfFindsFirstIndexOfDuplicateElements3", testIndexOfFindsFirstIndexOfDuplicateElements3),
533 | ("testIndexOfFindsFirstIndexOfDuplicateElements4", testIndexOfFindsFirstIndexOfDuplicateElements4),
534 | ("testIndexOfFindsFirstIndexOfDuplicateElements5", testIndexOfFindsFirstIndexOfDuplicateElements4),
535 | ("testIndexOfExistsAndIsAnAliasForFirstIndexOf", testIndexOfExistsAndIsAnAliasForFirstIndexOf),
536 | ("testFirstIndexWhereFindsElementInMiddle", testFirstIndexWhereFindsElementInMiddle),
537 | ("testFirstIndexWhereFindsFirstElement", testFirstIndexWhereFindsFirstElement),
538 | ("testFirstIndexWhereFindsLastElement", testFirstIndexWhereFindsLastElement),
539 | ("testFirstIndexWhereReturnsNilWhenNotFound", testFirstIndexWhereReturnsNilWhenNotFound),
540 | ("testFirstIndexWhereReturnsNilForEmptyArray", testFirstIndexWhereReturnsNilForEmptyArray),
541 | ("testFirstIndexWhereCanDealWithSingleElementArray", testFirstIndexWhereCanDealWithSingleElementArray),
542 | ("testFirstIndexWhereFindsFirstIndexOfDuplicateElements1", testFirstIndexWhereFindsFirstIndexOfDuplicateElements1),
543 | ("testFirstIndexWhereFindsFirstIndexOfDuplicateElements2", testFirstIndexWhereFindsFirstIndexOfDuplicateElements2),
544 | ("testFirstIndexWhereFindsFirstIndexOfDuplicateElements3", testFirstIndexWhereFindsFirstIndexOfDuplicateElements3),
545 | ("testFirstIndexWhereFindsFirstIndexOfDuplicateElements4", testFirstIndexWhereFindsFirstIndexOfDuplicateElements4),
546 | ("testFirstIndexWhereFindsFirstIndexOfDuplicateElements5", testFirstIndexWhereFindsFirstIndexOfDuplicateElements5),
547 | ("testFirstWhereFindsFirstMatchingElement", testFirstWhereFindsFirstMatchingElement),
548 | ("testLastIndexOfFindsElementInMiddle", testLastIndexOfFindsElementInMiddle),
549 | ("testLastIndexOfFindsFirstElement", testLastIndexOfFindsFirstElement),
550 | ("testLastIndexOfFindsLastElement", testLastIndexOfFindsLastElement),
551 | ("testLastIndexOfReturnsNilWhenNotFound", testLastIndexOfReturnsNilWhenNotFound),
552 | ("testLastIndexOfReturnsNilForEmptyArray", testLastIndexOfReturnsNilForEmptyArray),
553 | ("testLastIndexOfCanDealWithSingleElementArray", testLastIndexOfCanDealWithSingleElementArray),
554 | ("testLastIndexOfFindsLastIndexOfDuplicateElements1", testLastIndexOfFindsLastIndexOfDuplicateElements1),
555 | ("testLastIndexOfFindsLastIndexOfDuplicateElements2", testLastIndexOfFindsLastIndexOfDuplicateElements2),
556 | ("testLastIndexOfFindsLastIndexOfDuplicateElements3", testLastIndexOfFindsLastIndexOfDuplicateElements3),
557 | ("testLastIndexWhereFindsElementInMiddle", testLastIndexWhereFindsElementInMiddle),
558 | ("testLastIndexWhereFindsFirstElement", testLastIndexWhereFindsFirstElement),
559 | ("testLastIndexWhereFindsLastElement", testLastIndexWhereFindsLastElement),
560 | ("testLastIndexWhereReturnsNilWhenNotFound", testLastIndexWhereReturnsNilWhenNotFound),
561 | ("testLastIndexWhereReturnsNilForEmptyArray", testLastIndexWhereReturnsNilForEmptyArray),
562 | ("testLastIndexWhereCanDealWithSingleElementArray", testLastIndexWhereCanDealWithSingleElementArray),
563 | ("testLastIndexWhereFindsLastIndexOfDuplicateElements1", testLastIndexWhereFindsLastIndexOfDuplicateElements1),
564 | ("testLastIndexWhereFindsLastIndexOfDuplicateElements2", testLastIndexWhereFindsLastIndexOfDuplicateElements2),
565 | ("testLastIndexWhereFindsLastIndexOfDuplicateElements3", testLastIndexWhereFindsLastIndexOfDuplicateElements3),
566 | ("testLastWhereFindsLastMatchingElement", testLastWhereFindsLastMatchingElement),
567 | ("testsContains", testsContains),
568 | ("testMin", testMin),
569 | ("testMax", testMax),
570 | ("testCustomStringConvertible", testCustomStringConvertible),
571 | ("testCustomDebugStringConvertible", testCustomDebugStringConvertible),
572 | ("testFilter", testFilter),
573 | ("testRemoveAtIndex", testRemoveAtIndex),
574 | ("testRemoveSubrange", testRemoveSubrange),
575 | ("testRemoveCountableSubrange", testRemoveCountableSubrange),
576 | ("testRemoveFirst", testRemoveFirst),
577 | ("testRemoveFirstN", testRemoveFirstN),
578 | ("testRemoveLast", testRemoveLast),
579 | ("testRemoveLastN", testRemoveLastN),
580 | ("testRemoveAll", testRemoveAll),
581 | ("testRemoveElementAtBeginningPreservesSortOrder", testRemoveElementAtBeginningPreservesSortOrder),
582 | ("testRemoveElementInMiddlePreservesSortOrder", testRemoveElementInMiddlePreservesSortOrder),
583 | ("testRemoveElementAtEndPreservesSortOrder", testRemoveElementAtEndPreservesSortOrder),
584 | ("testIsEquatableInSwift4_1AndHigher", testIsEquatableInSwift4_1AndHigher),
585 | ("testComparatorFunctionIsNotRelevantForEquatable", testComparatorFunctionIsNotRelevantForEquatable),
586 | ("testImplementsEqual", testImplementsEqual),
587 | ("testImplementsNotEqual", testImplementsNotEqual),
588 | ("testIsHashableInSwift4_2AndHigher", testIsHashableInSwift4_2AndHigher),
589 | ]
590 | }
591 | }
592 |
593 | struct Pair {
594 | let first: A
595 | let second: B
596 |
597 | init(_ first: A, _ second: B) {
598 | self.first = first
599 | self.second = second
600 | }
601 | }
602 |
603 | extension Pair: Equatable where A: Equatable, B: Equatable {}
604 |
--------------------------------------------------------------------------------
/Tests/UnitTests/TestHelpers.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | // FIXME: Can be replaced with XCTAssertEqual when we drop Swift 4.0 compatibility
4 | func assertElementsEqual(_ expression1: @autoclosure () throws -> S1, _ expression2: @autoclosure () throws -> S2, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line)
5 | where S1: Sequence, S2: Sequence, S1.Element == S2.Element, S1.Element: Equatable
6 | {
7 | // This should give a better error message than using XCTAssert(try expression1().elementsEqual(expression2()), ...)
8 | try XCTAssertEqual(Array(expression1()), Array(expression2()), message, file: file, line: line)
9 | }
10 |
--------------------------------------------------------------------------------