Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stdlib] Switch to a stable sort algorithm #19717

Merged
merged 16 commits into from
Nov 7, 2018

Conversation

natecook1000
Copy link
Member

This switches the standard library's sort algorithm from an in-place introsort to use a modified timsort, a stable, adaptive sort that merges runs using a temporary buffer. This implementation performs straight merges instead of adopting timsort's galloping strategy.

In addition to maintaining the relative order of equal/non-comparable elements, this algorithm outperforms the introsort on data with any intrinsic structure, such as runs of ascending or descending elements or a significant number of equality collisions. Benchmarking script and results can be seen in this gist: https://gist.github.com/natecook1000/5161e10aeba09408c130284ea6ec4e11

@natecook1000
Copy link
Member Author

@swift-ci Please smoke benchmark

@natecook1000
Copy link
Member Author

@swift-ci Please test

@@ -146,9 +146,6 @@ where Self: RandomAccessCollection, Element: Comparable {
/// `Comparable` protocol by calling this method. Elements are sorted in
/// ascending order.
///
/// The sorting algorithm is not stable. A nonstable sort may change the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest leaving this in for now. If this sort is better than the current one, we can just land it as an implementation improvement. But officially committing to stability needs an evolution proposal.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good point.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it might be misleading to say it's "not stable" when it is: I'd suggest maybe wording it something like "is not guaranteed to be stable" or "may or may not be stable," or maybe explicitly, "It is an implementation detail whether the sorting algorithm is stable."

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, "not guaranteed stable" is the right phrasing.

@airspeedswift
Copy link
Member

@swift-ci please test compiler performance

@swift-ci
Copy link
Contributor

swift-ci commented Oct 4, 2018

Build comment file:

Build failed before running benchmark.


@airspeedswift
Copy link
Member

Looks like benchmarking blew up during SortStrings

@swift-ci
Copy link
Contributor

swift-ci commented Oct 4, 2018

Build failed
Swift Test OS X Platform
Git Sha - d0fed131b78750521292c340e53ca180fba117cb

@swift-ci
Copy link
Contributor

swift-ci commented Oct 5, 2018

Build comment file:

Summary for master full

Unexpected test results, excluded stats for RxSwift, Fluent, Wordy, ReactiveSwift

Regressions found (see below)

Debug-batch

debug-batch brief

Regressed (0)
name old new delta delta_pct
Improved (0)
name old new delta delta_pct
Unchanged (delta < 1.0% or delta < 100.0ms) (3)
name old new delta delta_pct
Frontend.NumInstructionsExecuted 14,381,111,712,014 14,378,625,285,403 -2,486,426,611 -0.02%
LLVM.NumLLVMBytesOutput 669,624,764 669,627,700 2,936 0.0%
time.swift-driver.wall 1662.6s 1650.9s -11.7s -0.7%

debug-batch detailed

Regressed (2)
name old new delta delta_pct
Driver.NumDriverPipePolls 205,489 209,750 4,261 2.07% ⛔
Driver.NumDriverPipeReads 228,382 232,187 3,805 1.67% ⛔
Improved (0)
name old new delta delta_pct
Unchanged (delta < 1.0% or delta < 100.0ms) (92)
name old new delta delta_pct
AST.NumASTBytesAllocated 19,657,377,192 19,657,779,188 401,996 0.0%
AST.NumDecls 46,267 46,267 0 0.0%
AST.NumDependencies 132,820 132,820 0 0.0%
AST.NumImportedExternalDefinitions 918,389 918,389 0 0.0%
AST.NumInfixOperators 19,744 19,744 0 0.0%
AST.NumLinkLibraries 0 0 0 0.0%
AST.NumLoadedModules 150,702 150,702 0 0.0%
AST.NumLocalTypeDecls 111 111 0 0.0%
AST.NumObjCMethods 13,059 13,059 0 0.0%
AST.NumPostfixOperators 14 14 0 0.0%
AST.NumPrecedenceGroups 9,238 9,238 0 0.0%
AST.NumPrefixOperators 61 61 0 0.0%
AST.NumReferencedDynamicNames 101 101 0 0.0%
AST.NumReferencedMemberNames 2,545,860 2,545,902 42 0.0%
AST.NumReferencedTopLevelNames 164,905 164,905 0 0.0%
AST.NumSourceBuffers 202,733 202,721 -12 -0.01%
AST.NumSourceLines 1,543,248 1,543,248 0 0.0%
AST.NumSourceLinesPerSecond 913,901 916,894 2,993 0.33%
AST.NumTotalClangImportedEntities 3,166,106 3,166,106 0 0.0%
AST.NumUsedConformances 145,051 145,051 0 0.0%
Driver.ChildrenMaxRSS 50,653,771,776 50,720,468,992 66,697,216 0.13%
Driver.DriverDepCascadingDynamic 0 0 0 0.0%
Driver.DriverDepCascadingExternal 0 0 0 0.0%
Driver.DriverDepCascadingMember 0 0 0 0.0%
Driver.DriverDepCascadingNominal 0 0 0 0.0%
Driver.DriverDepCascadingTopLevel 0 0 0 0.0%
Driver.DriverDepDynamic 0 0 0 0.0%
Driver.DriverDepExternal 0 0 0 0.0%
Driver.DriverDepMember 0 0 0 0.0%
Driver.DriverDepNominal 0 0 0 0.0%
Driver.DriverDepTopLevel 0 0 0 0.0%
Driver.NumDriverJobsRun 9,752 9,752 0 0.0%
Driver.NumDriverJobsSkipped 0 0 0 0.0%
Driver.NumProcessFailures 0 0 0 0.0%
Frontend.MaxMallocUsage 246,801,193,744 246,629,391,504 -171,802,240 -0.07%
Frontend.NumInstructionsExecuted 14,381,111,712,014 14,378,625,285,403 -2,486,426,611 -0.02%
Frontend.NumProcessFailures 0 0 0 0.0%
IRModule.NumIRAliases 74,661 74,661 0 0.0%
IRModule.NumIRBasicBlocks 2,506,595 2,506,607 12 0.0%
IRModule.NumIRComdatSymbols 0 0 0 0.0%
IRModule.NumIRFunctions 1,270,083 1,270,091 8 0.0%
IRModule.NumIRGlobals 1,475,477 1,475,485 8 0.0%
IRModule.NumIRIFuncs 0 0 0 0.0%
IRModule.NumIRInsts 27,140,405 27,140,457 52 0.0%
IRModule.NumIRNamedMetaData 47,563 47,563 0 0.0%
IRModule.NumIRValueSymbols 2,448,532 2,448,548 16 0.0%
LLVM.NumLLVMBytesOutput 669,624,764 669,627,700 2,936 0.0%
Parse.NumFunctionsParsed 1,514,222 1,514,222 0 0.0%
Parse.NumIterableDeclContextParsed 535,274 535,274 0 0.0%
SILModule.NumSILGenDefaultWitnessTables 0 0 0 0.0%
SILModule.NumSILGenFunctions 1,081,643 1,081,651 8 0.0%
SILModule.NumSILGenGlobalVariables 24,671 24,671 0 0.0%
SILModule.NumSILGenVtables 4,636 4,636 0 0.0%
SILModule.NumSILGenWitnessTables 27,502 27,502 0 0.0%
SILModule.NumSILOptDefaultWitnessTables 0 0 0 0.0%
SILModule.NumSILOptFunctions 921,759 921,769 10 0.0%
SILModule.NumSILOptGlobalVariables 25,136 25,136 0 0.0%
SILModule.NumSILOptVtables 8,850 8,850 0 0.0%
SILModule.NumSILOptWitnessTables 55,795 55,795 0 0.0%
Sema.AccessLevelRequest 1,294,882 1,294,882 0 0.0%
Sema.DefaultAndMaxAccessLevelRequest 31,166 31,166 0 0.0%
Sema.EnumRawTypeRequest 10,424 10,424 0 0.0%
Sema.ExtendedNominalRequest 1,943,562 1,944,344 782 0.04%
Sema.InheritedDeclsReferencedRequest 64,382,244 64,383,284 1,040 0.0%
Sema.InheritedTypeRequest 354,701 354,701 0 0.0%
Sema.IsDynamicRequest 1,192,455 1,192,471 16 0.0%
Sema.IsObjCRequest 997,842 997,842 0 0.0%
Sema.NamedLazyMemberLoadFailureCount 17,527 17,527 0 0.0%
Sema.NamedLazyMemberLoadSuccessCount 14,275,384 14,245,481 -29,903 -0.21%
Sema.NominalTypeLookupDirectCount 22,703,479 22,704,590 1,111 0.0%
Sema.NumConformancesDeserialized 1,983,771 1,983,776 5 0.0%
Sema.NumConstraintScopes 10,293,731 10,293,731 0 0.0%
Sema.NumConstraintsConsideredForEdgeContraction 19,309,998 19,309,998 0 0.0%
Sema.NumDeclsDeserialized 18,949,188 18,948,887 -301 -0.0%
Sema.NumDeclsValidated 1,202,395 1,202,395 0 0.0%
Sema.NumFunctionsTypechecked 793,535 793,535 0 0.0%
Sema.NumGenericSignatureBuilders 659,554 659,554 0 0.0%
Sema.NumLazyGenericEnvironments 4,101,899 4,101,721 -178 -0.0%
Sema.NumLazyGenericEnvironmentsLoaded 94,021 94,021 0 0.0%
Sema.NumLazyIterableDeclContexts 3,907,690 3,905,956 -1,734 -0.04%
Sema.NumTypesDeserialized 7,857,181 7,858,016 835 0.01%
Sema.NumTypesValidated 779,422 779,422 0 0.0%
Sema.NumUnloadedLazyIterableDeclContexts 3,151,363 3,149,634 -1,729 -0.05%
Sema.OverriddenDeclsRequest 1,051,406 1,051,406 0 0.0%
Sema.RequirementRequest 22,731 22,731 0 0.0%
Sema.SelfBoundsFromWhereClauseRequest 63,119 63,119 0 0.0%
Sema.SetterAccessLevelRequest 77,899 77,899 0 0.0%
Sema.SuperclassDeclRequest 53,301,388 53,302,196 808 0.0%
Sema.SuperclassTypeRequest 17,762 17,762 0 0.0%
Sema.TypeDeclsFromWhereClauseRequest 14,456 14,456 0 0.0%
Sema.USRGenerationRequest 234,940 234,940 0 0.0%
Sema.UnderlyingTypeDeclsReferencedRequest 1,791,925 1,791,925 0 0.0%

Release

release brief

Regressed (0)
name old new delta delta_pct
Improved (0)
name old new delta delta_pct
Unchanged (delta < 1.0% or delta < 100.0ms) (3)
name old new delta delta_pct
Frontend.NumInstructionsExecuted 17,811,393,602,049 17,899,037,472,883 87,643,870,834 0.49%
LLVM.NumLLVMBytesOutput 562,747,006 563,249,310 502,304 0.09%
time.swift-driver.wall 3372.6s 3381.8s 9.2s 0.27%

release detailed

Regressed (0)
name old new delta delta_pct
Improved (0)
name old new delta delta_pct
Unchanged (delta < 1.0% or delta < 100.0ms) (23)
name old new delta delta_pct
AST.NumImportedExternalDefinitions 170,056 170,056 0 0.0%
AST.NumLoadedModules 9,987 9,987 0 0.0%
AST.NumTotalClangImportedEntities 574,906 574,906 0 0.0%
AST.NumUsedConformances 148,171 148,171 0 0.0%
IRModule.NumIRBasicBlocks 2,445,303 2,459,684 14,381 0.59%
IRModule.NumIRFunctions 1,024,871 1,026,409 1,538 0.15%
IRModule.NumIRGlobals 1,146,551 1,147,459 908 0.08%
IRModule.NumIRInsts 19,725,838 19,816,023 90,185 0.46%
IRModule.NumIRValueSymbols 2,005,069 2,007,515 2,446 0.12%
LLVM.NumLLVMBytesOutput 562,747,006 563,249,310 502,304 0.09%
SILModule.NumSILGenFunctions 440,181 440,187 6 0.0%
SILModule.NumSILOptFunctions 631,107 633,848 2,741 0.43%
Sema.NumConformancesDeserialized 1,274,415 1,276,535 2,120 0.17%
Sema.NumConstraintScopes 10,041,520 10,041,520 0 0.0%
Sema.NumDeclsDeserialized 3,847,509 3,850,404 2,895 0.08%
Sema.NumDeclsValidated 565,342 565,342 0 0.0%
Sema.NumFunctionsTypechecked 341,792 341,792 0 0.0%
Sema.NumGenericSignatureBuilders 119,721 119,795 74 0.06%
Sema.NumLazyGenericEnvironments 811,379 812,355 976 0.12%
Sema.NumLazyGenericEnvironmentsLoaded 15,845 15,845 0 0.0%
Sema.NumLazyIterableDeclContexts 502,413 502,335 -78 -0.02%
Sema.NumTypesDeserialized 2,172,548 2,184,726 12,178 0.56%
Sema.NumTypesValidated 249,599 249,599 0 0.0%

@natecook1000
Copy link
Member Author

@swift-ci Please smoke benchmark

@swift-ci
Copy link
Contributor

swift-ci commented Oct 5, 2018

Build comment file:

Performance: -O

TEST OLD NEW DELTA RATIO
Regression
SortLargeExistentials 5573 11321 +103.1% 0.49x
SortStrings 1941 3240 +66.9% 0.60x
Phonebook 10575 15335 +45.0% 0.69x
SortStringsUnicode 2757 3899 +41.4% 0.71x
RGBHistogram 2254 2754 +22.2% 0.82x
StringWordBuilderReservingCapacity 1090 1228 +12.7% 0.89x (?)
SortLettersInPlace 957 1066 +11.4% 0.90x
CStringLongAscii 3287 3556 +8.2% 0.92x
Improvement
SortIntPyramid 20179 619 -96.9% 32.60x
SortAdjacentIntPyramids 11474 1231 -89.3% 9.32x
StaticArray 10 2 -80.0% 5.00x
SortSortedStrings 1339 591 -55.9% 2.27x
RGBHistogramOfObjects 17944 15927 -11.2% 1.13x
IterateData 1787 1626 -9.0% 1.10x (?)
Array2D 7506 6914 -7.9% 1.09x
MapReduce 398 368 -7.5% 1.08x
MapReduceAnyCollection 398 369 -7.3% 1.08x

Code size: -O

TEST OLD NEW DELTA RATIO
Regression
NibbleSort.o 14456 24910 +72.3% 0.58x
SortIntPyramids.o 9693 12872 +32.8% 0.75x
SortLettersInPlace.o 12074 14702 +21.8% 0.82x
RGBHistogram.o 25317 29639 +17.1% 0.85x
Phonebook.o 18245 20314 +11.3% 0.90x
SortLargeExistentials.o 21872 24038 +9.9% 0.91x
SortStrings.o 102854 108590 +5.6% 0.95x
WordCount.o 65375 67770 +3.7% 0.96x
DriverUtils.o 168737 174425 +3.4% 0.97x
Improvement
StaticArray.o 32170 14478 -55.0% 2.22x

Performance: -Osize

TEST OLD NEW DELTA RATIO
Regression
SortLargeExistentials 5526 11072 +100.4% 0.50x
SortStrings 1998 3235 +61.9% 0.62x
SortStringsUnicode 2769 3903 +41.0% 0.71x
Phonebook 10943 13078 +19.5% 0.84x
RGBHistogram 2414 2850 +18.1% 0.85x
StringWalk 1735 2008 +15.7% 0.86x
SortLettersInPlace 961 1086 +13.0% 0.88x
WordCountHistogramUTF16 11717 13198 +12.6% 0.89x
StringWordBuilderReservingCapacity 1090 1215 +11.5% 0.90x (?)
CStringLongAscii 3302 3553 +7.6% 0.93x
Improvement
SortIntPyramid 19998 659 -96.7% 30.35x
SortAdjacentIntPyramids 12024 1259 -89.5% 9.55x
SortSortedStrings 1403 600 -57.2% 2.34x
StaticArray 7 3 -57.1% 2.33x
IterateData 1817 1592 -12.4% 1.14x
RGBHistogramOfObjects 18250 16249 -11.0% 1.12x
FloatingPointPrinting_Float_description_small 5961 5513 -7.5% 1.08x

Code size: -Osize

TEST OLD NEW DELTA RATIO
Regression
Phonebook.o 17724 24775 +39.8% 0.72x
NibbleSort.o 19504 26206 +34.4% 0.74x
SortIntPyramids.o 9957 12873 +29.3% 0.77x
SortLettersInPlace.o 10043 12655 +26.0% 0.79x
RGBHistogram.o 23365 27151 +16.2% 0.86x
SortLargeExistentials.o 20608 23590 +14.5% 0.87x
WordCount.o 54400 57027 +4.8% 0.95x
SortStrings.o 78864 82160 +4.2% 0.96x
DriverUtils.o 146817 151121 +2.9% 0.97x
Improvement
StaticArray.o 18170 13213 -27.3% 1.38x

Performance: -Onone

TEST OLD NEW DELTA RATIO
Regression
SortStringsUnicode 3704 6913 +86.6% 0.54x
SortLargeExistentials 10492 19411 +85.0% 0.54x
SortStrings 2387 4060 +70.1% 0.59x
WordCountHistogramUTF16 43284 64552 +49.1% 0.67x
WordCountHistogramASCII 38371 56642 +47.6% 0.68x
SortLettersInPlace 1601 2196 +37.2% 0.73x
RGBHistogramOfObjects 69172 90926 +31.4% 0.76x
RGBHistogram 21456 28118 +31.0% 0.76x
Phonebook 26355 33915 +28.7% 0.78x
ArrayOfPOD 782 861 +10.1% 0.91x (?)
StringWordBuilderReservingCapacity 1307 1432 +9.6% 0.91x (?)
CStringLongNonAscii 2204 2399 +8.8% 0.92x
Improvement
SortIntPyramid 393631 16277 -95.9% 24.18x
SortAdjacentIntPyramids 207924 21657 -89.6% 9.60x
StaticArray 2341 666 -71.6% 3.52x
NibbleSort 399568 269947 -32.4% 1.48x
StrComplexWalk 7306 6651 -9.0% 1.10x

Code size: Swift libraries

TEST OLD NEW DELTA RATIO
Regression
libswiftCoreAudio.dylib 32768 36864 +12.5% 0.89x
Improvement
libswiftSwiftOnoneSupport.dylib 221184 200704 -9.3% 1.10x
How to read the data The tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.

If you see any unexpected regressions, you should consider fixing the regressions before you merge the PR.

Noise: Sometimes the performance results (not code size!) contain false alarms. Unexpected regressions which are marked with '(?)' are probably noise. If you see regressions which you cannot explain you can try to run the benchmarks again. If regressions still show up, please consult with the performance team (@eeckstein).

Hardware Overview
  Model Name: Mac Pro
  Model Identifier: MacPro6,1
  Processor Name: 12-Core Intel Xeon E5
  Processor Speed: 2.7 GHz
  Number of Processors: 1
  Total Number of Cores: 12
  L2 Cache (per Core): 256 KB
  L3 Cache: 30 MB
  Memory: 64 GB

// Move y forward
self[i] = predecessor

// Swap the elements at `i` and `j`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice comment =)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😅 I think I was just excited about not using the temporary any more

// 1 swap: 132, 121 --- 2 swaps: 231, 221
// swap(b, c): 132->123, 121->112, 231->213, 221->212
swapAt(b, c)
return true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look like there are any other returns here. So perhaps the whole -> Bool is not needed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely not needed — it's a workaround for an optimizer issue. Those can all come out once that's resolved.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optimizer issues also suggest the benchmarks could improve once resolved...

if c < 1 << bitsToUse {
return c
}
let offset = (MemoryLayout<Int>.size * 8 - bitsToUse) - c.leadingZeroBitCount
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't MemoryLayout<Int>.size * 8 equal to Int.bitWidth?

if next < elements.endIndex {
var current = next
elements.formIndex(after: &next)
if try next < elements.endIndex &&
Copy link
Contributor

@moiseev moiseev Oct 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we extract this next < elements.endIndex into a guard, and then replace the else if few lines below with just an else?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pulling this out allowed a nice refactor, which handled the next comment (about the repeats) too.

} else if next < elements.endIndex {
// The elements in this run are in ascending order. Equal elements can
// be included in the run.
repeat {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This repeat ... while duplication is annoying. Would extracting it into a nested function affect performance?

break Loop
} else if runs[lastIndex - 1].count <= runs[lastIndex].count {
// Last two runs do not follow Y > Z.
// Merge Y and Z.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment Merge Y and Z. looks very scary in absence of any code following it. What would you say about adding // Intentionally left blank. kind of comment here as well?

}

if !result { fatalError() }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it the same as precondition(result)?

// RUN: %target-run %t/a.out
// REQUIRES: executable_test

#if USE_STDLIBUNITTEST
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really needed? If so, the same guard should wrap around the actual test cases and a call to runAllTests.

func expectSortedCollection<C: Collection>(_ a: C,
by areInIncreasingOrder: (C.Element, C.Element) -> Bool
) {
expectFalse(zip(a.dropFirst(), a).contains(where: areInIncreasingOrder))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course you meant a.lazy.dropFirst() :-)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 Would that make any difference here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. It's just that I seem to have developed this habit of trying to apply .lazy everywhere and see if that'd work. Works in this case. Will perhaps make the test a millisecond faster.

@moiseev
Copy link
Contributor

moiseev commented Oct 5, 2018

This is great, @natecook1000! 👏 👏 👏

@@ -529,6 +528,8 @@ extension UnsafeMutableBufferPointer {

runs[i - 1] = low..<high
runs.remove(at: i)

// FIXME: Remove this, it works around rdar://problem/45044610
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

@moiseev moiseev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

1 similar comment
@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

This switches the standard library's sort algorithm from an in-place
introsort to use a modified timsort, a stable, adaptive sort that
merges runs using a temporary buffer. This implementation performs
straight merges instead of adopting timsort's galloping strategy.

In addition to maintaining the relative order of equal/non-comparable
elements, this algorithm outperforms the introsort on data with any
intrinsic structure, such as runs of ascending or descending elements
or a significant number of equality collisions.
This drops the new MutableCollection requirement in favor of using only
_withUnsafeMutableBufferPointerIfSupported to dispatch the sort algorithm
to a mutable buffer. This in turn requires that UnsafeMutableBufferPointer
implements _withUnsafeMutableBufferPointerIfSupported, so that change is also
included here (and makes more intuitive sense than a buffer not supporting
buffer operations).
@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@airspeedswift
Copy link
Member

:shipit:

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test OS X Platform

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test Linux platform

2 similar comments
@natecook1000
Copy link
Member Author

@swift-ci Please smoke test Linux platform

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test Linux platform

@natecook1000 natecook1000 merged commit e5c1567 into swiftlang:master Nov 7, 2018
@natecook1000 natecook1000 deleted the nc-stable-sort branch November 8, 2018 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants