{"id":13478190,"url":"https://github.com/orlp/glidesort","last_synced_at":"2025-05-15T02:07:26.197Z","repository":{"id":65678146,"uuid":"597137891","full_name":"orlp/glidesort","owner":"orlp","description":"A Rust implementation of Glidesort, my stable adaptive quicksort/mergesort hybrid sorting algorithm. ","archived":false,"fork":false,"pushed_at":"2023-02-07T08:34:01.000Z","size":61,"stargazers_count":1629,"open_issues_count":5,"forks_count":25,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-04-13T23:55:40.920Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/orlp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2023-02-03T18:00:09.000Z","updated_at":"2025-04-13T20:00:34.000Z","dependencies_parsed_at":"2023-02-19T16:01:09.420Z","dependency_job_id":null,"html_url":"https://github.com/orlp/glidesort","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orlp%2Fglidesort","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orlp%2Fglidesort/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orlp%2Fglidesort/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orlp%2Fglidesort/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/orlp","download_url":"https://codeload.github.com/orlp/glidesort/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254259383,"owners_count":22040820,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T16:01:53.697Z","updated_at":"2025-05-15T02:07:26.150Z","avatar_url":"https://github.com/orlp.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"# Glidesort\n\nGlidesort is a novel stable sorting algorithm that combines the best-case behavior\nof Timsort-style merge sorts for pre-sorted data with the best-case behavior of\n[pattern-defeating quicksort](https://github.com/orlp/pdqsort) for data with many duplicates.\nIt is a comparison-based sort supporting arbitrary comparison operators,\nand while exceptional on data with patterns it is also very fast for random data.\n\nFor sorting `n` elements with `k` distinct values glidesort has the following\ncharacteristics by default:\n\n```\nBest    Average     Worst       Memory      Stable      Deterministic\nn       n log k     n log n     n / 8       Yes         Yes\n```\n\nGlidesort can use as much (up to `n`) or as little extra memory as you want. If\ngiven only `O(1)` memory the average and worst case become `O(n (log n)^2)`, however\nin practice its performance is great for all but the most skewed data size /\nauxiliary space ratios. The default is to allocate up to `n` elements worth of\ndata, unless this exceeds 1 MiB, in which case we scale this down to `n / 2`\nelements worth of data up until 1 GiB after which glidesort uses `n / 8` memory.\n\n# Benchmark\n\nPerformance varies a lot from machine to machine and dataset to dataset, so your\nmileage will vary. Nevertheless, an example benchmark from a 2021 Apple M1\nmachine comparing against `[T]::sort` and `[T]::sort_unstable` for various input\ndistributions of `u64`:\n\n![Performance graph](https://i.imgur.com/8fIACqY.png)\n\nCompiled with `rustc 1.69.0-nightly (11d96b593)` using `--release --features unstable` and `lto = \"thin\"`.\n\n\n# Usage\n\nUse `cargo add glidesort` and replace `a.sort()` with `glidesort::sort(\u0026mut a)`.\nA similar process works for `sort_by` and `sort_by_key`.\n\nGlidesort exposes two more families of sorting functions.\n`glidesort::sort_with_buffer(\u0026mut a, buf)` asks you to pass a `\u0026mut\n[MaybeUninit\u003cT\u003e]` buffer which it will then (exclusively) use as auxiliary space\nto sort the elements. `glidesort::sort_in_vec(\u0026mut v)` behaves like normal\nglidesort but will allocate its auxiliary space at the end of the passed `Vec\u003cT\u003e`.\nThis allows future sorting calls to re-use the same space and reduce allocations.\nBoth these families also support the `_by` and `_by_key` interface.\n\n# Visualization\n\nThis visualization focuses on demonstrating the advanced merging techniques in glidesort:\n\nhttps://user-images.githubusercontent.com/202547/216675278-e4c8f15c-e42d-4224-b8c7-fdc67fdc2bde.mp4\n\nThis visualization shows how glidesort is adaptive to both pre-existing runs as well\nas many duplicates together:\n\nhttps://user-images.githubusercontent.com/202547/216675274-6e61689f-a120-4b7c-b1a7-9b5aa5fd013e.mp4\n\nNote that both visualizations have different small sorting thresholds and\nauxiliary memory parameters to show the techniques in action on a smaller scale.\n\n\n# Technique overview\n\nIf you prefer I also have a recorded talk\nI gave at FOSDEM 2023 that gives a high level overview of glidesort:\n\n[![Talk recording preview](https://i.imgur.com/Lcl0KbI.png)](https://fosdem.org/2023/schedule/event/rust_glidesort/)\n\nGlidesort uses a novel main loop based on powersort. Powersort is similar to\nTimsort, using heuristics to find a good order of stably merging sorted runs.\nLike powersort it does a linear scan over the input, recognizing any ascending\nor strictly descending sequences. However, unlike powersort it does not eagerly\nsort sequences that are considered unordered into small sorted blocks. Instead\nit processes them as-is, unsorted. This process produces *logical runs*, which\nmay be sorted or unsorted.\n\nGlidesort repeatedly uses a *logical* merge operation on these logical runs, as\npowersort would. In a logical merge unsorted runs are simply concatenated into\nlarger unsorted runs. Sorted runs are also concatenated into *double sorted*\nruns. Only when merging a sorted and unsorted run finally the unsorted run is\nsorted using stable quicksort, and when merging double sorted runs glidesort\nuses interleaved ping-pong merges.\n\nUsing this novel hybrid approach glidesort can take advantage of arbitrary\nsorted runs in the data as well as process data with many duplicate items faster\nsimilar to pattern-defeating quicksort.\n\n\n# Stable merging\n\nGlidesort merges multiple sorted runs at the same time, and interleaves their\nmerging loops for better memory-level and instruction-level parallelism as well\nas hiding data dependencies. For similar reasons it also interleaves independent\nleft-to-right and right-to-left merging loops as bidirectional merges, which are\na generalization of [quadsort](https://github.com/scandum/quadsort)s parity\nmerges. Merging multiple runs at the same time also lets glidesort use ping-pong\nmerging, avoiding unnecessary `memcpy` calls by using the implicit copy you get\nfrom an out-of-place merge. All merging loops are completely branchless, making\nit fast for random data as well.\n\nGlidesort further uses binary searches to split up large merge operations into\nsmaller merge operations that it then performs at the same time using\ninstruction-level parallelism. This splitting procedure also allows glidesort to\nuse arbitrarily small amounts of memory, as it can choose to split a merge\nrepeatedly until it fits in our scratch space to process.\n\n\n# Stable quicksort\n\nYes, stable quicksort. Wikipedia will outright tell you that quicksort is\nunstable, or at least all efficient implementations are. That simply isn't true,\nall it needs is auxiliary memory. Credit to Igor van den Hoven's\n[fluxsort](https://github.com/scandum/fluxsort) for demonstrating that stable\nquicksort can be efficient in practice.\n\nGlidesort uses a novel bidirectional stable partitioning method that interleaves\na left-to-right partition scan with a right-to-left partition scan for greater\nmemory-level parallelism and hiding data dependencies. Partitioning is done\nentirely branchlessly (if the comparison operator is), giving consistent\nperformance on all data.\n\n\n# License\n\nGlidesort is dual-licensed under the Apache License, Version 2.0 and the MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forlp%2Fglidesort","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Forlp%2Fglidesort","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forlp%2Fglidesort/lists"}