mirror of
https://github.com/ilyakooo0/metal-metaballs.git
synced 2024-09-11 10:35:56 +03:00
Merge branch 'dev'
This commit is contained in:
commit
b88fbfcaa5
@ -24,38 +24,13 @@
|
||||
24ED21CD1C6C2397009C40FC /* MetaballDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24ED21CC1C6C2397009C40FC /* MetaballDataSource.swift */; };
|
||||
24FC38341C7F931E0085C04A /* Metaball.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FC38331C7F931E0085C04A /* Metaball.swift */; };
|
||||
24FC38361C7F9ABE0085C04A /* Dispatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FC38351C7F9ABE0085C04A /* Dispatch.swift */; };
|
||||
24FFA86B1C6BA038005ACD60 /* ApproximationOperator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA84C1C6BA038005ACD60 /* ApproximationOperator.swift */; };
|
||||
24FFA86C1C6BA038005ACD60 /* Collections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA84D1C6BA038005ACD60 /* Collections.swift */; };
|
||||
24FFA86D1C6BA038005ACD60 /* ComparatorChains.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA84E1C6BA038005ACD60 /* ComparatorChains.swift */; };
|
||||
24FFA86E1C6BA038005ACD60 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA84F1C6BA038005ACD60 /* Dictionary.swift */; };
|
||||
24FFA86F1C6BA038005ACD60 /* NSNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8511C6BA038005ACD60 /* NSNumber.swift */; };
|
||||
24FFA8701C6BA038005ACD60 /* Numeric.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8521C6BA038005ACD60 /* Numeric.swift */; };
|
||||
24FFA8711C6BA038005ACD60 /* PowerOperator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8531C6BA038005ACD60 /* PowerOperator.swift */; };
|
||||
24FFA8721C6BA038005ACD60 /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8541C6BA038005ACD60 /* Sequence.swift */; };
|
||||
24FFA8731C6BA038005ACD60 /* Memoize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8561C6BA038005ACD60 /* Memoize.swift */; };
|
||||
24FFA8741C6BA038005ACD60 /* SignOperator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8571C6BA038005ACD60 /* SignOperator.swift */; };
|
||||
24FFA8751C6BA038005ACD60 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8581C6BA038005ACD60 /* String.swift */; };
|
||||
24FFA8761C6BA038005ACD60 /* Categorise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA85A1C6BA038005ACD60 /* Categorise.swift */; };
|
||||
24FFA8771C6BA038005ACD60 /* ChunkWindowSplit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA85B1C6BA038005ACD60 /* ChunkWindowSplit.swift */; };
|
||||
24FFA8781C6BA038005ACD60 /* Combinations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA85C1C6BA038005ACD60 /* Combinations.swift */; };
|
||||
24FFA8791C6BA038005ACD60 /* Cycle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA85D1C6BA038005ACD60 /* Cycle.swift */; };
|
||||
24FFA87A1C6BA038005ACD60 /* Enumerate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA85E1C6BA038005ACD60 /* Enumerate.swift */; };
|
||||
24FFA87B1C6BA038005ACD60 /* Finding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA85F1C6BA038005ACD60 /* Finding.swift */; };
|
||||
24FFA87C1C6BA038005ACD60 /* FlatMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8601C6BA038005ACD60 /* FlatMap.swift */; };
|
||||
24FFA87D1C6BA038005ACD60 /* Hopping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8611C6BA038005ACD60 /* Hopping.swift */; };
|
||||
24FFA87E1C6BA038005ACD60 /* Interpose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8621C6BA038005ACD60 /* Interpose.swift */; };
|
||||
24FFA87F1C6BA038005ACD60 /* Iterate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8631C6BA038005ACD60 /* Iterate.swift */; };
|
||||
24FFA8801C6BA038005ACD60 /* NestedSequences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8641C6BA038005ACD60 /* NestedSequences.swift */; };
|
||||
24FFA8811C6BA038005ACD60 /* Permutations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8651C6BA038005ACD60 /* Permutations.swift */; };
|
||||
24FFA8821C6BA038005ACD60 /* ScanReduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8661C6BA038005ACD60 /* ScanReduce.swift */; };
|
||||
24FFA8831C6BA038005ACD60 /* Slicing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8671C6BA038005ACD60 /* Slicing.swift */; };
|
||||
24FFA8841C6BA038005ACD60 /* TakeDrop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8681C6BA038005ACD60 /* TakeDrop.swift */; };
|
||||
24FFA8851C6BA038005ACD60 /* Zip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8691C6BA038005ACD60 /* Zip.swift */; };
|
||||
24FFA8861C6BA038005ACD60 /* TestCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA86A1C6BA038005ACD60 /* TestCommons.swift */; };
|
||||
2BF7957B6518CA68241BB2CE /* Pods_PixelImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C55F9558B3B267413C3A07A6 /* Pods_PixelImage.framework */; };
|
||||
400CECBA73C835B415805169 /* Pods_PixelImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D10DBF530542A19EEF699A /* Pods_PixelImage.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0C9CE70F7D2C2896912B7B14 /* Pods-PixelImage.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PixelImage.release.xcconfig"; path = "Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage.release.xcconfig"; sourceTree = "<group>"; };
|
||||
242686841C63B72A00D62456 /* PixelImage.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PixelImage.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
242686871C63B72A00D62456 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
242686891C63B72A00D62456 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
@ -75,37 +50,10 @@
|
||||
24ED21CC1C6C2397009C40FC /* MetaballDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetaballDataSource.swift; sourceTree = "<group>"; };
|
||||
24FC38331C7F931E0085C04A /* Metaball.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Metaball.swift; sourceTree = "<group>"; };
|
||||
24FC38351C7F9ABE0085C04A /* Dispatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dispatch.swift; sourceTree = "<group>"; };
|
||||
24FFA84C1C6BA038005ACD60 /* ApproximationOperator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApproximationOperator.swift; sourceTree = "<group>"; };
|
||||
24FFA84D1C6BA038005ACD60 /* Collections.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Collections.swift; sourceTree = "<group>"; };
|
||||
24FFA84E1C6BA038005ACD60 /* ComparatorChains.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComparatorChains.swift; sourceTree = "<group>"; };
|
||||
24FFA84F1C6BA038005ACD60 /* Dictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = "<group>"; };
|
||||
24FFA8511C6BA038005ACD60 /* NSNumber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSNumber.swift; sourceTree = "<group>"; };
|
||||
24FFA8521C6BA038005ACD60 /* Numeric.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Numeric.swift; sourceTree = "<group>"; };
|
||||
24FFA8531C6BA038005ACD60 /* PowerOperator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PowerOperator.swift; sourceTree = "<group>"; };
|
||||
24FFA8541C6BA038005ACD60 /* Sequence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sequence.swift; sourceTree = "<group>"; };
|
||||
24FFA8561C6BA038005ACD60 /* Memoize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Memoize.swift; sourceTree = "<group>"; };
|
||||
24FFA8571C6BA038005ACD60 /* SignOperator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignOperator.swift; sourceTree = "<group>"; };
|
||||
24FFA8581C6BA038005ACD60 /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
|
||||
24FFA85A1C6BA038005ACD60 /* Categorise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Categorise.swift; sourceTree = "<group>"; };
|
||||
24FFA85B1C6BA038005ACD60 /* ChunkWindowSplit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChunkWindowSplit.swift; sourceTree = "<group>"; };
|
||||
24FFA85C1C6BA038005ACD60 /* Combinations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Combinations.swift; sourceTree = "<group>"; };
|
||||
24FFA85D1C6BA038005ACD60 /* Cycle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cycle.swift; sourceTree = "<group>"; };
|
||||
24FFA85E1C6BA038005ACD60 /* Enumerate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Enumerate.swift; sourceTree = "<group>"; };
|
||||
24FFA85F1C6BA038005ACD60 /* Finding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Finding.swift; sourceTree = "<group>"; };
|
||||
24FFA8601C6BA038005ACD60 /* FlatMap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlatMap.swift; sourceTree = "<group>"; };
|
||||
24FFA8611C6BA038005ACD60 /* Hopping.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Hopping.swift; sourceTree = "<group>"; };
|
||||
24FFA8621C6BA038005ACD60 /* Interpose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Interpose.swift; sourceTree = "<group>"; };
|
||||
24FFA8631C6BA038005ACD60 /* Iterate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Iterate.swift; sourceTree = "<group>"; };
|
||||
24FFA8641C6BA038005ACD60 /* NestedSequences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NestedSequences.swift; sourceTree = "<group>"; };
|
||||
24FFA8651C6BA038005ACD60 /* Permutations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Permutations.swift; sourceTree = "<group>"; };
|
||||
24FFA8661C6BA038005ACD60 /* ScanReduce.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScanReduce.swift; sourceTree = "<group>"; };
|
||||
24FFA8671C6BA038005ACD60 /* Slicing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Slicing.swift; sourceTree = "<group>"; };
|
||||
24FFA8681C6BA038005ACD60 /* TakeDrop.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TakeDrop.swift; sourceTree = "<group>"; };
|
||||
24FFA8691C6BA038005ACD60 /* Zip.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Zip.swift; sourceTree = "<group>"; };
|
||||
24FFA86A1C6BA038005ACD60 /* TestCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestCommons.swift; sourceTree = "<group>"; };
|
||||
B1A755EFC03DA2A172C2B82F /* Pods-PixelImage.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PixelImage.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
C419D37C90A6BE8B5139806A /* Pods-PixelImage.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PixelImage.release.xcconfig"; path = "Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage.release.xcconfig"; sourceTree = "<group>"; };
|
||||
C55F9558B3B267413C3A07A6 /* Pods_PixelImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PixelImage.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
24FFA8521C6BA038005ACD60 /* Numeric.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Numeric.swift; path = SwiftSugar/Numeric.swift; sourceTree = "<group>"; };
|
||||
24FFA8531C6BA038005ACD60 /* PowerOperator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PowerOperator.swift; path = SwiftSugar/PowerOperator.swift; sourceTree = "<group>"; };
|
||||
6659D12A5984961F335BDF69 /* Pods-PixelImage.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PixelImage.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
93D10DBF530542A19EEF699A /* Pods_PixelImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PixelImage.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -115,13 +63,22 @@
|
||||
files = (
|
||||
24E1E7E41C67D39300ECF1C4 /* MetalKit.framework in Frameworks */,
|
||||
24E1E7E21C67D37F00ECF1C4 /* Metal.framework in Frameworks */,
|
||||
2BF7957B6518CA68241BB2CE /* Pods_PixelImage.framework in Frameworks */,
|
||||
400CECBA73C835B415805169 /* Pods_PixelImage.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
0C205AE1A1A55E89EFAEE593 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6659D12A5984961F335BDF69 /* Pods-PixelImage.debug.xcconfig */,
|
||||
0C9CE70F7D2C2896912B7B14 /* Pods-PixelImage.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2426867B1C63B72A00D62456 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -129,8 +86,8 @@
|
||||
24E1E7E11C67D37F00ECF1C4 /* Metal.framework */,
|
||||
242686861C63B72A00D62456 /* PixelImage */,
|
||||
242686851C63B72A00D62456 /* Products */,
|
||||
F1933B48ED44BA9FCD7A4A1F /* Pods */,
|
||||
588576572D7A188031904848 /* Frameworks */,
|
||||
0C205AE1A1A55E89EFAEE593 /* Pods */,
|
||||
8C02F866C2C0C9A954BB9375 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@ -145,7 +102,9 @@
|
||||
242686861C63B72A00D62456 /* PixelImage */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
24FFA84B1C6BA038005ACD60 /* SwiftSugar */,
|
||||
2461651A1C6DA4F400A913C8 /* Interpolation.swift */,
|
||||
24FFA8521C6BA038005ACD60 /* Numeric.swift */,
|
||||
24FFA8531C6BA038005ACD60 /* PowerOperator.swift */,
|
||||
242686871C63B72A00D62456 /* AppDelegate.swift */,
|
||||
24FC38351C7F9ABE0085C04A /* Dispatch.swift */,
|
||||
24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */,
|
||||
@ -153,10 +112,10 @@
|
||||
24FC38331C7F931E0085C04A /* Metaball.swift */,
|
||||
24E1E7EE1C67D74300ECF1C4 /* Metal.swift */,
|
||||
249CF84B1C6D113C008B0C78 /* Matrix.swift */,
|
||||
242686891C63B72A00D62456 /* ViewController.swift */,
|
||||
24ED21CC1C6C2397009C40FC /* MetaballDataSource.swift */,
|
||||
24E1E7EA1C67D70300ECF1C4 /* MetalMetaballRenderer.swift */,
|
||||
24E1E7EF1C67D74300ECF1C4 /* shaders.metal */,
|
||||
242686891C63B72A00D62456 /* ViewController.swift */,
|
||||
2426868B1C63B72A00D62456 /* Main.storyboard */,
|
||||
2426868E1C63B72A00D62456 /* Assets.xcassets */,
|
||||
242686901C63B72A00D62456 /* LaunchScreen.storyboard */,
|
||||
@ -165,83 +124,14 @@
|
||||
path = PixelImage;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
24FFA84B1C6BA038005ACD60 /* SwiftSugar */ = {
|
||||
8C02F866C2C0C9A954BB9375 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
24FFA84C1C6BA038005ACD60 /* ApproximationOperator.swift */,
|
||||
2461651A1C6DA4F400A913C8 /* Interpolation.swift */,
|
||||
24FFA84D1C6BA038005ACD60 /* Collections.swift */,
|
||||
24FFA84E1C6BA038005ACD60 /* ComparatorChains.swift */,
|
||||
24FFA84F1C6BA038005ACD60 /* Dictionary.swift */,
|
||||
24FFA8501C6BA038005ACD60 /* Foundation */,
|
||||
24FFA8521C6BA038005ACD60 /* Numeric.swift */,
|
||||
24FFA8531C6BA038005ACD60 /* PowerOperator.swift */,
|
||||
24FFA8541C6BA038005ACD60 /* Sequence.swift */,
|
||||
24FFA8551C6BA038005ACD60 /* Sequences */,
|
||||
24FFA8571C6BA038005ACD60 /* SignOperator.swift */,
|
||||
24FFA8581C6BA038005ACD60 /* String.swift */,
|
||||
24FFA8591C6BA038005ACD60 /* SwiftSequences */,
|
||||
24FFA86A1C6BA038005ACD60 /* TestCommons.swift */,
|
||||
);
|
||||
path = SwiftSugar;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
24FFA8501C6BA038005ACD60 /* Foundation */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
24FFA8511C6BA038005ACD60 /* NSNumber.swift */,
|
||||
);
|
||||
path = Foundation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
24FFA8551C6BA038005ACD60 /* Sequences */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
24FFA8561C6BA038005ACD60 /* Memoize.swift */,
|
||||
);
|
||||
path = Sequences;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
24FFA8591C6BA038005ACD60 /* SwiftSequences */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
24FFA85A1C6BA038005ACD60 /* Categorise.swift */,
|
||||
24FFA85B1C6BA038005ACD60 /* ChunkWindowSplit.swift */,
|
||||
24FFA85C1C6BA038005ACD60 /* Combinations.swift */,
|
||||
24FFA85D1C6BA038005ACD60 /* Cycle.swift */,
|
||||
24FFA85E1C6BA038005ACD60 /* Enumerate.swift */,
|
||||
24FFA85F1C6BA038005ACD60 /* Finding.swift */,
|
||||
24FFA8601C6BA038005ACD60 /* FlatMap.swift */,
|
||||
24FFA8611C6BA038005ACD60 /* Hopping.swift */,
|
||||
24FFA8621C6BA038005ACD60 /* Interpose.swift */,
|
||||
24FFA8631C6BA038005ACD60 /* Iterate.swift */,
|
||||
24FFA8641C6BA038005ACD60 /* NestedSequences.swift */,
|
||||
24FFA8651C6BA038005ACD60 /* Permutations.swift */,
|
||||
24FFA8661C6BA038005ACD60 /* ScanReduce.swift */,
|
||||
24FFA8671C6BA038005ACD60 /* Slicing.swift */,
|
||||
24FFA8681C6BA038005ACD60 /* TakeDrop.swift */,
|
||||
24FFA8691C6BA038005ACD60 /* Zip.swift */,
|
||||
);
|
||||
path = SwiftSequences;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
588576572D7A188031904848 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C55F9558B3B267413C3A07A6 /* Pods_PixelImage.framework */,
|
||||
93D10DBF530542A19EEF699A /* Pods_PixelImage.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F1933B48ED44BA9FCD7A4A1F /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B1A755EFC03DA2A172C2B82F /* Pods-PixelImage.debug.xcconfig */,
|
||||
C419D37C90A6BE8B5139806A /* Pods-PixelImage.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -249,13 +139,12 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 242686961C63B72A00D62456 /* Build configuration list for PBXNativeTarget "PixelImage" */;
|
||||
buildPhases = (
|
||||
EF55C7246917A184756D93D8 /* Check Pods Manifest.lock */,
|
||||
041D2472535A642E23154A31 /* [CP] Check Pods Manifest.lock */,
|
||||
242686801C63B72A00D62456 /* Sources */,
|
||||
242686811C63B72A00D62456 /* Frameworks */,
|
||||
242686821C63B72A00D62456 /* Resources */,
|
||||
C7A2DF67265A9D17DEFBD193 /* Embed Pods Frameworks */,
|
||||
FADC01F75BFAC01F0260D1C9 /* Copy Pods Resources */,
|
||||
DD0396CE594E3EAC8D18CC6C /* Tailor */,
|
||||
3CA888DC160972BAEB74EC52 /* [CP] Embed Pods Frameworks */,
|
||||
47F9F13E3CB75C7B4B0136A5 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -273,12 +162,13 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0720;
|
||||
LastUpgradeCheck = 0720;
|
||||
LastUpgradeCheck = 0830;
|
||||
ORGANIZATIONNAME = "Vinicius Vendramini";
|
||||
TargetAttributes = {
|
||||
242686831C63B72A00D62456 = {
|
||||
CreatedOnToolsVersion = 7.2;
|
||||
DevelopmentTeam = HHT774898M;
|
||||
LastSwiftMigration = 0830;
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -314,14 +204,29 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
C7A2DF67265A9D17DEFBD193 /* Embed Pods Frameworks */ = {
|
||||
041D2472535A642E23154A31 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Embed Pods Frameworks";
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
3CA888DC160972BAEB74EC52 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -329,43 +234,14 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
DD0396CE594E3EAC8D18CC6C /* Tailor */ = {
|
||||
47F9F13E3CB75C7B4B0136A5 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = Tailor;
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if hash tailor 2>/dev/null; then\n tailor --except=function-whitespace,leading-whitespace,constant-k-prefix --max-severity error\nelse\n echo \"warning: Please install Tailor from https://tailor.sh\"\nfi";
|
||||
};
|
||||
EF55C7246917A184756D93D8 /* Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
FADC01F75BFAC01F0260D1C9 /* Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Copy Pods Resources";
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -380,46 +256,20 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
24FFA87B1C6BA038005ACD60 /* Finding.swift in Sources */,
|
||||
24FFA8751C6BA038005ACD60 /* String.swift in Sources */,
|
||||
24FFA8781C6BA038005ACD60 /* Combinations.swift in Sources */,
|
||||
24FFA87E1C6BA038005ACD60 /* Interpose.swift in Sources */,
|
||||
2426868A1C63B72A00D62456 /* ViewController.swift in Sources */,
|
||||
24FFA8841C6BA038005ACD60 /* TakeDrop.swift in Sources */,
|
||||
24FFA8771C6BA038005ACD60 /* ChunkWindowSplit.swift in Sources */,
|
||||
24FFA86F1C6BA038005ACD60 /* NSNumber.swift in Sources */,
|
||||
2461651B1C6DA4F400A913C8 /* Interpolation.swift in Sources */,
|
||||
24FC38341C7F931E0085C04A /* Metaball.swift in Sources */,
|
||||
24FFA8861C6BA038005ACD60 /* TestCommons.swift in Sources */,
|
||||
24FFA8741C6BA038005ACD60 /* SignOperator.swift in Sources */,
|
||||
24FFA8821C6BA038005ACD60 /* ScanReduce.swift in Sources */,
|
||||
24ED21CD1C6C2397009C40FC /* MetaballDataSource.swift in Sources */,
|
||||
24FFA8831C6BA038005ACD60 /* Slicing.swift in Sources */,
|
||||
24FFA8721C6BA038005ACD60 /* Sequence.swift in Sources */,
|
||||
24FFA87F1C6BA038005ACD60 /* Iterate.swift in Sources */,
|
||||
24FC38361C7F9ABE0085C04A /* Dispatch.swift in Sources */,
|
||||
24FFA8761C6BA038005ACD60 /* Categorise.swift in Sources */,
|
||||
24FFA86D1C6BA038005ACD60 /* ComparatorChains.swift in Sources */,
|
||||
24FFA8711C6BA038005ACD60 /* PowerOperator.swift in Sources */,
|
||||
24E1E7D71C67C8B200ECF1C4 /* UIKit.swift in Sources */,
|
||||
24FFA8851C6BA038005ACD60 /* Zip.swift in Sources */,
|
||||
249CF84C1C6D113C008B0C78 /* Matrix.swift in Sources */,
|
||||
24FFA8791C6BA038005ACD60 /* Cycle.swift in Sources */,
|
||||
24E1E7F11C67D74300ECF1C4 /* shaders.metal in Sources */,
|
||||
24FFA86E1C6BA038005ACD60 /* Dictionary.swift in Sources */,
|
||||
24FFA87D1C6BA038005ACD60 /* Hopping.swift in Sources */,
|
||||
24E1E7EB1C67D70300ECF1C4 /* MetalMetaballRenderer.swift in Sources */,
|
||||
246B0F831C70635D00A71D05 /* UIColor.swift in Sources */,
|
||||
24FFA87A1C6BA038005ACD60 /* Enumerate.swift in Sources */,
|
||||
242686881C63B72A00D62456 /* AppDelegate.swift in Sources */,
|
||||
24E1E7F01C67D74300ECF1C4 /* Metal.swift in Sources */,
|
||||
24FFA87C1C6BA038005ACD60 /* FlatMap.swift in Sources */,
|
||||
24FFA8701C6BA038005ACD60 /* Numeric.swift in Sources */,
|
||||
24FFA8811C6BA038005ACD60 /* Permutations.swift in Sources */,
|
||||
24FFA86B1C6BA038005ACD60 /* ApproximationOperator.swift in Sources */,
|
||||
24FFA8801C6BA038005ACD60 /* NestedSequences.swift in Sources */,
|
||||
24FFA8731C6BA038005ACD60 /* Memoize.swift in Sources */,
|
||||
24FFA86C1C6BA038005ACD60 /* Collections.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -458,8 +308,10 @@
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@ -503,8 +355,10 @@
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@ -523,6 +377,7 @@
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
@ -530,25 +385,29 @@
|
||||
};
|
||||
242686971C63B72A00D62456 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = B1A755EFC03DA2A172C2B82F /* Pods-PixelImage.debug.xcconfig */;
|
||||
baseConfigurationReference = 6659D12A5984961F335BDF69 /* Pods-PixelImage.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
DEVELOPMENT_TEAM = HHT774898M;
|
||||
INFOPLIST_FILE = PixelImage/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = vinivendra.PixelImage;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
242686981C63B72A00D62456 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = C419D37C90A6BE8B5139806A /* Pods-PixelImage.release.xcconfig */;
|
||||
baseConfigurationReference = 0C9CE70F7D2C2896912B7B14 /* Pods-PixelImage.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
DEVELOPMENT_TEAM = HHT774898M;
|
||||
INFOPLIST_FILE = PixelImage/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = vinivendra.PixelImage;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
LastUpgradeVersion = "0830"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -13,30 +13,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(application: UIApplication) {
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(application: UIApplication) {
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(application: UIApplication) {
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(application: UIApplication) {
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
func applicationWillTerminate(application: UIApplication) {
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
|
||||
import Dispatch
|
||||
|
||||
func delay(duration: Float = 1, block: () -> ()) {
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(duration * Float(NSEC_PER_SEC))), dispatch_get_main_queue(), block)
|
||||
func delay(_ duration: Float = 1, block: @escaping () -> ()) {
|
||||
DispatchQueue.main.asyncAfter(
|
||||
deadline: DispatchTime.now() +
|
||||
Double(duration * Float(NSEC_PER_SEC)) /
|
||||
Double(NSEC_PER_SEC),
|
||||
execute: block)
|
||||
}
|
||||
|
@ -1,23 +1,23 @@
|
||||
|
||||
import Darwin
|
||||
|
||||
func interpolateCubeEaseIn<T: Numeric>(linear: T) -> T {
|
||||
func interpolateCubeEaseIn<T: Numeric>(_ linear: T) -> T {
|
||||
return linear ^ 3
|
||||
}
|
||||
|
||||
func interpolateSquareEaseIn<T: Numeric>(linear: T) -> T {
|
||||
func interpolateSquareEaseIn<T: Numeric>(_ linear: T) -> T {
|
||||
return linear ^ 2
|
||||
}
|
||||
|
||||
func interpolateSquareEaseOut<T: Numeric>(linear: T) -> T {
|
||||
func interpolateSquareEaseOut<T: Numeric>(_ linear: T) -> T {
|
||||
return 1 - (1 - linear) * (1 - linear)
|
||||
}
|
||||
|
||||
func interpolateSmooth<T: Numeric>(linear: T) -> T {
|
||||
func interpolateSmooth<T: Numeric>(_ linear: T) -> T {
|
||||
return ((linear) * (linear) * (linear) * ((linear) * ((linear) * 6 - 15) + 10))
|
||||
}
|
||||
|
||||
func createStringKeyframes(bounces: Int = 2, elasticity: Double = 1.1, bounceSpeed: Double) -> [(time: Double, position: Double)] {
|
||||
func createStringKeyframes(_ bounces: Int = 2, elasticity: Double = 1.1, bounceSpeed: Double) -> [(time: Double, position: Double)] {
|
||||
// Setup keyframes
|
||||
var keyFrames: [(time: Double, position: Double)] = [(1, 1)]
|
||||
|
||||
@ -28,14 +28,9 @@ func createStringKeyframes(bounces: Int = 2, elasticity: Double = 1.1, bounceSpe
|
||||
var bounceReach = overreach / (2 ^ Double(bounces - 1))
|
||||
var currentBouncePosition: Double = 1.0 + bounceDirection * bounceReach
|
||||
|
||||
print(currentBounceTime)
|
||||
print(bounceDirection)
|
||||
print(bounceReach)
|
||||
print(currentBouncePosition)
|
||||
|
||||
keyFrames.append((1.0 - currentBounceTime, currentBouncePosition))
|
||||
|
||||
for i in (1..<bounces).reverse() {
|
||||
for i in (1..<bounces).reversed() {
|
||||
currentBounceTime += overreach / (bounceSpeed ^ Double(i + 1))
|
||||
currentBounceTime += overreach / (bounceSpeed ^ Double(i))
|
||||
bounceDirection = Double((i % 2) * 2 - 1)
|
||||
@ -43,24 +38,19 @@ func createStringKeyframes(bounces: Int = 2, elasticity: Double = 1.1, bounceSpe
|
||||
currentBouncePosition = 1.0 + bounceDirection * bounceReach
|
||||
|
||||
keyFrames.append((1.0 - currentBounceTime, currentBouncePosition))
|
||||
|
||||
print(currentBounceTime)
|
||||
print(bounceDirection)
|
||||
print(bounceReach)
|
||||
print(currentBouncePosition)
|
||||
}
|
||||
|
||||
keyFrames.append((0, 0))
|
||||
|
||||
var reversed = [(time: Double, position: Double)]()
|
||||
for keyFrame in keyFrames.reverse() {
|
||||
for keyFrame in keyFrames.reversed() {
|
||||
reversed.append(keyFrame)
|
||||
}
|
||||
|
||||
return reversed
|
||||
}
|
||||
|
||||
func interpolateSpring<T: Numeric>(linear: T, bounces: Int = 2, elasticity: Double = 1.1, bounceSpeed: Double = 1.0) -> T {
|
||||
func interpolateSpring<T: Numeric>(_ linear: T, bounces: Int = 2, elasticity: Double = 1.1, bounceSpeed: Double = 1.0) -> T {
|
||||
let keyFrames: [(time: Double, position: Double)]
|
||||
keyFrames = createStringKeyframes(bounces, elasticity: elasticity, bounceSpeed: bounceSpeed)
|
||||
|
||||
|
@ -17,12 +17,12 @@ class Graph<T> {
|
||||
self.adjacencyMatrix = Matrix(size: size)
|
||||
}
|
||||
|
||||
func addEdge(i: Int, _ j: Int) {
|
||||
func addEdge(_ i: Int, _ j: Int) {
|
||||
adjacencyMatrix.set(i, j)
|
||||
adjacencyMatrix.set(j, i)
|
||||
}
|
||||
|
||||
func removeEdge(i: Int, _ j: Int) {
|
||||
func removeEdge(_ i: Int, _ j: Int) {
|
||||
adjacencyMatrix.reset(i, j)
|
||||
adjacencyMatrix.reset(j, i)
|
||||
}
|
||||
@ -35,30 +35,30 @@ struct Matrix: CustomStringConvertible {
|
||||
let size: Int
|
||||
|
||||
init(size: Int) {
|
||||
buffer = [Float](count: size * size, repeatedValue: 0.0)
|
||||
buffer = [Float](repeating: 0.0, count: size * size)
|
||||
self.size = size
|
||||
}
|
||||
|
||||
func get(i: Int, j: Int) -> Float {
|
||||
func get(_ i: Int, j: Int) -> Float {
|
||||
return buffer[index(i, j)]
|
||||
}
|
||||
|
||||
mutating func set(i: Int, _ j: Int, value: Float = 1.0) {
|
||||
mutating func set(_ i: Int, _ j: Int, value: Float = 1.0) {
|
||||
buffer[index(i, j)] = value
|
||||
}
|
||||
|
||||
mutating func reset(i: Int, _ j: Int) {
|
||||
mutating func reset(_ i: Int, _ j: Int) {
|
||||
buffer[index(i, j)] = 0.0
|
||||
}
|
||||
|
||||
private func index(i: Int, _ j: Int) -> Int {
|
||||
fileprivate func index(_ i: Int, _ j: Int) -> Int {
|
||||
return j * size + i
|
||||
}
|
||||
|
||||
var description: String {
|
||||
get {
|
||||
var result = ""
|
||||
for (index, value) in buffer.enumerate() {
|
||||
for (index, value) in buffer.enumerated() {
|
||||
result = result + "\(value)"
|
||||
if index % size == size - 1 {
|
||||
result = result + "\n"
|
||||
|
@ -5,7 +5,8 @@ class Metaball: UIView {
|
||||
|
||||
var color: UIColor
|
||||
|
||||
init(position: CGPoint, color: UIColor = UIColor(randomFlatColorOfShadeStyle: .Light)) {
|
||||
init(position: CGPoint,
|
||||
color: UIColor = UIColor(randomFlatColorOf: .light)) {
|
||||
self.color = color
|
||||
super.init(frame: CGRect.zero)
|
||||
|
||||
@ -14,23 +15,25 @@ class Metaball: UIView {
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
self.color = UIColor(randomFlatColorOfShadeStyle: .Light)
|
||||
self.color = UIColor(randomFlatColorOf: .light)
|
||||
super.init(coder: aDecoder)
|
||||
}
|
||||
}
|
||||
|
||||
class EdgeAnimationParameters {
|
||||
let startDate: NSDate
|
||||
let startDate: Date
|
||||
let duration: Float
|
||||
let fadeIn: Bool
|
||||
let i: Int
|
||||
let j: Int
|
||||
|
||||
func unpack() -> (startDate: NSDate, duration: Float, fadeIn: Bool, i: Int, j: Int) {
|
||||
func unpack() -> (startDate: Date, duration: Float, fadeIn: Bool,
|
||||
i: Int, j: Int)
|
||||
{
|
||||
return (startDate, duration, fadeIn, i, j)
|
||||
}
|
||||
|
||||
init(startDate: NSDate, duration: Float, fadeIn: Bool, i: Int, j: Int) {
|
||||
init(startDate: Date, duration: Float, fadeIn: Bool, i: Int, j: Int) {
|
||||
self.startDate = startDate
|
||||
self.duration = duration
|
||||
self.fadeIn = fadeIn
|
||||
@ -40,17 +43,21 @@ class EdgeAnimationParameters {
|
||||
}
|
||||
|
||||
class VertexAnimationParameters {
|
||||
let startDate: NSDate
|
||||
let startDate: Date
|
||||
let duration: Float
|
||||
let origin: CGPoint
|
||||
let destination: CGPoint
|
||||
let metaball: Metaball
|
||||
|
||||
func unpack() -> (startDate: NSDate, duration: Float, origin: CGPoint, destination: CGPoint, metaball: Metaball) {
|
||||
func unpack() -> (startDate: Date, duration: Float, origin: CGPoint,
|
||||
destination: CGPoint, metaball: Metaball)
|
||||
{
|
||||
return (startDate, duration, origin, destination, metaball)
|
||||
}
|
||||
|
||||
init(startDate: NSDate, duration: Float, origin: CGPoint, destination: CGPoint, metaball: Metaball) {
|
||||
init(startDate: Date, duration: Float, origin: CGPoint,
|
||||
destination: CGPoint, metaball: Metaball)
|
||||
{
|
||||
self.startDate = startDate
|
||||
self.duration = duration
|
||||
self.origin = origin
|
||||
|
@ -9,13 +9,13 @@ class MTLContext {
|
||||
init(device: MTLDevice = MTLCreateSystemDefaultDevice()!) {
|
||||
self.device = device
|
||||
self.library = device.newDefaultLibrary()!
|
||||
self.commandQueue = device.newCommandQueue()
|
||||
self.commandQueue = device.makeCommandQueue()
|
||||
}
|
||||
}
|
||||
|
||||
class MTLComputeContext {
|
||||
var texture: MTLTexture
|
||||
var imageBuffer: UnsafeMutablePointer<Void>
|
||||
var imageBuffer: UnsafeMutableRawPointer
|
||||
|
||||
init(size: CGSize, texture: MTLTexture) {
|
||||
let width = Int(size.width)
|
||||
@ -26,7 +26,7 @@ class MTLComputeContext {
|
||||
self.texture = texture
|
||||
}
|
||||
|
||||
func updateToSize(size: CGSize, texture: MTLTexture) {
|
||||
func updateToSize(_ size: CGSize, texture: MTLTexture) {
|
||||
free(imageBuffer)
|
||||
|
||||
let width = Int(size.width)
|
||||
|
@ -14,18 +14,18 @@ import ChameleonFramework
|
||||
|
||||
let dataSource: MetaballDataSource
|
||||
|
||||
let semaphore = dispatch_semaphore_create(2)
|
||||
let semaphore = DispatchSemaphore(value: 2)
|
||||
|
||||
enum RendererState {
|
||||
case Idle
|
||||
case Running
|
||||
case Ending
|
||||
case idle
|
||||
case running
|
||||
case ending
|
||||
}
|
||||
|
||||
var state: RendererState = .Idle {
|
||||
var state: RendererState = .idle {
|
||||
willSet {
|
||||
if state == .Idle {
|
||||
if newValue == .Running {
|
||||
if state == .idle {
|
||||
if newValue == .running {
|
||||
updateTargetView()
|
||||
}
|
||||
}
|
||||
@ -39,32 +39,40 @@ import ChameleonFramework
|
||||
|
||||
let width = Int(frame.width)
|
||||
let height = Int(frame.height)
|
||||
let textureDescriptor = MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.BGRA8Unorm, width: width, height: height, mipmapped: false)
|
||||
let textureDescriptor =
|
||||
MTLTextureDescriptor.texture2DDescriptor(
|
||||
pixelFormat: .bgra8Unorm,
|
||||
width: width,
|
||||
height: height,
|
||||
mipmapped: false)
|
||||
|
||||
let texture1 = context.device.newTextureWithDescriptor(textureDescriptor)
|
||||
activeComputeContext = MTLComputeContext(size: targetView.size, texture: texture1)
|
||||
let texture2 = context.device.newTextureWithDescriptor(textureDescriptor)
|
||||
idleComputeContext = MTLComputeContext(size: targetView.size, texture: texture2)
|
||||
let texture1 =
|
||||
context.device.makeTexture(descriptor: textureDescriptor)
|
||||
activeComputeContext = MTLComputeContext(size: targetView.size,
|
||||
texture: texture1)
|
||||
let texture2 =
|
||||
context.device.makeTexture(descriptor: textureDescriptor)
|
||||
idleComputeContext = MTLComputeContext(size: targetView.size,
|
||||
texture: texture2)
|
||||
}
|
||||
|
||||
internal func updateTargetView() {
|
||||
let timeout = DispatchTime.now() + Double(1000000000) / Double(NSEC_PER_SEC)
|
||||
_ = semaphore.wait(timeout: timeout)
|
||||
|
||||
let timeout = dispatch_time(DISPATCH_TIME_NOW, 1000000000)
|
||||
dispatch_semaphore_wait(semaphore, timeout)
|
||||
|
||||
state = .Ending
|
||||
|
||||
let userInteractiveQueue = dispatch_get_global_queue(Int(QOS_CLASS_USER_INTERACTIVE.rawValue), 0)
|
||||
dispatch_async(userInteractiveQueue) { () -> Void in
|
||||
state = .ending
|
||||
|
||||
let userInteractiveQueue =
|
||||
DispatchQueue.global(qos: DispatchQoS.QoSClass.userInteractive)
|
||||
userInteractiveQueue.async { () -> Void in
|
||||
let computeContext = self.activeComputeContext
|
||||
swap(&self.activeComputeContext, &self.idleComputeContext)
|
||||
|
||||
// Render graphics to metal texture
|
||||
self.renderToContext(computeContext)
|
||||
|
||||
if self.state != .Running {
|
||||
self.state = .Idle
|
||||
if self.state != .running {
|
||||
self.state = .idle
|
||||
} else {
|
||||
self.updateTargetView()
|
||||
}
|
||||
@ -72,16 +80,16 @@ import ChameleonFramework
|
||||
// Transform metal texture into image
|
||||
let uiimage = self.createImageFromContext(computeContext)
|
||||
|
||||
dispatch_semaphore_signal(self.semaphore)
|
||||
self.semaphore.signal()
|
||||
|
||||
dispatch_async(dispatch_get_main_queue()) { () -> Void in
|
||||
DispatchQueue.main.async { () -> Void in
|
||||
// Send image to view
|
||||
self.targetView.image = uiimage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal func renderToContext(computeContext: MTLComputeContext) {
|
||||
internal func renderToContext(_ computeContext: MTLComputeContext) {
|
||||
let width = Int(targetView.width)
|
||||
let height = Int(targetView.height)
|
||||
|
||||
@ -89,23 +97,27 @@ import ChameleonFramework
|
||||
let pipeline: MTLComputePipelineState
|
||||
do {
|
||||
// Get long-lived objects
|
||||
kernelFunction = context.library.newFunctionWithName("drawMetaballs")
|
||||
pipeline = try context.device.newComputePipelineStateWithFunction(kernelFunction!)
|
||||
kernelFunction =
|
||||
context.library.makeFunction(name: "drawMetaballs")
|
||||
pipeline = try context.device.makeComputePipelineState(
|
||||
function: kernelFunction!)
|
||||
|
||||
// Configure info for computing
|
||||
let threadGroupCounts = MTLSizeMake(8, 8, 1)
|
||||
let threadGroups = MTLSizeMake(width / threadGroupCounts.width, height / threadGroupCounts.height, 1)
|
||||
let threadGroups = MTLSizeMake(width / threadGroupCounts.width,
|
||||
height / threadGroupCounts.height,
|
||||
1)
|
||||
|
||||
// Send commands to metal and render
|
||||
let commandBuffer = context.commandQueue.commandBuffer()
|
||||
let commandBuffer = context.commandQueue.makeCommandBuffer()
|
||||
|
||||
let commandEncoder = commandBuffer.computeCommandEncoder()
|
||||
let commandEncoder = commandBuffer.makeComputeCommandEncoder()
|
||||
commandEncoder.setComputePipelineState(pipeline)
|
||||
commandEncoder.setTexture(computeContext.texture, atIndex: 0)
|
||||
commandEncoder.setTexture(computeContext.texture, at: 0)
|
||||
let metaballInfoBuffer = metaballBuffer()
|
||||
commandEncoder.setBuffer(metaballInfoBuffer, offset: 0, atIndex: 0)
|
||||
commandEncoder.setBuffer(metaballInfoBuffer, offset: 0, at: 0)
|
||||
let edgesBuffer = metaballEdgesBuffer()
|
||||
commandEncoder.setBuffer(edgesBuffer, offset: 0, atIndex: 1)
|
||||
commandEncoder.setBuffer(edgesBuffer, offset: 0, at: 1)
|
||||
commandEncoder.dispatchThreadgroups(threadGroups,
|
||||
threadsPerThreadgroup: threadGroupCounts)
|
||||
commandEncoder.endEncoding()
|
||||
@ -117,37 +129,50 @@ import ChameleonFramework
|
||||
}
|
||||
}
|
||||
|
||||
internal func createImageFromContext(computeContext: MTLComputeContext) -> UIImage {
|
||||
internal func createImageFromContext(_ computeContext: MTLComputeContext)
|
||||
-> UIImage
|
||||
{
|
||||
let texture = computeContext.texture
|
||||
|
||||
// Get image info
|
||||
let imageSize = CGSizeMake(CGFloat(texture.width), CGFloat(texture.height))
|
||||
let imageSize = CGSize(width: CGFloat(texture.width),
|
||||
height: CGFloat(texture.height))
|
||||
let width = Int(imageSize.width)
|
||||
let height = Int(imageSize.height)
|
||||
let imageByteCount = width * height * 4
|
||||
let bytesPerRow = width * 4
|
||||
let region = MTLRegionMake2D(0, 0, width, height)
|
||||
|
||||
// Allocate the buffer if needed
|
||||
if computeContext.imageBuffer == nil {
|
||||
computeContext.imageBuffer = malloc(imageByteCount)
|
||||
}
|
||||
|
||||
// Transfer texture info into image buffer
|
||||
texture.getBytes(computeContext.imageBuffer, bytesPerRow: bytesPerRow, fromRegion: region, mipmapLevel: 0)
|
||||
texture.getBytes(computeContext.imageBuffer,
|
||||
bytesPerRow: bytesPerRow,
|
||||
from: region,
|
||||
mipmapLevel: 0)
|
||||
|
||||
// Get info for UIImage
|
||||
let provider = CGDataProviderCreateWithData(nil, computeContext.imageBuffer, imageByteCount, nil)
|
||||
let bitsPerComponent = 8
|
||||
let provider = CGDataProvider(dataInfo: nil,
|
||||
data: computeContext.imageBuffer,
|
||||
size: imageByteCount) {
|
||||
(_, _, _) in }
|
||||
let bitsPerComponent = 8
|
||||
let bitsperPixel = 32
|
||||
let colorSpaceRef = CGColorSpaceCreateDeviceRGB()
|
||||
let bitmapInfoRaw = CGImageAlphaInfo.PremultipliedLast.rawValue | CGBitmapInfo.ByteOrder32Big.rawValue
|
||||
let bitmapInfoRaw = CGImageAlphaInfo.premultipliedLast.rawValue |
|
||||
CGBitmapInfo.byteOrder32Big.rawValue
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: bitmapInfoRaw)
|
||||
let renderingIntent = CGColorRenderingIntent.RenderingIntentDefault
|
||||
let renderingIntent = CGColorRenderingIntent.defaultIntent
|
||||
|
||||
// Create UIImage from image buffer
|
||||
let imageRef = CGImageCreate(width, height, bitsPerComponent, bitsperPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, nil, false, renderingIntent)
|
||||
let image = UIImage(CGImage: imageRef!, scale: 0.0, orientation: .Up)
|
||||
let imageRef = CGImage(width: width, height: height,
|
||||
bitsPerComponent: bitsPerComponent,
|
||||
bitsPerPixel: bitsperPixel,
|
||||
bytesPerRow: bytesPerRow,
|
||||
space: colorSpaceRef,
|
||||
bitmapInfo: bitmapInfo,
|
||||
provider: provider!,
|
||||
decode: nil, shouldInterpolate: false,
|
||||
intent: renderingIntent)
|
||||
let image = UIImage(cgImage: imageRef!, scale: 0.0, orientation: .up)
|
||||
|
||||
return image
|
||||
}
|
||||
@ -155,9 +180,11 @@ import ChameleonFramework
|
||||
internal func metaballEdgesBuffer() -> MTLBuffer {
|
||||
let floats = dataSource.metaballGraph.adjacencyMatrix.buffer
|
||||
|
||||
let bufferLength = floats.count * sizeof(Float)
|
||||
let bufferLength = floats.count * MemoryLayout<Float>.size
|
||||
let device = context.device
|
||||
let buffer = device.newBufferWithBytes(floats, length: bufferLength, options: .StorageModeShared)
|
||||
let buffer = device.makeBuffer(bytes: floats,
|
||||
length: bufferLength,
|
||||
options: MTLResourceOptions())
|
||||
|
||||
return buffer
|
||||
}
|
||||
@ -166,16 +193,19 @@ import ChameleonFramework
|
||||
// Create Float array for buffer
|
||||
// Exclude metaballs far from the view's bounds
|
||||
let border: CGFloat = 100
|
||||
let metaballs = self.dataSource.metaballs
|
||||
let metaballs = self.dataSource.metaballs!
|
||||
|
||||
var floats = [Float](count: 5, repeatedValue: 0)
|
||||
var floats = [Float](repeating: 0, count: 5)
|
||||
floats = metaballs.reduce(floats) {
|
||||
(var array, metaball) -> [Float] in
|
||||
(array, metaball) -> [Float] in
|
||||
var array = array
|
||||
|
||||
let x = CGFloat(metaball.midX)
|
||||
let y = CGFloat(metaball.midY)
|
||||
if -border < x ≤ targetView.width + border &&
|
||||
-border < y ≤ targetView.height + border {
|
||||
if -border < x,
|
||||
x < targetView.width + border,
|
||||
-border < y,
|
||||
y < targetView.height + border {
|
||||
array.append(Float(x))
|
||||
array.append(Float(y))
|
||||
|
||||
@ -192,9 +222,11 @@ import ChameleonFramework
|
||||
floats[0] = Float(floats.count) / 5
|
||||
|
||||
// Create buffer
|
||||
let bufferLength = floats.count * sizeof(Float)
|
||||
let bufferLength = floats.count * MemoryLayout<Float>.size
|
||||
let device = context.device
|
||||
let buffer = device.newBufferWithBytes(floats, length: bufferLength, options: .StorageModeShared)
|
||||
let buffer = device.makeBuffer(bytes: floats,
|
||||
length: bufferLength,
|
||||
options: MTLResourceOptions())
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
import Darwin
|
||||
|
||||
infix operator ==~ { associativity right precedence 130 }
|
||||
|
||||
func ==~ (left: DoubleValuable, right: DoubleValuable) -> Bool {
|
||||
let leftDouble = left.toDouble
|
||||
let rightDouble = right.toDouble
|
||||
let epsilon = abs(leftDouble/10000)
|
||||
|
||||
return (leftDouble <= rightDouble + epsilon) &&
|
||||
(leftDouble >= rightDouble - epsilon)
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
func iterate<C, R>(collection: C, block: (String?, Any) -> R) {
|
||||
let mirror = Mirror(reflecting: collection)
|
||||
for child in mirror.children {
|
||||
block(child.0, child.1)
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
let doubleMax: Double = 1E+37
|
||||
let doubleMin: Double = -1E+37
|
||||
let floatMax: Float = 1E+37
|
||||
let floatMin: Float = -1E+37
|
||||
let int32Max: Int = 0x7fffffff
|
||||
let int32Min: Int = -0x7fffffff - 1
|
||||
|
||||
infix operator ≤ { associativity right precedence 131 }
|
||||
|
||||
func ≤ <T: Numeric>
|
||||
(left: T, right: T) -> T {
|
||||
|
||||
if left < right {
|
||||
return left
|
||||
} else {
|
||||
return -0x7fffffff
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
infix operator ≤= { associativity right precedence 131 }
|
||||
|
||||
func ≤= <T: Numeric>
|
||||
(left: T, right: T) -> T {
|
||||
|
||||
if left <= right {
|
||||
return left
|
||||
} else {
|
||||
return -0x7fffffff
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
infix operator ≥ { associativity right precedence 131 }
|
||||
|
||||
func ≥ <T: Numeric>
|
||||
(left: T, right: T) -> T {
|
||||
|
||||
if left > right {
|
||||
return left
|
||||
} else {
|
||||
return 0x7fffffff
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
infix operator ≥= { associativity right precedence 131 }
|
||||
|
||||
func ≥= <T: Numeric>
|
||||
(left: T, right: T) -> T {
|
||||
|
||||
if left >= right {
|
||||
return left
|
||||
} else {
|
||||
return 0x7fffffff
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
extension Dictionary {
|
||||
subscript(keys: [Key]) -> [Value] {
|
||||
get {
|
||||
return keys.unwrappedMap { self[$0] }
|
||||
}
|
||||
set (values) {
|
||||
for (key, value) in zip(keys, values) {
|
||||
self[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
extension NSNumber: DoubleValuable {
|
||||
var toDouble: Double {
|
||||
get {
|
||||
return self.doubleValue
|
||||
}
|
||||
}
|
||||
|
||||
static func fromDouble(double: Double) -> Self {
|
||||
return self.init(double: double)
|
||||
}
|
||||
|
||||
}
|
@ -1,23 +1,23 @@
|
||||
protocol DoubleValuable {
|
||||
var toDouble: Double { get }
|
||||
|
||||
static func fromDouble(double: Double) -> Self
|
||||
static func fromDouble(_ double: Double) -> Self
|
||||
}
|
||||
|
||||
postfix operator ++ { }
|
||||
|
||||
protocol Incrementable {
|
||||
postfix func ++ (inout _: Self) -> Self
|
||||
postfix func ++ (_: inout Self) -> Self
|
||||
}
|
||||
|
||||
protocol Numeric: DoubleValuable, Incrementable, Comparable,
|
||||
IntegerLiteralConvertible {
|
||||
ExpressibleByIntegerLiteral {
|
||||
|
||||
@warn_unused_result func / (lhs: Self, rhs: Self) -> Self
|
||||
@warn_unused_result func - (lhs: Self, rhs: Self) -> Self
|
||||
@warn_unused_result func + (lhs: Self, rhs: Self) -> Self
|
||||
@warn_unused_result func * (lhs: Self, rhs: Self) -> Self
|
||||
postfix func ++ (inout _: Self) -> Self
|
||||
postfix func ++ (_: inout Self) -> Self
|
||||
}
|
||||
|
||||
protocol FastNumeric: Numeric {}
|
||||
@ -29,7 +29,7 @@ extension Double: FastNumeric {
|
||||
}
|
||||
}
|
||||
|
||||
static func fromDouble(double: Double) -> Double {
|
||||
static func fromDouble(_ double: Double) -> Double {
|
||||
return double
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ extension Float: FastNumeric {
|
||||
}
|
||||
}
|
||||
|
||||
static func fromDouble(double: Double) -> Float {
|
||||
static func fromDouble(_ double: Double) -> Float {
|
||||
return Float(double)
|
||||
}
|
||||
|
||||
@ -55,19 +55,8 @@ extension Int: FastNumeric {
|
||||
}
|
||||
}
|
||||
|
||||
static func fromDouble(double: Double) -> Int {
|
||||
static func fromDouble(_ double: Double) -> Int {
|
||||
return Int(double)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
extension Int {
|
||||
|
||||
func times(@noescape block: () throws -> ()) rethrows {
|
||||
for _ in 1...self {
|
||||
try block()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,12 @@
|
||||
import Darwin
|
||||
|
||||
infix operator ^ { associativity right precedence 131 }
|
||||
precedencegroup PowerPrecedence {
|
||||
higherThan: MultiplicationPrecedence
|
||||
associativity: right
|
||||
}
|
||||
|
||||
//
|
||||
infix operator ^: PowerPrecedence
|
||||
|
||||
func ^ <T: DoubleValuable>(left: T, right: T) -> T {
|
||||
return T.fromDouble(pow(left.toDouble, right.toDouble))
|
||||
|
@ -1,16 +0,0 @@
|
||||
extension SequenceType {
|
||||
func unwrappedMap<T>
|
||||
(@noescape transform: (Self.Generator.Element) throws -> T?) rethrows
|
||||
-> [T] {
|
||||
return try self.reduce( [T]() ) {
|
||||
(var accumulator: [T], element: Self.Generator.Element) -> [T] in
|
||||
|
||||
let transformed = try transform(element)
|
||||
if let unwrapped = transformed {
|
||||
accumulator.append(unwrapped)
|
||||
}
|
||||
|
||||
return accumulator
|
||||
}
|
||||
}
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
protocol MemoizedSequence: LazySequenceType {
|
||||
typealias IndexType: Hashable
|
||||
typealias ReturnType
|
||||
|
||||
init(first: IndexType,
|
||||
incrementer: ((inout IndexType) -> Void),
|
||||
memoizedFunction: (IndexType -> ReturnType))
|
||||
}
|
||||
|
||||
struct HashMemoizedSequence<IndexType: Hashable, ReturnType>:
|
||||
MemoizedSequence {
|
||||
|
||||
let memoizedFunction: (IndexType -> ReturnType)
|
||||
let increment: ((inout IndexType) -> Void)
|
||||
let firstIndex: IndexType
|
||||
|
||||
var index: IndexType
|
||||
|
||||
init(first: IndexType,
|
||||
incrementer: ((inout IndexType) -> Void),
|
||||
memoizedFunction: (IndexType -> ReturnType)) {
|
||||
|
||||
self.firstIndex = first
|
||||
|
||||
self.index = first
|
||||
self.increment = incrementer
|
||||
self.memoizedFunction = memoizedFunction
|
||||
}
|
||||
|
||||
init(first: IndexType,
|
||||
incrementer: ((inout IndexType) -> Void),
|
||||
closure: ((IndexType -> ReturnType, IndexType) -> ReturnType)) {
|
||||
let memoizedFunction = memoize(closure)
|
||||
|
||||
self.init(first: first, incrementer: incrementer,
|
||||
memoizedFunction: memoizedFunction)
|
||||
}
|
||||
|
||||
init(first: IndexType,
|
||||
incrementer: ((inout IndexType) -> Void),
|
||||
function: (IndexType -> ReturnType)) {
|
||||
|
||||
let memoizedFunction = memoize(function)
|
||||
|
||||
self.init(first: first, incrementer: incrementer,
|
||||
memoizedFunction: memoizedFunction)
|
||||
}
|
||||
}
|
||||
|
||||
extension HashMemoizedSequence: GeneratorType {
|
||||
|
||||
mutating func next() -> ReturnType? {
|
||||
let result = memoizedFunction(index)
|
||||
increment(&index)
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension HashMemoizedSequence: LazySequenceType {
|
||||
|
||||
func generate() -> HashMemoizedSequence {
|
||||
return self
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension HashMemoizedSequence where ReturnType: Comparable {
|
||||
|
||||
@warn_unused_result
|
||||
func contains(element: ReturnType) -> Bool {
|
||||
var index = firstIndex
|
||||
|
||||
while true {
|
||||
let value = memoizedFunction(index)
|
||||
|
||||
if value == element {
|
||||
return true
|
||||
} else if value > element {
|
||||
return false
|
||||
}
|
||||
|
||||
increment(&index)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension HashMemoizedSequence where IndexType: Incrementable {
|
||||
init(first: IndexType,
|
||||
closure: ((IndexType -> ReturnType, IndexType) -> ReturnType)) {
|
||||
self.firstIndex = first
|
||||
self.index = first
|
||||
self.increment = { (inout index: IndexType) in
|
||||
index++
|
||||
}
|
||||
self.memoizedFunction = memoize(closure)
|
||||
}
|
||||
|
||||
init(first: IndexType,
|
||||
function: (IndexType -> ReturnType)) {
|
||||
self.firstIndex = first
|
||||
self.index = first
|
||||
self.increment = { (inout index: IndexType) in
|
||||
index++
|
||||
}
|
||||
self.memoizedFunction = memoize(function)
|
||||
}
|
||||
}
|
||||
|
||||
extension HashMemoizedSequence where IndexType: Incrementable,
|
||||
IndexType: IntegerLiteralConvertible {
|
||||
init(_ closure: ((IndexType -> ReturnType, IndexType) -> ReturnType)) {
|
||||
self.firstIndex = 1
|
||||
self.index = 1
|
||||
self.increment = { (inout index: IndexType) in
|
||||
index++
|
||||
}
|
||||
self.memoizedFunction = memoize(closure)
|
||||
}
|
||||
|
||||
init(_ function: (IndexType -> ReturnType)) {
|
||||
self.firstIndex = 1
|
||||
self.index = 1
|
||||
self.increment = { (inout index: IndexType) in
|
||||
index++
|
||||
}
|
||||
self.memoizedFunction = memoize(function)
|
||||
}
|
||||
}
|
||||
|
||||
func memoize<H: Hashable, R>(closure: ((H -> R, H) -> R)) -> (H -> R) {
|
||||
|
||||
var table = [H: R]()
|
||||
|
||||
var auxiliaryFunction: (H -> R)!
|
||||
auxiliaryFunction = { index in
|
||||
if let result = table[index] {
|
||||
return result
|
||||
}
|
||||
|
||||
let result = closure(auxiliaryFunction, index)
|
||||
table[index] = result
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
return auxiliaryFunction
|
||||
}
|
||||
|
||||
func memoize<H: Hashable, R>(function: (H -> R)) -> (H -> R) {
|
||||
|
||||
var table = [H: R]()
|
||||
|
||||
let result: (H -> R) = { index in
|
||||
if let result = table[index] {
|
||||
return result
|
||||
}
|
||||
|
||||
let result = function(index)
|
||||
table[index] = result
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
prefix operator ± { }
|
||||
|
||||
prefix func ± <T: Numeric>(number: T) -> T {
|
||||
|
||||
if number > 0 {
|
||||
return 1
|
||||
} else if number == 0 {
|
||||
return 0
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
extension String: DoubleValuable {
|
||||
var toDouble: Double {
|
||||
get {
|
||||
return Double(self) ?? Double(0)
|
||||
}
|
||||
}
|
||||
|
||||
static func fromDouble(double: Double) -> String {
|
||||
return "\(double)"
|
||||
}
|
||||
|
||||
}
|
@ -1,211 +0,0 @@
|
||||
// MARK: - Eager
|
||||
|
||||
// MARK: Categorise
|
||||
|
||||
public extension SequenceType {
|
||||
|
||||
/**
|
||||
Categorises elements of `self` into a dictionary, with the keys
|
||||
given by `keyFunc`
|
||||
```swift
|
||||
struct Person : CustomStringConvertible {
|
||||
let name: String
|
||||
let age : Int
|
||||
init(_ name: String, _ age: Int) {
|
||||
self.name = name
|
||||
self.age = age
|
||||
}
|
||||
var description: String { return name }
|
||||
}
|
||||
|
||||
let people = [
|
||||
Person("Jo", 20),
|
||||
Person("An", 20),
|
||||
Person("Cthulu", 4000)
|
||||
]
|
||||
|
||||
people.categorise { p in p.age }
|
||||
|
||||
//[20: [Jo, An], 4000: [Cthulu]]
|
||||
```
|
||||
*/
|
||||
@warn_unused_result
|
||||
func categorise<U : Hashable>(@noescape keyFunc: Generator.Element throws -> U)
|
||||
rethrows -> [U:[Generator.Element]] {
|
||||
var dict: [U:[Generator.Element]] = [:]
|
||||
for el in self {
|
||||
let key = try keyFunc(el)
|
||||
if case nil = dict[key]?.append(el) { dict[key] = [el] }
|
||||
}
|
||||
return dict
|
||||
}
|
||||
}
|
||||
|
||||
public extension SequenceType where Generator.Element : Hashable {
|
||||
|
||||
// MARK: Frequencies
|
||||
|
||||
/**
|
||||
Returns a dictionary where the keys are the elements of self, and
|
||||
the values are their respective frequencies
|
||||
```swift
|
||||
[0, 3, 0, 1, 1, 3, 2, 3, 1, 0].freqs()
|
||||
// [2: 1, 0: 3, 3: 3, 1: 3]
|
||||
```
|
||||
*/
|
||||
@warn_unused_result
|
||||
func freqs() -> [Generator.Element:Int] {
|
||||
var freqs: [Generator.Element:Int] = [:]
|
||||
for el in self { freqs[el] = freqs[el]?.successor() ?? 1 }
|
||||
return freqs
|
||||
}
|
||||
|
||||
// MARK: Uniques
|
||||
|
||||
/**
|
||||
Returns an array of the elements of `self`, in order, with
|
||||
duplicates removed
|
||||
```swift
|
||||
[3, 1, 2, 3, 2, 1, 1, 2, 3, 3].uniques()
|
||||
// [3, 1, 2]
|
||||
```
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func uniques() -> [Generator.Element] {
|
||||
var prevs: Set<Generator.Element> = []
|
||||
var uniqs: [Generator.Element] = []
|
||||
for el in self where !prevs.contains(el) {
|
||||
prevs.insert(el)
|
||||
uniqs.append(el)
|
||||
}
|
||||
return uniqs
|
||||
}
|
||||
|
||||
/// Returns the element which occurs most frequently in `self`
|
||||
@warn_unused_result
|
||||
public func mostFrequent() -> Generator.Element? {
|
||||
var g = generate()
|
||||
guard let b = g.next() else { return nil }
|
||||
var be = b
|
||||
var bn = 1
|
||||
var freqs: [Generator.Element:Int] = [:]
|
||||
for e in self {
|
||||
let n = (freqs[e] ?? 0) + 1
|
||||
if n > bn { (be,bn) = (e,n) }
|
||||
freqs[e] = n
|
||||
}
|
||||
return be
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Lazy
|
||||
|
||||
// MARK: Uniques
|
||||
/// :nodoc:
|
||||
public struct UniquesGen<G : GeneratorType where G.Element : Hashable> : GeneratorType {
|
||||
|
||||
private var prevs: Set<G.Element>
|
||||
private var g: G
|
||||
/// :nodoc:
|
||||
public mutating func next() -> G.Element? {
|
||||
while let next = g.next() {
|
||||
if !prevs.contains(next) {
|
||||
prevs.insert(next)
|
||||
return next
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct UniquesSeq<
|
||||
S : SequenceType where
|
||||
S.Generator.Element : Hashable
|
||||
> : LazySequenceType {
|
||||
private let seq: S
|
||||
/// :nodoc:
|
||||
public func generate() -> UniquesGen<S.Generator> {
|
||||
return UniquesGen(prevs: [], g: seq.generate())
|
||||
}
|
||||
}
|
||||
|
||||
public extension LazySequenceType where Generator.Element : Hashable {
|
||||
|
||||
/// returns a `LazySequence` of the elements of `self`, in order, with
|
||||
/// duplicates removed
|
||||
@warn_unused_result
|
||||
func uniques() -> UniquesSeq<Self> {
|
||||
return UniquesSeq(seq: self)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Grouping
|
||||
|
||||
/// :nodoc:
|
||||
|
||||
public struct GroupByGen<G : GeneratorType> : GeneratorType {
|
||||
|
||||
private var genr: G
|
||||
private var last: G.Element?
|
||||
private let isEq: (G.Element, G.Element) -> Bool
|
||||
/// :nodoc:
|
||||
mutating public func next() -> [G.Element]? {
|
||||
guard let head = last else { return nil }
|
||||
var group = [head]
|
||||
last = nil
|
||||
while let next = genr.next() {
|
||||
guard isEq(group.last!, next) else {
|
||||
last = next
|
||||
return group
|
||||
}
|
||||
group.append(next)
|
||||
}
|
||||
return group
|
||||
}
|
||||
private init(g : G, isEquivalent: (G.Element, G.Element) -> Bool) {
|
||||
genr = g
|
||||
last = genr.next()
|
||||
isEq = isEquivalent
|
||||
}
|
||||
}
|
||||
|
||||
/// :nodoc:
|
||||
|
||||
public struct GroupBySeq<S : SequenceType> : LazySequenceType {
|
||||
private let seq: S
|
||||
private let isEquivalent: (S.Generator.Element, S.Generator.Element) -> Bool
|
||||
/// :nodoc:
|
||||
public func generate() -> GroupByGen<S.Generator> {
|
||||
return GroupByGen(g: seq.generate(), isEquivalent: isEquivalent)
|
||||
}
|
||||
}
|
||||
|
||||
public extension LazySequenceType where Generator.Element : Equatable {
|
||||
|
||||
/// Returns a lazy sequence of self, chunked into arrays of adjacent equal values
|
||||
/// ```swift
|
||||
/// [1, 2, 2, 3, 1, 1, 3, 4, 2].lazy.group()
|
||||
///
|
||||
/// [1], [2, 2], [3], [1, 1], [3], [4], [2]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func group() -> GroupBySeq<Self> {
|
||||
return GroupBySeq(seq: self, isEquivalent: ==)
|
||||
}
|
||||
}
|
||||
|
||||
public extension LazySequenceType {
|
||||
|
||||
/// Returns a lazy sequence of self, chunked into arrays of adjacent equal values
|
||||
/// - Parameter isEquivalent: a function that returns true if its two parameters are equal
|
||||
/// ```swift
|
||||
/// [1, 3, 5, 20, 22, 18, 6, 7].lazy.groupBy { (a,b) in abs(a - b) < 5 }
|
||||
///
|
||||
/// [1, 3, 5], [20, 22, 18], [6, 7]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func group(isEquivalent: (Generator.Element, Generator.Element) -> Bool)
|
||||
-> GroupBySeq<Self> {
|
||||
return GroupBySeq(seq: self, isEquivalent: isEquivalent)
|
||||
}
|
||||
}
|
@ -1,146 +0,0 @@
|
||||
// MARK: - Eager
|
||||
|
||||
// MARK: Chunk
|
||||
|
||||
public extension CollectionType {
|
||||
|
||||
/// Returns an array of arrays of n non-overlapping elements of self
|
||||
/// - Parameter n: The size of the chunk
|
||||
/// - Precondition: `n > 0`
|
||||
/// - SeeAlso: `func window(n: Int) -> [[Self.Generator.Element]]`
|
||||
/// ```swift
|
||||
/// [1, 2, 3, 4, 5].chunk(2)
|
||||
///
|
||||
/// [[1, 2], [3, 4], [5]]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func chunk(n: Index.Distance) -> [SubSequence] {
|
||||
var res: [SubSequence] = []
|
||||
var i = startIndex
|
||||
var j: Index
|
||||
while i != endIndex {
|
||||
j = i.advancedBy(n, limit: endIndex)
|
||||
res.append(self[i..<j])
|
||||
i = j
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Window
|
||||
|
||||
public extension CollectionType {
|
||||
|
||||
/// Returns an array of arrays of n overlapping elements of self
|
||||
/// - Parameter n: The size of the window
|
||||
/// - SeeAlso: `func chunk(n: Int) -> [[Self.Generator.Element]]`
|
||||
/// ```swift
|
||||
/// [1, 2, 3, 4].window(2)
|
||||
///
|
||||
/// [[1, 2], [2, 3], [3, 4]]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func window(n: Index.Distance) -> [SubSequence] {
|
||||
var ret: [SubSequence] = []
|
||||
ret.reserveCapacity(underestimateCount() - numericCast(n))
|
||||
var i = startIndex
|
||||
var j = i.advancedBy(n, limit: endIndex)
|
||||
while true {
|
||||
ret.append(self[i..<j])
|
||||
i = i.successor()
|
||||
if j == endIndex { return ret }
|
||||
j = j.successor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Lazy
|
||||
|
||||
// MARK: Chunk
|
||||
/// :nodoc:
|
||||
public struct ChunkGen<C: CollectionType> : GeneratorType {
|
||||
|
||||
private var c: C
|
||||
private let n: C.Index.Distance
|
||||
private var i: C.Index
|
||||
|
||||
public mutating func next() -> C.SubSequence? {
|
||||
if i == c.endIndex { return nil }
|
||||
let j = i.advancedBy(n, limit: c.endIndex)
|
||||
defer { i = j }
|
||||
return c[i..<j]
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct ChunkSeq<C: CollectionType> : LazySequenceType {
|
||||
|
||||
private let c: C
|
||||
private let n: C.Index.Distance
|
||||
/// :nodoc:
|
||||
public func generate() -> ChunkGen<C> {
|
||||
return ChunkGen(c: c, n: n, i: c.startIndex)
|
||||
}
|
||||
}
|
||||
|
||||
public extension LazyCollectionType {
|
||||
|
||||
/// Returns lazily-generated arrays of n non-overlapping elements of self
|
||||
/// - Parameter n: The size of the chunk
|
||||
/// - SeeAlso: `func window(n: Int) -> WindowSeq<Self>`
|
||||
/// ```swift
|
||||
/// lazy([1, 2, 3, 4, 5]).chunk(2)
|
||||
///
|
||||
/// [1, 2], [3, 4], [5]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func chunk(n: Index.Distance) -> ChunkSeq<Self> {
|
||||
return ChunkSeq(c: self, n: n)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Window
|
||||
/// :nodoc:
|
||||
public struct WindowGen<C: CollectionType> : GeneratorType {
|
||||
|
||||
private let c: C
|
||||
private var i, j: C.Index
|
||||
private var s: Bool
|
||||
/// :nodoc:
|
||||
mutating public func next() -> C.SubSequence? {
|
||||
if s { return nil }
|
||||
if j == c.endIndex {
|
||||
s = true
|
||||
return c[i..<j]
|
||||
}
|
||||
defer { (i,j) = (i.successor(),j.successor()) }
|
||||
return c[i..<j]
|
||||
}
|
||||
}
|
||||
|
||||
/// :nodoc:
|
||||
|
||||
public struct WindowSeq<C: CollectionType> : LazySequenceType {
|
||||
|
||||
private let c: C
|
||||
private let n: C.Index.Distance
|
||||
/// :nodoc:
|
||||
public func generate() -> WindowGen<C> {
|
||||
return WindowGen(c: c, i: c.startIndex, j: c.startIndex.advancedBy(n, limit: c.endIndex), s: false)
|
||||
}
|
||||
}
|
||||
|
||||
public extension LazyCollectionType {
|
||||
|
||||
/// Returns lazily-generated arrays of n overlapping elements of self
|
||||
/// - Parameter n: The size of the window
|
||||
/// - SeeAlso: `func chunk(n: Int) -> ChunkSeq<Self>`
|
||||
/// ```swift
|
||||
/// lazy([1, 2, 3, 4]).window(2)
|
||||
///
|
||||
/// [1, 2], [2, 3], [3, 4]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func window(n: Index.Distance) -> WindowSeq<Self> {
|
||||
return WindowSeq(c: self, n: n)
|
||||
}
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
/// :nodoc:
|
||||
public struct ComboGen<SubElement> : GeneratorType {
|
||||
|
||||
private let coll: [SubElement]
|
||||
private var curr: [SubElement]
|
||||
private var inds: [Int]
|
||||
/// :nodoc:
|
||||
mutating public func next() -> [SubElement]? {
|
||||
for (max, curInd) in zip(coll.indices.reverse(), inds.indices.reverse())
|
||||
where max != inds[curInd] {
|
||||
curr[curInd] = coll[++inds[curInd]]
|
||||
for j in inds.indices.suffixFrom(curInd+1) {
|
||||
inds[j] = inds[j-1].successor()
|
||||
curr[j] = coll[inds[j]]
|
||||
}
|
||||
return curr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct ComboSeq<Element> : LazySequenceType {
|
||||
|
||||
private let start: [Element]
|
||||
private let col : [Element]
|
||||
private let inds : [Int]
|
||||
/// :nodoc:
|
||||
public func generate() -> ComboGen<Element> {
|
||||
return ComboGen<Element>(coll: col, curr: start, inds: inds)
|
||||
}
|
||||
|
||||
internal init(n: Int, col: [Element]) {
|
||||
self.col = col
|
||||
start = Array(col.prefixUpTo(n))
|
||||
var inds = Array(col.indices.prefixUpTo(n))
|
||||
if !inds.isEmpty { --inds[n.predecessor()] }
|
||||
self.inds = inds
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct ComboRepGen<Element> : GeneratorType {
|
||||
|
||||
private let coll: [Element]
|
||||
private var curr: [Element]
|
||||
private var inds: [Int]
|
||||
private let max : Int
|
||||
/// :nodoc:
|
||||
mutating public func next() -> [Element]? {
|
||||
for curInd in inds.indices.reverse() where max != inds[curInd] {
|
||||
curr[curInd] = coll[++inds[curInd]]
|
||||
for j in (curInd+1)..<inds.count {
|
||||
inds[j] = inds[j-1]
|
||||
curr[j] = coll[inds[j]]
|
||||
}
|
||||
return curr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct ComboRepSeq<Element> : LazySequenceType {
|
||||
|
||||
private let start: [Element]
|
||||
private let inds : [Int]
|
||||
private let col : [Element]
|
||||
private let max : Int
|
||||
/// :nodoc:
|
||||
public func generate() -> ComboRepGen<Element> {
|
||||
return ComboRepGen(coll: col, curr: start, inds: inds, max: max)
|
||||
}
|
||||
|
||||
internal init(n: Int, col: [Element]) {
|
||||
self.col = col
|
||||
start = col.first.map { x in Array(count: n, repeatedValue: x) } ?? []
|
||||
var inds = Array(count: n, repeatedValue: col.startIndex)
|
||||
if !inds.isEmpty { --inds[n-1] }
|
||||
self.inds = inds
|
||||
max = col.endIndex.predecessor()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension SequenceType {
|
||||
/**
|
||||
Returns the combinations without repetition of length `n` of `self`
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func combos(n: Int = 2) -> [[Generator.Element]] {
|
||||
return Array(ComboSeq(n: n, col: Array(self)))
|
||||
}
|
||||
/**
|
||||
Returns the combinations with repetition of length `n` of `self`
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func combosWithRep(n: Int) -> [[Generator.Element]] {
|
||||
return Array(ComboRepSeq(n: n, col: Array(self)))
|
||||
}
|
||||
/**
|
||||
Returns the combinations without repetition of length `n` of `self`, generated lazily
|
||||
and on-demand
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func lazyCombos(n: Int) -> ComboSeq<Generator.Element> {
|
||||
return ComboSeq(n: n, col: Array(self))
|
||||
}
|
||||
/**
|
||||
Returns the combinations with repetition of length `n` of `self`, generated lazily and
|
||||
on-demand
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func lazyCombosWithRep(n: Int) -> ComboRepSeq<Generator.Element> {
|
||||
return ComboRepSeq(n: n, col: Array(self))
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
// MARK: - Eager
|
||||
|
||||
// MARK: Cycle n
|
||||
|
||||
public extension CollectionType {
|
||||
|
||||
/// Returns an array of n cycles of self.
|
||||
/// ```swift
|
||||
/// [1, 2, 3].cycle(2)
|
||||
///
|
||||
/// [1, 2, 3, 1, 2, 3]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func cycle(n: Int) -> [Generator.Element] {
|
||||
var cycled: [Generator.Element] = []
|
||||
cycled.reserveCapacity(underestimateCount() * n)
|
||||
for _ in 0..<n {
|
||||
cycled.appendContentsOf(self)
|
||||
}
|
||||
return cycled
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Lazy
|
||||
|
||||
// MARK: Cycle n
|
||||
/// :nodoc:
|
||||
public struct CycleNGen<C: CollectionType> : GeneratorType, LazySequenceType {
|
||||
|
||||
private let inner: C
|
||||
private var innerGen: C.Generator
|
||||
private var n: Int
|
||||
/// :nodoc:
|
||||
public mutating func next() -> C.Generator.Element? {
|
||||
while true {
|
||||
if let next = innerGen.next() { return next }
|
||||
n -= 1
|
||||
if n > 0 { innerGen = inner.generate() }
|
||||
else { return nil }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension LazySequenceType where Self : CollectionType {
|
||||
|
||||
/// Returns a generator of n cycles of self.
|
||||
/// ```swift
|
||||
/// [1, 2, 3].lazy.cycle(2)
|
||||
///
|
||||
/// 1, 2, 3, 1, 2, 3
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func cycle(n: Int) -> CycleNGen<Self> {
|
||||
return CycleNGen(inner: self, innerGen: generate(), n: n)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Cycle infinite
|
||||
/// :nodoc:
|
||||
public struct CycleGen<C: CollectionType> : GeneratorType, LazySequenceType {
|
||||
|
||||
private let inner: C
|
||||
private var innerGen: C.Generator
|
||||
/// :nodoc:
|
||||
public mutating func next() -> C.Generator.Element? {
|
||||
for ;;innerGen = inner.generate() {
|
||||
if let next = innerGen.next() {
|
||||
return next
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension CollectionType {
|
||||
|
||||
/// Returns an infinite generator of cycles of self.
|
||||
/// ```swift
|
||||
/// [1, 2, 3].cycle()
|
||||
///
|
||||
/// 1, 2, 3, 1, 2, 3, 1...
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func cycle() -> CycleGen<Self> {
|
||||
return CycleGen(inner: self, innerGen: generate())
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/// :nodoc:
|
||||
public struct SpecEnumerateGen<Base : CollectionType> : GeneratorType {
|
||||
|
||||
private let base: Base
|
||||
private var i: Base.Index
|
||||
/// :nodoc:
|
||||
public mutating func next() -> (Base.Index, Base.Generator.Element)? {
|
||||
return i == base.endIndex ? nil : (i, base[i++])
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct SpecEnumerateSeq<Base : CollectionType> : SequenceType {
|
||||
|
||||
private let col: Base
|
||||
/// :nodoc:
|
||||
public func generate() -> SpecEnumerateGen<Base> {
|
||||
return SpecEnumerateGen(base: col, i: col.startIndex)
|
||||
}
|
||||
}
|
||||
|
||||
public extension CollectionType {
|
||||
|
||||
/// Returns a lazy generator of tuples `(i, e)` where `i` is successive indices of self,
|
||||
/// and `e` is the respective elements. Effectively the same as `.enumerate()`, but the
|
||||
/// indices returned are `Self.Index`s, rather than `Int`s
|
||||
/// - SeeAlso: `enumerate()`
|
||||
@warn_unused_result
|
||||
func specEnumerate() -> SpecEnumerateSeq<Self> {
|
||||
return SpecEnumerateSeq(col: self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,80 +0,0 @@
|
||||
prefix operator ! {}
|
||||
public prefix func !<A>(f: A -> Bool) -> A -> Bool {
|
||||
return { x in !f(x) }
|
||||
}
|
||||
|
||||
public extension SequenceType {
|
||||
|
||||
/// Returns the first element in self that satisfies a predicate, or nil if it doesn't
|
||||
/// exist
|
||||
@warn_unused_result
|
||||
func first(@noescape thatSatisfies: Generator.Element throws -> Bool) rethrows -> Generator.Element? {
|
||||
for el in self where try thatSatisfies(el) { return el }
|
||||
return nil
|
||||
}
|
||||
|
||||
/// Returns the number of elements in `self` that satisfy `predicate`
|
||||
@warn_unused_result
|
||||
func count(@noescape predicate: Generator.Element throws -> Bool) rethrows -> Int {
|
||||
var i = 0
|
||||
for el in self where try predicate(el) { i += 1 }
|
||||
return i
|
||||
}
|
||||
|
||||
/// Returns true iff every element in `self` satisfies `predicate`
|
||||
@warn_unused_result
|
||||
func all(@noescape predicate: Generator.Element throws -> Bool) rethrows -> Bool {
|
||||
for x in self { guard try predicate(x) else { return false } }
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public extension CollectionType where Index : BidirectionalIndexType {
|
||||
|
||||
|
||||
/// Returns the last element in self that satisfies a predicate, or nil if it doesn't
|
||||
/// exist
|
||||
@warn_unused_result
|
||||
func last(@noescape predicate: Generator.Element throws -> Bool) rethrows -> Generator.Element? {
|
||||
for el in reverse() {
|
||||
if try predicate(el) {
|
||||
return el
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the index of the final element in `self` which satisfies
|
||||
`isElement`, or `nil` if it doesn't exist.
|
||||
*/
|
||||
@warn_unused_result
|
||||
func lastIndexOf(@noescape isElement: Generator.Element throws -> Bool) rethrows -> Index? {
|
||||
for i in indices.reverse() where try isElement(self[i]) {
|
||||
return i
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
extension CollectionType {
|
||||
/**
|
||||
Returns the indices of elements of `self` that satisfy the predicate `isElement`
|
||||
*/
|
||||
@warn_unused_result
|
||||
func indicesOf(@noescape isElement: Generator.Element throws -> Bool) rethrows -> [Index] {
|
||||
return try indices.filter { i in try isElement(self[i]) }
|
||||
}
|
||||
}
|
||||
|
||||
public extension SequenceType {
|
||||
@warn_unused_result
|
||||
func partition(@noescape predicate: Generator.Element throws -> Bool) rethrows -> ([Generator.Element], [Generator.Element]) {
|
||||
var t,f: [Generator.Element]
|
||||
(t,f) = ([],[])
|
||||
for e in self {
|
||||
if try predicate(e) { t.append(e) } else { f.append(e) }
|
||||
}
|
||||
return (t,f)
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
extension LazySequenceType {
|
||||
|
||||
@warn_unused_result
|
||||
public func flatMap<T>(transform: Elements.Generator.Element -> T?)
|
||||
-> LazyMapSequence<LazyFilterSequence<LazyMapSequence<Elements, T?>>, T> {
|
||||
return self
|
||||
.map(transform)
|
||||
.filter { opt in opt != nil }
|
||||
.map { notNil in notNil! }
|
||||
}
|
||||
}
|
||||
|
||||
extension LazyCollectionType {
|
||||
|
||||
@warn_unused_result
|
||||
public func flatMap<T>(transform: Elements.Generator.Element -> T?)
|
||||
-> LazyMapCollection<LazyFilterCollection<LazyMapCollection<Elements, T?>>, T> {
|
||||
return self
|
||||
.map(transform)
|
||||
.filter { opt in opt != nil }
|
||||
.map { notNil in notNil! }
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
public struct RandomAccessHopCollection<
|
||||
Base: CollectionType where
|
||||
Base.Index : RandomAccessIndexType,
|
||||
Base.Index.Distance : ForwardIndexType
|
||||
>: CollectionType {
|
||||
|
||||
private let base: Base
|
||||
private let by : Base.Index.Stride
|
||||
private let fac : Base.Index.Distance
|
||||
|
||||
public let startIndex: Base.Index.Distance
|
||||
public let endIndex: Base.Index.Distance
|
||||
|
||||
public typealias SubSequence = RandomAccessHopCollection<Base>
|
||||
|
||||
public subscript(i: Base.Index.Distance) -> Base.Generator.Element {
|
||||
return base[base.startIndex.advancedBy(fac * i)]
|
||||
}
|
||||
|
||||
public func generate() -> IndexingGenerator<RandomAccessHopCollection<Base>> {
|
||||
return IndexingGenerator(self)
|
||||
}
|
||||
|
||||
private init(_ b: Base, _ by: Base.Index.Stride) {
|
||||
base = b
|
||||
self.by = by
|
||||
fac = base.startIndex.distanceTo(base.startIndex.advancedBy(by))
|
||||
if base.isEmpty { endIndex = 0 }
|
||||
else { endIndex = (base.startIndex.distanceTo(base.endIndex.predecessor()) / fac).successor() }
|
||||
startIndex = 0
|
||||
}
|
||||
|
||||
private init(_ b: Base, _ by: Base.Index.Stride, from: Base.Index.Distance, to: Base.Index.Distance) {
|
||||
base = b
|
||||
self.by = by
|
||||
fac = base.startIndex.distanceTo(base.startIndex.advancedBy(by))
|
||||
startIndex = from
|
||||
endIndex = to
|
||||
}
|
||||
|
||||
public subscript(r: Range<Base.Index.Distance>) -> RandomAccessHopCollection<Base> {
|
||||
return RandomAccessHopCollection(base, by, from: r.startIndex, to: r.endIndex)
|
||||
}
|
||||
}
|
||||
|
||||
extension CollectionType where Index: RandomAccessIndexType, Index.Distance: ForwardIndexType {
|
||||
public subscript(by by: Index.Stride) -> RandomAccessHopCollection<Self> {
|
||||
return RandomAccessHopCollection(self, by)
|
||||
}
|
||||
}
|
||||
|
||||
extension RandomAccessHopCollection: CustomStringConvertible, CustomDebugStringConvertible {
|
||||
public var debugDescription: String {
|
||||
return Array(self).debugDescription
|
||||
}
|
||||
public var description: String {
|
||||
return String(Array(self))
|
||||
}
|
||||
}
|
||||
|
||||
public extension CollectionType where
|
||||
SubSequence: CollectionType,
|
||||
Index == SubSequence.Index,
|
||||
SubSequence.Index: RandomAccessIndexType,
|
||||
SubSequence.Index.Distance: ForwardIndexType {
|
||||
subscript(r: Range<Index>, by by: Index.Stride) -> RandomAccessHopCollection<SubSequence> {
|
||||
return self[r][by: by]
|
||||
}
|
||||
subscript(r: OpenEndedRange<Index>, by by: Index.Stride) -> RandomAccessHopCollection<SubSequence> {
|
||||
return suffixFrom(r.val)[by: by]
|
||||
}
|
||||
subscript(r: OpenStartedRangeTo<Index>, by by: Index.Stride) -> RandomAccessHopCollection<SubSequence> {
|
||||
return prefixUpTo(r.val)[by: by]
|
||||
}
|
||||
subscript(r: OpenStartedRangeThrough<Index>, by by: Index.Stride) -> RandomAccessHopCollection<SubSequence> {
|
||||
return prefixThrough(r.val)[by: by]
|
||||
}
|
||||
}
|
@ -1,366 +0,0 @@
|
||||
// MARK: - Eager
|
||||
|
||||
// MARK: Interpose with single element
|
||||
|
||||
public extension SequenceType {
|
||||
|
||||
/// Returns an array that alternates between successive elements of self and element
|
||||
/// ```swift
|
||||
/// [1, 2, 3].interpose(10)
|
||||
///
|
||||
/// [1, 10, 2, 10, 3]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func interpose(element: Generator.Element) -> [Generator.Element] {
|
||||
var g = generate()
|
||||
|
||||
return g.next().map {
|
||||
var ret = [$0]
|
||||
while let next = g.next() {
|
||||
ret.append(element)
|
||||
ret.append(next)
|
||||
}
|
||||
return ret
|
||||
} ?? []
|
||||
}
|
||||
|
||||
/// Returns an array that alternates between n successive elements of self and element
|
||||
/// ```swift
|
||||
/// [1, 2, 3, 4, 5].interpose(10, n: 2)
|
||||
///
|
||||
/// [1, 2, 10, 3, 4, 10, 5]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func interpose(element: Generator.Element, n: Int) -> [Generator.Element] {
|
||||
|
||||
var ret: [Generator.Element] = []
|
||||
var g = generate()
|
||||
var i = n + 1
|
||||
|
||||
while let next = g.next() {
|
||||
if --i == 0 {
|
||||
ret.append(element)
|
||||
i = n
|
||||
}
|
||||
ret.append(next)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Interpose with collection
|
||||
|
||||
public extension SequenceType {
|
||||
|
||||
/// Returns an array that alternates between successive elements of self and elements of
|
||||
/// a colletion
|
||||
/// ```swift
|
||||
/// [1, 2, 3].interpose([10, 20])
|
||||
///
|
||||
/// [1, 10, 20, 2, 10, 20, 3]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func interpose<C : CollectionType where C.Generator.Element == Generator.Element>
|
||||
(col: C) -> [Generator.Element] {
|
||||
var g = generate()
|
||||
return g.next().map {
|
||||
var ret = [$0]
|
||||
while let next = g.next() {
|
||||
ret.appendContentsOf(col)
|
||||
ret.append(next)
|
||||
}
|
||||
return ret
|
||||
} ?? []
|
||||
}
|
||||
|
||||
/// Returns an array that alternates between n successive elements of self and elements
|
||||
/// of a colletion
|
||||
/// ```swift
|
||||
/// [1, 2, 3, 4, 5].interpose([10, 20], n: 2)
|
||||
///
|
||||
/// [1, 2, 10, 20, 3, 4, 10, 20, 5]
|
||||
/// ```
|
||||
|
||||
func interpose<C : CollectionType where C.Generator.Element == Generator.Element>
|
||||
(col: C, n: Int) -> [Generator.Element] {
|
||||
var g = generate()
|
||||
return g.next().map {
|
||||
var i = n
|
||||
var ret = [$0]
|
||||
while let next = g.next() {
|
||||
if --i == 0 {
|
||||
ret.appendContentsOf(col)
|
||||
i = n
|
||||
}
|
||||
ret.append(next)
|
||||
}
|
||||
return ret
|
||||
} ?? []
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Interdigitate
|
||||
|
||||
/// Returns an array of two sequences interdigitated
|
||||
/// ```swift
|
||||
/// interdig([1, 2, 3], [10, 20, 30])
|
||||
///
|
||||
/// [1, 10, 2, 20, 3, 30]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func interdig<
|
||||
S0 : SequenceType, S1 : SequenceType where
|
||||
S0.Generator.Element == S1.Generator.Element
|
||||
>(s0: S0, _ s1: S1) -> [S0.Generator.Element] {
|
||||
|
||||
var ret: [S0.Generator.Element] = []
|
||||
|
||||
var (g0, g1) = (s0.generate(), s1.generate())
|
||||
|
||||
while let e0 = g0.next(), e1 = g1.next() {
|
||||
ret.append(e0)
|
||||
ret.append(e1)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
/// Returns an array of two sequences interdigitated, with the respective length of each
|
||||
/// interdigitation specified
|
||||
/// - Parameter s0Len: The length of the first sequence's interdigitations
|
||||
/// - Parameter s1Len: The length of the second sequence's interdigitations
|
||||
/// ```swift
|
||||
/// interdig([1, 2, 3, 4, 5], [10, 20, 30, 40, 50, 60], s0Len: 2, s1Len: 3)
|
||||
///
|
||||
/// [1, 2, 10, 20, 30, 3, 4, 40, 50, 60, 5]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func interdig<
|
||||
S0 : SequenceType, S1 : SequenceType where
|
||||
S0.Generator.Element == S1.Generator.Element
|
||||
>(s0: S0, _ s1: S1, s0Len: Int, s1Len: Int) -> [S0.Generator.Element] {
|
||||
|
||||
var ret: [S0.Generator.Element] = []
|
||||
|
||||
var (g0, g1) = (s0.generate(), s1.generate())
|
||||
|
||||
for ;; {
|
||||
for _ in 0..<s0Len {
|
||||
if let next = g0.next() {
|
||||
ret.append(next)
|
||||
} else {
|
||||
return ret
|
||||
}
|
||||
}
|
||||
for _ in 0..<s1Len {
|
||||
if let next = g1.next() {
|
||||
ret.append(next)
|
||||
} else {
|
||||
return ret
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Lazy
|
||||
|
||||
// MARK: Interpose with single element
|
||||
/// :nodoc:
|
||||
public struct InterposeElGen<G : GeneratorType> : GeneratorType {
|
||||
|
||||
private let n: Int
|
||||
private var count: Int
|
||||
private var g: G
|
||||
private let element: G.Element
|
||||
/// :nodoc:
|
||||
public mutating func next() -> G.Element? {
|
||||
return --count < 0 ? {count = n; return element}() : g.next()
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct InterposeElSeq<S : SequenceType> : LazySequenceType {
|
||||
|
||||
private let element: InterposeElGen<S.Generator>.Element
|
||||
private let n: Int
|
||||
private let seq: S
|
||||
/// :nodoc:
|
||||
public func generate() -> InterposeElGen<S.Generator> {
|
||||
return InterposeElGen(n: n, count: n, g: seq.generate(), element: element)
|
||||
}
|
||||
}
|
||||
|
||||
public extension LazySequenceType {
|
||||
|
||||
/// Returns a lazy sequence that alternates between successive elements of self and an
|
||||
/// element
|
||||
/// ```swift
|
||||
/// [1, 2, 3].lazy.interpose(10)
|
||||
///
|
||||
/// 1, 10, 2, 10, 3, 10
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func interpose(element: Generator.Element) -> InterposeElSeq<Self> {
|
||||
return InterposeElSeq(element: element, n: 1, seq: self)
|
||||
}
|
||||
|
||||
/// Returns a lazy sequence that alternates between n successive elements of self and an
|
||||
/// element
|
||||
/// ```swift
|
||||
/// [1, 2, 3, 4, 5].lazy.interpose(10, n: 2)
|
||||
///
|
||||
/// 1, 2, 10, 3, 4, 10, 5
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func interpose(element: Generator.Element, n: Int) -> InterposeElSeq<Self> {
|
||||
return InterposeElSeq(element: element, n: n, seq: self)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Interpose with collection
|
||||
/// :nodoc:
|
||||
public struct InterposeColGen<
|
||||
G : GeneratorType,
|
||||
C: CollectionType where
|
||||
G.Element == C.Generator.Element
|
||||
> : GeneratorType {
|
||||
|
||||
private let col: C
|
||||
private var g: G
|
||||
private let n: Int
|
||||
private var count: Int
|
||||
private var colG: C.Generator
|
||||
/// :nodoc:
|
||||
public mutating func next() -> G.Element? {
|
||||
return --count <= 0 ? {
|
||||
colG.next() ?? {
|
||||
count = n
|
||||
colG = col.generate()
|
||||
return g.next()
|
||||
}()}() : g.next()
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct InterposeColSeq<
|
||||
S : SequenceType,
|
||||
C: CollectionType where
|
||||
S.Generator.Element == C.Generator.Element
|
||||
> : LazySequenceType {
|
||||
|
||||
private let col: C
|
||||
private let n: Int
|
||||
private let seq: S
|
||||
/// :nodoc:
|
||||
public func generate() -> InterposeColGen<S.Generator, C> {
|
||||
return InterposeColGen(col: col, g: seq.generate(), n: n, count: n + 1, colG: col.generate())
|
||||
}
|
||||
}
|
||||
|
||||
public extension LazySequenceType {
|
||||
|
||||
/// Returns a lazy sequence that alternates between successive elements of self and
|
||||
/// elements of a colletion
|
||||
/// ```swift
|
||||
/// [1, 2, 3].lazy.interpose([10, 20])
|
||||
///
|
||||
/// 1, 10, 20, 2, 10, 20, 3, 10, 20
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func interpose<
|
||||
C: CollectionType where
|
||||
C.Generator.Element == Generator.Element
|
||||
>(elements: C) -> InterposeColSeq<Self, C> {
|
||||
return InterposeColSeq(col: elements, n: 1, seq: self)
|
||||
}
|
||||
|
||||
/// Returns a lazy sequence that alternates between n successive elements of self and
|
||||
/// elements of a colletion
|
||||
/// ```swift
|
||||
/// [1, 2, 3, 4, 5].lazy.interpose([10, 20], n: 2)
|
||||
///
|
||||
/// 1, 2, 10, 20, 3, 4, 10, 20, 5
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func interpose<
|
||||
C: CollectionType where
|
||||
C.Generator.Element == Generator.Element
|
||||
>(elements: C, n: Int) -> InterposeColSeq<Self, C> {
|
||||
return InterposeColSeq(col: elements, n: n, seq: self)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Interdigitate
|
||||
/// :nodoc:
|
||||
public struct InterDigGen<
|
||||
G0 : GeneratorType,
|
||||
G1 : GeneratorType where
|
||||
G0.Element == G1.Element
|
||||
> : GeneratorType {
|
||||
|
||||
private var g0: G0
|
||||
private var g1: G1
|
||||
|
||||
private let aN: Int
|
||||
private let bN: Int
|
||||
|
||||
private var count: Int
|
||||
/// :nodoc:
|
||||
public mutating func next() -> G0.Element? {
|
||||
for (--count;;count = aN) {
|
||||
if count >= bN { return count < 0 ? g1.next() : g0.next() }
|
||||
}
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct InterDigSeq<
|
||||
S0 : LazySequenceType,
|
||||
S1 : LazySequenceType where
|
||||
S0.Generator.Element == S1.Generator.Element
|
||||
> : LazySequenceType {
|
||||
|
||||
private let s0: S0
|
||||
private let s1: S1
|
||||
|
||||
private let aN: Int
|
||||
private let bN: Int
|
||||
/// :nodoc:
|
||||
public func generate() -> InterDigGen<S0.Generator, S1.Generator> {
|
||||
return InterDigGen(
|
||||
g0: s0.generate(),
|
||||
g1: s1.generate(),
|
||||
aN: aN - 1,
|
||||
bN: -bN,
|
||||
count: aN
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a lazy sequence of two sequences interdigitated
|
||||
/// ```swift
|
||||
/// interdig([1, 2, 3].lazy, [10, 20, 30].lazy)
|
||||
///
|
||||
/// 1, 10, 2, 20, 3, 30
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func interdig<
|
||||
S0 : LazySequenceType, S1 : LazySequenceType where
|
||||
S0.Generator.Element == S1.Generator.Element
|
||||
>(s0: S0, _ s1: S1) -> InterDigSeq<S0, S1> {
|
||||
return InterDigSeq(s0: s0, s1: s1, aN: 1, bN: 1)
|
||||
}
|
||||
|
||||
/// Returns a lazy sequence of two sequences interdigitated, with the respective length of
|
||||
/// each interdigitation specified
|
||||
/// - Parameter s0Len: The length of the first sequence's interdigitations
|
||||
/// - Parameter s1Len: The length of the second sequence's interdigitations
|
||||
/// ```swift
|
||||
/// interdig([1, 2, 3, 4, 5].lazy, [10, 20, 30, 40, 50, 60].lazy, s0Len: 2, s1Len: 3)
|
||||
///
|
||||
/// 1, 2, 10, 20, 30, 3, 4, 40, 50, 60, 5
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func interdig<
|
||||
S0 : SequenceType, S1 : SequenceType where
|
||||
S0.Generator.Element == S1.Generator.Element
|
||||
>(s0: S0, _ s1: S1, s0Len: Int, s1Len: Int = 1) -> InterDigSeq<S0, S1> {
|
||||
return InterDigSeq(s0: s0, s1: s1, aN: s0Len, bN: s1Len)
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
public struct IterateGenerator<Element>: GeneratorType {
|
||||
private var x: Element
|
||||
private let f: Element -> Element
|
||||
public mutating func next() -> Element? {
|
||||
defer { x = f(x) }
|
||||
return x
|
||||
}
|
||||
}
|
||||
|
||||
public struct IterateSequence<Element>: SequenceType {
|
||||
private let x: Element
|
||||
private let f: Element -> Element
|
||||
public func generate() -> IterateGenerator<Element> {
|
||||
return IterateGenerator(x: x, f: f)
|
||||
}
|
||||
}
|
||||
|
||||
public struct IterateEndGenerator<Element>: GeneratorType {
|
||||
private var x: Element?
|
||||
private var f: Element -> Element?
|
||||
public mutating func next() -> Element? {
|
||||
guard let y = x else { return nil }
|
||||
defer { x = f(y) }
|
||||
return y
|
||||
}
|
||||
}
|
||||
|
||||
public struct IterateEndSequence<Element>: SequenceType {
|
||||
private let x: Element
|
||||
private let f: Element -> Element?
|
||||
public func generate() -> IterateEndGenerator<Element> {
|
||||
return IterateEndGenerator(x: x, f: f)
|
||||
}
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
// MARK: - Eager
|
||||
|
||||
// MARK: Cartesian Product
|
||||
|
||||
private extension GeneratorType where Element : CollectionType {
|
||||
mutating private func product() -> [[Element.Generator.Element]] {
|
||||
guard let x = next() else { return [[]] }
|
||||
let xs = product()
|
||||
return x.flatMap { h in xs.map { [h] + $0 } }
|
||||
}
|
||||
}
|
||||
|
||||
public extension SequenceType where Generator.Element : SequenceType, Generator.Element : CollectionType {
|
||||
|
||||
/// Returns a cartesian product of self
|
||||
/// ```swift
|
||||
/// [[1, 2], [3, 4]].product()
|
||||
/// [[1, 3], [1, 4], [2, 3], [2, 4]]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func product() -> [[Generator.Element.Generator.Element]] {
|
||||
var g = generate()
|
||||
return g.product()
|
||||
}
|
||||
}
|
||||
|
||||
public extension SequenceType where Generator.Element : SequenceType {
|
||||
|
||||
/// Returns a cartesian product of self
|
||||
/// ```swift
|
||||
/// [[1, 2], [3, 4]].product()
|
||||
/// [[1, 3], [1, 4], [2, 3], [2, 4]]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func product() -> [[Generator.Element.Generator.Element]] {
|
||||
return map(Array.init).product()
|
||||
}
|
||||
}
|
||||
|
||||
/// Cartesian product
|
||||
/// ```swift
|
||||
/// product([1, 2], [3, 4])
|
||||
/// [[1, 3], [1, 4], [2, 3], [2, 4]]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func product<C : CollectionType>(cols: C...) -> [[C.Generator.Element]] {
|
||||
return cols.product()
|
||||
}
|
||||
|
||||
/// Cartesian product
|
||||
/// ```swift
|
||||
/// product([1, 2], [3, 4])
|
||||
/// [[1, 3], [1, 4], [2, 3], [2, 4]]
|
||||
/// ```
|
||||
|
||||
public func product<S : SequenceType>(cols: S...) -> [[S.Generator.Element]] {
|
||||
return cols.product()
|
||||
}
|
||||
|
||||
// MARK: Transposition
|
||||
|
||||
private extension SequenceType {
|
||||
private func mapM<U>(@noescape transform: Generator.Element -> U?) -> [U]? {
|
||||
var result: [U] = []
|
||||
result.reserveCapacity(underestimateCount())
|
||||
for e in self {
|
||||
if let r = transform(e) { result.append(r) } else { return nil }
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
public extension SequenceType where Generator.Element : SequenceType {
|
||||
|
||||
/// Returns a transposed self
|
||||
/// ```swift
|
||||
/// [[1, 2, 3], [1, 2, 3], [1, 2, 3]].transpose()
|
||||
///
|
||||
/// [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func transpose() -> [[Generator.Element.Generator.Element]] {
|
||||
return Array(TransposeSeq(seq: self))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Lazy
|
||||
|
||||
// MARK: Cartesian Product
|
||||
/// :nodoc:
|
||||
public struct ProdGen<C : CollectionType> : GeneratorType {
|
||||
|
||||
private let cols: [C] // Must be collections, not sequences, in order to be multi-pass
|
||||
|
||||
private var gens: [C.Generator]
|
||||
private var curr: [C.Generator.Element]
|
||||
/// :nodoc:
|
||||
public mutating func next() -> [C.Generator.Element]? {
|
||||
|
||||
for i in gens.indices.reverse() { // Loop through generators in reverse order, rolling over
|
||||
if let n = gens[i].next() { // if generator isn't finished, just increment that column, return
|
||||
curr[i] = n
|
||||
return curr
|
||||
} else { // generator is finished
|
||||
gens[i] = cols[i].generate() // reset the generator
|
||||
curr[i] = gens[i].next()! // set the current column to the first element of the generator
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private init(cols: [C]) {
|
||||
var gens = cols.map{$0.generate()}
|
||||
self.cols = cols
|
||||
curr = gens.dropLast().indices.map{gens[$0].next()!} + [self.cols.last!.first!]
|
||||
/**
|
||||
set curr to the first value of each of the generators, except the last: don't
|
||||
increment this generator, so that the first value returned contains it.
|
||||
*/
|
||||
self.gens = gens
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct ProdSeq<C : CollectionType> : LazySequenceType {
|
||||
private let cols: [C]
|
||||
/// :nodoc:
|
||||
public func generate() -> ProdGen<C> {
|
||||
return ProdGen( cols: cols )
|
||||
}
|
||||
/// :nodoc:
|
||||
public func underestimateCount() -> Int {
|
||||
return cols.reduce(1) { (n,c) in n * c.underestimateCount() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Lazy Cartesian Product
|
||||
/// ```swift
|
||||
/// lazyProduct([1, 2], [3, 4])
|
||||
///
|
||||
/// [1, 3], [1, 4], [2, 3], [2, 4]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func lazyProduct<C : CollectionType>
|
||||
(cols: C...) -> ProdSeq<C> {
|
||||
return ProdSeq(cols: cols)
|
||||
}
|
||||
|
||||
/// Lazy Cartesian Product
|
||||
/// ```swift
|
||||
/// lazyProduct([1, 2], [3, 4])
|
||||
///
|
||||
/// [1, 3], [1, 4], [2, 3], [2, 4]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func lazyProduct<S : SequenceType>
|
||||
(cols: S...) -> ProdSeq<[S.Generator.Element]> {
|
||||
return ProdSeq(cols: cols.map(Array.init))
|
||||
}
|
||||
|
||||
public extension SequenceType where Generator.Element : SequenceType {
|
||||
|
||||
/// Lazy Cartesian Product
|
||||
/// ```swift
|
||||
/// [[1, 2], [3, 4]].lazyProduct()
|
||||
///
|
||||
/// [1, 3], [1, 4], [2, 3], [2, 4]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func lazyProduct() -> ProdSeq<[Generator.Element.Generator.Element]> {
|
||||
return ProdSeq(cols: map(Array.init))
|
||||
}
|
||||
}
|
||||
|
||||
public extension SequenceType where Generator.Element : CollectionType {
|
||||
|
||||
/// Lazy Cartesian Product
|
||||
/// ```swift
|
||||
/// [[1, 2], [3, 4]].lazyProduct()
|
||||
///
|
||||
/// [1, 3], [1, 4], [2, 3], [2, 4]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func lazyProduct() -> ProdSeq<Generator.Element> {
|
||||
return ProdSeq(cols: Array(self))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Transposition
|
||||
/// :nodoc:
|
||||
public struct TransposeGen<T, G : GeneratorType where G.Element == T> : GeneratorType {
|
||||
private var gens: [G]
|
||||
/// :nodoc:
|
||||
mutating public func next() -> [T]? {
|
||||
return gens.indices.mapM { i in gens[i].next() }
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct TransposeSeq<
|
||||
S : SequenceType where
|
||||
S.Generator.Element : SequenceType
|
||||
> : LazySequenceType {
|
||||
private let seq: S
|
||||
/// :nodoc:
|
||||
public func generate()
|
||||
-> TransposeGen<S.Generator.Element.Generator.Element, S.Generator.Element.Generator>{
|
||||
return TransposeGen(gens: seq.map { g in g.generate() })
|
||||
}
|
||||
}
|
||||
|
||||
public extension TransposeSeq where S: CollectionType {
|
||||
@warn_unused_result
|
||||
public func underestimateCount() -> Int {
|
||||
return seq.first?.underestimateCount() ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
public extension LazySequenceType where Generator.Element: SequenceType {
|
||||
|
||||
/// Returns a lazily transposed self
|
||||
/// ```swift
|
||||
/// lazy([[1, 2, 3], [1, 2, 3], [1, 2, 3]]).transpose()
|
||||
///
|
||||
/// [1, 1, 1], [2, 2, 2], [3, 3, 3]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func transpose() -> TransposeSeq<Self> {
|
||||
return TransposeSeq(seq: self)
|
||||
}
|
||||
}
|
@ -1,187 +0,0 @@
|
||||
// MARK: - Common
|
||||
|
||||
public extension MutableCollectionType {
|
||||
|
||||
/// [Algorithm](https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order)
|
||||
|
||||
public mutating func nextLexPerm
|
||||
(isOrderedBefore: (Generator.Element, Generator.Element) -> Bool) -> Self? {
|
||||
for k in indices.reverse().dropFirst()
|
||||
where isOrderedBefore(self[k], self[k.successor()]) {
|
||||
for l in indices.reverse() where isOrderedBefore(self[k], self[l]) {
|
||||
swap(&self[k], &self[l])
|
||||
let r = (k.successor()..<endIndex)
|
||||
for (x, y) in zip(r, r.reverse()) {
|
||||
if x == y || x == y.successor() { return self }
|
||||
swap(&self[x], &self[y])
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public extension MutableCollectionType where Generator.Element : Comparable {
|
||||
|
||||
/// [Algorithm](https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order)
|
||||
|
||||
public mutating func nextLexPerm() -> Self? {
|
||||
return nextLexPerm(<)
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct LexPermGen<C : MutableCollectionType> : GeneratorType {
|
||||
private var col: C?
|
||||
private let order: (C.Generator.Element, C.Generator.Element) -> Bool
|
||||
/// :nodoc:
|
||||
mutating public func next() -> C? {
|
||||
defer { col = col?.nextLexPerm(order) }
|
||||
return col
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct LexPermSeq<C : MutableCollectionType> : LazySequenceType {
|
||||
private let col: C
|
||||
private let order: (C.Generator.Element, C.Generator.Element) -> Bool
|
||||
/// :nodoc:
|
||||
public func generate() -> LexPermGen<C> {
|
||||
return LexPermGen(col: col, order: order)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Eager
|
||||
|
||||
public extension SequenceType {
|
||||
|
||||
/// Returns an array of the permutations of self, ordered lexicographically, according
|
||||
/// to the closure `isOrderedBefore`.
|
||||
/// - Note: The permutations returned follow self, so if self is not the first
|
||||
/// lexicographically ordered permutation, not all permutations will be returned.
|
||||
/// ```swift
|
||||
/// [1, 2, 3].lexPermutations(<)
|
||||
///
|
||||
/// [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
|
||||
/// ```
|
||||
/// ```swift
|
||||
/// [1, 2, 3].lexPermutations(>)
|
||||
///
|
||||
/// [[1, 2, 3]]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func lexPermutations
|
||||
(isOrderedBefore: (Generator.Element, Generator.Element) -> Bool) -> [[Generator.Element]] {
|
||||
return Array(LexPermSeq(col: Array(self), order: isOrderedBefore))
|
||||
}
|
||||
}
|
||||
|
||||
public extension MutableCollectionType where Generator.Element : Comparable {
|
||||
|
||||
/// Returns an array of the permutations of self, ordered lexicographically.
|
||||
/// - Note: The permutations returned follow self, so if self is not the first
|
||||
/// lexicographically ordered permutation, not all permutations will be returned.
|
||||
/// ```swift
|
||||
/// [1, 2, 3].lexPermutations()
|
||||
///
|
||||
/// [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
|
||||
/// ```
|
||||
/// ```swift
|
||||
/// [3, 2, 1].lexPermutations()
|
||||
///
|
||||
/// [[3, 2, 1]]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func lexPermutations() -> [[Generator.Element]] {
|
||||
return Array(LexPermSeq(col: Array(self), order: <))
|
||||
}
|
||||
}
|
||||
|
||||
public extension SequenceType {
|
||||
|
||||
/// Returns an array of the permutations of self.
|
||||
/// ```swift
|
||||
/// [1, 2, 3].permutations()
|
||||
///
|
||||
/// [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func permutations() -> [[Generator.Element]] {
|
||||
var col = Array(self)
|
||||
return Array(LexPermSeq(col: Array(col.indices), order: <).map { inds in inds.map{col[$0]} })
|
||||
}
|
||||
/// Returns an array of the permutations of length `n` of self.
|
||||
/// ```swift
|
||||
/// [1, 2, 3].permutations()
|
||||
///
|
||||
/// [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
|
||||
/// ```
|
||||
public func permutations(n: Int) -> [[Generator.Element]] {
|
||||
return Array(lazyCombos(n).flatMap { a in a.permutations() })
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Lazy
|
||||
|
||||
public extension SequenceType {
|
||||
|
||||
/// Returns a lazy sequence of the permutations of self, ordered lexicographically,
|
||||
/// according to the closure `isOrderedBefore`.
|
||||
/// - Note: The permutations returned follow self, so if self is not the first
|
||||
/// lexicographically ordered permutation, not all permutations will be returned.
|
||||
/// ```swift
|
||||
/// lazy([1, 2, 3]).lazyLexPermutations(<)
|
||||
///
|
||||
/// [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
|
||||
/// ```
|
||||
/// ```swift
|
||||
/// lazy([1, 2, 3]).lazyLexPermutations(>)
|
||||
///
|
||||
/// [1, 2, 3]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func lazyLexPermutations(isOrderedBefore: (Generator.Element, Generator.Element) -> Bool)
|
||||
-> LexPermSeq<[Generator.Element]> {
|
||||
return LexPermSeq(col: Array(self), order: isOrderedBefore)
|
||||
}
|
||||
}
|
||||
|
||||
public extension SequenceType where Generator.Element : Comparable {
|
||||
|
||||
/// Returns a lazy sequence of the permutations of self, ordered lexicographically.
|
||||
/// - Note: The permutations returned follow self, so if self is not the first
|
||||
/// lexicographically ordered permutation, not all permutations will be returned.
|
||||
/// ```swift
|
||||
/// lazy([1, 2, 3]).lazyLexPermutations()
|
||||
///
|
||||
/// [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
|
||||
/// ```
|
||||
/// ```swift
|
||||
/// lazy([3, 2, 1]).lazyLexPermutations()
|
||||
///
|
||||
/// [3, 2, 1]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func lazyLexPermutations() -> LexPermSeq<[Generator.Element]> {
|
||||
return LexPermSeq(col: Array(self), order: <)
|
||||
}
|
||||
}
|
||||
|
||||
public extension SequenceType {
|
||||
|
||||
/// Returns a lazy sequence of the permutations of self.
|
||||
/// - Note: The permutations are lexicographically ordered, based on the indices of self
|
||||
/// ```swift
|
||||
/// lazy([1, 2, 3]).lazyPermutations()
|
||||
///
|
||||
/// [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
|
||||
/// ```
|
||||
/// ```swift
|
||||
/// lazy([3, 2, 1]).lazyPermutations()
|
||||
///
|
||||
/// [3, 2, 1], [3, 1, 2], [2, 3, 1], [2, 1, 3], [1, 3, 2], [1, 2, 3]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func lazyPermutations() -> LazyMapSequence<LexPermSeq<[Int]>, [Self.Generator.Element]> {
|
||||
let col = Array(self)
|
||||
return col.indices.lazyLexPermutations().map { $0.map { col[$0] } }
|
||||
}
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
// MARK: - Eager
|
||||
|
||||
public extension SequenceType {
|
||||
|
||||
// MARK: Reduce1
|
||||
|
||||
/// Return the result of repeatedly calling combine with an accumulated value
|
||||
/// initialized to the first element of self and each element of self, in turn, i.e.
|
||||
/// return combine(combine(...combine(combine(self[0], self[1]),
|
||||
/// self[2]),...self[count-2]), self[count-1]).
|
||||
/// ```swift
|
||||
/// [1, 2, 3].reduce(+) // 6
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func reduce
|
||||
(@noescape combine: (accumulator: Generator.Element, element: Generator.Element) throws -> Generator.Element)
|
||||
rethrows -> Generator.Element? {
|
||||
var g = generate()
|
||||
guard let a = g.next() else { return nil }
|
||||
var accu = a
|
||||
while let next = g.next() {
|
||||
accu = try combine(accumulator: accu, element: next)
|
||||
}
|
||||
return accu
|
||||
}
|
||||
|
||||
// MARK: Scan
|
||||
|
||||
/// Return an array where every value is equal to combine called on the previous
|
||||
/// element, and the current element. The first element is taken to be initial.
|
||||
/// ```swift
|
||||
/// [1, 2, 3].scan(0, combine: +)
|
||||
///
|
||||
/// [1, 3, 6]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func scan<T>(initial: T, @noescape combine: (accumulator: T, element: Generator.Element) throws -> T) rethrows -> [T] {
|
||||
var accu = initial
|
||||
return try map { e in
|
||||
accu = try combine(accumulator: accu, element: e)
|
||||
return accu
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Scan1
|
||||
|
||||
/// Return an array where every value is equal to combine called on the previous
|
||||
/// element, and the current element.
|
||||
/// ```swift
|
||||
/// [1, 2, 3].scan(+)
|
||||
///
|
||||
/// [3, 6]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func scan(@noescape combine: (accumulator: Generator.Element, element: Generator.Element) throws -> Generator.Element) rethrows -> [Generator.Element] {
|
||||
var g = generate()
|
||||
guard let i = g.next() else { return [] }
|
||||
return try GeneratorSequence(g).scan(i, combine: combine)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Lazy
|
||||
|
||||
// MARK: Scan
|
||||
|
||||
/// :nodoc:
|
||||
public struct ScanGen<G : GeneratorType, T> : GeneratorType {
|
||||
|
||||
private let combine: (T, G.Element) -> T
|
||||
private var initial: T
|
||||
private var g: G
|
||||
/// :nodoc:
|
||||
public mutating func next() -> T? {
|
||||
guard let e = g.next() else { return nil }
|
||||
initial = combine(initial, e)
|
||||
return initial
|
||||
}
|
||||
}
|
||||
|
||||
/// :nodoc:
|
||||
public struct LazyScanSeq<S : SequenceType, T> : LazySequenceType {
|
||||
|
||||
private let seq : S
|
||||
private let combine: (T, S.Generator.Element) -> T
|
||||
private let initial: T
|
||||
/// :nodoc:
|
||||
public func generate() -> ScanGen<S.Generator, T> {
|
||||
return ScanGen(combine: combine, initial: initial, g: seq.generate())
|
||||
}
|
||||
}
|
||||
|
||||
public extension LazySequenceType {
|
||||
|
||||
/// Return a lazy sequence where every value is equal to combine called on the previous
|
||||
/// element, and the current element. The first element is taken to be initial.
|
||||
/// ```swift
|
||||
/// lazy([1, 2, 3]).scan(0, combine: +)
|
||||
///
|
||||
/// 1, 3, 6
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func scan<T>(initial: T, combine: (accumulator: T, element: Generator.Element) -> T) -> LazyScanSeq<Self, T> {
|
||||
return LazyScanSeq(seq: self, combine: combine, initial: initial)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Scan1
|
||||
/// :nodoc:
|
||||
public struct Scan1Gen<G : GeneratorType> : GeneratorType {
|
||||
|
||||
private let combine: (G.Element, G.Element) -> G.Element
|
||||
private var accu: G.Element?
|
||||
private var g: G
|
||||
|
||||
public mutating func next() -> G.Element? {
|
||||
guard let a = accu, e = g.next() else { return nil }
|
||||
accu = combine(a, e)
|
||||
return accu!
|
||||
}
|
||||
|
||||
private init(combine: (G.Element, G.Element) -> G.Element, generator: G) {
|
||||
g = generator
|
||||
self.combine = combine
|
||||
accu = g.next()
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct LazyScan1Seq<S : SequenceType> : LazySequenceType {
|
||||
|
||||
private let seq: S
|
||||
private let combine: (S.Generator.Element, S.Generator.Element) -> S.Generator.Element
|
||||
/// :nodoc:
|
||||
public func generate() -> Scan1Gen<S.Generator> {
|
||||
return Scan1Gen(combine: combine, generator: seq.generate())
|
||||
}
|
||||
}
|
||||
|
||||
public extension LazySequenceType {
|
||||
|
||||
/// Return a lazy sequence where every value is equal to combine called on the previous
|
||||
/// element, and the current element.
|
||||
/// ```swift
|
||||
/// lazy([1, 2, 3]).scan(+)
|
||||
///
|
||||
/// 3, 6
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func scan(combine: (accumulator: Generator.Element, element: Generator.Element) -> Generator.Element)
|
||||
-> LazyScan1Seq<Self> {
|
||||
return LazyScan1Seq(seq: self, combine: combine)
|
||||
}
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
// IntervalTypes
|
||||
|
||||
public protocol OpenIntervalType {
|
||||
typealias Value
|
||||
func contains(v: Value) -> Bool
|
||||
}
|
||||
public protocol OpenEndedIntervalType: OpenIntervalType {
|
||||
typealias Value: Comparable
|
||||
var val: Value { get }
|
||||
}
|
||||
public protocol OpenStartedIntervalTypeTo: OpenIntervalType {
|
||||
typealias Value: Comparable
|
||||
var val: Value { get }
|
||||
}
|
||||
public protocol OpenStartedIntervalTypeThrough: OpenIntervalType {
|
||||
typealias Value: Comparable
|
||||
var val: Value { get }
|
||||
}
|
||||
|
||||
// Interval Structs
|
||||
|
||||
public struct OpenEndedInterval<C: Comparable>: OpenEndedIntervalType {
|
||||
public let val: C
|
||||
}
|
||||
public struct OpenStartedIntervalTo<C: Comparable>: OpenStartedIntervalTypeTo {
|
||||
public let val: C
|
||||
}
|
||||
public struct OpenStartedIntervalThrough<C: Comparable>: OpenStartedIntervalTypeThrough {
|
||||
public let val: C
|
||||
}
|
||||
|
||||
// Range structs
|
||||
|
||||
public struct OpenEndedRange<I: ForwardIndexType where I: Comparable>: OpenEndedIntervalType {
|
||||
public var val: I
|
||||
}
|
||||
public struct OpenStartedRangeTo<I: BidirectionalIndexType where I: Comparable>: OpenStartedIntervalTypeTo {
|
||||
public var val: I
|
||||
}
|
||||
public struct OpenStartedRangeThrough<I: BidirectionalIndexType where I: Comparable>: OpenStartedIntervalTypeThrough {
|
||||
public var val: I
|
||||
}
|
||||
|
||||
// Generators
|
||||
|
||||
public struct EndlessIncrement<I: ForwardIndexType>: GeneratorType {
|
||||
private var i: I
|
||||
public mutating func next() -> I? {
|
||||
defer { i = i.successor() }
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
// SequenceType
|
||||
|
||||
extension OpenEndedRange: SequenceType {
|
||||
public func generate() -> EndlessIncrement<I> {
|
||||
return EndlessIncrement(i: val)
|
||||
}
|
||||
}
|
||||
|
||||
// Operators
|
||||
|
||||
postfix operator ... {}
|
||||
prefix operator ... {}
|
||||
prefix operator ..< {}
|
||||
|
||||
public postfix func ...<C: Comparable>(c: C) -> OpenEndedInterval<C> {
|
||||
return OpenEndedInterval(val: c)
|
||||
}
|
||||
public postfix func ...<I: ForwardIndexType>(c: I) -> OpenEndedRange<I> {
|
||||
return OpenEndedRange(val: c)
|
||||
}
|
||||
public prefix func ..<<C: Comparable>(c: C) -> OpenStartedIntervalTo<C> {
|
||||
return OpenStartedIntervalTo(val: c)
|
||||
}
|
||||
public prefix func ..<<C: BidirectionalIndexType>(c: C) -> OpenStartedRangeTo<C> {
|
||||
return OpenStartedRangeTo(val: c)
|
||||
}
|
||||
public prefix func ... <C: Comparable>(c: C) -> OpenStartedIntervalThrough<C> {
|
||||
return OpenStartedIntervalThrough(val: c)
|
||||
}
|
||||
public prefix func ... <C: BidirectionalIndexType>(c: C) -> OpenStartedRangeThrough<C> {
|
||||
return OpenStartedRangeThrough(val: c)
|
||||
}
|
||||
|
||||
// Contains
|
||||
|
||||
extension OpenEndedIntervalType {
|
||||
public func contains(v: Value) -> Bool { return val <= v }
|
||||
}
|
||||
extension OpenStartedIntervalTypeTo {
|
||||
public func contains(v: Value) -> Bool { return val > v }
|
||||
}
|
||||
extension OpenStartedIntervalTypeThrough {
|
||||
public func contains(v: Value) -> Bool { return val >= v }
|
||||
}
|
||||
|
||||
// Pattern Matching
|
||||
|
||||
public func ~=<I: OpenIntervalType>(lhs: I, rhs: I.Value) -> Bool {
|
||||
return lhs.contains(rhs)
|
||||
}
|
||||
|
||||
// Indexing
|
||||
|
||||
public extension CollectionType where Index: Comparable {
|
||||
subscript(r: OpenEndedRange<Index>) -> SubSequence {
|
||||
return suffixFrom(r.val)
|
||||
}
|
||||
}
|
||||
|
||||
public extension CollectionType where Index: Comparable, Index: BidirectionalIndexType {
|
||||
subscript(r: OpenStartedRangeTo<Index>) -> SubSequence {
|
||||
return prefixUpTo(r.val)
|
||||
}
|
||||
subscript(r: OpenStartedRangeThrough<Index>) -> SubSequence {
|
||||
return prefixThrough(r.val)
|
||||
}
|
||||
}
|
||||
|
||||
public extension MutableCollectionType where Index: Comparable {
|
||||
subscript(r: OpenEndedRange<Index>) -> SubSequence {
|
||||
get { return suffixFrom(r.val) }
|
||||
set { self[r.val..<endIndex] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public extension MutableCollectionType where Index: Comparable, Index: BidirectionalIndexType {
|
||||
subscript(r: OpenStartedRangeTo<Index>) -> SubSequence {
|
||||
get { return prefixUpTo(r.val) }
|
||||
set { self[startIndex..<r.val] = newValue }
|
||||
}
|
||||
subscript(r: OpenStartedRangeThrough<Index>) -> SubSequence {
|
||||
get { return prefixThrough(r.val) }
|
||||
set { self[startIndex...r.val] = newValue }
|
||||
}
|
||||
}
|
@ -1,208 +0,0 @@
|
||||
// MARK: - Eager
|
||||
|
||||
// MARK: prefixWhile
|
||||
|
||||
public extension SequenceType {
|
||||
|
||||
/// Returns an array of self up until the first element that returns false for condition
|
||||
/// ```swift
|
||||
/// [1, 2, 3, 4, 5, 2].prefixWhile { $0 < 4 }
|
||||
///
|
||||
/// [1, 2, 3]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func prefixWhile(@noescape condition: Generator.Element throws -> Bool) rethrows -> [Generator.Element] {
|
||||
var ret : [Generator.Element] = []
|
||||
var g = generate()
|
||||
while let next = g.next() where try condition(next) { ret.append(next) }
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: DropWhile
|
||||
|
||||
public extension SequenceType {
|
||||
|
||||
/// Returns an array of self with the first elements that return true for condition
|
||||
/// dropped
|
||||
/// ```swift
|
||||
/// [1, 2, 3, 4, 5, 2].dropWhile { $0 < 4 }
|
||||
///
|
||||
/// [4, 5, 2]
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func dropWhile(@noescape condition: Generator.Element throws -> Bool) rethrows -> [Generator.Element] {
|
||||
var g = generate()
|
||||
while let next = g.next() {
|
||||
if try !condition(next) {
|
||||
return [next] + GeneratorSequence(g)
|
||||
}
|
||||
}
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
public extension SequenceType {
|
||||
/**
|
||||
Returns a tuple of the prefix and suffix of `self`, the first element
|
||||
being the prefix up to `n`.
|
||||
*/
|
||||
public func breakAt(n: Int) -> ([Generator.Element],[Generator.Element]) {
|
||||
let r = max(0, underestimateCount() - n)
|
||||
var f,b : [Generator.Element]
|
||||
(f,b) = ([],[])
|
||||
f.reserveCapacity(n)
|
||||
b.reserveCapacity(r)
|
||||
var g = generate()
|
||||
for _ in 0..<n {
|
||||
if let e = g.next() { f.append(e) } else { return (f,b) }
|
||||
}
|
||||
while let e = g.next() { b.append(e) }
|
||||
return (f,b)
|
||||
}
|
||||
}
|
||||
|
||||
public extension CollectionType {
|
||||
/**
|
||||
Returns a tuple of the prefix and suffix of `self`, the first element
|
||||
being the prefix up to `n`.
|
||||
*/
|
||||
public func breakAt(n: Index) -> (SubSequence, SubSequence) {
|
||||
return (prefixUpTo(n),suffixFrom(n))
|
||||
}
|
||||
}
|
||||
|
||||
public extension CollectionType where Index == Int {
|
||||
/**
|
||||
Returns a tuple of the prefix and suffix of `self`, the first element
|
||||
being the prefix up to `n`.
|
||||
*/
|
||||
public func breakAt(n: Int) -> (SubSequence, SubSequence) {
|
||||
return (prefixUpTo(n),suffixFrom(n))
|
||||
}
|
||||
}
|
||||
public extension SequenceType {
|
||||
/**
|
||||
Returns a tuple of the prefix and suffix of `self`, the first element
|
||||
being the prefix up to the first elements of `self` which returns
|
||||
`true` for `isBreak`.
|
||||
*/
|
||||
public func breakAt(@noescape isBreak: Generator.Element throws -> Bool)
|
||||
rethrows -> ([Generator.Element],[Generator.Element]) {
|
||||
var f,b : [Generator.Element]
|
||||
(f,b) = ([],[])
|
||||
var g = generate()
|
||||
while let e = g.next() {
|
||||
if try isBreak(e) {
|
||||
b.append(e)
|
||||
while let be = g.next() { b.append(be) }
|
||||
return (f,b)
|
||||
} else {
|
||||
f.append(e)
|
||||
}
|
||||
}
|
||||
return (f,b)
|
||||
}
|
||||
}
|
||||
public extension CollectionType {
|
||||
/**
|
||||
Returns a tuple of the prefix and suffix of `self`, the first element
|
||||
being the prefix up to the first elements of `self` which returns
|
||||
`true` for `isBreak`.
|
||||
*/
|
||||
public func breakAt(@noescape isBreak: Generator.Element throws -> Bool) rethrows -> (SubSequence, SubSequence) {
|
||||
return try indexOf(isBreak).map(breakAt) ?? (suffixFrom(startIndex),prefixUpTo(startIndex))
|
||||
}
|
||||
}
|
||||
// MARK: - Lazy
|
||||
|
||||
// MARK: TakeWhile
|
||||
/// :nodoc:
|
||||
public struct WhileGen<G : GeneratorType> : GeneratorType {
|
||||
|
||||
private var g: G
|
||||
private let condition : G.Element -> Bool
|
||||
/// :nodoc:
|
||||
mutating public func next() -> G.Element? {
|
||||
if let next = g.next() where condition(next) {
|
||||
return next
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct WhileSeq<S : SequenceType> : LazySequenceType {
|
||||
|
||||
private let seq: S
|
||||
private let condition: S.Generator.Element -> Bool
|
||||
/// :nodoc:
|
||||
public func generate() -> WhileGen<S.Generator> {
|
||||
return WhileGen(g: seq.generate(), condition: condition)
|
||||
}
|
||||
}
|
||||
|
||||
public extension LazySequenceType {
|
||||
|
||||
/// Returns a lazy sequence of self up until the first element that returns false for
|
||||
/// condition
|
||||
/// ```swift
|
||||
/// [1, 2, 3, 4, 5, 2].lazy.takeWhile { $0 < 4 }
|
||||
///
|
||||
/// 1, 2, 3
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func prefixWhile(condition: Generator.Element -> Bool) -> WhileSeq<Self> {
|
||||
return WhileSeq(seq: self, condition: condition)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: DropWhile
|
||||
/// :nodoc:
|
||||
public struct DropWhileGen<G : GeneratorType> : GeneratorType {
|
||||
|
||||
private let predicate: G.Element -> Bool
|
||||
private var nG: G?
|
||||
private var oG: G
|
||||
|
||||
private init(g: G, predicate: G.Element -> Bool) {
|
||||
nG = nil
|
||||
oG = g
|
||||
self.predicate = predicate
|
||||
}
|
||||
/// :nodoc:
|
||||
public mutating func next() -> G.Element? {
|
||||
guard nG == nil else { return nG!.next() }
|
||||
while let next = oG.next() {
|
||||
if !predicate(next) {
|
||||
nG = oG
|
||||
return next
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct DropWhileSeq<S : SequenceType> : LazySequenceType {
|
||||
|
||||
private let predicate: S.Generator.Element -> Bool
|
||||
private let seq: S
|
||||
/// :nodoc:
|
||||
public func generate() -> DropWhileGen<S.Generator> {
|
||||
return DropWhileGen(g: seq.generate(), predicate: predicate)
|
||||
}
|
||||
}
|
||||
|
||||
public extension LazySequenceType {
|
||||
|
||||
/// Returns a lazy sequence of self with the first elements that return true for
|
||||
/// condition dropped
|
||||
/// ```swift
|
||||
/// [1, 2, 3, 4, 5, 2].lazy.dropWhile { $0 < 4 }
|
||||
///
|
||||
/// 4, 5, 2
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
func dropWhile(predicate: Generator.Element -> Bool) -> DropWhileSeq<Self> {
|
||||
return DropWhileSeq(predicate: predicate, seq: self)
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/// :nodoc:
|
||||
public struct NilPaddedZipGenerator<G0: GeneratorType, G1: GeneratorType> : GeneratorType {
|
||||
|
||||
private var (g0, g1): (G0?, G1?)
|
||||
|
||||
public mutating func next() -> (G0.Element?, G1.Element?)? {
|
||||
let (e0,e1) = (g0?.next(),g1?.next())
|
||||
switch (e0,e1) {
|
||||
case (nil,nil): return nil
|
||||
case ( _,nil): g1 = nil
|
||||
case (nil, _): g0 = nil
|
||||
default: break
|
||||
}
|
||||
return (e0,e1)
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct NilPaddedZip<S0: SequenceType, S1: SequenceType> : LazySequenceType {
|
||||
|
||||
private let (s0, s1): (S0, S1)
|
||||
/// :nodoc:
|
||||
public func generate() -> NilPaddedZipGenerator<S0.Generator, S1.Generator> {
|
||||
return NilPaddedZipGenerator(g0: s0.generate(), g1: s1.generate())
|
||||
}
|
||||
}
|
||||
|
||||
/// A sequence of pairs built out of two underlying sequences, where the elements of the
|
||||
/// ith pair are optional ith elements of each underlying sequence. If one sequence is
|
||||
/// shorter than the other, pairs will continue to be returned after it is exhausted, but
|
||||
/// with its elements replaced by nil.
|
||||
/// ```swift
|
||||
/// zipWithPadding([1, 2, 3], [1, 2])
|
||||
///
|
||||
/// (1?, 1?), (2?, 2?), (3?, nil)
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func zipWithPadding<S0: SequenceType, S1: SequenceType>(s0: S0, _ s1: S1)
|
||||
-> NilPaddedZip<S0, S1> {
|
||||
return NilPaddedZip(s0: s0, s1: s1)
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct PaddedZipGenerator<G0: GeneratorType, G1: GeneratorType> : GeneratorType {
|
||||
|
||||
typealias E0 = G0.Element
|
||||
typealias E1 = G1.Element
|
||||
|
||||
private var g: NilPaddedZipGenerator<G0, G1>
|
||||
private let (p0, p1): (E0, E1)
|
||||
|
||||
public mutating func next() -> (E0, E1)? {
|
||||
guard let (e0,e1) = g.next() else { return nil }
|
||||
return (e0 ?? p0, e1 ?? p1)
|
||||
}
|
||||
}
|
||||
/// :nodoc:
|
||||
public struct PaddedZip<S0: SequenceType, S1: SequenceType> : LazySequenceType {
|
||||
|
||||
private let (s0, s1): (S0, S1)
|
||||
private let (p0, p1): (S0.Generator.Element, S1.Generator.Element)
|
||||
/// :nodoc:
|
||||
public func generate() -> PaddedZipGenerator<S0.Generator, S1.Generator> {
|
||||
return PaddedZipGenerator(
|
||||
g: NilPaddedZipGenerator(
|
||||
g0: s0.generate(),
|
||||
g1: s1.generate()
|
||||
),
|
||||
p0: p0,
|
||||
p1: p1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A sequence of pairs built out of two underlying sequences, where the elements of the
|
||||
/// ith pair are the ith elements of each underlying sequence. If one sequence is
|
||||
/// shorter than the other, pairs will continue to be returned after it is exhausted, but
|
||||
/// with its elements replaced by its respective pad.
|
||||
/// - Parameter pad0: the element to pad `s0` with after it is exhausted
|
||||
/// - Parameter pad1: the element to pad `s1` with after it is exhausted
|
||||
/// ```swift
|
||||
/// zipWithPadding([1, 2, 3], [1, 2], pad0: 100, pad1: 900)
|
||||
///
|
||||
/// (1, 1), (2, 2), (3, 900)
|
||||
/// ```
|
||||
@warn_unused_result
|
||||
public func zipWithPadding<
|
||||
S0: SequenceType, S1: SequenceType
|
||||
>(s0: S0, _ s1: S1, pad0: S0.Generator.Element, pad1: S1.Generator.Element)
|
||||
-> PaddedZip<S0, S1> {
|
||||
return PaddedZip(s0: s0, s1: s1, p0: pad0, p1: pad1)
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
// TODO: Preconditions
|
||||
// TODO: Test memoization
|
||||
// TODO: Reorganize Swift Sugar folders
|
||||
// TODO: Sugar documentation
|
||||
// TODO: Add Swift Sugar to git
|
||||
// TODO: Add LINT to EngineKit
|
||||
// TODO: Add @warnunusedresult where appropriate
|
||||
|
||||
import Darwin
|
||||
|
||||
class Random<T: Numeric> {
|
||||
|
||||
let max: Double = Double(INT32_MAX)
|
||||
let exponent: Double = 7
|
||||
|
||||
init(example: T) {
|
||||
setupRandomSeed()
|
||||
}
|
||||
|
||||
private func expRandom() -> Double {
|
||||
let rawRandom = Double(rand()) / max
|
||||
let exponentiated = (3 * rawRandom) ^ exponent
|
||||
return exponentiated
|
||||
}
|
||||
|
||||
private func uniRandom() -> Double {
|
||||
return Double(rand()) / max
|
||||
}
|
||||
|
||||
private func setupRandomSeed() {
|
||||
var now = time(nil)
|
||||
var date = tm()
|
||||
localtime_r(&now, &date)
|
||||
let day = date.tm_yday
|
||||
let year = date.tm_year
|
||||
srand(UInt32(365 * year + day))
|
||||
}
|
||||
|
||||
func nonnegativeRandomNumber() -> T {
|
||||
let random = expRandom()
|
||||
return T.fromDouble(random)
|
||||
}
|
||||
|
||||
func positiveRandomNumber() -> T {
|
||||
let random = expRandom()
|
||||
let result = T.fromDouble(random)
|
||||
|
||||
guard result != 0 else {
|
||||
return positiveRandomNumber()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func randomNumber() -> T {
|
||||
let random = expRandom()
|
||||
let signed = random * ±(Double(rand()) - max)
|
||||
return T.fromDouble(signed)
|
||||
}
|
||||
|
||||
func uniformRandomNumber(from tStart: T, to tEnd: T) -> T {
|
||||
let start = tStart.toDouble
|
||||
let end = tEnd.toDouble
|
||||
|
||||
let rawRandom = uniRandom()
|
||||
let interval = end - start
|
||||
let result = start + (rawRandom * interval)
|
||||
return T.fromDouble(result)
|
||||
}
|
||||
|
||||
func uniformRandomNumber(start tStart: T, interval tInterval: T)
|
||||
-> T {
|
||||
let start = tStart.toDouble
|
||||
let interval = tInterval.toDouble
|
||||
|
||||
let rawRandom = uniRandom()
|
||||
let result = start + (rawRandom * interval)
|
||||
return T.fromDouble(result)
|
||||
}
|
||||
|
||||
func uniformRandomNumber(center tCenter: T,
|
||||
maxDeviation tInterval: T) -> T {
|
||||
let center = tCenter.toDouble
|
||||
let interval = tInterval.toDouble
|
||||
let start = T.fromDouble(center - interval / 2)
|
||||
|
||||
return uniformRandomNumber(start: start, interval: tInterval)
|
||||
}
|
||||
|
||||
func randomSign() -> T {
|
||||
let rawRandom = rand() % 2
|
||||
let result = Double((2 * rawRandom) - 1)
|
||||
return T.fromDouble(result)
|
||||
}
|
||||
|
||||
}
|
@ -42,7 +42,7 @@ extension CGFloat: DoubleValuable {
|
||||
}
|
||||
}
|
||||
|
||||
static func fromDouble(double: Double) -> CGFloat {
|
||||
static func fromDouble(_ double: Double) -> CGFloat {
|
||||
return CGFloat(double)
|
||||
}
|
||||
|
||||
@ -206,7 +206,7 @@ extension CALayer {
|
||||
}
|
||||
}
|
||||
|
||||
let screenRect = UIScreen.mainScreen().bounds
|
||||
let screenRect = UIScreen.main.bounds
|
||||
let screenWidth = screenRect.size.width
|
||||
let screenHeight = screenRect.size.height
|
||||
|
||||
|
@ -2,186 +2,225 @@ import UIKit
|
||||
|
||||
class ViewController: UIViewController, MetaballDataSource {
|
||||
|
||||
var metaballView: UIImageView!
|
||||
var renderer: MetalMetaballRenderer!
|
||||
var metaballView: UIImageView!
|
||||
var renderer: MetalMetaballRenderer!
|
||||
|
||||
let width = 350
|
||||
let height = 600
|
||||
let width = 350
|
||||
let height = 600
|
||||
|
||||
var metaballGraph: Graph<Metaball>!
|
||||
var previousLocation: CGPoint!
|
||||
var metaballGraph: Graph<Metaball>!
|
||||
var previousLocation: CGPoint!
|
||||
|
||||
var selectedMetaball: Metaball?
|
||||
var selectedMetaball: Metaball?
|
||||
|
||||
let edgeAnimationDuration: Float = 1
|
||||
let edgeAnimationDuration: Float = 1
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
view.backgroundColor = UIColor.whiteColor()
|
||||
view.backgroundColor = UIColor.white
|
||||
|
||||
let recognizer = UIPanGestureRecognizer(target: self, action: "handlePan:")
|
||||
view.addGestureRecognizer(recognizer)
|
||||
let recognizer = UIPanGestureRecognizer(
|
||||
target: self,
|
||||
action: #selector(ViewController.handlePan(_:)))
|
||||
view.addGestureRecognizer(recognizer)
|
||||
|
||||
var positions = [CGPoint]()
|
||||
positions.append(CGPoint(x: Double(screenWidth) / 2, y: Double(screenHeight) / 2))
|
||||
for i in 1...5 {
|
||||
let sine = sin(Double(i) * 2 * M_PI / 5)
|
||||
let cosine = cos(Double(i) * 2 * M_PI / 5)
|
||||
let radius: Double = 150
|
||||
let x = Double(screenWidth) / 2 + sine * radius
|
||||
let y = Double(screenHeight) / 2 + cosine * radius
|
||||
positions.append(CGPoint(x: x, y: y))
|
||||
}
|
||||
var positions = [CGPoint]()
|
||||
positions.append(CGPoint(
|
||||
x: Double(screenWidth) / 2,
|
||||
y: Double(screenHeight) / 2))
|
||||
for i in 1...5 {
|
||||
let sine = sin(Double(i) * 2 * .pi / 5)
|
||||
let cosine = cos(Double(i) * 2 * .pi / 5)
|
||||
let radius: Double = 150
|
||||
let x = Double(screenWidth) / 2 + sine * radius
|
||||
let y = Double(screenHeight) / 2 + cosine * radius
|
||||
positions.append(CGPoint(x: x, y: y))
|
||||
}
|
||||
|
||||
let colors =
|
||||
[UIColor(red255: 110, green: 220, blue: 220, alpha: 1.0),
|
||||
UIColor(red255: 250, green: 235, blue: 50, alpha: 1.0),
|
||||
UIColor(red255: 110, green: 220, blue: 220, alpha: 1.0),
|
||||
UIColor(red255: 90, green: 170, blue: 170, alpha: 1.0),
|
||||
UIColor(red255: 90, green: 170, blue: 170, alpha: 1.0),
|
||||
UIColor(red255: 110, green: 220, blue: 220, alpha: 1.0)]
|
||||
let metaballs = zip(positions, colors).map { Metaball(position: $0.0, color: $0.1) }
|
||||
let colors =
|
||||
[UIColor(red255: 110, green: 220, blue: 220, alpha: 1.0),
|
||||
UIColor(red255: 250, green: 235, blue: 50, alpha: 1.0),
|
||||
UIColor(red255: 110, green: 220, blue: 220, alpha: 1.0),
|
||||
UIColor(red255: 90, green: 170, blue: 170, alpha: 1.0),
|
||||
UIColor(red255: 90, green: 170, blue: 170, alpha: 1.0),
|
||||
UIColor(red255: 110, green: 220, blue: 220, alpha: 1.0)]
|
||||
let metaballs = zip(positions, colors).map {
|
||||
Metaball(position: $0.0, color: $0.1)
|
||||
}
|
||||
|
||||
metaballGraph = Graph(vertices: metaballs)
|
||||
metaballGraph = Graph(vertices: metaballs)
|
||||
|
||||
let metaballViewFrame = screenRect
|
||||
renderer = MetalMetaballRenderer(dataSource: self, frame: metaballViewFrame)
|
||||
metaballView = renderer.targetView
|
||||
view.addSubview(metaballView)
|
||||
let metaballViewFrame = screenRect
|
||||
renderer = MetalMetaballRenderer(dataSource: self,
|
||||
frame: metaballViewFrame)
|
||||
metaballView = renderer.targetView
|
||||
view.addSubview(metaballView)
|
||||
|
||||
for metaball in metaballs {
|
||||
metaballView.addSubview(metaball)
|
||||
}
|
||||
for metaball in metaballs {
|
||||
metaballView.addSubview(metaball)
|
||||
}
|
||||
|
||||
delay(1.0) {
|
||||
self.addEdge(0, 1)
|
||||
self.addEdge(0, 2)
|
||||
self.addEdge(0, 3)
|
||||
self.addEdge(0, 4)
|
||||
self.addEdge(0, 5)
|
||||
}
|
||||
delay(1.0) {
|
||||
self.addEdge(0, 1)
|
||||
self.addEdge(0, 2)
|
||||
self.addEdge(0, 3)
|
||||
self.addEdge(0, 4)
|
||||
self.addEdge(0, 5)
|
||||
}
|
||||
|
||||
delay(2.3) {
|
||||
self.removeEdge(0, 1)
|
||||
self.removeEdge(0, 2)
|
||||
self.removeEdge(0, 3)
|
||||
self.removeEdge(0, 4)
|
||||
self.removeEdge(0, 5)
|
||||
}
|
||||
delay(2.3) {
|
||||
self.removeEdge(0, 1)
|
||||
self.removeEdge(0, 2)
|
||||
self.removeEdge(0, 3)
|
||||
self.removeEdge(0, 4)
|
||||
self.removeEdge(0, 5)
|
||||
}
|
||||
|
||||
delay(4) {
|
||||
for i in 1...5 {
|
||||
UIView.animateWithDuration(1.0, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in
|
||||
let sine = sin(Double(i) * 2 * M_PI / 5)
|
||||
let cosine = cos(Double(i) * 2 * M_PI / 5)
|
||||
let radius: Double = 85
|
||||
let x = Double(screenWidth) / 2 + sine * radius
|
||||
let y = Double(screenHeight) / 2 + cosine * radius
|
||||
let metaball = metaballs[i]
|
||||
self.animateMetaball(metaball, toPoint: CGPoint(x: x, y: y))
|
||||
}, completion: nil)
|
||||
}
|
||||
}
|
||||
delay(4) {
|
||||
for i in 1...5 {
|
||||
UIView.animate(withDuration: 1.0, delay: 0,
|
||||
options: UIViewAnimationOptions(),
|
||||
animations: { () -> Void in
|
||||
let sine = sin(Double(i) * 2 * .pi / 5)
|
||||
let cosine = cos(Double(i) * 2 * .pi / 5)
|
||||
let radius: Double = 85
|
||||
let x = Double(screenWidth) / 2 + sine * radius
|
||||
let y = Double(screenHeight) / 2 + cosine * radius
|
||||
let metaball = metaballs[i]
|
||||
self.animateMetaball(metaball, toPoint: CGPoint(x: x, y: y))
|
||||
}, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
delay(6) { () -> () in
|
||||
for i in 1...5 {
|
||||
UIView.animateWithDuration(1.0, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in
|
||||
let sine = sin(Double(i) * 2 * M_PI / 5)
|
||||
let cosine = cos(Double(i) * 2 * M_PI / 5)
|
||||
let radius: Double = 150
|
||||
let x = Double(screenWidth) / 2 + sine * radius
|
||||
let y = Double(screenHeight) / 2 + cosine * radius
|
||||
let metaball = metaballs[i]
|
||||
self.animateMetaball(metaball, toPoint: CGPoint(x: x, y: y))
|
||||
}, completion: nil)
|
||||
}
|
||||
}
|
||||
delay(6) { () -> () in
|
||||
for i in 1...5 {
|
||||
UIView.animate(withDuration: 1.0, delay: 0,
|
||||
usingSpringWithDamping: 0.5,
|
||||
initialSpringVelocity: 0,
|
||||
options: UIViewAnimationOptions(),
|
||||
animations: { () -> Void in
|
||||
let sine = sin(Double(i) * 2 * .pi / 5)
|
||||
let cosine = cos(Double(i) * 2 * .pi / 5)
|
||||
let radius: Double = 150
|
||||
let x = Double(screenWidth) / 2 + sine * radius
|
||||
let y = Double(screenHeight) / 2 + cosine * radius
|
||||
let metaball = metaballs[i]
|
||||
self.animateMetaball(metaball, toPoint: CGPoint(x: x, y: y))
|
||||
}, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
renderer.state = .Running
|
||||
}
|
||||
renderer.state = .running
|
||||
}
|
||||
|
||||
func addEdge(i: Int, _ j: Int) {
|
||||
animateEdge(i, j, fadeIn: true)
|
||||
}
|
||||
func addEdge(_ i: Int, _ j: Int) {
|
||||
animateEdge(i, j, fadeIn: true)
|
||||
}
|
||||
|
||||
func removeEdge(i: Int, _ j: Int) {
|
||||
animateEdge(i, j, fadeIn: false)
|
||||
}
|
||||
func removeEdge(_ i: Int, _ j: Int) {
|
||||
animateEdge(i, j, fadeIn: false)
|
||||
}
|
||||
|
||||
func animateMetaball(metaball: Metaball, toPoint destination: CGPoint) {
|
||||
let parameters = VertexAnimationParameters(startDate: NSDate(), duration: 1.0, origin: metaball.center, destination: destination, metaball: metaball)
|
||||
NSTimer.scheduledTimerWithTimeInterval(1.0 / 60.0, target: self, selector: "animateMetaballWithTimer:", userInfo: parameters, repeats: true)
|
||||
}
|
||||
func animateMetaball(_ metaball: Metaball, toPoint destination: CGPoint) {
|
||||
let parameters = VertexAnimationParameters(startDate: Date(),
|
||||
duration: 1.0,
|
||||
origin: metaball.center,
|
||||
destination: destination,
|
||||
metaball: metaball)
|
||||
Timer.scheduledTimer(
|
||||
timeInterval: 1.0 / 60.0,
|
||||
target: self,
|
||||
selector: #selector(ViewController.animateMetaball(withTimer:)),
|
||||
userInfo: parameters,
|
||||
repeats: true)
|
||||
}
|
||||
|
||||
func animateMetaball(withTimer timer: NSTimer) {
|
||||
guard let userInfo = timer.userInfo as? VertexAnimationParameters else { preconditionFailure() }
|
||||
let (animationStart, duration, origin, destination, metaball) = (userInfo).unpack()
|
||||
func animateMetaball(withTimer timer: Timer) {
|
||||
guard let userInfo = timer.userInfo as? VertexAnimationParameters else {
|
||||
preconditionFailure()
|
||||
}
|
||||
let (animationStart, duration, origin, destination, metaball) =
|
||||
(userInfo).unpack()
|
||||
|
||||
let now = NSDate()
|
||||
var timeElapsed = Float(now.timeIntervalSinceDate(animationStart))
|
||||
let now = Date()
|
||||
var timeElapsed = Float(now.timeIntervalSince(animationStart))
|
||||
|
||||
if timeElapsed > duration {
|
||||
timer.invalidate()
|
||||
timeElapsed = duration
|
||||
}
|
||||
if timeElapsed > duration {
|
||||
timer.invalidate()
|
||||
timeElapsed = duration
|
||||
}
|
||||
|
||||
let linearValue = timeElapsed / duration
|
||||
let interpolatedValue = interpolateSmooth(linearValue)
|
||||
print(interpolatedValue)
|
||||
let linearValue = timeElapsed / duration
|
||||
let interpolatedValue = interpolateSmooth(linearValue)
|
||||
|
||||
let position = origin + ((destination - origin) * interpolatedValue)
|
||||
metaball.center = position
|
||||
let position = origin + ((destination - origin) * interpolatedValue)
|
||||
metaball.center = position
|
||||
|
||||
renderer.state = .Running
|
||||
}
|
||||
renderer.state = .running
|
||||
}
|
||||
|
||||
func animateEdge(i: Int, _ j: Int, fadeIn: Bool) {
|
||||
let parameters = EdgeAnimationParameters(startDate: NSDate(), duration: edgeAnimationDuration, fadeIn: fadeIn, i: i, j: j)
|
||||
NSTimer.scheduledTimerWithTimeInterval(1.0 / 60.0, target: self, selector: "animateEdgeWithTimer:", userInfo: parameters, repeats: true)
|
||||
}
|
||||
func animateEdge(_ i: Int, _ j: Int, fadeIn: Bool) {
|
||||
let parameters = EdgeAnimationParameters(startDate: Date(),
|
||||
duration: edgeAnimationDuration,
|
||||
fadeIn: fadeIn,
|
||||
i: i,
|
||||
j: j)
|
||||
Timer.scheduledTimer(
|
||||
timeInterval: 1.0 / 60.0,
|
||||
target: self,
|
||||
selector: #selector(ViewController.animateEdge(withTimer:)),
|
||||
userInfo: parameters,
|
||||
repeats: true)
|
||||
}
|
||||
|
||||
func animateEdge(withTimer timer: NSTimer) {
|
||||
guard let userInfo = timer.userInfo as? EdgeAnimationParameters else { preconditionFailure() }
|
||||
let (animationStart, duration, fadeIn, i, j) = (userInfo).unpack()
|
||||
func animateEdge(withTimer timer: Timer) {
|
||||
guard let userInfo = timer.userInfo as? EdgeAnimationParameters else {
|
||||
preconditionFailure()
|
||||
}
|
||||
let (animationStart, duration, fadeIn, i, j) = (userInfo).unpack()
|
||||
|
||||
let now = NSDate()
|
||||
var timeElapsed = Float(now.timeIntervalSinceDate(animationStart))
|
||||
let now = Date()
|
||||
var timeElapsed = Float(now.timeIntervalSince(animationStart))
|
||||
|
||||
if timeElapsed > duration {
|
||||
timer.invalidate()
|
||||
timeElapsed = duration
|
||||
}
|
||||
if timeElapsed > duration {
|
||||
timer.invalidate()
|
||||
timeElapsed = duration
|
||||
}
|
||||
|
||||
let linearValue = timeElapsed / duration
|
||||
let interpolatedValue = fadeIn ? interpolateSquareEaseOut(linearValue) : (1 - interpolateSquareEaseIn(linearValue))
|
||||
let linearValue = timeElapsed / duration
|
||||
let interpolatedValue = fadeIn ?
|
||||
interpolateSquareEaseOut(linearValue) :
|
||||
(1 - interpolateSquareEaseIn(linearValue))
|
||||
|
||||
metaballGraph.adjacencyMatrix.set(i, j, value: interpolatedValue)
|
||||
metaballGraph.adjacencyMatrix.set(j, i, value: interpolatedValue)
|
||||
metaballGraph.adjacencyMatrix.set(i, j, value: interpolatedValue)
|
||||
metaballGraph.adjacencyMatrix.set(j, i, value: interpolatedValue)
|
||||
|
||||
renderer.state = .Running
|
||||
}
|
||||
renderer.state = .running
|
||||
}
|
||||
|
||||
func handlePan(recognizer: UIPanGestureRecognizer) {
|
||||
let location = recognizer.locationInView(metaballView)
|
||||
func handlePan(_ recognizer: UIPanGestureRecognizer) {
|
||||
let location = recognizer.location(in: metaballView)
|
||||
|
||||
if selectedMetaball == nil {
|
||||
for metaball in metaballs where
|
||||
abs(metaball.midX - location.x) < 50 && abs(metaball.midY - location.y) < 50 {
|
||||
selectedMetaball = metaball
|
||||
break
|
||||
}
|
||||
}
|
||||
if selectedMetaball == nil {
|
||||
for metaball in metaballs where
|
||||
abs(metaball.midX - location.x) < 50 &&
|
||||
abs(metaball.midY - location.y) < 50
|
||||
{
|
||||
selectedMetaball = metaball
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
guard selectedMetaball != nil else { return }
|
||||
guard selectedMetaball != nil else { return }
|
||||
|
||||
selectedMetaball?.middle = location
|
||||
selectedMetaball?.middle = location
|
||||
|
||||
renderer.state = .Running
|
||||
renderer.state = .running
|
||||
|
||||
if recognizer.state == .Ended {
|
||||
selectedMetaball = nil
|
||||
}
|
||||
}
|
||||
if recognizer.state == .ended {
|
||||
selectedMetaball = nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,7 +33,8 @@ kernel void
|
||||
for (x = 1; x <= numberOfMetaballs; x += 1) {
|
||||
metaballData metaball = metaballBuffer[x];
|
||||
float2 metaballPosition = float2(metaball.x, metaball.y);
|
||||
float2 vector = float2(metaballPosition.x - gid.x, metaballPosition.y - gid.y);
|
||||
float2 vector = float2(metaballPosition.x - gid.x,
|
||||
metaballPosition.y - gid.y);
|
||||
float dotProduct = dot(vector, vector);
|
||||
float squaredDistance = dotProduct > 0 ? dotProduct : 1;
|
||||
float realDistance = sqrt(squaredDistance);
|
||||
|
2
Podfile
2
Podfile
@ -2,5 +2,5 @@ platform :ios, '9.2'
|
||||
use_frameworks!
|
||||
|
||||
target 'PixelImage' do
|
||||
pod 'ChameleonFramework/Swift'
|
||||
pod 'ChameleonFramework/Swift', :git => 'https://github.com/ViccAlexander/Chameleon.git'
|
||||
end
|
||||
|
15
Podfile.lock
15
Podfile.lock
@ -4,9 +4,20 @@ PODS:
|
||||
- ChameleonFramework/Default
|
||||
|
||||
DEPENDENCIES:
|
||||
- ChameleonFramework/Swift
|
||||
- ChameleonFramework/Swift (from `https://github.com/ViccAlexander/Chameleon.git`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
ChameleonFramework:
|
||||
:git: https://github.com/ViccAlexander/Chameleon.git
|
||||
|
||||
CHECKOUT OPTIONS:
|
||||
ChameleonFramework:
|
||||
:commit: acc480fbe023c6e5fe40f68593f4a70a8c4c7ad5
|
||||
:git: https://github.com/ViccAlexander/Chameleon.git
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
ChameleonFramework: d21a3cc247abfe5e37609a283a8238b03575cf64
|
||||
|
||||
COCOAPODS: 0.39.0
|
||||
PODFILE CHECKSUM: 01ad8f20bdbed983c319dde08426f855f26bc5a0
|
||||
|
||||
COCOAPODS: 1.2.0
|
||||
|
Loading…
Reference in New Issue
Block a user