diff --git a/.github/.codecov.yml b/.github/.codecov.yml index 84fab2a6..6befda0e 100644 --- a/.github/.codecov.yml +++ b/.github/.codecov.yml @@ -1,14 +1,14 @@ -# Copyright (c) 2018-2020 Morwenn +# Copyright (c) 2018-2022 Morwenn # SPDX-License-Identifier: MIT coverage: ignore: - - "testsuite" + - "tests" # This unrolled version of a merge-insertion sort derivative was tested # exhaustively for every permutation of an integer sequence of 9 elements, # thus we don't include it - "include/cpp-sort/detail/low_comparisons/sort9.h" # Sorting networks have been tested independently with the 0-1 principle - # when needed, and are otherwise simple enough that we do not need the - # testsuite to test all of them + # when needed, so we do not need to test them exhaustively in the test + # suite - "include/cpp-sort/detail/sorting_network/*" diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 85534772..057437f2 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2021 Morwenn +# Copyright (c) 2021-2022 Morwenn # SPDX-License-Identifier: MIT name: MacOS Builds @@ -11,7 +11,7 @@ on: - 'cmake/**' - 'examples/**' - 'include/**' - - 'testsuite/**' + - 'tests/**' pull_request: paths: - '.github/workflows/build-macos.yml' @@ -19,7 +19,7 @@ on: - 'cmake/**' - 'examples/**' - 'include/**' - - 'testsuite/**' + - 'tests/**' jobs: build: diff --git a/.github/workflows/build-mingw.yml b/.github/workflows/build-mingw.yml index 0ebcdec7..2b3f7986 100644 --- a/.github/workflows/build-mingw.yml +++ b/.github/workflows/build-mingw.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2021 Morwenn +# Copyright (c) 2021-2022 Morwenn # SPDX-License-Identifier: MIT name: MinGW-w64 Builds @@ -11,7 +11,7 @@ on: - 'cmake/**' - 'examples/**' - 'include/**' - - 'testsuite/**' + - 'tests/**' pull_request: paths: - '.github/workflows/build-mingw.yml' @@ -19,7 +19,7 @@ on: - 'cmake/**' - 'examples/**' - 'include/**' - - 'testsuite/**' + - 'tests/**' jobs: build: diff --git a/.github/workflows/build-msvc.yml b/.github/workflows/build-msvc.yml index 09603a4e..17c0cc3c 100644 --- a/.github/workflows/build-msvc.yml +++ b/.github/workflows/build-msvc.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2021 Morwenn +# Copyright (c) 2021-2022 Morwenn # SPDX-License-Identifier: MIT name: MSVC Builds @@ -11,7 +11,7 @@ on: - 'cmake/**' - 'examples/**' - 'include/**' - - 'testsuite/**' + - 'tests/**' pull_request: paths: - '.github/workflows/build-msvc.yml' @@ -19,7 +19,7 @@ on: - 'cmake/**' - 'examples/**' - 'include/**' - - 'testsuite/**' + - 'tests/**' jobs: build: diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index ce824030..d4bc586f 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -11,7 +11,7 @@ on: - 'cmake/**' - 'examples/**' - 'include/**' - - 'testsuite/**' + - 'tests/**' pull_request: paths: - '.github/workflows/build-ubuntu.yml' @@ -19,7 +19,7 @@ on: - 'cmake/**' - 'examples/**' - 'include/**' - - 'testsuite/**' + - 'tests/**' jobs: build: diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 00930489..e8c7a4d4 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2021 Morwenn +# Copyright (c) 2020-2022 Morwenn # SPDX-License-Identifier: MIT name: Coverage Upload to Codecov @@ -15,7 +15,7 @@ on: - 'CMakeLists.txt' - 'cmake/**' - 'include/**' - - 'testsuite/**' + - 'tests/**' jobs: upload-coverage: @@ -55,7 +55,7 @@ jobs: run: cmake --build . --target lcov-capture - name: Upload coverage info - uses: codecov/codecov-action@v2 + uses: codecov/codecov-action@v3 with: directory: ${{runner.workspace}}/build/lcov/data files: '*.info' diff --git a/.github/workflows/deploy-to-wiki.yml b/.github/workflows/deploy-to-wiki.yml index a5bd1852..62804cfb 100644 --- a/.github/workflows/deploy-to-wiki.yml +++ b/.github/workflows/deploy-to-wiki.yml @@ -1,3 +1,6 @@ +# Copyright (c) 2020-2022 Morwenn +# SPDX-License-Identifier: MIT + name: Wiki Deployment on: @@ -5,7 +8,7 @@ on: branches: - master paths: - - 'docs/**' + - 'docs/**' jobs: sync-wiki-files: @@ -15,10 +18,37 @@ jobs: steps: - name: Checkout /docs - uses: actions/checkout@master - - name: Sync .wiki with /docs - uses: SwiftDocOrg/github-wiki-publish-action@rsync + uses: actions/checkout@v2 + with: + repository: ${{github.repository}} + path: main + + - name: Checkout wiki + uses: actions/checkout@v2 + with: + repository: ${{github.repository}}.wiki + path: wiki + + - name: Sync wiki files + run: | + for docname in main/docs/*.md; do + old=$(basename "$docname"); + new=${old%.*}; + find main/docs -name "*.md" -exec sed -i "s/$old/$new/g" {} \; + done + rsync -avzr --delete --exclude='.git/' "main/docs/" "wiki/" + + - name: Commit changes + working-directory: wiki + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add . + git commit -m "Synchronize wiki with docs/" + + - name: Push changes to wiki + uses: ad-m/github-push-action@master with: - path: docs/ - env: - GH_PERSONAL_ACCESS_TOKEN: ${{ secrets.DEPLOY_TO_WIKI_ACCESS_TOKEN }} + directory: wiki + repository: ${{github.repository}}.wiki + branch: master diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a78f7c2..ac1c68ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.8.0) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) -project(cpp-sort VERSION 1.12.1 LANGUAGES CXX) +project(cpp-sort VERSION 1.13.0 LANGUAGES CXX) include(CMakePackageConfigHelpers) include(GNUInstallDirs) @@ -86,7 +86,7 @@ export( if (PROJECT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) if (CPPSORT_BUILD_TESTING) enable_testing() - add_subdirectory(testsuite) + add_subdirectory(tests) endif() if (CPPSORT_BUILD_EXAMPLES) diff --git a/NOTICE.txt b/NOTICE.txt index 57f2babe..7ea96e0b 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -26,7 +26,37 @@ THE SOFTWARE. In addition, certain files include the notices provided below. +/* + * C++ implementation of timsort + * + * ported from Python's and OpenJDK's: + * - http://svn.python.org/projects/python/trunk/Objects/listobject.c + * - http://cr.openjdk.java.net/~martin/webrevs/openjdk7/timsort/raw_files/new/src/share/classes/java/util/TimSort.java + * + * Copyright (c) 2011 Fuji, Goro (gfx) . + * Copyright (c) 2015-2022 Morwenn. + * Copyright (c) 2021 Igor Kushnir . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +---------------------- /* * WikiSort: a public domain implementation of "Block Sort" diff --git a/README.md b/README.md index 2b81af77..e47ff8b5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ -[![Latest Release](https://img.shields.io/badge/release-1.12.1-blue.svg)](https://github.com/Morwenn/cpp-sort/releases/tag/1.12.1) -[![Conan Package](https://img.shields.io/badge/conan-cpp--sort%2F1.12.1-blue.svg)](https://conan.io/center/cpp-sort?version=1.12.1) +![cpp-sort logo](docs/images/cpp-sort-logo.svg) + +[![Latest Release](https://img.shields.io/badge/release-1.13.0-blue.svg)](https://github.com/Morwenn/cpp-sort/releases/tag/1.13.0) +[![Conan Package](https://img.shields.io/badge/conan-cpp--sort%2F1.13.0-blue.svg)](https://conan.io/center/cpp-sort?version=1.13.0) [![Code Coverage](https://codecov.io/gh/Morwenn/cpp-sort/branch/develop/graph/badge.svg)](https://codecov.io/gh/Morwenn/cpp-sort) +[![Pitchfork Layout](https://img.shields.io/badge/standard-PFL-orange.svg)](https://github.com/vector-of-bool/pitchfork) > *It would be nice if only one or two of the sorting methods would dominate all of the others, > regardless of application or the computer being used. But in fact, each method has its own @@ -201,17 +204,9 @@ slightly modified version of Matthew Bentley's [indiesort](https://github.com/ma comes from Danila Kutenin's [miniselect library](https://github.com/danlark1/miniselect) and uses Andrei Alexandrescu's [*AdaptiveQuickselect*](https://arxiv.org/abs/1606.00484) algorithm. -* The algorithms 0 to 16 used by `sorting_network_sorter` have been generated with -Perl's [`Algorithm::Networksort` module](https://metacpan.org/pod/release/JGAMBLE/Algorithm-Networksort-1.30/lib/Algorithm/Networksort.pm). - -* The algorithm 17 used by `sorting_network_sorter` correspond to the ones found by -Symmetry and Evolution based Network Sort Optimization (SENSO) published in *Using -Symmetry and Evolutionary Search to Minimize Sorting Networks* by Valsalam and Miikkulainen. - -* The algorithms 18 to 26 and 28 used by `sorting_network_sorter` have been found and -proposed for inclusion by Bert Dobbelaere with his [SorterHunter project](https://github.com/bertdobbelaere/SorterHunter). -Huge thanks for this contribution :) You can find a full list of most well-known sorting -networks up to 32 inputs on his website. +* The sorting networks used by `sorting_network_sorter` all come [from this list](http://users.telenet.be/bertdobbelaere/SorterHunter/sorting_networks.html) +maintained by Bert Dobbelaere. The page has references to the sources of all of the sorting networks +it lists. * Some of the optimizations used by `sorting_network_sorter` come from [this discussion](https://stackoverflow.com/q/2786899/1364752) on StackOverflow and are diff --git a/conanfile.py b/conanfile.py index f5d54780..544b6007 100644 --- a/conanfile.py +++ b/conanfile.py @@ -10,7 +10,7 @@ class CppSortConan(ConanFile): name = "cpp-sort" - version = "1.12.1" + version = "1.13.0" description = "Additional sorting algorithms & related tools" topics = "conan", "cpp-sort", "sorting", "algorithms" url = "https://github.com/Morwenn/cpp-sort" diff --git a/docs/Benchmarks.md b/docs/Benchmarks.md index 43be3e95..a45f733c 100644 --- a/docs/Benchmarks.md +++ b/docs/Benchmarks.md @@ -177,6 +177,6 @@ It makes rather easy to see the different groups of complexities: * All of the other measures of presortedness run in O(n log n) time. - [measures-of-presortedness]: https://github.com/Morwenn/cpp-sort/wiki/Measures-of-presortedness + [measures-of-presortedness]: Measures-of-presortedness.md [std-forward-list-sort]: https://en.cppreference.com/w/cpp/container/list/sort [std-list-sort]: https://en.cppreference.com/w/cpp/container/list/sort diff --git a/docs/Chainable-projections.md b/docs/Chainable-projections.md index 2561c4a5..2e8061fc 100644 --- a/docs/Chainable-projections.md +++ b/docs/Chainable-projections.md @@ -13,7 +13,7 @@ struct my_negate: }; ``` -Making a function object inherit from `cppsort::utility::projection_base` allows it to benefit from the `operator|` overload used to compose projections; the projection inheriting from that class can appear on any side of the operator, and the other argument can be any suitable [*Callable*][callable]. Here is an example of what is possible with the custom projection defined above: +Making a function object inherit from `utility::projection_base` allows it to benefit from the `operator|` overload used to compose projections; the projection inheriting from that class can appear on any side of the operator, and the other argument can be any suitable [*Callable*][callable]. Here is an example of what is possible with the custom projection defined above: ```cpp // Create a vector of wrapper @@ -25,8 +25,13 @@ my_negate projection; cppsort::poplar_sort(vec, &wrapper::value | projection); ``` -The object returned by the utility function [`cppsort::utility::as_projection`][as_projection] also inherits from `cppsort::utility::projection_base`, making `as_projection` the proper function to turn any suitable projection into a projection composable with `operator|`. +The object returned by the utility function [`utility::as_projection`][as_projection] also inherits from `utility::projection_base`, making `as_projection` the proper function to turn any suitable projection into a projection composable with `operator|`. +If both of the projections composed with `operator|` are [*transparent*][transparent-func], then the returned object is also a *transparent* projection. - [as_projection]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#as_comparison-and-as_projection - [callable]: https://en.cppreference.com/w/cpp/named_req/Callable \ No newline at end of file +*Changed in version 1.13.0:* the object returned by `operator|` is now conditionally [*transparent*][transparent-func]. + + + [as_projection]: Miscellaneous-utilities.md#as_comparison-and-as_projection + [callable]: https://en.cppreference.com/w/cpp/named_req/Callable + [transparent-func]: Comparators-and-projections.md#Transparent-function-objects diff --git a/docs/Changelog.md b/docs/Changelog.md index 6cf986ad..cc5559af 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -92,14 +92,15 @@ When compiled with C++20, **cpp-sort** might gain a few additional features depe * When using libstdc++, libc++ or the Microsoft STL, the return type of [`std::mem_fn`][std-mem-fn] is considered ["probably branchless"][branchless-traits] when it wraps a pointer to data member, which can improve the speed of [`pdq_sorter`][pdq-sorter] and everything that relies on it in some scenarios. - [branchless-traits]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#branchless-traits - [counting-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Sorters#counting_sorter - [cpp-sort-function-objects]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects + [branchless-traits]: Miscellaneous-utilities.md#branchless-traits + [counting-sorter]: Sorters.md#counting_sorter + [cpp-sort-function-objects]: Miscellaneous-utilities.md#miscellaneous-function-objects [cpp-sort-releases]: https://github.com/Morwenn/cpp-sort/releases [feature-test-macros]: https://wg21.link/SD6 - [pdq-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Sorters#pdq_sorter - [ska-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Sorters#ska_sorter - [sorter-facade]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-facade + [pdq-sorter]: Sorters.md#pdq_sorter + [ska-sorter]: Sorters.md#ska_sorter + [smooth-sorter]: Sorters.md#smooth-sorter_sorter + [sorter-facade]: Sorter-facade.md [std-greater-void]: https://en.cppreference.com/w/cpp/utility/functional/greater_void [std-identity]: https://en.cppreference.com/w/cpp/utility/functional/identity [std-less-void]: https://en.cppreference.com/w/cpp/utility/functional/less_void @@ -107,4 +108,5 @@ When compiled with C++20, **cpp-sort** might gain a few additional features depe [std-ranges-greater]: https://en.cppreference.com/w/cpp/utility/functional/ranges/greater [std-ranges-less]: https://en.cppreference.com/w/cpp/utility/functional/ranges/less [std-string-view]: https://en.cppreference.com/w/cpp/string/basic_string_view - [utility-iter-move]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#iter_move-and-iter_swap + [std-swap]: https://en.cppreference.com/w/cpp/algorithm/swap + [utility-iter-move]: Miscellaneous-utilities.md#iter_move-and-iter_swap diff --git a/docs/Comparator-adapters.md b/docs/Comparator-adapters.md new file mode 100644 index 00000000..9fba1fff --- /dev/null +++ b/docs/Comparator-adapters.md @@ -0,0 +1,156 @@ +The comparator adapters below are classes mainly designed to wrap binary predicates and should themselves satisfy the [*BinaryPredicate*][binary-predicate] named requirement. + +All adapters below are composed of two elements: +* A class template that wraps a comparator and is itself a comparator (ex: `not_fn_t`, `flip_t`). +* A function template that simplifies the construction and sometimes implements optimizations (ex: `not_fn`, `flip`). + +The optimizations performed by the function templates are of the "unwrapping" kind, with a goal to reduce the nesting of templates in the library and to eventually reduce the overall number of instantiated templates. + +```cpp +auto cmp = std::less{}; +auto cmp2 = cppsort::flip(cmp); // cppsort::flip_t> +auto cmp3 = cppsort::flip(cmp2); // std::less<> +``` + +Those unwrappings are meant to be simple and only intended to work with "well-formed" functions that don't go against simple logic rules. If the passed comparators are too tricky and absolutely need the extra wrapping, then it is advised to use the adapter template classes directly instead of the construction functions. + +### `flip` + +```cpp +#include +``` + +The class template `flip_t` is a function object which, when called, passes the arguments in reversed order to the *Callable* it holds with and returns the result. It is named after the [`flip`][prelude-flip] function from Haskell's Prelude module. + +`flip_t` has the following member functions: + +```cpp +// Construction +flip_t() = default; +explicit constexpr flip_t(const F& func); +explicit constexpr flip_t(F&& func); + +// Call with flipped arguments +template +constexpr auto operator()(T1&& x, T2&& y) &/const&/&&/const&& + noexcept(noexcept(std::invoke(base(), std::forward(y), std::forward(x)))) + -> decltype(std::invoke(base(), std::forward(y), std::forward(x))); + +// Retrieve the passed callable +constexpr auto base() const + -> F; +``` + +`cppsort::flip` takes a *Callable* `f` of type `F` and returns an instance of `flip_t>` except in the following cases: +* When given a `flip_t`, it returns a `F`. +* When given a `not_fn_t>`, it returns a `not_fn_t`. +* When given a `projection_compare` it returns `make_projection_compare(flip(f.comparison()), f.projection())`. + +`flip_t` is [*transparent*][transparent-func] when `F` is *transparent*. + +`flip_t` is considered [branchless][branchless-traits] when `F` is considered branchless. + +*New in version 1.13.0* + +### `not_fn` + +```cpp +#include +``` + +The class template `not_fn_t` is roughly equivalent to the one returned by the C++17 [`std::not_fn`][std-not-fn], a function object which, when called, returns the negation of the *Callable* it holds. + +`not_fn_t` has the following member functions: + +```cpp +// Construction +not_fn_t() = default; +explicit constexpr not_fn_t(const F& func); +explicit constexpr not_fn_t(F&& func); + +// Call and negate +template +constexpr auto operator()(Args&&... args) &/const&/&&/const&& + noexcept(noexcept(not std::invoke(base(), std::forward(args)...))) + -> decltype(not std::invoke(base(), std::forward(args)...)); + +// Retrieve the passed callable +constexpr auto base() const + -> F; +``` + +`cppsort::not_fn` takes a *Callable* `f` of type `F` and returns an instance of `not_fn_t>` except in the following cases: +* When given a `not_fn_t`, it returns a `F`. +* When given a `flip_t>`, it returns a `flip_t`. +* When given a `projection_compare` it returns `make_projection_compare(not_fn(f.comparison()), f.projection())`. + +`not_fn_t` is [*transparent*][transparent-func] when `F` is *transparent*. + +*New in version 1.13.0* + +### `projection_compare` + +```cpp +#include +``` + +The class template `projection_compare` can be used to embed a comparison and a projection in a single comparison object, allowing to provide projection support to algorithms that only support comparisons, such as standard library algorithms prior to C++20. Both the passed comparison and projection functions can be [*Callable*][callable]. + +It is accompanied by a `make_projection_compare` function template to avoid having to pass the template parameters by hand. + +**Example:** + +```cpp +// Sort a family from older to younger member +std::vector family = { /* ... */ }; +std::sort(family.begin(), family.end(), cppsort::make_projection_compare(std::greater<>{}, &Person::age)); +``` + +`projection_compare` has the following member functions: + +```cpp +// Construction +projection_compare() = default; +projection_compare(C comp, P proj); + +// Call +template +constexpr auto operator()(T1&& x, T2&& y) &/const&/&&/const&& + noexcept(noexcept(std::invoke(comparison(), + std::invoke(projection(), std::forward(x)), + std::invoke(projection(), std::forward(y))))) + -> decltype(std::invoke(comparison(), + std::invoke(projection(), std::forward(x)), + std::invoke(projection(), std::forward(y)))); + +// Retrieve the passed comparison +constexpr auto comparison() const + -> C; + +// Retrieve the passed projection +constexpr auto projection() const + -> P; +``` + +`cppsort::make_projection_compare` takes two *Callable* of types `C` and `P` and returns an instance of `projection_compare, std::decay_t

>` except in the following cases: +* When `std::decay_t

` is of type [`utility::identity`][utility-identity] or [`std::identity`][std-identity], it returns `C` directly. + +`projection_compare` is [*transparent*][transparent-func] when the passed comparison and projection are both *transparent*. + +`projection_compare` is considered [branchless][branchless-traits] when the projection it wraps is considered branchless and the comparison it wraps is considered branchless when called with the result of the projection. + +*New in version 1.9.0* + +*Changed in version 1.13.0:* `projection_compare` is now conditionally default-constructible. + +*Changed in version 1.13.0:* `make_projection_compare` now returns the comparison directly when the passed projection is an identity function object. + + + [binary-predicate]: https://en.cppreference.com/w/cpp/concept/BinaryPredicate + [branchless-traits]: Miscellaneous-utilities.md#branchless-traits + [callable]: https://en.cppreference.com/w/cpp/named_req/Callable + [prelude-flip]: https://hackage.haskell.org/package/base-4.16.0.0/docs/Prelude.html#v:flip + [std-identity]: https://en.cppreference.com/w/cpp/utility/functional/identity + [std-not-fn]: https://en.cppreference.com/w/cpp/utility/functional/not_fn + [transparent-func]: Comparators-and-projections.md#Transparent-function-objects + [utility-identity]: Miscellaneous-utilities.md#miscellaneous-function-objects diff --git a/docs/Comparators-and-projections.md b/docs/Comparators-and-projections.md index 18d3b76f..3b7227b4 100644 --- a/docs/Comparators-and-projections.md +++ b/docs/Comparators-and-projections.md @@ -1,4 +1,4 @@ -Most sorting algorithms in **cpp-sort** accept comparison and/or projection parameters. The library therefore considers these kinds of functions to be first-class citizens too and provides dedicated comparators, projections and tools to combine them and to solve common related problems. +Most sorting algorithms in **cpp-sort** accept comparison and/or projection parameters. The library therefore considers these kinds of functions to be first-class citizens too and provides dedicated [comparators][comparators], [comparator adapters][comparator-adapters] projections and tools to combine them and to solve common problems in the domain. All the functions and classes in **cpp-sort** that take comparison or projection functions as parameters expect [*Callable*][callable] parameters, which correspond to anything that can be used as the first parameter of [`std::invoke`][std-invoke]. This allows to pass entities such as pointers to members or pointer to member functions to the sorting algorithms; it should work out-of-the-box without any wrapping needed on the user side. @@ -10,6 +10,15 @@ Several of the [miscellaneous utilities][utilities] provided by the library are - [`is_probably_branchless_comparison` and `is_probably_branchless_projection`][branchless-traits] are type traits that can be used to mark whether functions are likely to be branchless when called with a specific type. - [`identity`][misc-function-objects] is the default projection returning the argument it is passed without modifying it. +### Transparent function objects + +When possible, comparison and projection objects available in **cpp-sort** are *transparent function objects*. This means that: +* They accept arguments of arbitrary types (generally via forwarding references). +* They perfectly forward their arguments to avoid unnecessary copy operations or conversions. +* They have a public member type named `is_transparent` (which generally aliases `void` for convenience, but the exact type is irrelevant). + +The concept of transparent function objects was introduced in C++14 for [`std::less<>`][std-less-void] and friends as an optimization mechanism. Nothing in this library actively cares about whether a function object is transparent or not, but some standard library components do: for example [`std::set::find`][std-set-find] and [`std::set::lower_bound`][std-set-lower-bound] use this information to avoid needless conversions of the parameters to their key type. + ### LWG3031 Sorters and adapters in the library accept comparators taking their parameters by non-`const` reference, and should work as expected as long as comparators do not actually modify their parameters in a way that affects the sort consistency. This is mostly meant to support legacy comparators, but it also covers more unusual use cases such as when a comparator needs to update the compared objects to store additional information (preferably fields that do not affect the result of the comparison). @@ -19,11 +28,16 @@ This additional guarantee is allowed by the resolution of [LWG3031][lwg3031]. Ho *New in version 1.7.0* - [as-comparison-as-projection]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#as_comparison-and-as_projection - [as-function]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#as_function - [branchless-traits]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#branchless-traits + [as-comparison-as-projection]: Miscellaneous-utilities.md#as_comparison-and-as_projection + [as-function]: Miscellaneous-utilities.md#as_function + [branchless-traits]: Miscellaneous-utilities.md#branchless-traits [callable]: https://en.cppreference.com/w/cpp/named_req/Callable + [comparator-adapters]: Comparator-adapters.md + [comparators]: Comparators.md [lwg3031]: https://wg21.link/LWG3031 - [misc-function-objects]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects + [misc-function-objects]: Miscellaneous-utilities.md#miscellaneous-function-objects [std-invoke]: https://en.cppreference.com/w/cpp/utility/functional/invoke - [utilities]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities + [std-less-void]: https://en.cppreference.com/w/cpp/utility/functional/less_void + [std-set-find]: https://en.cppreference.com/w/cpp/container/set/find + [std-set-lower-bound]: https://en.cppreference.com/w/cpp/container/set/lower_bound + [utilities]: Miscellaneous-utilities.md diff --git a/docs/Comparators.md b/docs/Comparators.md index 27eedde5..05221f31 100644 --- a/docs/Comparators.md +++ b/docs/Comparators.md @@ -1,28 +1,8 @@ -While comparators are not inherent to sorting *per se*, most sorting algorithms (at least in this library) are *comparison sorts*, hence providing some common useful comparators along with the sorters can be useful. Every comparator in this module satisfies the [`BinaryPredicate`][binary-predicate] library concept. +The comparators described below can be used as needed with [*sorters*][sorters] and [*sorter adapters*][sorter-adapters] that accept comparisons. Every comparator in this module satisfies the [`BinaryPredicate`][binary-predicate] library concept. -Every non-refined comparator described below is also a [transparent comparator][transparent-comparator]. While this ability is not used by the library itself, it means that the comparators can be used with the standard library associative containers to compare heterogeneous objects without having to create temporaries. +Every non-refined comparator described below is also a [transparent comparator][transparent-func]. While this ability is not used by the library itself, it means that the comparators can be used with the standard library associative containers to compare heterogeneous objects without having to create temporaries. -*Changed in version 1.5.0:* every non-refined comparator is now a [transparent comparator][transparent-comparator]. - -### `projection_compare` - -```cpp -#include -``` - -The class template `projection_compare` can be used to embed a comparison and a projection in a single comparison object, allowing to provide projection support to algorithms that only support comparisons, such as standard library algorithms prior to C++20. Both the passed comparison and projection functions can be [*Callable*][callable]. - -It is accompanied by a `make_projection_compare` function template to avoid having to pass the template parameters by hand. - -**Example:** - -```cpp -// Sort a family from older to younger member -std::vector family = { /* ... */ }; -std::sort(family.begin(), family.end(), cppsort::make_projection_compare(std::greater<>{}, &Person::age)); -``` - -*New in version 1.9.0* +*Changed in version 1.5.0:* every non-refined comparator is now a [transparent comparator][transparent-func]. ### Total order comparators @@ -132,7 +112,7 @@ The two-parameter version of the customization point calls the three-parameter o [binary-predicate]: https://en.cppreference.com/w/cpp/concept/BinaryPredicate - [branchless-traits]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#branchless-traits + [branchless-traits]: Miscellaneous-utilities.md#branchless-traits [callable]: https://en.cppreference.com/w/cpp/named_req/Callable [case-sensitivity]: https://en.wikipedia.org/wiki/Case_sensitivity [cppcon2015-compare]: https://github.com/CppCon/CppCon2015/tree/master/Presentations/Comparison%20is%20not%20simple%2C%20but%20it%20can%20be%20simpler%20-%20Lawrence%20Crowl%20-%20CppCon%202015 @@ -140,12 +120,14 @@ The two-parameter version of the customization point calls the three-parameter o [natural-sort]: https://en.wikipedia.org/wiki/Natural_sort_order [P0100]: http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0100r1.html [partial-order]: https://en.wikipedia.org/wiki/Partially_ordered_set#Formal_definition - [refining]: https://github.com/Morwenn/cpp-sort/wiki/Refined-functions + [refining]: Refined-functions.md + [sorter-adapters]: Sorter-adapters.md + [sorters]: Sorters.md [std-is-arithmetic]: https://en.cppreference.com/w/cpp/types/is_arithmetic [std-is-digit]: https://en.cppreference.com/w/cpp/string/byte/isdigit [std-is-integral]: https://en.cppreference.com/w/cpp/types/is_integral [std-locale]: https://en.cppreference.com/w/cpp/locale/locale [to-lower]: https://en.cppreference.com/w/cpp/locale/ctype/tolower [total-order]: https://en.wikipedia.org/wiki/Total_order - [transparent-comparator]: https://stackoverflow.com/q/20317413/1364752 + [transparent-func]: Comparators-and-projections.md#Transparent-function-objects [weak-order]: https://en.wikipedia.org/wiki/Weak_ordering diff --git a/docs/Fixed-size-sorters.md b/docs/Fixed-size-sorters.md index b03b5757..43c5dfdc 100644 --- a/docs/Fixed-size-sorters.md +++ b/docs/Fixed-size-sorters.md @@ -1,6 +1,6 @@ Fixed-size sorters, sometimes called *fixed sorters* for simplicity are a special kind of sorters designed to sort a fixed number of values. Their `operator()` also takes either an iterable or a pair of iterators as well as an optional comparison and projection functions. Most of the time the end iterator is unused, but future versions of the library may start to use it to optionally perform bound-checking. -Fixed-size sorters are not actual sorters *per se* but class templates that take an `std::size_t` template parameter. Every valid specialization of a fixed-size sorter for a given size yields a "valid" sorter. Several fixed-size sorters have specializations for some sizes only and will trigger a compile-time error when one tries to instantiate a specialization which is not part of the fixed-size sorter's domain (the domain corresponds to the set of valid specializations). Information about fixed-size sorters can be obtained via [`fixed_sorter_traits`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#fixed_sorter_traits). One can also make sure that a given fixed-size sorter is automatically used to sort small fixed-size arrays thanks to [`small_array_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#small_array_adapter). +Fixed-size sorters are not actual sorters *per se* but class templates that take an `std::size_t` template parameter. Every valid specialization of a fixed-size sorter for a given size yields a "valid" sorter. Several fixed-size sorters have specializations for some sizes only and will trigger a compile-time error when one tries to instantiate a specialization which is not part of the fixed-size sorter's domain (the domain corresponds to the set of valid specializations). Information about fixed-size sorters can be obtained via [`fixed_sorter_traits`][fixed-sorter-traits]. One can also make sure that a given fixed-size sorter is automatically used to sort small fixed-size arrays thanks to [`small_array_adapter`][small-array-adapter]. It is possible to include all the fixed-size sorters at once with the following directive: @@ -34,10 +34,10 @@ Size | Comparison weight | Algorithm 9 | 6759936 | Merge-insertion sort 10 | 79937280 | Insertion sort* 11 | 1020833280 | Insertion sort* -12 | 15167554560 | [Double gnome sort*](https://github.com/Morwenn/cpp-sort/wiki/Original-research#double-insertion-sort) +12 | 15167554560 | [Double gnome sort*][double-insertion-sort] 13 | 223436206080 | Double gnome sort* -While `low_comparisons_sorter` is optimal from 0 through 8 with regard to the *comparison weight*, it is worth noting that [`merge_insertion_sorter`](https://github.com/Morwenn/cpp-sort/wiki/Sorters#merge_insertion_sorter) performs fewer comparisons on average than some other specializations. However the algorithm is rather complex and has a high runtime cost, which makes it unsuitable for such a sorter, which seeks to provide tiny and fast algorithm. +While `low_comparisons_sorter` is optimal from 0 through 8 with regard to the *comparison weight*, it is worth noting that [`merge_insertion_sort`][merge-insertion-sorter] performs fewer comparisons on average than some other specializations. However the algorithm is rather complex and has a high runtime cost, which makes it unsuitable for such a sorter, which seeks to provide tiny and fast algorithm. It is worth noting that the algorithm used to sort 9 elements in not strictly a merge-insertion sort: instead it uses an equivalent algorithm described in *A variant of the Ford–Johnson algorithm that is more space efficient* by Ayala-Rincón et al. That said I did not implement it correctly since it still performs more comparisons than `merge_insertion_sorter` (but it's still better than the previous solution, so that's ok for now). @@ -80,7 +80,7 @@ template struct low_moves_sorter; ``` -Note that this fixed-size sorter is *not* move-optimal: it tries to perform a few moves without wasting too much memory and with a somewhat reasonable number of comparisons for small collections. If you really need a sorting algorithm that performs the lowest possible number of move operations, you can use the library's [`indirect_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#indirect_adapter) instead, but it comes at the cost of a higher memory footprint. You probably want to use if only when the objects are *really* expensive to copy. +Note that this fixed-size sorter is *not* move-optimal: it tries to perform a few moves without wasting too much memory and with a somewhat reasonable number of comparisons for small collections. If you really need a sorting algorithm that performs the lowest possible number of move operations, you can use the library's [`indirect_adapter`][indirect-adapter] instead, but it comes at the cost of a higher memory footprint. You probably want to use if only when the objects are *really* expensive to copy. ### `merge_exchange_network_sorter` @@ -90,7 +90,7 @@ Note that this fixed-size sorter is *not* move-optimal: it tries to perform a fe This fixed-size sorter implements *merge-exchange sort* a variation of Batcher's [*odd-even mergesort*][odd-even-mergesort] described by Knuth in *[The Art of Computer Programming][taocp] vol.3 - Sorting and Searching*. Unlike the algorithm described in the Wikipedia article, this produces two interleaved [sorting networks][sorting-network] and merges them. -![Merge-exchange sorting network for 8 inputs](https://github.com/Morwenn/cpp-sort/wiki/images/merge-exchange-network-8.png) +![Merge-exchange sorting network for 8 inputs](images/merge-exchange-network-8.png) ```cpp template @@ -113,7 +113,7 @@ template This fixed-size sorter implements Batcher's [*odd-even mergesort*][odd-even-mergesort], which can be implemented as a family of sorting networks recursively sorting both halves of the input and merging them. -![Odd-even mergesort network for 8 inputs](https://github.com/Morwenn/cpp-sort/wiki/images/odd-even-merge-network-8.png) +![Odd-even mergesort network for 8 inputs](images/odd-even-merge-network-8.png) ```cpp template @@ -147,7 +147,7 @@ Size | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: **CEs** | 0 | 1 | 3 | 5 | 9 | 12 | 16 | 19 | 25 | 29 | 35 | 39 | 45 | 51 | 56 | 60 **Size** | **17** | **18** | **19** | **20** | **21** | **22** | **23** | **24** | **25** | **26** | **27** | **28** | **29** | **30** | **31** | **32** -**CEs** | 71 | 77 | 85 | 91 | 100 | 107 | 115 | 120 | 132 | 139 | 150 | 155 | 165 | 172 | 180 | 185 +**CEs** | 71 | 77 | 85 | 91 | 99 | 106 | 114 | 120 | 131 | 139 | 148 | 155 | 164 | 172 | 180 | 185 One of the main advantages of sorting networks is the fixed number of CEs required to sort a collection: this means that sorting networks are far more resistant to time and cache attacks since the number of performed comparisons does not depend on the contents of the collection. However, additional care (not provided by the library) is required to ensure that the algorithms always perform the same amount of memory loads and stores. For example, one could create a `constant_time_iterator` with a dedicated `iter_swap` tuned to perform a constant-time compare-exchange operation. @@ -167,11 +167,18 @@ static constexpr auto index_pairs() *Changed in version 1.8.0:* sorting 18 inputs requires 77 CEs instead of 78. -*Changed in version 1.10.0:* added `sorting_network_sorter::index_pairs` +*Changed in version 1.10.0:* added `sorting_network_sorter::index_pairs`. +*Changed in version 1.13.0:* sorting 21, 22, 23, 25, 27 and 29 inputs respectively require 99, 106, 114, 131, 149 and 164 CEs instead of 100, 107, 115, 132, 150 and 165. + + [double-insertion-sort]: Original-research.md#double-insertion-sort + [fixed-sorter-traits]: Sorter-traits.md#fixed_sorter_traits + [indirect-adapter]: Sorter-adapters.md#indirect_adapter + [merge-insertion-sorter]: Sorters.md#merge_insertion_sorter [odd-even-mergesort]: https://en.wikipedia.org/wiki/Batcher_odd%E2%80%93even_mergesort + [small-array-adapter]: Sorter-adapters.md#small_array_adapter [sorting-network]: https://en.wikipedia.org/wiki/Sorting_network [std-array]: https://en.cppreference.com/w/cpp/container/array [taocp]: https://en.wikipedia.org/wiki/The_Art_of_Computer_Programming - [utility-sorting-networks]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#Sorting-network-tools + [utility-sorting-networks]: Miscellaneous-utilities.md#Sorting-network-tools diff --git a/docs/Home.md b/docs/Home.md index 5c692680..58d1ec40 100644 --- a/docs/Home.md +++ b/docs/Home.md @@ -1,4 +1,6 @@ -Welcome to the **cpp-sort 1.12.1** documentation! +![cpp-sort logo](images/cpp-sort-logo.svg) + +Welcome to the **cpp-sort 1.13.0** documentation! You probably read the introduction in the README, so I won't repeat it here. This wiki contains documentation about the library: basic documentation about the many sorting tools and how to use them, documentation about the additional utilities provided by the library and even some detailed tutorials if you ever want to write your own sorters or sorter adapters. This main page explains a few general things that didn't quite fit in other parts of the documentation. @@ -77,12 +79,14 @@ A similar `CPPSORT_ENABLE_AUDITS` macro can be defined to enable audits: those a ## Miscellaneous -This wiki also includes a small section about the [[original research|Original research]] that happened during the conception of the library and the results of this research. While it is not needed to understand how the library works or how to use it, it may be of interest if you want to discover new things about sorting. +This wiki also includes a small section about the [original research][original-research] that happened during the conception of the library and the results of this research. While it is not needed to understand how the library works or how to use it, it may be of interest if you want to discover new things about sorting. If you ever feel that this wiki is incomplete, that it needs more examples or more detailed explanation about stuff, you are welcome to report it and/or contribute. -*Always keep in mind that even if the library does contain production-ready algorithms, many of them are also experimental algorithms taken straight from research papers and reimplemented from scratch. If you are only interested in usable algorithms, you should look at the ones analyzed in the [[benchmarks]].* +*Always keep in mind that even if the library does contain production-ready algorithms, many of them are also experimental algorithms taken straight from research papers and reimplemented from scratch. If you are only interested in usable algorithms, you should look at the ones analyzed in the [benchmarks][benchmarks].* Hope you have fun! + [benchmarks]: Benchmarks.md + [original-research]: Original-research.md [swappable]: https://en.cppreference.com/w/cpp/concepts/swappable diff --git a/docs/Library-nomenclature.md b/docs/Library-nomenclature.md index 1e498af9..04e98167 100644 --- a/docs/Library-nomenclature.md +++ b/docs/Library-nomenclature.md @@ -6,57 +6,78 @@ cppsort::utility::fixed_buffer<512> >; -* *Comparison function*: most of the sorting algorithms in the library are comparison sorts. It means that the algorithm uses a comparison function to know the order of the elements and sort them accordingly; such a comparison function shall take two values and have a return type convertible to `bool`. The available sorting algorithms transform comparison functions on the fly so that some pointers to member functions can also be used as comparison functions, as if called with [`std::invoke`](https://en.cppreference.com/w/cpp/utility/functional/invoke). The default comparison function used by the sorting algorithms is [`std::less<>`](https://en.cppreference.com/w/cpp/utility/functional/less_void). Many sorters can take a comparison function as an additional parameter. For example, using `std::greater<>` instead of the default comparison function would sort a collection in descending order. +* *Comparison function*: most of the sorting algorithms in the library are comparison sorts. It means that the algorithm uses a comparison function to know the order of the elements and sort them accordingly; such a comparison function shall take two values and have a return type convertible to `bool`. The available sorting algorithms transform comparison functions on the fly so that some pointers to member functions can also be used as comparison functions, as if called with [`std::invoke`][std-invoke]. The default comparison function used by the sorting algorithms is [`std::less<>`][std-less-void]. Many sorters can take a comparison function as an additional parameter. For example, using `std::greater<>` instead of the default comparison function would sort a collection in descending order. cppsort::heap_sort(collection, std::greater<>{}); - Some algorithms don't accept such an additional parameter. It may be because they implement a non-comparison sort instead, a sorting algorithm that uses other properties of the elements to perform the sort rather than a comparison function (for example a [radix sort](https://en.wikipedia.org/wiki/Radix_sort)). + Some algorithms don't accept such an additional parameter. It may be because they implement a non-comparison sort instead, a sorting algorithm that uses other properties of the elements to perform the sort rather than a comparison function (for example a [radix sort][radix-sort]). - The library provides a set of additional [comparators](https://github.com/Morwenn/cpp-sort/wiki/Comparators) generally corresponding to common ways to compare common types. + The library provides a set of additional [comparators][comparators] generally corresponding to common ways to compare common types. -* *Fixed-size sorter*: [[fixed-size sorters]] are a special breed of sorters designed to sort a fixed number of values. While they try their best to be full-fledge sorters, they are definitely not full-fledge sorters and probably don't blend as well as one would like into the library. Their main advantage is that they can be more performant than regular sorters in some specific scenarios. +* *Fixed-size sorter*: [fixed-size sorters][fixed-size-sorters] are a special breed of sorters designed to sort a fixed number of values. While they try their best to be full-fledge sorters, they are definitely not full-fledge sorters and probably don't blend as well as one would like into the library. Their main advantage is that they can be more performant than regular sorters in some specific scenarios. -* *Iterator category*: the C++ standard defines [several categories of iterators](https://en.cppreference.com/w/cpp/iterator) such as forward iterators, bidirectional iterators or random-access iterators. The standard library uses [iterator tags](https://en.cppreference.com/w/cpp/iterator/iterator_tags) to document the category of an iterator. These categories are important since algorithms are designed to work with some categories of iterators and not with other categories, and those in this library are not different: in-place sorting needs at least forward iterators. You can use the [`iterator_category`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#iterator_category) sorter trait to get the least constrained iterator category associated with a sorter. +* *Iterator category*: the C++ standard defines [several categories of iterators][iterator-categories] such as forward iterators, bidirectional iterators or random-access iterators. The standard library uses [iterator tags][iterator-tags] to document the category of an iterator. These categories are important since algorithms are designed to work with some categories of iterators and not with other categories, and those in this library are not different: in-place sorting needs at least forward iterators. You can use the [`iterator_category`][iterator-category] sorter trait to get the least constrained iterator category associated with a sorter. using category = cppsort::iterator_category; Note that the *sorters* (and virtually bery algorithm) in **cpp-sort** accept iterators that do not implement post-increment and post-decrement operations. The iterator categories accepted by the library are thus less restrictive than the ones mandated for the standard library. -* *Measure of presortedness*: also known as a *measure of disorder*, it corresponds to an algorithm telling how much a collection is already sorted. There isn't a single way to tell how much a collection is already sorted, one can for example count the number of inversions or the number of elements to remove to get a sorted subsequence. The main advantage of measures of presortedness are that some algorithms, known as *adaptative algorithms*, are known to be optimal for some of these measures, which means that they can advantage of the order that already exists in the collection in some way. **cpp-sort** provides a number of [[measures of presortedness]] in the namespace `cppsort::probe`: +* *Measure of presortedness*: also known as a *measure of disorder*, it corresponds to an algorithm telling how much a collection is already sorted. There isn't a single way to tell how much a collection is already sorted, one can for example count the number of inversions or the number of elements to remove to get a sorted subsequence. The main advantage of measures of presortedness are that some algorithms, known as *adaptative algorithms*, are known to be optimal for some of these measures, which means that they can advantage of the order that already exists in the collection in some way. **cpp-sort** provides a number of [measures of presortedness][measures-of-presortedness] in the namespace `cppsort::probe`: auto max_inversion = cppsort::probe::dis(collection); -* *Projection*: some sorters accept a projection as an additional parameter. A projection is a unary function that allows to "view" the values of a collection differently. For example it may allow to sort a collection of values on a specific field. The available sorting algorithms transform projections on the fly so that pointers to member data can also be used as projections. Projections were pioneered by the [Adobe Source Libraries](https://stlab.adobe.com/) and appear in the C++20 [Constrained algorithms](https://en.cppreference.com/w/cpp/algorithm/ranges). +* *Projection*: some sorters accept a projection as an additional parameter. A projection is a unary function that allows to "view" the values of a collection differently. For example it may allow to sort a collection of values on a specific field. The available sorting algorithms transform projections on the fly so that pointers to member data can also be used as projections. Projections were pioneered by the [Adobe Source Libraries][stlab] and appear in the C++20 [constrained algorithms][std-ranges]. struct wrapper { int value; }; std::vector collection = { /* ... */ }; cppsort::heap_sort(collection, &wrapper::value); - Every *comparison sorter* is also a *projection sorter*, but there are also projection-only sorters, such as [`spread_sorter`](https://github.com/Morwenn/cpp-sort/wiki/Sorters). + Every *comparison sorter* is also a *projection sorter*, but there are also projection-only sorters, such as [`spread_sorter`][spread-sorter]. -* *Proxy iterator*: sometimes `std::move` and `std::swap` are not enough to correctly move values around, and we need to know more about the iterators in order to perform the appropriate operation. It's typically the case with proxy iterators: iterators whose `reference` type is not actually a reference type (*e.g.* `std::vector::reference`). Traditional algorithms don't play well with these types, however there are [standard proposals](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0022r1.html) to solve the problem by introducing a function named `iter_move` and making it as well as `iter_swap` customization points. No proposal has been accepted yet, so standard libraries don't handle proxy iterators; however every sorter in **cpp-sort** can actually handle such iterators (except `std_sorter` and `std_stable_sorter`). The library exposes the functions [`utility::iter_move` and `utility::iter_swap`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#iter_move-and-iter_swap) in case you also need to make your own algorithms handle proxy iterators. +* *Proxy iterator*: sometimes `std::move` and `std::swap` are not enough to correctly move values around, and we need to know more about the iterators in order to perform the appropriate operation. It's typically the case with proxy iterators: iterators whose `reference` type is not actually a reference type (*e.g.* `std::vector::reference`). Traditional algorithms don't play well with these types, however there are [standard proposals][p0022] to solve the problem by introducing a function named `iter_move` and making it as well as `iter_swap` customization points. No proposal has been accepted yet, so standard libraries don't handle proxy iterators; however every sorter in **cpp-sort** can actually handle such iterators (except `std_sorter` and `std_stable_sorter`). The library exposes the functions [`utility::iter_move` and `utility::iter_swap`][utility-iter-move] in case you also need to make your own algorithms handle proxy iterators. -* *Sorter*: [[sorters]] are the protagonists in this library. They are function objects implementing specific sorting algorithms. Their `operator()` is overloaded so that it can handle iterables or pairs of iterators, and conditionally overloaded so that it can handle user-provided comparison and/or projection functions. +* *Sorter*: [sorters][sorters] are the protagonists in this library. They are function objects implementing specific sorting algorithms. Their `operator()` is overloaded so that it can handle iterables or pairs of iterators, and conditionally overloaded so that it can handle user-provided comparison and/or projection functions. cppsort::pdq_sorter{}(std::begin(collection), std::end(collection), std::greater<>{}, &wrapper::value); -* *Sorter adapter*: [[sorter adapters]] are class templates that take one or several sorters and produce a new sorter from the parameters. What a sorter adapter can do is not constrained, but they are generally expected to behave like sorters themselves. For example, **cpp-sort** contains adapters to count the number of comparisons performed by a sorting algorithms or to aggregate several sorters together. The best way to learn more about them is still to read the dedicated section in the documentation. +* *Sorter adapter*: [sorter adapters][sorter-adapters] are class templates that take one or several sorters and produce a new sorter from the parameters. What a sorter adapter can do is not constrained, but they are generally expected to behave like sorters themselves. For example, **cpp-sort** contains adapters to count the number of comparisons performed by a sorting algorithms or to aggregate several sorters together. The best way to learn more about them is still to read the dedicated section in the documentation. -* *Stability*: a sorting algorithm is *stable* if it preserves the relative order of equivalent elements. While it does not matter when the equivalence relationship is also an equality relationship, it may have its importance in other situations. It is possible to query whether a sorter is guaranteed to always use a stable sorting algorithm with the [`is_always_stable`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#is_always_stable) sorter trait. +* *Stability*: a sorting algorithm is *stable* if it preserves the relative order of equivalent elements. While it does not matter when the equivalence relationship is also an equality relationship, it may have its importance in other situations. It is possible to query whether a sorter is guaranteed to always use a stable sorting algorithm with the [`is_always_stable`][is-always-stable] sorter trait. using stability = cppsort::is_stable; - It is possible have have more fine-grained information about the stability of a sorter with the [`is_stable`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#is_stable) type trait, which tells whether a sorter is stable when called with a specific set of parameters. + It is possible have have more fine-grained information about the stability of a sorter with the [`is_stable`][is-stable] type trait, which tells whether a sorter is stable when called with a specific set of parameters. using sorter = cppsort::self_sort_adapter; using stability1 = cppsort::is_stable&)>; // stable using stability2 = cppsort::is_stable&)>; // unstable - The library also provides the adapter [`stable_adapter`](https://github.com/Morwenn/cpp-sort/wiki/sorting-function) to obtain a stable sorter corresponding to the passed sorter. When calling the adapted sorter yields an unstable sorting algorithm, the utility adapter `make_stable` is used to transform it into a stable sorting algorithm, providing the underlying algorithm handles proxy iterators. + The library also provides the adapter [`stable_adapter`][stable-adapter] to obtain a stable sorter corresponding to the passed sorter. When calling the adapted sorter yields an unstable sorting algorithm, the utility adapter `make_stable` is used to transform it into a stable sorting algorithm, providing the underlying algorithm handles proxy iterators. * *Stateful/Stateless sorter*: a sorter either carries a state or not; when it does so it is called a *stateful* sorter, otherwise it is called a *stateless* sorter. Most of the *sorters* in the library are stateless sorters. Stateless sorters are generally empty default-constructible types. If they indeed satisfy these guarantees, then several components of the library will provide space optimizations, and some wrapping components will also provide overloaded operators to be turned into several kinds of function pointers. Therefore, authors of *stateless sorters* are encouraged to also make them empty and default-constructible to benefit from the full powers of the library. -* *Type-specific sorter*: some non-comparison sorters such as the [`spread_sorter`](https://github.com/Morwenn/cpp-sort/wiki/Sorters#spread_sorter) implement specific sorting algorithms which only work with some specific types (for example integers or strings). \ No newline at end of file +* *Type-specific sorter*: some non-comparison sorters such as the [`spread_sorter`][spread-sorter] implement specific sorting algorithms which only work with some specific types (for example integers or strings). + + + [comparators]: Comparators.md + [fixed-size-sorters]: Fixed-size-sorters.md + [is-always-stable]: Sorter-traits.md#is_always_stable + [is-stable]: Sorter-traits.md#is_stable + [iterator-categories]: https://en.cppreference.com/w/cpp/iterator + [iterator-category]: Sorter-traits.md#iterator_category + [iterator-tags]: https://en.cppreference.com/w/cpp/iterator/iterator_tags + [measures-of-presortedness]: Measures-of-presortedness.md + [p0022]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0022r1.html + [radix-sort]: https://en.wikipedia.org/wiki/Radix_sort + [sorter-adapters]: Sorter-adapters.md + [sorters]: Sorters.md + [spread-sorter]: Sorters.md#spread_sorter + [stable-adapter]: Sorter-adapters.md#stable_adapter-make_stable-and-stable_t + [std-invoke]: https://en.cppreference.com/w/cpp/utility/functional/invoke + [std-less-void]: https://en.cppreference.com/w/cpp/utility/functional/less_void + [std-ranges]: https://en.cppreference.com/w/cpp/algorithm/ranges + [stlab]: https://stlab.adobe.com/ + [utility-iter-move]: Miscellaneous-utilities.md#iter_move-and-iter_swap diff --git a/docs/Measures-of-presortedness.md b/docs/Measures-of-presortedness.md index 9f275b59..e33cafd1 100644 --- a/docs/Measures-of-presortedness.md +++ b/docs/Measures-of-presortedness.md @@ -29,7 +29,7 @@ The graph below shows the partial ordering of several measures of presortedness: - *m₀* is a measure of presortedness that always returns 0. - *m₀₁* is a measure of presortedness that returns 0 when *X* is sorted and 1 otherwise. -![Partial ordering of measures of presortedness](https://github.com/Morwenn/cpp-sort/wiki/images/mops-partial-ordering.png) +![Partial ordering of measures of presortedness](images/mops-partial-ordering.png) This graph is a modified version of the one in *A framework for adaptive sorting* by O. Petersson and A. Moffat. The relations of *Mono* are empirically derived [original research][original-research] and incomplete (unknown relations with *Max*, *Osc* and *SUS*). @@ -323,6 +323,6 @@ T. Altman and Y. Igarashi mention the concept of *k*-sortedness and the measure [hamming-distance]: https://en.wikipedia.org/wiki/Hamming_distance [longest-increasing-subsequence]: https://en.wikipedia.org/wiki/Longest_increasing_subsequence [neatsort]: https://arxiv.org/pdf/1407.6183.pdf - [original-research]: https://github.com/Morwenn/cpp-sort/wiki/Original-research#partial-ordering-of-mono - [probe-dis]: https://github.com/Morwenn/cpp-sort/wiki/Measures-of-presortedness#dis + [original-research]: Original-research.md#partial-ordering-of-mono + [probe-dis]: Measures-of-presortedness.md#dis [sort-race]: https://arxiv.org/ftp/arxiv/papers/1609/1609.04471.pdf diff --git a/docs/Miscellaneous-utilities.md b/docs/Miscellaneous-utilities.md index d1b8781f..5a4b1fae 100644 --- a/docs/Miscellaneous-utilities.md +++ b/docs/Miscellaneous-utilities.md @@ -6,7 +6,7 @@ The following utilities are available in the directory `cpp-sort/utility` and li #include ``` -`adapter_storage` is a wrapper type meant to be used to store a *sorter* in the internals of [[*sorter adapter*|Sorter adapters]] which adapts a single [[*sorter*|Sorters]]. One of its goal is to remain an empty type when possible in order to play nice with the parts of the libraries that allow to cast empty sorters to function pointers. It provides three different operations: +`adapter_storage` is a wrapper type meant to be used to store a *sorter* in the internals of [*sorter adapter*][sorter-adapters] which adapts a single [*sorter*][sorters]. One of its goal is to remain an empty type when possible in order to play nice with the parts of the libraries that allow to cast empty sorters to function pointers. It provides three different operations: * *Construction:* it is constructed with a copy of the wrapped sorter which it stores in its internals. If `Sorter` is empty and default-constructible, then `adapter_storage` is also empty and default-constructible. * *Sorter access:* a `get()` member function returns a reference to the wrapped sorter with `const` and reference qualifications matching those of the `adapter_storage` instance. If `Sorter` is empty and default-constructible, then `get()` returns a default-constructed instance of `Sorter` instead. * *Invocation:* it has a `const`-qualified `operator()` which forwards its parameter to the corresponding operator in the wrapped `Sorter` (or in a default-constructed instance of `Sorter`) and returns its result. @@ -28,7 +28,7 @@ The usual way to use it when implementing a *sorter adapter* is to make said ada When given a [*Callable*][callable] that satisfies both the comparison and projection concepts, every sorter in **cpp-sort** considers that it is a comparison function (unless it is a projection-only sorter, in which case the function is considered to be a projection). To make such ambiguous callables usable as projections, the utility function `as_projection` is provided, which wraps a function and exposes only its unary overload. A similar `as_comparison` function is also provided in case one needs to explicitly expose the binary overload of a function. -The result of `as_projection` also inherits from `projection_base`, which makes it usable to [[compose projections|Chainable projections]] with `operator|`. +The result of `as_projection` also inherits from `projection_base`, which makes it usable to [compose projections][chainable-projections] with `operator|`. ```cpp template @@ -40,10 +40,14 @@ constexpr auto as_comparison(Function&& func) -> /* implementation-defined */; ``` +When the object passed to `as_comparison` or `as_projection` is a [*transparent function object*][transparent-func], then the object returned by those functions will also be *transparent*. + *Changed in version 1.7.0:* `as_comparison` and `as_projection` accept any *Callable*. *Changed in version 1.7.0:* the object returned by `as_projection` inherits from `projection_base`. +*Changed in version 1.13.0:* the objects returned by `as_comparison` and `as_projection` are now conditionally [*transparent*][transparent-func]. + ### `as_function` ```cpp @@ -58,7 +62,7 @@ To be more specific, `as_function` returns the passed object as is if it is alre struct wrapper { int foo; }; // func is a function taking an instance of wrapper // and returning the value of its member foo -auto&& func = utility::as_function(&wrapper::foo); +auto&& func = cppsort::utility::as_function(&wrapper::foo); ``` ### Branchless traits @@ -132,7 +136,7 @@ This buffer provider allocates on the heap a number of elements depending on a g ***WARNING:** `utility::identity` is removed in version 2.0.0, use `std::identity` instead.* -This header provides the class `projection_base` and the mechanism used to compose projections with `operator|`. See [[Chainable projections]] for more information. +This header provides the class `projection_base` and the mechanism used to compose projections with `operator|`. See [Chainable projections][chainable-projections] for more information. Also available in this header, the struct `identity` is a function object that can type any value of any movable type and return it as is. It is used as a default for every projection parameter in the library so that sorters view the values as they are by default, without a modification. @@ -155,6 +159,8 @@ This header also provides additional function objects implementing basic unary o * `log`: returns the base 10 logarithm of the passed value. * `sqrt`: returns the square root of the passed value. +All of those function objects can double as projections are are [*transparent function objects*][transparent-func]. + Since C++17, the following utility is also available when some level of micro-optimization is needed: ```cpp @@ -184,6 +190,8 @@ This utility is modeled after [`std::integral_constant`][std-integral-constant], *Changed in version 1.9.0:* `std::identity` is now also supported wherever the library has special behavior for `utility::identity`. +*Changed in version 1.13.0:* `half`, `log` and `sqrt` are now [*transparent function objects*][transparent-func]. + ### `iter_move` and `iter_swap` ```cpp @@ -255,7 +263,7 @@ using make_index_range = make_integer_range; #include ``` -Some of the library's *fixed-size sorters* implement [sorting networks][sorting-network]. It is a subdomain of sorting that has seen extensive research and there is no way all of the interesting bits could be provided as mere sorters; therefore the following tools are provided specifically to experiment with sorting networks, and with comparator networks more generally. +Some of the library's [*fixed-size sorters*][fixed-size-sorters] implement [sorting networks][sorting-network]. It is a subdomain of sorting that has seen extensive research and there is no way all of the interesting bits could be provided as mere sorters; therefore the following tools are provided specifically to experiment with sorting networks, and with comparator networks more generally. All comparator networks execute a fixed sequence of compare-exchanges, operations that compare two elements and exchange them if they are out-of-order. The following `index_pair` class template represents a pair of indices meant to contain the indices used to perform a compare-exchange operation: @@ -321,13 +329,17 @@ namespace You can read more about this instantiation pattern in [this article][eric-niebler-static-const] by Eric Niebler. + [chainable-projections]: Chainable-projections.md [callable]: https://en.cppreference.com/w/cpp/named_req/Callable [ebo]: https://en.cppreference.com/w/cpp/language/ebo [eric-niebler-static-const]: https://ericniebler.com/2014/10/21/customization-point-design-in-c11-and-beyond/ + [fixed-size-sorters]: Fixed-size-sorters.md [inline-variables]: https://en.cppreference.com/w/cpp/language/inline [p0022]: https://wg21.link/P0022 - [pdq-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Sorters#pdq_sorter + [pdq-sorter]: Sorters.md#pdq_sorter [range-v3]: https://github.com/ericniebler/range-v3 + [sorter-adapters]: Sorter-adapters.md + [sorters]: Sorters.md [sorting-network]: https://en.wikipedia.org/wiki/Sorting_network [std-array]: https://en.cppreference.com/w/cpp/container/array [std-bad-alloc]: https://en.cppreference.com/w/cpp/memory/new/bad_alloc @@ -345,3 +357,4 @@ You can read more about this instantiation pattern in [this article][eric-nieble [std-ranges-greater]: https://en.cppreference.com/w/cpp/utility/functional/ranges/greater [std-ranges-less]: https://en.cppreference.com/w/cpp/utility/functional/ranges/less [std-size]: https://en.cppreference.com/w/cpp/iterator/size + [transparent-func]: Comparators-and-projections.md#Transparent-function-objects diff --git a/docs/Original-research.md b/docs/Original-research.md index ba45c941..ada69128 100644 --- a/docs/Original-research.md +++ b/docs/Original-research.md @@ -58,7 +58,7 @@ The following 24 inputs network uses the technique described in the previous sec The resulting network has 123 compare-exchanges and a depth of 18. The 12-12 merging network has 45 compare-exchanges, which is equivalent to a 12-12 odd-even merge. -![Sorting network 24](https://github.com/Morwenn/cpp-sort/wiki/images/sorting-network-24.png) +![Sorting network 24](images/sorting-network-24.png) [[0, 1],[2, 3],[4, 5],[6, 7],[8, 9],[10, 11],[12, 13],[14, 15],[16, 17],[18, 19],[20, 21],[22, 23]] [[1, 3],[5, 7],[9, 11],[0, 2],[4, 6],[8, 10],[13, 15],[17, 19],[21, 23],[12, 14],[16, 18],[20, 22]] @@ -81,7 +81,7 @@ The resulting network has 123 compare-exchanges and a depth of 18. The 12-12 mer Removing the first or the last line of the network yields the following 23-sorter with 118 compare-exchanges and a depth of 18. -![Sorting network 23](https://github.com/Morwenn/cpp-sort/wiki/images/sorting-network-23.png) +![Sorting network 23](images/sorting-network-23.png) [[0, 1],[2, 3],[4, 5],[6, 7],[8, 9],[10, 11],[12, 13],[14, 15],[16, 17],[18, 19],[20, 21]] [[1, 3],[5, 7],[9, 11],[0, 2],[4, 6],[8, 10],[13, 15],[17, 19],[12, 14],[16, 18],[20, 22]] @@ -116,7 +116,7 @@ That said, even though I have been unable to find a 29-input sorting network wit The paper does not mention a better result than 166 CEs for the 29-input sorting networks, but that's only because our solution relies on a 13-input sorting networks that uses 45 CEs, while the best known such network in 1971 used 46 CEs. I couldn't find any resource using the technique to improve the 29-input sorting network since then, even though some of them mention a 156-CE 28-input sorting network that has apparently only been described in the aforementioned paper. -![Sorting network 29](https://github.com/Morwenn/cpp-sort/wiki/images/sorting-network-29.png) +![Sorting network 29](images/sorting-network-29.png) [[0, 1],[2, 3],[4, 5],[6, 7],[8, 9],[10, 11],[12, 13],[14, 15],[17, 23],[25, 27]] [[0, 2],[4, 6],[8, 10],[12, 14],[19, 20],[21, 24]] @@ -229,7 +229,7 @@ The following relations have yet to be analyzed: [cycle-sort]: https://en.wikipedia.org/wiki/Cycle_sort [divide-sort-merge-strategy]: http://www.dtic.mil/dtic/tr/fulltext/u2/737270.pdf [exact-sort]: https://www.geocities.ws/p356spt/ - [indirect-adapter]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#indirect_adapter + [indirect-adapter]: Sorter-adapters.md#indirect_adapter [morwenn-gist]: https://gist.github.com/Morwenn [mountain_sort]: https://github.com/Morwenn/mountain-sort [poplar-heap]: https://github.com/Morwenn/poplar-heap diff --git a/docs/Refined-functions.md b/docs/Refined-functions.md index 7e3d7b49..2fe6cb92 100644 --- a/docs/Refined-functions.md +++ b/docs/Refined-functions.md @@ -39,5 +39,5 @@ using refined_t = std::remove_cvref_t< ``` - [case-insensitive-less]: https://github.com/Morwenn/cpp-sort/wiki/Comparators#case-insensitive-comparator + [case-insensitive-less]: Comparators.md#case-insensitive-comparator [case-insensitive-strcmp]: http://lafstern.org/matt/col2_new.pdf \ No newline at end of file diff --git a/docs/Sorter-adapters.md b/docs/Sorter-adapters.md index c1e0026d..8717b61a 100644 --- a/docs/Sorter-adapters.md +++ b/docs/Sorter-adapters.md @@ -1,4 +1,4 @@ -Sorter adapters are the main reason for using sorter function objects instead of regular functions. A *sorter adapter* is a class template that takes another `Sorter` template parameter and alters its behavior. The resulting class can be used as a regular sorter, and be adapted in turn. Note that some of the adapters are actually *[[fixed-size sorter|Fixed-size sorters]] adapters* instead of regular *sorter adapters*. It is possible to include all of the available adapters at once with the following directive: +Sorter adapters are the main reason for using sorter function objects instead of regular functions. A *sorter adapter* is a class template that takes another `Sorter` template parameter and alters its behavior. The resulting class can be used as a regular sorter, and be adapted in turn. Note that some of the adapters are actually *[fixed-size sorter][fixed-size-sorters] adapters* instead of regular *sorter adapters*. It is possible to include all of the available adapters at once with the following directive: ```cpp #include @@ -191,7 +191,7 @@ Since it is impossible to guarantee the stability of the `sort` method of a give #include ``` -This adapter is not a regular sorter adapter, but a *fixed-size sorter adapter*. It wraps a [fixed-size sorter][fixed-size-sorter] and calls it whenever it is passed a fixed-size C array or an `std::array` with an appropriate size. +This adapter is not a regular sorter adapter, but a *fixed-size sorter adapter*. It wraps a [fixed-size sorter][fixed-size-sorters] and calls it whenever it is passed a fixed-size C array or an `std::array` with an appropriate size. ```cpp template< @@ -258,7 +258,7 @@ Specializations of `stable_adapter` must provide an `is_always_stable` member ty The main `stable_adapter` template uses [`is_stable`][is-stable] when called to check whether the *adapted sorter* produces a stable sorter when called with a given set of parameters. If the call is already stable then th *adapted sorter* is used directly otherwise `make_stable` is used to artificially turn it into a stable sort. -![Visual explanation of what stable_adapter does](https://github.com/Morwenn/cpp-sort/wiki/images/stable_adapter.png) +![Visual explanation of what stable_adapter does](images/stable_adapter.png) ```cpp template @@ -273,7 +273,7 @@ using stable_t = /* implementation-defined */; This little dance sometimes allows to reduce the nesting of function calls and to get better error messages in some places (it notably unwraps nested top-level `stable_adapter`). As such `stable_t` is generally a better alternative to `stable_adapter` from a consumer point of view. -![Visual explanation of what stable_t aliases](https://github.com/Morwenn/cpp-sort/wiki/images/stable_t.png) +![Visual explanation of what stable_t aliases](images/stable_t.png) *New in version 1.9.0:* `stable_t` and `stable_adapter::type` @@ -299,23 +299,23 @@ When wrapped into [`stable_adapter`][stable-adapter], it has a slightly differen [ctad]: https://en.cppreference.com/w/cpp/language/class_template_argument_deduction [cycle-sort]: https://en.wikipedia.org/wiki/Cycle_sort - [default-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Sorters#default_sorter - [fixed-size-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Fixed-size-sorters - [fixed-sorter-traits]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#fixed_sorter_traits - [hybrid-adapter]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#hybrid_adapter - [is-always-stable]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#is_always_stable - [is-stable]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#is_stable + [default-sorter]: Sorters.md#default_sorter + [fixed-size-sorters]: Fixed-size-sorters.md + [fixed-sorter-traits]: Sorter-traits.md#fixed_sorter_traits + [hybrid-adapter]: Sorter-adapters.md#hybrid_adapter + [is-always-stable]: Sorter-traits.md#is_always_stable + [is-stable]: Sorter-traits.md#is_stable [issue-104]: https://github.com/Morwenn/cpp-sort/issues/104 - [low-moves-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Fixed-size-sorters#low_moves_sorter + [low-moves-sorter]: Fixed-size-sorters.md#low_moves_sorter [mountain-sort]: https://github.com/Morwenn/mountain-sort [schwartzian-transform]: https://en.wikipedia.org/wiki/Schwartzian_transform - [stable-adapter]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#stable_adapter-make_stable-and-stable_t - [self-sort-adapter]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#self_sort_adapter + [stable-adapter]: Sorter-adapters.md#stable_adapter-make_stable-and-stable_t + [self-sort-adapter]: Sorter-adapters.md#self_sort_adapter [std-index-sequence]: https://en.cppreference.com/w/cpp/utility/integer_sequence [std-sort]: https://en.cppreference.com/w/cpp/algorithm/sort - [std-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Sorters#std_sorter + [std-sorter]: Sorters.md#std_sorter [std-stable-sort]: https://en.cppreference.com/w/cpp/algorithm/stable_sort [std-true-type]: https://en.cppreference.com/w/cpp/types/integral_constant - [verge-adapter]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#verge_adapter - [verge-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Sorters#verge_sorter + [verge-adapter]: Sorter-adapters.md#verge_adapter + [verge-sorter]: Sorters.md#verge_sorter [vergesort-fallbacks]: https://github.com/Morwenn/vergesort/blob/master/fallbacks.md diff --git a/docs/Sorter-facade.md b/docs/Sorter-facade.md index eb715766..2b871b05 100644 --- a/docs/Sorter-facade.md +++ b/docs/Sorter-facade.md @@ -47,7 +47,7 @@ The return type `Ret` can either match that of the sorter, or be `void`, in whic Note that the function pointer conversion syntax above is made up, but it allows to clearly highlight what it does while hiding the `typedef`s needed for the syntax to be valid. In these signatures, `Ret` is the [`std::result_of_t`][std-result-of] of the sorter called with the parameters. The actual implementation is more verbose and redundant, but it allows to transform a sorter into a function pointer corresponding to any valid overload of `operator()`. -***WARNING:** conversion to function pointers does not work with MSVC (issue #185).* +***WARNING:** conversion to function pointers does not work with MSVC ([issue #185][issue-185]).* *Changed in version 1.5.0:* these conversion operators exists if and only if the wrapped *sorter implementation* is empty and default-constructible. @@ -194,6 +194,7 @@ While it does not appear in this documentation, `sorter_facade` actually relies *Changed in version 1.10.0:* those overloads are now `constexpr`. + [issue-185]: https://github.com/Morwenn/cpp-sort/issues/185 [selection-sort]: https://en.wikipedia.org/wiki/Selection_sort [std-begin]: https://en.cppreference.com/w/cpp/iterator/begin [std-end]: https://en.cppreference.com/w/cpp/iterator/end @@ -201,4 +202,4 @@ While it does not appear in this documentation, `sorter_facade` actually relies [std-less-void]: https://en.cppreference.com/w/cpp/utility/functional/less_void [std-ranges-less]: https://en.cppreference.com/w/cpp/utility/functional/ranges/less [std-result-of]: https://en.cppreference.com/w/cpp/types/result_of - [utility-identity]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects + [utility-identity]: Miscellaneous-utilities.md#miscellaneous-function-objects diff --git a/docs/Sorter-traits.md b/docs/Sorter-traits.md index b18c6aa7..b2d124e6 100644 --- a/docs/Sorter-traits.md +++ b/docs/Sorter-traits.md @@ -106,7 +106,7 @@ constexpr bool is_comparison_projection_sorter_iterator_v ### `sorter_traits` -The class template `sorter_traits` contains information about *[[sorters|Sorters]]* and *[[sorter adapters|Sorter adapters]]* such as the kind of iterators accepted by a sorter and whether it is guaranteed to always sort stably. +The class template `sorter_traits` contains information about *[sorters][sorters]* and *[sorter adapters][sorter-adapters]* such as the kind of iterators accepted by a sorter and whether it is guaranteed to always sort stably. ```cpp template @@ -130,7 +130,7 @@ using iterator_category = typename sorter_traits::iterator_category; Some tools need to know which category of iterators a sorting algorithm can work with. A sorter that intends to work with those tools must document its iterator category by aliasing one of the standard library [iterator tags][iterator-tags]. -The iterator category of the *resulting sorter* of a [[*sorter adapter*|Sorter adapters]] doesn't always match that of the *adapted sorter*: for example [`heap_sorter`][heap-sorter] only accepts random-access iterators, but it accepts forward iterators when wrapped into [`out_of_place_adapter`][out-of-place-adapter]. +The iterator category of the *resulting sorter* of a [*sorter adapter*][sorter-adapters] doesn't always match that of the *adapted sorter*: for example [`heap_sorter`][heap-sorter] only accepts random-access iterators, but it accepts forward iterators when wrapped into [`out_of_place_adapter`][out-of-place-adapter]. ### `is_always_stable` @@ -143,7 +143,7 @@ constexpr bool is_always_stable_v = is_always_stable::value; ``` -This type trait is always either [`std::true_type` or `std::false_type`][integral-constant] and tells whether a sorter is always [stable][stability] or not. This information may be useful in some contexts, and is most notably by [`stable_t`][stable-adapter] to avoid unnecessarily nesting templates when possible. +This type trait is always either [`std::true_type` or `std::false_type`][std-integral-constant] and tells whether a sorter is always [stable][stability] or not. This information may be useful in some contexts, and is most notably by [`stable_t`][stable-adapter] to avoid unnecessarily nesting templates when possible. When a sorter adapter is used, the *resulting sorter* is considered always stable if and only if its stability can be guaranteed, and considered unstable otherwise, even when the *adapted sorter* may be stable (for example, [`self_sort_adapter`][self-sort-adapter]`::is_always_stable` is aliased to `std::false_type` since it is impossible to guarantee the stability of every collection's `sort` method). @@ -169,7 +169,7 @@ using sorter = self_sort_adapter; static_assert(is_stable&)>, ""); ``` -[`self_sort_adapter`][self-sort-adapter] is a [[*sorter adapter*|Sorter adapters]] that checks whether a container can sort itself and, if so, uses the container's sorting method instead of the *adapted sorter*. As a matter of fact, [`std::list::sort`][std-list-sort] implements a stable sorting algorithm and **cpp-sort** specializes `is_stable` to take that information into account, so `is_stable_v&)>` is `true` despite `is_always_stable_v` being `false`. However, `is_stable_v&)>` and `is_stable_v::iterator, std::list::iterator)>` remain `false`. +[`self_sort_adapter`][self-sort-adapter] is a [*sorter adapter*][sorter-adapters] that checks whether a container can sort itself and, if so, uses the container's sorting method instead of the *adapted sorter*. As a matter of fact, [`std::list::sort`][std-list-sort] implements a stable sorting algorithm and **cpp-sort** specializes `is_stable` to take that information into account, so `is_stable_v&)>` is `true` despite `is_always_stable_v` being `false`. However, `is_stable_v&)>` and `is_stable_v::iterator, std::list::iterator)>` remain `false`. The default version of `is_stable` uses `sorter_traits::is_always_stable` to infer the stability of a sorter, but most sorter adapters have dedicated specializations. These specializations notably allow [`stable_adapter`][stable-adapter] to sometimes avoid using `make_stable` and to instead use the *adapted sorter* directly when it knows that calling it with specific parameters already yields a stable sort. @@ -214,14 +214,16 @@ This class template can be specialized for any fixed-size sorter and exposes the * `is_always_stable`: an alias for [`std::true_type`][std-integral-constant] if every specialization of the fixed-size sorter is guaranteed to always be stable, and `std::false_type` otherwise. - [heap-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Sorters#heap_sorter - [hybrid-adapter]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#hybrid_adapter - [is-always-stable]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#is_always_stable + [heap-sorter]: Sorters.md#heap_sorter + [hybrid-adapter]: Sorter-adapters.md#hybrid_adapter + [is-always-stable]: Sorter-traits.md#is_always_stable [iterator-tags]: https://en.cppreference.com/w/cpp/iterator/iterator_tags - [out-of-place-adapter]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#out_of_place_adapter - [self-sort-adapter]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#self_sort_adapter + [out-of-place-adapter]: Sorter-adapters.md#out_of_place_adapter + [self-sort-adapter]: Sorter-adapters.md#self_sort_adapter + [sorter-adapters]: Sorter-adapters.md + [sorters]: Sorters.md [stability]: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability - [stable-adapter]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#stable_adapter-make_stable-and-stable_t + [stable-adapter]: Sorter-adapters.md#stable_adapter-make_stable-and-stable_t [std-integer-sequence]: https://en.cppreference.com/w/cpp/utility/integer_sequence [std-integral-constant]: https://en.cppreference.com/w/cpp/types/integral_constant [std-list-sort]: https://en.cppreference.com/w/cpp/container/list/sort diff --git a/docs/Sorters.md b/docs/Sorters.md index e78f90de..e53ca4f8 100644 --- a/docs/Sorters.md +++ b/docs/Sorters.md @@ -1,19 +1,35 @@ **cpp-sort** uses function objects called *sorters* instead of regular function templates in order to implement sorting algorithms. The library provides two categories of sorters: generic sorters that will sort a collection with any given comparison function, and type-specific sorters which will be optimized to sort collections of a given type, and generally don't allow to use custom comparison functions due to the way they work. Every comparison sorter as well as some type-specific sorters may also take an additional projection parameter, allowing the algorithm to "view" the data to sort through an on-the-fly transformation. -While these function objects offer little more than regular sorting functions by themselves, they can be used together with *[[sorter adapters|Sorter adapters]]* to craft more elaborate sorters effortlessly. Every sorter is available in its own file. However, all the available sorters can be included at once with the following line: +While these function objects offer little more than regular sorting functions by themselves, they can be used together with *[sorter adapters][sorter-adapters]* to craft more elaborate sorters effortlessly. Every sorter is available in its own file. However, all the available sorters can be included at once with the following line: ```cpp #include ``` -Note that for every `foobar_sorter` described in this page, there is a corresponding `foobar_sort` global instance that allows not to care about the sorter abstraction as long as it is not needed (the instances are usable as regular function templates). The only sorter without a corresponding global instance is [`default_sorter`](https://github.com/Morwenn/cpp-sort/wiki/Sorters#default_sorter) since it mainly exists as a fallback sorter for the functions [`cppsort::sort` and `cppsort::stable_sort`](https://github.com/Morwenn/cpp-sort/wiki/Sorting-functions) when they are called without an explicit sorter. +Note that for every `foobar_sorter` described in this page, there is a corresponding `foobar_sort` global instance that allows not to care about the sorter abstraction as long as it is not needed (the instances are usable as regular function templates). The only sorter without a corresponding global instance is [`default_sorter`][default-sorter] since it mainly exists as a fallback sorter for the functions [`cppsort::sort` and `cppsort::stable_sort`][sorting-functions] when they are called without an explicit sorter. -If you want to read more about sorters and/or write your own one, then you should have a look at [[the dedicated page|Writing a sorter]] or at [[a specific example|Writing a bubble_sorter]]. +If you want to read more about sorters and/or write your own one, then you should have a look at [the dedicated page][writing-a-sorter] or at [a specific example][writing-a-bubble-sorter]. ## Comparison sorters The following sorters are available and will work with any type for which `std::less` works and should accept any well-formed comparison function: +### `adaptive_shivers_sorter` + +```cpp +#include +``` + +Implements an [adative ShiversSort][adaptive-shivers-sort], a *k*-aware natural mergesort with a better worst case than [timsort][timsort] described by Vincent Jugé in *Adaptive Shivers Sort: An Alternative Sorting Algorithm*. + +| Best | Average | Worst | Memory | Stable | Iterators | +| ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | +| n | n log n | n log n | n | Yes | Random-access | + +While the sorting algorithm is stable and the complexity guarantees are good enough, this sorter is rather slow compared to the some other ones when the data distribution is random. That said, it would probably be a good choice when comparing data is expensive, but moving it is inexpensive (this is the use case for which it was designed). + +*New in version 1.13.0* + ### `block_sorter<>` ```cpp @@ -44,9 +60,9 @@ Implements a [Cartesian tree sort][cartesian-tree-sort], a rather slow but highl #include ``` -***WARNING:** `default_sorter` is deprecated in version 1.8.0 and removed in version 2.0.0, see [issue #168](https://github.com/Morwenn/cpp-sort/issues/167) for the rationale.* +***WARNING:** `default_sorter` is deprecated in version 1.8.0 and removed in version 2.0.0, see [issue #168][issue-168] for the rationale.* -Sorter striving to use a sorting algorithm as optimized as possible. It is the fallback sorter used by [`cppsort::sort`](https://github.com/Morwenn/cpp-sort/wiki/sorting-function) when no sorter is given. The current implementation defines it as follows: +Sorter striving to use a sorting algorithm as optimized as possible. It is the fallback sorter used by [`cppsort::sort`][cppsort-sort] when no sorter is given. The current implementation defines it as follows: ```cpp struct default_sorter: @@ -63,7 +79,7 @@ struct default_sorter: {}; ``` -The adapter [`stable_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#stable_adapter) has an explicit specialization for `default_sorter` defined as follows: +The adapter [`stable_adapter`][stable-adapter] has an explicit specialization for `default_sorter` defined as follows: ```cpp template<> @@ -82,13 +98,13 @@ struct stable_adapter: #include ``` -Implements a [drop-merge sort](https://github.com/emilk/drop-merge-sort). +Implements a [drop-merge sort][drop-merge-sort]. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | | n | n log n | n log n | n | No | Bidirectional | -Drop-merge sort is a [*Rem*-adaptive](https://github.com/Morwenn/cpp-sort/wiki/Measures-of-presortedness#rem) sorting algorithm. While it is not as good as other sorting algorithms to sort shuffled data, it is excellent when more than 80% of the data is already ordered according to *Rem*. +Drop-merge sort is a [*Rem*-adaptive][probe-rem] sorting algorithm. While it is not as good as other sorting algorithms to sort shuffled data, it is excellent when more than 80% of the data is already ordered according to *Rem*. ### `grail_sorter<>` @@ -96,7 +112,7 @@ Drop-merge sort is a [*Rem*-adaptive](https://github.com/Morwenn/cpp-sort/wiki/M #include ``` -Implements a [Grail sort](https://github.com/Mrrl/GrailSort). +Implements a [Grail sort][grailsort]. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | @@ -121,7 +137,7 @@ Whether this sorter works with types that are not default-constructible depends #include ``` -Implements a [heapsort](https://en.wikipedia.org/wiki/Heapsort). +Implements a [heapsort][heapsort]. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | @@ -133,13 +149,13 @@ Implements a [heapsort](https://en.wikipedia.org/wiki/Heapsort). #include ``` -Implements an [insertion sort](https://en.wikipedia.org/wiki/Insertion_sort). +Implements an [insertion sort][insertion-sort]. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | | n | n² | n² | 1 | Yes | Bidirectional | -This sorter also has the following dedicated algorithms when used together with [`container_aware_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#container_aware_adapter): +This sorter also has the following dedicated algorithms when used together with [`container_aware_adapter`][container-aware-adapter]: | Container | Best | Average | Worst | Memory | Stable | | ------------------- | ----------- | ----------- | ----------- | ----------- | ----------- | @@ -185,7 +201,7 @@ Implements the Ford-Johnson merge-insertion sort. This algorithm isn't meant to | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | | ? | n log n | n log n | n | No | Random-access | -*Until version 1.7.0:* the algorithm used GNU's [`bitmap_allocator`](https://gcc.gnu.org/onlinedocs/libstdc++/manual/bitmap_allocator.html) with `std::list` when possible instead of the default allocator, leading to speed improvements up to 25%. +*Until version 1.7.0:* the algorithm used GNU's [`bitmap_allocator`][bitmap-allocator] with `std::list` when possible instead of the default allocator, leading to speed improvements up to 25%. *Changed in version 1.7.0:* the `std::list` used by the algorithm has been replaced with a custom list implementation whose speed does not depend on the availability of some allocator, and which should be faster than the previous implementation in any case (still not anywhere near fast). @@ -195,7 +211,7 @@ Implements the Ford-Johnson merge-insertion sort. This algorithm isn't meant to #include ``` -Implements a [merge sort](https://en.wikipedia.org/wiki/Merge_sort). +Implements a [merge sort][merge-sort]. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | @@ -204,7 +220,7 @@ Implements a [merge sort](https://en.wikipedia.org/wiki/Merge_sort). When additional memory is available, `merge_sorter` runs in O(n log n), however if there is no additional memory available, it uses a O(n log² n) algorithm instead. The merging algorithm is memory adaptive, so even if it can only allocate a bit of memory instead of all the memory it needs, it will still take advantage of this additional memory. This memory scheme means that this sorter can't throw `std::bad_alloc`. -This sorter also has the following dedicated algorithms when used together with [`container_aware_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#container_aware_adapter): +This sorter also has the following dedicated algorithms when used together with [`container_aware_adapter`][container-aware-adapter]: | Container | Best | Average | Worst | Memory | Stable | | ------------------- | ----------- | ----------- | ----------- | ----------- | ----------- | @@ -219,13 +235,13 @@ None of the container-aware algorithms invalidates iterators. #include ``` -Implements a [pattern-defeating quicksort](https://github.com/orlp/pdqsort). +Implements a [pattern-defeating quicksort][pdqsort]. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | | n | n log n | n log n | log n | No | Random-access | -`pdq_sorter` uses a more performant partitioning algorithm under the hood if the comparison and projection functions generate branchless code. You can provide this information to the algorithm by specializing the library's [branchless traits](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#branchless-traits) for the given comparison/type or projection/type pairs if they aren't arleady handled natively by the library. +`pdq_sorter` uses a more performant partitioning algorithm under the hood if the comparison and projection functions generate branchless code. You can provide this information to the algorithm by specializing the library's [branchless traits][branchless-traits] for the given comparison/type or projection/type pairs if they aren't arleady handled natively by the library. This sorter can't throw `std::bad_alloc`. @@ -275,14 +291,14 @@ This sorter can't throw `std::bad_alloc`. #include ``` -Implements a [quicksort](https://en.wikipedia.org/wiki/Quicksort). +Implements a [quicksort][quicksort]. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | | n | n log n | n log n | log² n | No | Bidirectional | | n | n log² n | n log² n | log² n | No | Forward | -Despite the name, this sorter actually implements some flavour of introsort: if quicksort performs more than 2*log(n) steps, it falls back to a [median-of-medians](https://en.wikipedia.org/wiki/Median_of_medians) pivot selection instead of the usual median-of-9 one. The median-of-medians selection being mutually recursive with an introselect algorithm explains the use of log²n stack memory. +Despite the name, this sorter actually implements some flavour of introsort: if quicksort performs more than 2*log(n) steps, it falls back to a [median-of-medians][median-of-medians] pivot selection instead of the usual median-of-9 one. The median-of-medians selection being mutually recursive with an introselect algorithm explains the use of log²n stack memory. This sorter can't throw `std::bad_alloc`. @@ -294,13 +310,13 @@ This sorter can't throw `std::bad_alloc`. #include ``` -Implements a [selection sort](https://en.wikipedia.org/wiki/Selection_sort). +Implements a [selection sort][selection-sort]. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | | n² | n² | n² | 1 | No | Forward | -This sorter also has the following dedicated algorithms when used together with [`container_aware_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#container_aware_adapter): +This sorter also has the following dedicated algorithms when used together with [`container_aware_adapter`][container-aware-adapter]: | Container | Best | Average | Worst | Memory | Stable | | ------------------- | ----------- | ----------- | ----------- | ----------- | ----------- | @@ -333,7 +349,7 @@ This algorithm actually uses a rather big amount of memory but scales better tha #include ``` -Implements a [smoothsort](https://en.wikipedia.org/wiki/Smoothsort). +Implements a [smoothsort][smoothsort]. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | @@ -347,7 +363,7 @@ While the complexity guarantees of this algorithm are optimal, this smoothsort i #include ``` -Implements a [spinsort](https://www.boost.org/doc/libs/1_72_0/libs/sort/doc/html/sort/single_thread/spinsort.html) +Implements a [spinsort][spinsort] | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | @@ -367,7 +383,7 @@ Implements an in-place *SplitSort* as descirbed in *Splitsort — an adaptive so | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | | n | n log n | n log n | n | No | Random-Access | -SplitSort is a [*Rem*-adaptive](https://github.com/Morwenn/cpp-sort/wiki/Measures-of-presortedness#rem) sorting algorithm and shares many similarities with drop-merge sort but has the following differences: +SplitSort is a [*Rem*-adaptive][probe-rem] sorting algorithm and shares many similarities with drop-merge sort but has the following differences: * It only works with random-access iterators. * While it uses O(n) extra memory to merge some elements, it can run perfectly fine with O(1) extra memory. * Benchmarks shows that drop-merge sort is better when few elements aren't in place, but SplitSort has a lower overhead on random data while still performing better than most general-purpose sorting algorithms when the data is already somewhat sorted. @@ -382,7 +398,7 @@ This sorter can't throw `std::bad_alloc`. #include ``` -Uses the standard library [`std::sort`](https://en.cppreference.com/w/cpp/algorithm/sort) to sort a collection. While the complexity guarantees are only partial in the standard, here is what's expected: +Uses the standard library [`std::sort`][std-sort] to sort a collection. While the complexity guarantees are only partial in the standard, here is what's expected: | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | @@ -390,14 +406,14 @@ Uses the standard library [`std::sort`](https://en.cppreference.com/w/cpp/algori \* *`std::sort` is mandated by the standard to be O(n log n), but the libc++ implementation of the algorithm - despite non-trivial optimizations - [is still O(n²)](https://bugs.llvm.org/show_bug.cgi?id=20837). If you are using another standard library implementation then `std_sorter` should be O(n log n) for randon-access iterators, as expected.* -The adapter [`stable_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#stable_adapter) has an explicit specialization for `std_sorter` which calls [`std::stable_sort`](https://en.cppreference.com/w/cpp/algorithm/stable_sort) instead. Its complexity depends on whether it can allocate additional memory or not. While the complexity guarantees are only partial in the standard, here is what's expected: +The adapter [`stable_adapter`][stable-adapter] has an explicit specialization for `std_sorter` which calls [`std::stable_sort`][std-stable-sort] instead. Its complexity depends on whether it can allocate additional memory or not. While the complexity guarantees are only partial in the standard, here is what's expected: | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | | n log n | n log n | n log n | n | Yes | Random-access | | n log² n | n log² n | n log² n | 1 | Yes | Random-access | -`std::sort` and `std::stable_sort` are likely not able to handle proxy iterators, therefore trying to use `std_sorter` with code that relies on proxy iterators (*e.g.* [`schwartz_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#schwartz_adapter)) is deemed to cause errors. However, some standard libraries provide overloads of standard algorithms for some containers; for example, libc++ has an overload of `std::sort` for bit iterators, which means that `std_sorter` could be the best choice to sort an [`std::vector`](https://en.cppreference.com/w/cpp/container/vector_bool). +`std::sort` and `std::stable_sort` are likely not able to handle proxy iterators, therefore trying to use `std_sorter` with code that relies on proxy iterators (*e.g.* [`schwartz_adapter`][schwartz-adapter]) is deemed to cause errors. However, some standard libraries provide overloads of standard algorithms for some containers; for example, libc++ has an overload of `std::sort` for bit iterators, which means that `std_sorter` could be the best choice to sort an [`std::vector`][std-vector-bool]. This sorter can't throw `std::bad_alloc`. @@ -407,7 +423,7 @@ This sorter can't throw `std::bad_alloc`. #include ``` -Implements a [timsort](https://en.wikipedia.org/wiki/Timsort). +Implements a [timsort][timsort]. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | @@ -423,7 +439,7 @@ While the sorting algorithm is stable and the complexity guarantees are good eno #include ``` -Implements a [vergesort](https://github.com/Morwenn/vergesort) algorithm backed by a quicksort derivative. +Implements a [vergesort][vergesort] algorithm backed by a quicksort derivative. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------------- | ----------- | ----------- | ------------- | @@ -432,7 +448,7 @@ Implements a [vergesort](https://github.com/Morwenn/vergesort) algorithm backed | n | n log n | n log n log log n | n | No | Bidirectional | | n | n log n | n log n | log² n | No | Bidirectional | -Vergesort is a [*Runs*-adaptive](https://github.com/Morwenn/cpp-sort/wiki/Measures-of-presortedness#runs) algorithm (including descending runs) as long as the size of those runs is greater than *n / log n*; when the runs are smaller, it falls back to another sorting algorithm to sort them (pdqsort for random-access iterators, QuickMergesort otherwise). +Vergesort is a [*Runs*-adaptive][probe-runs] algorithm (including descending runs) as long as the size of those runs is greater than *n / log n*; when the runs are smaller, it falls back to another sorting algorithm to sort them (pdqsort for random-access iterators, QuickMergesort otherwise). Vergesort's complexity is bound either by its optimization layer or by the fallback sorter's complexity: * When it doesn't find big runs, the complexity is bound by the fallback sorter: depending on the category of iterators you can refer to the tables of either `pdq_sorter` or `quick_merge_sorter`. @@ -479,7 +495,7 @@ The following sorters are available but will only work for some specific types i #include ``` -`counting_sorter` implements a simple [counting sort](https://en.wikipedia.org/wiki/Counting_sort). This sorter also supports reverse sorting with `std::greater<>` or `std::ranges::greater`. +`counting_sorter` implements a simple [counting sort][counting-sort]. This sorter also supports reverse sorting with [`std::greater<>`][std-greater-void] or [`std::ranges::greater`][std-ranges-greater]. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | @@ -491,7 +507,7 @@ This sorter works with any type satisfying the trait `std::is_integral` (as well *Changed in version 1.6.0:* support for `[un]signed __int128`. -*Changed in version 1.9.0:* conditional support for [`std::ranges::greater`](https://en.cppreference.com/w/cpp/utility/functional/ranges/greater). +*Changed in version 1.9.0:* conditional support for [`std::ranges::greater`][std-ranges-greater]. ### `ska_sorter` @@ -499,7 +515,7 @@ This sorter works with any type satisfying the trait `std::is_integral` (as well #include ``` -`ska_sorter` implements a [ska_sort](https://probablydance.com/2016/12/27/i-wrote-a-faster-sorting-algorithm/). +`ska_sorter` implements a [ska_sort][ska-sort]. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | @@ -522,7 +538,7 @@ This sorter accepts projections, as long as `ska_sorter` can handle the return t #include ``` -`spread_sorter` implements a [spreadsort](https://en.wikipedia.org/wiki/Spreadsort). +`spread_sorter` implements a [spreadsort][spreadsort]. | Best | Average | Worst | Memory | Stable | Iterators | | ----------- | ----------- | ----------- | ----------- | ----------- | ------------- | @@ -546,15 +562,50 @@ struct spread_sorter: {}; ``` -*Changed in version 1.9.0:* conditional support for [`std::ranges::greater`](https://en.cppreference.com/w/cpp/utility/functional/ranges/greater). +*Changed in version 1.9.0:* conditional support for [`std::ranges::greater`][std-ranges-greater]. [adaptive-quickselect]: https://arxiv.org/abs/1606.00484 + [adaptive-shivers-sort]: https://arxiv.org/abs/1809.08411 + [bitmap-allocator]: https://gcc.gnu.org/onlinedocs/libstdc++/manual/bitmap_allocator.html [block-sort]: https://en.wikipedia.org/wiki/Block_sort + [branchless-traits]: Miscellaneous-utilities.md#branchless-traits [cartesian-tree-sort]: https://en.wikipedia.org/wiki/Cartesian_tree#Application_in_sorting - [container-aware-adapter]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#container_aware_adapter + [container-aware-adapter]: Sorter-adapters.md#container_aware_adapter + [counting-sort]: https://en.wikipedia.org/wiki/Counting_sort + [cppsort-sort]: Sorting-functions.md#cppsortsort + [default-sorter]: Sorters.md#default_sorter + [drop-merge-sort]: https://github.com/emilk/drop-merge-sort + [grailsort]: https://github.com/Mrrl/GrailSort + [heapsort]: https://en.wikipedia.org/wiki/Heapsort + [insertion-sort]: https://en.wikipedia.org/wiki/Insertion_sort [introselect]: https://en.wikipedia.org/wiki/Introselect + [issue-168]: https://github.com/Morwenn/cpp-sort/issues/168 + [median-of-medians]: https://en.wikipedia.org/wiki/Median_of_medians + [merge-sort]: https://en.wikipedia.org/wiki/Merge_sort + [pdqsort]: https://github.com/orlp/pdqsort + [probe-rem]: Measures-of-presortedness.md#rem + [probe-runs]: Measures-of-presortedness.md#runs [quick-mergesort]: https://arxiv.org/abs/1307.3033 + [quicksort]: https://en.wikipedia.org/wiki/Quicksort + [schwartz-adapter]: Sorter-adapters.md#schwartz_adapter [selection-algorithm]: https://en.wikipedia.org/wiki/Selection_algorithm + [selection-sort]: https://en.wikipedia.org/wiki/Selection_sort + [ska-sort]: https://probablydance.com/2016/12/27/i-wrote-a-faster-sorting-algorithm/ + [smoothsort]: https://en.wikipedia.org/wiki/Smoothsort + [sorter-adapters]: Sorter-adapters.md + [sorting-functions]: Sorting-functions.md + [spinsort]: https://www.boost.org/doc/libs/1_78_0/libs/sort/doc/html/sort/single_thread/spinsort.html + [spreadsort]: https://en.wikipedia.org/wiki/Spreadsort + [stable-adapter]: Sorter-adapters.md#stable_adapter-make_stable-and-stable_t + [std-greater-void]: https://en.cppreference.com/w/cpp/utility/functional/greater_void + [std-ranges-greater]: https://en.cppreference.com/w/cpp/utility/functional/ranges/greater + [std-sort]: https://en.cppreference.com/w/cpp/algorithm/sort + [std-stable-sort]: https://en.cppreference.com/w/cpp/algorithm/stable_sort + [std-vector-bool]: https://en.cppreference.com/w/cpp/container/vector_bool + [timsort]: https://en.wikipedia.org/wiki/Timsort + [vergesort]: https://github.com/Morwenn/vergesort [wiki-sort]: https://github.com/BonzaiThePenguin/WikiSort - [wiki-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Sorters#wiki_sorter + [wiki-sorter]: Sorters.md#wiki_sorter + [writing-a-sorter]: Writing-a-sorter.md + [writing-a-bubble-sorter]: Writing-a-bubble_sorter.md diff --git a/docs/Sorting-functions.md b/docs/Sorting-functions.md index 2e154216..4235ab43 100644 --- a/docs/Sorting-functions.md +++ b/docs/Sorting-functions.md @@ -1,10 +1,10 @@ -***WARNING:** sorting functions are deprecated in version 1.8.0 and removed in version 2.0.0, see [issue #167](https://github.com/Morwenn/cpp-sort/issues/167) for the rationale.* +***WARNING:** sorting functions are deprecated in version 1.8.0 and removed in version 2.0.0, see [issue #167][issue-167] for the rationale.* -**cpp-sort** has two general sorting functions designed to match the ones in the standard library: `cppsort::sort` and `cppsort::stable_sort`. Both of them have several overloads: some take a [[sorter|Sorters]] to sort the given iterable while others call the library's default sorter instead. They are designed so that it is possible to pass either a collection to sort or a pair of iterators, and to specify a comparison function and/or a projection function. They can also be passed a sorter to perform the sort. +**cpp-sort** has two general sorting functions designed to match the ones in the standard library: `cppsort::sort` and `cppsort::stable_sort`. Both of them have several overloads: some take a [sorter][sorters] to sort the given iterable while others call the library's default sorter instead. They are designed so that it is possible to pass either a collection to sort or a pair of iterators, and to specify a comparison function and/or a projection function. They can also be passed a sorter to perform the sort. ## `cppsort::sort` -### Overloads calling [`default_sorter`](https://github.com/Morwenn/cpp-sort/wiki/Sorters#default_sorter) +### Overloads calling [`default_sorter`][default-sorter] ```cpp template @@ -40,7 +40,7 @@ auto sort(Iterator first, Iterator last, Compare compare, Projection projection) -> void; ``` -These overloads take either an `Iterable` or a pair of `Iterator`, and sort the corresponding collection in-place in ascending order using [`cppsort::default_sorter`](https://github.com/Morwenn/cpp-sort/wiki/Sorters#default_sorter) to perform the sort. If provided, the comparison function `compare` and the projection function `projection` are used instead of the default [`std::less<>`](https://en.cppreference.com/w/cpp/utility/functional/less_void) and [`utility::identity`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects). +These overloads take either an `Iterable` or a pair of `Iterator`, and sort the corresponding collection in-place in ascending order using [`cppsort::default_sorter`][default-sorter] to perform the sort. If provided, the comparison function `compare` and the projection function `projection` are used instead of the default [`std::less<>`][std-less-void] and [`utility::identity`][utility-identity]. ### Overload calling a user-provided sorter @@ -82,13 +82,13 @@ auto sort(const Sorter& sorter, Iterator first, Iterator last, -> decltype(auto); ``` -These overloads take either an `Iterable` or a pair of `Iterator`, and sort the corresponding collection in-place in ascending order using the given sorter. If provided, the comparison function `compare` and the projection function `projection` are used instead of the default [`std::less<>`](https://en.cppreference.com/w/cpp/utility/functional/less_void) and [`utility::identity`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects). The returned value corresponds to the value returned by the sorter's `operator()` when it is given the other parameters. +These overloads take either an `Iterable` or a pair of `Iterator`, and sort the corresponding collection in-place in ascending order using the given sorter. If provided, the comparison function `compare` and the projection function `projection` are used instead of the default [`std::less<>`][std-less-void] and [`utility::identity`][utility-identity]. The returned value corresponds to the value returned by the sorter's `operator()` when it is given the other parameters. -Note that there is some heavy SFINAE wizardry happening to ensure that none of the `sort` overloads are ambiguous. This magic has been stripped from the documentation for clarity but may contribute to highly unreadable error messages. However, there is still some ambiguity left: the overload resolution might fail if `sort` is given an object that satisfies both the `Compare` and `Projection` concepts. This issue can we worked around with [`as_comparison` and `as_projection`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#as_comparison-and-as_projection) +Note that there is some heavy SFINAE wizardry happening to ensure that none of the `sort` overloads are ambiguous. This magic has been stripped from the documentation for clarity but may contribute to highly unreadable error messages. However, there is still some ambiguity left: the overload resolution might fail if `sort` is given an object that satisfies both the `Compare` and `Projection` concepts. This issue can be worked around with [`as_comparison` and `as_projection`][as-comparison]. ## `cppsort::stable_sort` -The overload set for `cppsort::stable_sort` matches that of `cppsort::sort`, so their exact behavior won't be repeated here. The main difference is that they will use [`stable_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#stable_adapter) to wrap the given sorter instead of using the raw sorter. The sorter instance is actually discarded and is only used for overload resolution, so mutable sorters won't work at all. The overloads that do not take a sorter use `stable_adapter` instead. +The overload set for `cppsort::stable_sort` matches that of `cppsort::sort`, so their exact behavior won't be repeated here. The main difference is that they will use [`stable_adapter`][stable-adapter] to wrap the given sorter instead of using the raw sorter. The sorter instance is actually discarded and is only used for overload resolution, so mutable sorters won't work at all. The overloads that do not take a sorter use `stable_adapter` instead. ### Overloads calling `stable_adapter` @@ -165,3 +165,12 @@ auto stable_sort(const Sorter& sorter, Iterator first, Iterator last, Compare compare, Projection projection) -> decltype(auto); ``` + + + [as-comparison]: Miscellaneous-utilities.md#as_comparison-and-as_projection + [default-sorter]: Sorters.md#default_sorter + [issue-167]: https://github.com/Morwenn/cpp-sort/issues/167 + [sorters]: Sorters.md + [std-less-void]: https://en.cppreference.com/w/cpp/utility/functional/less_void + [stable-adapter]: Sorter-adapters.md#stable_adapter-make_stable-and-stable_t + [utility-identity]: Miscellaneous-utilities.md#Miscellaneous-function-objects diff --git a/docs/Tooling.md b/docs/Tooling.md index a4dc51cc..88e435bd 100644 --- a/docs/Tooling.md +++ b/docs/Tooling.md @@ -24,25 +24,30 @@ target_link_libraries(my-target PRIVATE cpp-sort::cpp-sort) ### Building cpp-sort -The project's CMake files do offer some options, but they are mainly used to configure the test suite and the examples: +The project's CMake files offers some options, though they are mainly used to configure the test suite and examples: * `CPPSORT_BUILD_TESTING`: whether to build the test suite, defaults to `ON`. * `CPPSORT_BUILD_EXAMPLES`: whether to build the examples, defaults to `OFF`. * `CPPSORT_ENABLE_COVERAGE`: whether to produce code coverage information when building the test suite, defaults to `OFF`. * `CPPSORT_USE_VALGRIND`: whether to run the test suite through Valgrind, defaults to `OFF`. -* `CPPSORT_SANITIZE`: values to pass to the `-fsanitize` falgs of compilers that supports them, default to empty. +* `CPPSORT_SANITIZE`: values to pass to the `-fsanitize` flags of compilers that supports them, default to empty. +* `CPPSORT_STATIC_TESTS`: when `ON`, some tests are executed at compile time instead of runtime, defaults to `OFF`. -The same options exist without the `CPPSORT_` prefix exist, but are deprecated. For compatibility reasons, the options with the `CPPSORT_` prefix default the values of the equivalent unprefixed options. +Some of those options also exist without the `CPPSORT_` prefix, but they are deprecated. For compatibility reasons, the options with the `CPPSORT_` prefix default to the values of the equivalent unprefixed options. *New in version 1.6.0:* added the option `BUILD_EXAMPLES`. *New in version 1.9.0:* options with the `CPPSORT_` prefix. +*New in version 1.13.0:* added the option `CPPSORT_STATIC_TESTS`. + ***WARNING:** options without a `CPPSORT_` prefixed are deprecated in version 1.9.0 and removed in version 2.0.0.* -[Catch2][catch2] 2.6.0 or greater is required to build the tests: if a suitable version has been installed on the system it will be used, otherwise the latest Catch2 release will be downloaded. +[Catch2][catch2] 3.0.0-preview4 or greater is required to build the tests: if a suitable version has been installed on the system it will be used, otherwise the latest suitable Catch2 release will be downloaded. *Changed in version 1.7.0:* if a suitable Catch2 version is found on the system, it will be used. +*Changed in version 1.13.0:* cpp-sort now requires Catch2 version 3.0.0-preview4 instead of 2.6.0. + ## Conan **cpp-sort** is available directly on [Conan Center][conan-center]. You can find the different versions available with the following command: @@ -51,16 +56,29 @@ The same options exist without the `CPPSORT_` prefix exist, but are deprecated. conan search cpp-sort --remote=conan-center ``` -And then install any version to your local cache as follows (here with version 1.12.1): +And then install any version to your local cache as follows (here with version 1.13.0): ```sh -conan install cpp-sort/1.12.1 +conan install cpp-sort/1.13.0 ``` The packages downloaded from conan-center are minimal and only contain the files required to use **cpp-sort** as a library: the headers, CMake files and licensing information. If you need anything else you have to build your own package with the `conanfile.py` available in this repository. +## Gollum + +[Gollum][gollum], if installed, can be used to browse this documentation offline: + +1. Navigate to the main `cpp-sort` directory in the command line +2. `gollum --page-file-dir docs --ref ` +3. Visit http://localhost:4567/Home + +This can notably used to browse old versions of the documentation. It seems however that `--ref` doesn't understand Git tags, so you have to create a proper branch from the version tag you want to browse beforehand. + +Due to slight markup differences, some pages might not fully render correctly but it should nonetheless be a better experience than navigaitng the Markdown files by hand. + [catch2]: https://github.com/catchorg/Catch2 [cmake]: https://cmake.org/ [conan]: https://conan.io/ [conan-center]: https://conan.io/center/cpp-sort + [gollum]: https://github.com/gollum/gollum diff --git a/docs/Writing-a-bubble_sorter.md b/docs/Writing-a-bubble_sorter.md index 8847f2ca..8aa0d9c6 100644 --- a/docs/Writing-a-bubble_sorter.md +++ b/docs/Writing-a-bubble_sorter.md @@ -1,4 +1,4 @@ -If you have read the general tutorial about [[writing sorters|Writing a sorter]], you might be interested in a full concrete example. In this tutorial, we will see how to implement a simple [bubble sort][bubble-sort] and how to write a `bubble_sorter` to wrap it. Step by step. +If you have read the general tutorial about [writing sorters][writing-a-sorter], you might be interested in a full concrete example. In this tutorial, we will see how to implement a simple [bubble sort][bubble-sort] and how to write a `bubble_sorter` to wrap it. Step by step. ## The bubble sort algorithm @@ -75,7 +75,7 @@ Now our `bubble_sorter` satisfies the library's requirements and implements all ## Sorter traits -For example let's take [`hybrid_adapter`][hybrid-adapter], a [[*sorter adapter*|Sorter adapters]] which allows to aggregate different sorters together: it needs to know the iterator category of the sorters it aggregates. In order to provide that information, we need to explicitly document the iterator category our sorter is designed to work with by giving it an `iterator_category` type aliasing one of the standard iterator tags: +For example let's take [`hybrid_adapter`][hybrid-adapter], a [*sorter adapter*][sorter-adapters] which allows to aggregate different sorters together: it needs to know the iterator category of the sorters it aggregates. In order to provide that information, we need to explicitly document the iterator category our sorter is designed to work with by giving it an `iterator_category` type aliasing one of the standard iterator tags: ```cpp struct bubble_sorter_impl @@ -437,16 +437,18 @@ Concepts might improve some error messages too, but they're out of scope for **c That's it: we have covered pretty much every interesting aspect of writing a simple comparison sorter. I hope you enjoyed the tutorial, even if bubble sort is not the most interesting sorting algorithm around. You can find the full implementation in the examples folder :) - [as-function]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#as_function + [as-function]: Miscellaneous-utilities.md#as_function + [bubble-sort]: https://en.wikipedia.org/wiki/Bubble_sort [bubble-sorter]: https://en.wikipedia.org/wiki/Bubble_sort - [heap-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Sorters#heap_sorter - [hybrid-adapter]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#hybrid_adapter - [is-projection]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#is_projection-and-is_projection_iterator + [heap-sorter]: Sorters.md#heap_sorter + [hybrid-adapter]: Sorter-adapters.md#hybrid_adapter + [is-projection]: Sorter-traits.md#is_projection-and-is_projection_iterator [projections]: https://ezoeryou.github.io/blog/article/2019-01-22-ranges-projection.html [proxy-iterators]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0022r2.html - [sorter-facade]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-facade - [sorter-traits]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#sorter_traits - [stable-adapter]: https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#stable_adapter-make_stable-and-stable_t + [sorter-adapters]: Sorter-adapters.md + [sorter-facade]: Sorter-facade.md + [sorter-traits]: Sorter-traits.md#sorter_traits + [stable-adapter]: Sorter-adapters.md#stable_adapter-make_stable-and-stable_t [std-identity]: https://en.cppreference.com/w/cpp/utility/functional/identity [std-invoke]: https://en.cppreference.com/w/cpp/utility/functional/invoke [std-iter-move]: https://en.cppreference.com/w/cpp/iterator/ranges/iter_move @@ -454,7 +456,8 @@ That's it: we have covered pretty much every interesting aspect of writing a sim [std-list]: https://en.cppreference.com/w/cpp/container/list [std-span]: https://en.cppreference.com/w/cpp/container/span [std-vector-bool]: https://en.cppreference.com/w/cpp/container/vector_bool - [utility-identity]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects - [utility-iter-move]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#iter_move-and-iter_swap - [utility-size]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#size - [utility-static-const]: https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#static_const + [utility-identity]: Miscellaneous-utilities.md#miscellaneous-function-objects + [utility-iter-move]: Miscellaneous-utilities.md#iter_move-and-iter_swap + [utility-size]: Miscellaneous-utilities.md#size + [utility-static-const]: Miscellaneous-utilities.md#static_const + [writing-a-sorter]: Writing-a-sorter.md diff --git a/docs/Writing-a-container-aware-algorithm.md b/docs/Writing-a-container-aware-algorithm.md index af612235..0bf6f6c4 100644 --- a/docs/Writing-a-container-aware-algorithm.md +++ b/docs/Writing-a-container-aware-algorithm.md @@ -1,4 +1,4 @@ -Sometimes, iterators are not enough and you want to use the full abilities of containers to sort them, like O(1) insertion for [`std::list`](https://en.cppreference.com/w/cpp/container/list) and [`std::forward_list`](https://en.cppreference.com/w/cpp/container/forward_list). **cpp-sort** makes it possible to enhance sorters so that they can recognize specific containers and use a dedicated altered version of the sorting algorithm to sort the container thanks to [`container_aware_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#container_aware_adapter). +Sometimes, iterators are not enough and you want to use the full abilities of containers to sort them, like O(1) insertion for [`std::list`][std-list] and [`std::forward_list`][std-forward-list]. **cpp-sort** makes it possible to enhance sorters so that they can recognize specific containers and use a dedicated altered version of the sorting algorithm to sort the container thanks to [`container_aware_adapter`][container-aware-adapter]. Let's get straight to example and enhance `selection_sort` for a custom list class to take advantage of the O(1) insertion. Here is the list implementation: @@ -38,7 +38,7 @@ namespace example } ``` -As is, `container_aware_adapter` doesn't know about the sorting algorithm and can't use it. In order to find dedicated algorithm, it performs an ADL lookup to find a suitable `sort` function in the container's namespace. The `sort` function shall take the "overloaded" sorter as a first parameter, the container to sort as a second parameter, and comparison and projection functions may follow. Many overload generation rules from [`sorter_facade`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-facade) are also implemented in `container_aware_adapter` to ensure that it will try to call the dedicated algorithm whenever it can. Here is the whole thing: +As is, `container_aware_adapter` doesn't know about the sorting algorithm and can't use it. In order to find dedicated algorithm, it performs an ADL lookup to find a suitable `sort` function in the container's namespace. The `sort` function shall take the "overloaded" sorter as a first parameter, the container to sort as a second parameter, and comparison and projection functions may follow. Many overload generation rules from [`sorter_facade`][sorter-facade] are also implemented in `container_aware_adapter` to ensure that it will try to call the dedicated algorithm whenever it can. Here is the whole thing: ```cpp namespace example @@ -70,4 +70,10 @@ namespace example } ``` -There will be improvements to `container_aware_adapter` in the future to make `stable_sort` another customization point, and probably to make `sort` fall back to `stable_sort` when there is an ADL-found `stable_sort` but no ADL-found `sort`. However, it's a huge piece of work, so it probably won't be before a while. \ No newline at end of file +There will be improvements to `container_aware_adapter` in the future to make `stable_sort` another customization point, and probably to make `sort` fall back to `stable_sort` when there is an ADL-found `stable_sort` but no ADL-found `sort`. However, it's a huge piece of work, so it probably won't be before a while. + + + [container-aware-adapter]: Sorter-adapters.md#container_aware_adapter + [sorter-facade]: Sorter-facade.md + [std-forward-list]: https://en.cppreference.com/w/cpp/container/forward_list + [std-list]: https://en.cppreference.com/w/cpp/container/list diff --git a/docs/Writing-a-sorter.md b/docs/Writing-a-sorter.md index d788ee06..1eea40b8 100644 --- a/docs/Writing-a-sorter.md +++ b/docs/Writing-a-sorter.md @@ -1,10 +1,10 @@ Someday, you might want to use a specific sorting algorithm that does not exist in **cpp-sort** (there are plenty of those) but still benefit from the tools available in this library. In order to do so, you would have to wrap such an algorithm into a sorter. In this tutorial, we will see the quirks involved in writing a good sorter to wrap a sorting algorithm. Writing a basic sorter is easy, but getting everything right to the details might be a bit tricky from time to time. This guide should help you to make the good choices (well, at least I hope so). -*This tutorial is mostly a collection of good practice, tips, and design considerations. For a full step-by-step tutorial to write a sorter, you can read [Writing a `bubble_sorter`](https://github.com/Morwenn/cpp-sort/wiki/writing-a-bubble_sorter).* +*This tutorial is mostly a collection of good practice, tips, and design considerations. For a full step-by-step tutorial to write a sorter, you can read [Writing a `bubble_sorter`][writing-a-bubble-sorter].* ## Which kind of sorter -Writing a proper **cpp-sort**-compatible sorter generally implies some familiarity with library's [nomenclature](https://github.com/Morwenn/cpp-sort/wiki/Library-nomenclature): each term of art might imply design decisions and tricky things to take into account. These terms of art can be converted into a series of questions to answer before designing a sorter: +Writing a proper **cpp-sort**-compatible sorter generally implies some familiarity with library's [nomenclature][library-nomenclature]: each term of art might imply design decisions and tricky things to take into account. These terms of art can be converted into a series of questions to answer before designing a sorter: * Is it a *fixed-size sorter*? Is it meant to sort a collection of arbitrary size or a fixed number of values? * Which *category of iterators* does it work with? Can it be used to sort an `std::forward_list`? * Does it implement a *comparison sort*? Does it handle arbitrary comparison functions? @@ -18,7 +18,7 @@ This tutorial describes what should be taken into account when writing a sorter, ## The most basic sorter -Let's put *fixed-size sorters* aside for a while since they are a really special breed of sorters, and concentrate on sorters meant to sort collections of any size. Let's assume that we already have the following `selection_sort` algorithm, which implements a [selection sort](https://en.wikipedia.org/wiki/Selection_sort) in the most straightforward way, taking a pair of iterators like many standard library algorithms, and sorting the corresponding range in-place: +Let's put *fixed-size sorters* aside for a while since they are a really special breed of sorters, and concentrate on sorters meant to sort collections of any size. Let's assume that we already have the following `selection_sort` algorithm, which implements a [selection sort][selection-sort] in the most straightforward way, taking a pair of iterators like many standard library algorithms, and sorting the corresponding range in-place: ```cpp template @@ -51,11 +51,11 @@ struct selection_sorter: {}; ``` -We just wrote what we call a *sorter implementation* and wrapped it into [`sorter_facade`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-facade), a class template designed to provide additional features to a given sorter implementation. We only had to write an `operator()` that takes a pair of iterators and forwards it to `selection_sort`, yet the resulting `selection_sorter` also has an `operator()` overload which can be passed a full collection instead of a pair of iterators, and it is additionally convertible to function pointers of type `void(*)(Iterator, Iterator)` and `void(*)(Iterable&)`. This is what `sorter_facade` gives you for even the most basic sorter, without any effort. +We just wrote what we call a *sorter implementation* and wrapped it into [`sorter_facade`][sorter-facade], a class template designed to provide additional features to a given sorter implementation. We only had to write an `operator()` that takes a pair of iterators and forwards it to `selection_sort`, yet the resulting `selection_sorter` also has an `operator()` overload which can be passed a full collection instead of a pair of iterators, and it is additionally convertible to function pointers of type `void(*)(Iterator, Iterator)` and `void(*)(Iterable&)`. This is what `sorter_facade` gives you for even the most basic sorter, without any effort. Now, let's define a set of rules to apply when writing sorters. These rules don't *have* to be enforced, but enforcing them will ensure that a sorter will work smoothly with most tool available in this library. In this tutorial, every section will define a small set of rules instead of defining all of them at once without introducing the relevant concepts first. Fortunately, the simpler the sorter, the simpler the rules. -**Rule 1.1:** for any *sorter*, [`std::is_sorted`](https://en.cppreference.com/w/cpp/algorithm/is_sorted) called without a comparison function on the resulting range shall return `true` (note that this is not exactly true: floating point numbers are an example of types that will almost always cause problems). +**Rule 1.1:** for any *sorter*, [`std::is_sorted`][std-is-sorted] called without a comparison function on the resulting range shall return `true` (note that this is not exactly true: floating point numbers are an example of types that will almost always cause problems). **Rule 1.2:** a *sorter* shall be callable with either a pair of iterators or an iterable. @@ -63,11 +63,11 @@ Now, let's define a set of rules to apply when writing sorters. These rules don' **Rule 1.4:** *sorters* shall be immutable and every overload of `operator()` shall explicitly be marked `const` (make sure to check twice: forgetting to `const`-qualify them can cause hundreds of lines of cryptic error messages). Some parts of the library *may* accept mutable sorters, but that's never guaranteed unless specified otherwise. -**Rule 1.5:** *sorter* implementers are encouraged but not required to provide a default instance of their *sorters* for convenience. `inline` variables (C++17) or the library's [`static_const`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#static_const) utility (C++14) can be used to avoid ODR-related problems. +**Rule 1.5:** *sorter* implementers are encouraged but not required to provide a default instance of their *sorters* for convenience. `inline` variables (C++17) or the library's [`static_const`][static-const] utility (C++14) can be used to avoid ODR-related problems. ## Category of iterators -When writing a sorter, one of the most important things to consider is the [category of iterators](https://en.cppreference.com/w/cpp/iterator) it is meant to work with. It directly influences the kinds of collections that the sorter will be able to sort. Sorters implement in-place sorting algorithms, therefore they can only sort forward iterators or more specific types. **cpp-sort** does more than document the sorter category a sorter is supposed to work with: it actually embeds the information directly into the *sorter implementation* itself. If we take the `selection_sorter` from the previous section, we can document its properties as follows: +When writing a sorter, one of the most important things to consider is the [category of iterators][std-iterators] it is meant to work with. It directly influences the kinds of collections that the sorter will be able to sort. Sorters implement in-place sorting algorithms, therefore they can only sort forward iterators or more specific types. **cpp-sort** does more than document the sorter category a sorter is supposed to work with: it actually embeds the information directly into the *sorter implementation* itself. If we take the `selection_sorter` from the previous section, we can document its properties as follows: ```cpp struct selection_sorter_impl @@ -83,7 +83,7 @@ struct selection_sorter_impl }; ``` -The standard library's [iterator tags](https://en.cppreference.com/w/cpp/iterator/iterator_tags) are used to document the iterator category supported by the sorter (stability is also documented but we'll come back to that later). It is a bit useful for error messages, but some other tools from the library rely of this information. For example [`hybrid_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#hybrid_adapter) can take several sorters with different iterator categories and generate a new sorter that will call the appropriate sorter depending on the iterator category of the passed collection: +The standard library's [iterator tags][std-iterator-tags] are used to document the iterator category supported by the sorter (stability is also documented but we'll come back to that later). It is a bit useful for error messages, but some other tools from the library rely of this information. For example [`hybrid_adapter`][hybrid-adapter] can take several sorters with different iterator categories and generate a new sorter that will call the appropriate sorter depending on the iterator category of the passed collection: ```cpp using sorter = cppsort::hybrid_adapter< @@ -97,7 +97,7 @@ sorter{}(std::forward_list{}); // calls forward_sorter sorter{}(std::list{}); // calls bidirectional_sorter ``` -Say you have several sorters with the same iterator category (`std::forward_iterator_tag`) but you know that one of them is better with forward iterators while the other one is better when it comes to random-access and bidirectional iterators. You can use [`rebind_iterator_category`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#rebind_iterator_category) so that the second sorter is considered as a bidirectional sorter instead: +Say you have several sorters with the same iterator category (`std::forward_iterator_tag`) but you know that one of them is better with forward iterators while the other one is better when it comes to random-access and bidirectional iterators. You can use [`rebind_iterator_category`][rebind-iterator-category] so that the second sorter is considered as a bidirectional sorter instead: ```cpp using sorter = cppsort::hybrid_adapter< @@ -109,7 +109,7 @@ using sorter = cppsort::hybrid_adapter< >; ``` -If you ever need to access the iterator category of a sorter, don't directly ask for it, use [sorter traits](https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#sorter_traits) instead. It shouldn't make a difference when using the regular sorters provided by **cpp-sort**, but the library's *fixed-size sorters* are an example of sorters for which the traits are not embedded in the sorter but provided as a specialization of `sorter_traits` (mainly for maintainability reasons). +If you ever need to access the iterator category of a sorter, don't directly ask for it, use [sorter traits][sorter-traits] instead. It shouldn't make a difference when using the regular sorters provided by **cpp-sort**, but the library's *fixed-size sorters* are an example of sorters for which the traits are not embedded in the sorter but provided as a specialization of `sorter_traits` (mainly for maintainability reasons). As you can see, the iterator category supported by a given sorter is not only there for documentation. You have tools to play with it and tools that actually need the information, so make sure to get it right when designing your sorters. @@ -121,7 +121,7 @@ As you can see, the iterator category supported by a given sorter is not only th ## Comparison sorters -Most sorting algorithms are [comparison sorts](https://en.wikipedia.org/wiki/Comparison_sort). It means that, to sort the elements of a collection, they repeatedly use a comparison function that returns whether two elements are already in order. The standard library's [`std::sort`](https://en.cppreference.com/w/cpp/algorithm/sort) implicitly uses an ADL-found `operator<` to compare two elements, but it also provides an overload which takes a user-provided comparison function to compare two elements. **cpp-sort** loosely follows this design (it defaults to `std::less<>` instead of `operator<`) and allows its sorters to take an additional parameter for user-provided comparison functions. Let's write a *sorter implementation* to wrap the three-parameter overload of `std::sort`: +Most sorting algorithms are [comparison sorts][comparison-sort]. It means that, to sort the elements of a collection, they repeatedly use a comparison function that returns whether two elements are already in order. The standard library's [`std::sort`][std-sort] implicitly uses an ADL-found `operator<` to compare two elements, but it also provides an overload which takes a user-provided comparison function to compare two elements. **cpp-sort** loosely follows this design (it defaults to `std::less<>` instead of `operator<`) and allows its sorters to take an additional parameter for user-provided comparison functions. Let's write a *sorter implementation* to wrap the three-parameter overload of `std::sort`: ```cpp struct std_sorter_impl @@ -147,22 +147,22 @@ struct std_sorter: {}; ``` -Compared to the previous `selection_sorter_impl`, the only things we had to add was a template parameter defaulted to [`std::less<>`](https://en.cppreference.com/w/cpp/utility/functional/less_void) and a default-contructed (when not provided) parameter to `operator()`. As usual, [`sorter_facade`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-facade) generates a bunch of additional features: it still adds the overload of `operator()` taking a single iterable, but also adds an overload taking an iterable and a comparison function. Basically, it ensures that you always only have to provide a single overload of `operator()`, and generates all the other ones as well as all the corresponding conversions to function pointers. +Compared to the previous `selection_sorter_impl`, the only things we had to add was a template parameter defaulted to [`std::less<>`][std-less-void] and a default-contructed (when not provided) parameter to `operator()`. As usual, [`sorter_facade`][sorter-facade] generates a bunch of additional features: it still adds the overload of `operator()` taking a single iterable, but also adds an overload taking an iterable and a comparison function. Basically, it ensures that you always only have to provide a single overload of `operator()`, and generates all the other ones as well as all the corresponding conversions to function pointers. -This kind of comparison sorters help to compare things that don't have an overloaded `operator<` or to compare things differently. For example, passing [`std::greater<>`](https://en.cppreference.com/w/cpp/utility/functional/greater_void) to a sorter instead of `std::less<>` sorts a collection in descending order: +This kind of comparison sorters help to compare things that don't have an overloaded `operator<` or to compare things differently. For example, passing [`std::greater<>`][std-greater-void] to a sorter instead of `std::less<>` sorts a collection in descending order: ```cpp // Sort collection in reverse order with std::sort cppsort::std_sort(collection, std::greater<>{}); ``` -It is worth noting that every *comparison sorter* provided by the library transforms the comparison parameter with [`utility::as_function`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#as_function) before actually using it. It allows to use pointers to member functions of the `lhs.compare_to(rhs)` kind out-of-the-box. +It is worth noting that every *comparison sorter* provided by the library transforms the comparison parameter with [`utility::as_function`][utility-as-function] before actually using it. It allows to use pointers to member functions of the `lhs.compare_to(rhs)` kind out-of-the-box. The rules for *comparison sorters* are but an extension to the rules defined for basic sorters. You will see that they are very similar. **Rule 3.1:** a *comparison sorter* is also a *sorter*, which means that it shall be called without a comparison function and shall obey all the rules defined for regular *sorters*. -**Rule 3.2:** for any *comparison sorter* called with a specific comparison function, [`std::is_sorted`](https://en.cppreference.com/w/cpp/algorithm/is_sorted) called with the same comparison function on the resulting collection shall return `true`. +**Rule 3.2:** for any *comparison sorter* called with a specific comparison function, [`std::is_sorted`][std-is-sorted] called with the same comparison function on the resulting collection shall return `true`. **Rule 3.3:** calling a *comparison sorter* with `std::less<>` or without a comparison function shall be strictly equivalent: calling `std::is_sorted` without a comparison function on the resulting collection shall return `true`. @@ -172,7 +172,7 @@ The rules for *comparison sorters* are but an extension to the rules defined for ## Handling projections -The [Ranges TS](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4560.pdf) introduces the notion of callable *projections*, borrowed from the [Adobe Source Libraries](https://stlab.adobe.com/). A projection is a callable object that can be passed to an algorithm so that it "views" the values to be compared differently. For example, [`std::negate<>`](https://en.cppreference.com/w/cpp/utility/functional/negate_void) could be used to sort a collection of integers in descending order. Let's assume that our `selection_sort` algorithm from a while has been given a fourth parameter to handle projections; here is the corresponding *sorter implementation*: +C++20 introduces the notion of callable *projections*, borrowed from the [Adobe Source Libraries][stlab]. A projection is a callable object that can be passed to an algorithm so that it "views" the values to be compared differently. For example, [`std::negate<>`][std-negate-void] could be used to sort a collection of integers in descending order. Let's assume that our `selection_sort` algorithm from a while has been given a fourth parameter to handle projections; here is the corresponding *sorter implementation*: ```cpp struct selection_sorter_impl @@ -198,11 +198,11 @@ struct selection_sorter_impl }; ``` -As you can see, extending the sorter to handle projections is similar to extending it to support comparisons. Note that this sorter is both a *comparison sorter* and a *projection sorter*, but some sorters can also handle projections without handling comparisons. While the default function object for comparisons is `std::less`, the equivalent default function object for projections is [`utility::identity`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects) (and probably `std::identity` in a future revision of the C++ standard): it simply returns the passed value as is. +As you can see, extending the sorter to handle projections is similar to extending it to support comparisons. Note that this sorter is both a *comparison sorter* and a *projection sorter*, but some sorters can also handle projections without handling comparisons. While the default function object for comparisons is `std::less`, the equivalent default function objects for projections is [`utility::identity`][utility-identity] (and probably [`std::identity`][std-identity] in C++20): it simply returns the passed value as is. -The only subtle trick in the example above is the use of [`is_projection_iterator`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#is_projection-and-is_projection_iterator): this trait is used to disambiguate comparison functions from projection functions when a sorter can be called with both, and is not needed when the sorter is only a *projection sorter*. It is actually some kind of concept check and should go away when concepts make their way to the standard. +The only subtle trick in the example above is the use of [`is_projection_iterator`][is-projection]: this trait is used to disambiguate comparison functions from projection functions when a sorter can be called with both, and is not needed when the sorter is only a *projection sorter*. It is actually some kind of concept check and should go away when concepts make their way to the standard. -Note that most of the algorithms (actually, every *projection sorter* provided by the library) transform the projection parameter with [`utility::as_function`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#as_function) before actually using it. This small tool allows to use pointers to member data as projections; here is an example of how it can be used: +Note that most of the algorithms (actually, every *projection sorter* provided by the library) transform the projection parameter with [`utility::as_function`][utility-as-function] before actually using it. This small tool allows to use pointers to member data as projections; here is an example of how it can be used: ```cpp struct wrapper { int value; } @@ -212,7 +212,7 @@ cppsort::selection_sort(vec, &wrapper::value); Thanks to that small trick, the `selection_sorter` will sort `vec`, using the member data `wrapper::value` instead of a full `wrapper` instance (which cannot be compared) to perform the comparisons on. -Algorithms generally apply the projection on-the-fly to the values when they are compared. Some algorithms are a bit more subtle and project a specific object once when they know that its projection will be used extensively (*e.g.* quicksort projects a pivot once before calling the partition function). If projections are really expensive, one can still use [`schwartz_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#schwartz_adapter), which projects every element of the collection once prior to the sorting. +Algorithms generally apply the projection on-the-fly to the values when they are compared. Some algorithms are a bit more subtle and project a specific object once when they know that its projection will be used extensively (*e.g.* quicksort projects a pivot once before calling the partition function). If projections are really expensive, one can still use [`schwartz_adapter`][schwartz-adapter], which projects every element of the collection once prior to the sorting. Now that you know everything about implementing projections... it's time tell you that you don't actually need to implement them most of the time: if you create a *sorter implementation* with an `operator()` taking only two iterators and a comparison function, `sorter_facade` will create additional overloads that accept projection parameters, bake the projection into the comparison function and pass that hybrid to the appropriate overload of `operator()` in the *sorter implementation*. You only need to add a small SFINAE guard to disambiguate between comparison and projection functions: @@ -245,9 +245,9 @@ The general rules for *projection sorters* are really close to the ones for *com **Rule 4.2:** a sorter can be both a *comparison sorter* and a *projection sorter* at once. Such a sorter shall also obey all the rules defined for *sorters*, for *comparison sorters* and for *projection sorters*. -**Rule 4.3:** for any *projection sorter* called with a specific projection function, [`std::is_sorted`](https://en.cppreference.com/w/cpp/algorithm/is_sorted) called with `std::less<>` and the same projection function on the resulting collection shall return `true`. If the *projection sorter* is also a *comparison sorter*, for any such sorter called with a specific pair of comparison and projection function, `std::is_sorted` called with the same pair of functions on the resulting collection shall return `true`. +**Rule 4.3:** for any *projection sorter* called with a specific projection function, [`std::is_sorted`][std-is-sorted] called with `std::less<>` and the same projection function on the resulting collection shall return `true`. If the *projection sorter* is also a *comparison sorter*, for any such sorter called with a specific pair of comparison and projection function, `std::is_sorted` called with the same pair of functions on the resulting collection shall return `true`. -**Rule 4.4:** calling a *projection sorter* with [`utility::identity`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects) or without a projection function shall be strictly equivalent: calling `std::is_sorted` without a comparison function and without a projection function on the resulting collection shall return `true`. If the *projection sorter* is also a *comparison sorter*, calling such a sorter with any valid combination of `std::less<>` and `utility::identity`, and calling it without any additional function should be strictly equivalent. +**Rule 4.4:** calling a *projection sorter* with [`utility::identity`][utility-identity] or without a projection function shall be strictly equivalent: calling `std::is_sorted` without a comparison function and without a projection function on the resulting collection shall return `true`. If the *projection sorter* is also a *comparison sorter*, calling such a sorter with any valid combination of `std::less<>` and `utility::identity`, and calling it without any additional function should be strictly equivalent. **Rule 4.5:** a *projection sorter* which can be called with a collection and a projection function shall also be callable with two corresponding iterators and the same projection function. If the *projection sorter* is also a *comparison sorter*, it shall also be callable with an iterable, a comparison function and a projection function. @@ -257,7 +257,7 @@ The general rules for *projection sorters* are really close to the ones for *com ## Non-comparison sorters -While most of the well-known sorting algorithms handle user-provided comparison functions, some do not. It might be for several reasons: the sorter might wrap an algorithm that does not support such custom comparisons, or the algorithm may simply not be based on comparison (*e.g.* [radix sort](https://en.wikipedia.org/wiki/Radix_sort)). Let's assume that we have got our hands on a `counting_sort` function, implementing a [counting sort](https://en.wikipedia.org/wiki/Counting_sort) algorithm. We can trivially write a *sorter implementation* to wrap it: +While most of the well-known sorting algorithms handle user-provided comparison functions, some do not. It might be for several reasons: the sorter might wrap an algorithm that does not support such custom comparisons, or the algorithm may simply not be based on comparison (*e.g.* [radix sort][radix-sort]). Let's assume that we have got our hands on a `counting_sort` function, implementing a [counting sort][counting-sort] algorithm. We can trivially write a *sorter implementation* to wrap it: ```cpp struct counting_sorter_impl @@ -307,7 +307,7 @@ struct counting_sorter_impl }; ``` -With such an implementation, this sorter satisfies the *comparison sorter* concept when given an instance of `std::greater<>` without breaking any of the rules defined in the previous sections. Now it may seem a bit unfair for `std::less<>`... but actually [`sorter_facade`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-facade) automagically generates several `operator()` overloads taking `std::less<>` when the provided *sorter implementation* doesn't handle it natively. Note that even though this section is about non-comparison sorters, the same applies to non-projection sorters (you could provide a specific overload for [`std::negate<>`](https://en.cppreference.com/w/cpp/utility/functional/negate_void) for a descending sort too), and `sorter_facade` would provide equivalent `operator()` overloads taking [`utility::identity`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects) for *sorter implementations* that cannot handle it natively). +With such an implementation, this sorter satisfies the *comparison sorter* concept when given an instance of `std::greater<>` without breaking any of the rules defined in the previous sections. Now it may seem a bit unfair for `std::less<>`... but actually [`sorter_facade`][sorter-facade] automagically generates several `operator()` overloads taking `std::less<>` when the provided *sorter implementation* doesn't handle it natively. Note that even though this section is about non-comparison sorters, the same applies to non-projection sorters (you could provide a specific overload for [`std::negate<>`][std-negate-void] for a descending sort too), and `sorter_facade` would provide equivalent `operator()` overloads taking [`utility::identity`][utility-identity] for *sorter implementations* that cannot handle it natively). The most beautiful thing in my opinion is that no new rule is needed to support that model. All the rules previously defined guarantee that these specific overloads using standard function object as tags work. The only advice I can give is to try to use the most standard function objects as tags, or at least the ones that are the most likely to be used for the specific task. Since **cpp-sort** is heavily based on modern C++ features, it is designed to only work with the `void` specializations of the standard function objects from ``. @@ -347,7 +347,7 @@ struct counting_sorter_impl }; ``` -Using such a soft error mechanism instead of a hard one will make it possible to use this sorter together with [`hybrid_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#hybrid_adapter) (as long as the sorter provides a valid `iterator_category`) so that it can fall back to another sorter when a collection not handled by `counting_sorter` is given to the resulting sorter: +Using such a soft error mechanism instead of a hard one will make it possible to use this sorter together with [`hybrid_adapter`][hybrid-adapter] (as long as the sorter provides a valid `iterator_category`) so that it can fall back to another sorter when a collection not handled by `counting_sorter` is given to the resulting sorter: ```cpp // This sorter will use couting_sorter if a random-access collection of @@ -362,19 +362,19 @@ using generic_sorter = cppsort::hybrid_adapter< Note that the aggregate above plays well: `counting_sorter` sorter will be called if `generic_sorter` is given a collection of integers and either `std::less<>`, `std::greater<>` or no comparison function at all. `cppsort::merge_sorter` will only be called if `counting_sorter` really has no means to sort the collection. -While type-specific sorters are, by their very nature, unable to generically handle comparison functions, it might be possible for some of them to handle projections. A simple `counting_sorter` can't handle them because it "discards" the original information and recreates integer values laters, but other sorters such as [`spread_sorter`](https://github.com/Morwenn/cpp-sort/wiki/Sorters#spread_sorter) keep the original items around. Typically, a projection-enhanced type-specific sorter will be able to handle collections of any type provided the projection function projects the items to a type originally handled by the sorter (*e.g.* `spread_sorter` handles any type projected to an integer, a floating point number or an `std::string`). +While type-specific sorters are, by their very nature, unable to generically handle comparison functions, it might be possible for some of them to handle projections. A simple `counting_sorter` can't handle them because it "discards" the original information and recreates integer values laters, but other sorters such as [`spread_sorter`][spread-sorter] keep the original items around. Typically, a projection-enhanced type-specific sorter will be able to handle collections of any type provided the projection function projects the items to a type originally handled by the sorter (*e.g.* `spread_sorter` handles any type projected to an integer, a floating point number or an `std::string`). **Rule 5.1:** a *type-specific sorter*'s `operator()` shall use SFINAE instead of hard errors to avoid being considered during overload resolution when the value type of the collection to sort is not compatible. ## Stability -A sorting algorithm is said to be [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability) if it preserves the relative order of equivalent elements. **cpp-sort** documents the stability of every sorter by giving them an `is_always_stable` type aliasing a boolean specialization of `std::integer_constant`. This information should be accessed via [`sorter_traits`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#sorter_traits) or via the more specific [`is_always_stable`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#is_always_stable) type alias. The stability of a sorter is always either [`std::true_type`](https://en.cppreference.com/w/cpp/types/integral_constant) or `std::false_type`. +A sorting algorithm is said to be [stable][stability] if it preserves the relative order of equivalent elements. **cpp-sort** documents the stability of every sorter by giving them an `is_always_stable` type aliasing a boolean specialization of `std::integer_constant`. This information should be accessed via [`sorter_traits`][sorter-traits] or via the more specific [`is_always_stable`][is-always-stable] trait. The stability of a sorter is always either [`std::true_type` or `std::false_type`][std-integral-constant]. ```cpp using stability = cppsort::is_always_stable; ``` -The library contains a *sorter adapter* named [`stable_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#stable_adapter) that can be used to obtain a stable sorter, no matter which sorter it is given. If the *adapted sorter* `Sorter` is guaranteed to always be stable (if it defines `is_always_stable` as `std::true_type`), then `stable_sorter` will use it directly, otherwise it will use `make_stable`, where `make_stable` is a sorter adapter that uses the starting position of the elements in the collection to sort to make the *adapted sorter* stable. This mechanism only works if the *adapted sorter* is able to handle *proxy iterators*. +The library contains a *sorter adapter* named [`stable_adapter`][stable-adapter] that can be used to obtain a stable sorter, no matter which sorter it is given. If the *adapted sorter* `Sorter` is guaranteed to always be stable (if it defines `is_always_stable` as `std::true_type`), then `stable_sorter` will use it directly, otherwise it will use `make_stable`, where `make_stable` is a sorter adapter that uses the starting position of the elements in the collection to sort to make the *adapted sorter* stable. This mechanism only works if the *adapted sorter* is able to handle *proxy iterators*. Users are allowed to explicitly specialize `stable_adapter` to provide a stable sorter related to the original sorter. For example, if we have a `stable_selection_sorter` wrapping a stable selection sort algorithm, we can specialize `selection_sorter` as follows: @@ -388,7 +388,7 @@ namespace cppsort } ``` -The library also contains another stability-related type trait, [`is_stable`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#is_stable), which tells whether a *sorter* is stable when called with a specific set of parameters. It doesn't make a difference for *sorters* alone, but become incredibly useful to predict whether a call to an *adapted sorter* is stable or not. This trait is specialized for the library's *sorter adapters* and used by [`stable_adapter`]. When not specialized, it uses a *sorter*'s `is_always_stable` property as the stability of every call. +The library also contains another stability-related type trait, [`is_stable`][is-stable], which tells whether a *sorter* is stable when called with a specific set of parameters. It doesn't make a difference for *sorters* alone, but become incredibly useful to predict whether a call to an *adapted sorter* is stable or not. This trait is specialized for the library's *sorter adapters* and used by [`stable_adapter`][stable-adapter]. When not specialized, it uses a *sorter*'s `is_always_stable` property as the stability of every call. **Rule 6.1:** to document the *stability* of a *sorter*, it shall be given an `is_always_stable` type aliasing either `std::true_type` or `std::false_type`. If the sorter can't be altered, `sorter_traits` shall be specialized instead. @@ -420,15 +420,15 @@ There are no specific rules to differentiate the way *stateful* and *stateless s ## Buffered sorters -Some sorting algorithms can take advantage of buffers of any size to improve their performance, generally to perform merge operations. However, depending on many parameters not known to a sorter's implementer, the best method used to get a buffer of reasonable size might not always be the same. To avoid this problem (and to avoid the duplication of similar algorithms), **cpp-sort** provides some tools to specify the way a buffer is allocated. Let's take a simple example: [SqrtSort](https://github.com/Mrrl/SqrtSort) is apparently a [GrailSort](https://github.com/Mrrl/GrailSort) whose exchange buffer has a size roughly equal to the square root of the size of the collection to sort. While these algorithms are presented as separate algorithms, one can simply pass a *buffer provider* template parameter to a [`grail_sorter`][grail-sorter] and use it to define define `sqrt_sorter`: +Some sorting algorithms can take advantage of buffers of any size to improve their performance, generally to perform merge operations. However, depending on many parameters not known to a sorter's implementer, the best method used to get a buffer of reasonable size might not always be the same. To avoid this problem (and to avoid the duplication of similar algorithms), **cpp-sort** provides some tools to specify the way a buffer is allocated. Let's take a simple example: [SqrtSort][sqrtsort] is apparently a [GrailSort][grailsort] whose exchange buffer has a size roughly equal to the square root of the size of the collection to sort. While these algorithms are presented as separate algorithms, one can simply pass a *buffer provider* template parameter to a [`grail_sorter`][grail-sorter] and use it to define `sqrt_sorter`: ```cpp using sqrt_sorter = grail_sorter>; ``` -In this example, `dynamic_buffer` is one of the [*buffer providers*](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#buffer-providers) that come with the library. A *buffer provider* is a class that describes how the buffer should be allocated; it has a nested class template `buffer` that actually contains the allocated memory. While `sqrt_sorter` is a regular sorter, [`grail_sorter`][grail-sorter] is a *buffered sorter*. +In this example, `dynamic_buffer` is one of the [*buffer providers*][buffer-providers] that come with the library. A *buffer provider* is a class that describes how the buffer should be allocated; it has a nested class template `buffer` that actually contains the allocated memory. While `sqrt_sorter` is a regular sorter, [`grail_sorter`][grail-sorter] is a *buffered sorter*. -The library's `dynamic_buffer` takes what is called a *size policy*: this is a class with an overloaded `operator()` taking an instance of `std::size_t` and returning an instance of a type convertible to `std::size_t`. The library provides [some function objects](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects) that can be used as size policies. It also provides a `fixed_buffer` which takes an `std::size_t` template parameter corresponding to the number of elements to allocate on the stack for the buffer. For example, [`wiki_sorter`][wiki-sorter] uses a fixed-size buffer of 512 elements unless told otherwise: +The library's `dynamic_buffer` takes what is called a *size policy*: this is a class with an overloaded `operator()` taking an instance of `std::size_t` and returning an instance of a type convertible to `std::size_t`. The library provides [some function objects][utility-function-objects] that can be used as size policies. It also provides a `fixed_buffer` which takes an `std::size_t` template parameter corresponding to the number of elements to allocate on the stack for the buffer. For example, [`wiki_sorter`][wiki-sorter] uses a fixed-size buffer of 512 elements unless told otherwise: ```cpp template< @@ -447,7 +447,7 @@ struct wiki_sorter; ## Fixed-size sorters -Sorters are generally designed to sort collections of arbitrary size. However, **cpp-sort** also includes [*fixed-size sorters*](https://github.com/Morwenn/cpp-sort/wiki/Fixed-size-sorters), especially designed to sort a fixed number of values. Among other things, those algorithms include [sorting networks](https://en.wikipedia.org/wiki/Sorting_network) and sorting algorithms designed to perform a minimal number of move or comparison operations. They mainly exist to sort small fixed-size arrays, when the sorting operation appears in a critical section of the code and needs to be as fast as possible. +Sorters are generally designed to sort collections of arbitrary size. However, **cpp-sort** also includes [*fixed-size sorters*][fixed-size-sorters], especially designed to sort a fixed number of values. Among other things, those algorithms include [sorting networks][sorting-networks] and sorting algorithms designed to perform a minimal number of move or comparison operations. They mainly exist to sort small fixed-size arrays, when the sorting operation appears in a critical section of the code and needs to be as fast as possible. A *fixed-size sorter* is not a sorter *per se*: it's a class template taking an `std::size_t` template parameter corresponding to the number of values to sort. Every specialization of such a template is an actual sorter, which obeys all the rules defined in the previous sections as long as the collection to sort has the right size. Let's have a look at what a `low_projections_sorter` - a fixed-size sorter designed to perform a minimal number of projections - may look like: @@ -511,7 +511,7 @@ struct low_projections_sorter_impl<2u> }; ``` -We won't show other specializations here because it is rather tedious and takes some place in the tutorial, but the idea is clear: any valid specialization can be a full-fledged sorter when used properly and can also be both a *comparison sorter* and a *projection sorter* if needed. It might be interesting to know which specializations of a fixed-size sorter can be used; in order to provide this information and some more, one has to specialize the trait class template [`fixed_sorter_traits`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#fixed_sorter_traits): +We won't show other specializations here because it is rather tedious and takes some place in the tutorial, but the idea is clear: any valid specialization can be a full-fledged sorter when used properly and can also be both a *comparison sorter* and a *projection sorter* if needed. It might be interesting to know which specializations of a fixed-size sorter can be used; in order to provide this information and some more, one has to specialize the trait class template [`fixed_sorter_traits`][fixed-sorter-traits]: ```cpp namespace cppsort @@ -533,7 +533,7 @@ namespace cppsort If `domain` does not exist in the `fixed_sorter_traits` specialization, it means that every specialization of the fixed-size sorter is a valid sorter. -Using the specializations of a fixed-size sorter by hand is not the sweetest thing either; that is why the library provides the fixed-size sorter adapter [`small_array_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#small_array_adapter) which takes a whole *fixed-size sorter* and almost transforms it into a sorter (the resulting class doesn't handle pairs of iterators). The resulting object, when given an instance of [`std::array`](https://en.cppreference.com/w/cpp/container/array) or a fixed-size C array, will sort it in-place with the specialization corresponding to the size of the passed array. To transform that into a full sorter able to handle anything, one needs to aggregate it with another sorter into a `hybrid_adapter`: +Using the specializations of a fixed-size sorter by hand is not the sweetest thing either; that is why the library provides the fixed-size sorter adapter [`small_array_adapter`][small-array-adapter] which takes a whole *fixed-size sorter* and almost transforms it into a sorter (the resulting class doesn't handle pairs of iterators). The resulting object, when given an instance of [`std::array`][std-array] or a fixed-size C array, will sort it in-place with the specialization corresponding to the size of the passed array. To transform that into a full sorter able to handle anything, one needs to aggregate it with another sorter into a `hybrid_adapter`: ```cpp using sorter = cppsort::hybrid_adapter< @@ -545,7 +545,7 @@ using sorter = cppsort::hybrid_adapter< >; ``` -In the example above, the resulting sorter will use our `low_projections_sorter` when given an `std::array` or a fixed-size C array of size less than 5, and fall back to [`verge_sorter`](https://github.com/Morwenn/cpp-sort/wiki/Sorters#verge_sorter) when given any other collection or a pair of iterators. +In the example above, the resulting sorter will use our `low_projections_sorter` when given an `std::array` or a fixed-size C array of size less than 5, and fall back to [`verge_sorter`][verge-sorter] when given any other collection or a pair of iterators. **Rule 8.1:** a *fixed-size sorter* is allowed but not required to work with fixed arrays of any size. @@ -554,5 +554,45 @@ In the example above, the resulting sorter will use our `low_projections_sorter` **Rule 8.3:** a *fixed-size sorter* shall specialize the class `cppsort::fixed_sorter_traits` if it needs to provide information about its domain, its iterator category or its stability. See the exact meaning of these types and how to define them in the dedicated part of the documentation. - [grail-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Sorters#grail_sorter - [wiki-sorter]: https://github.com/Morwenn/cpp-sort/wiki/Sorters#wiki_sorter + [buffer-providers]: Miscellaneous-utilities.md#buffer-providers + [comparison-sort]: https://en.wikipedia.org/wiki/Comparison_sort + [counting-sort]: https://en.wikipedia.org/wiki/Counting_sort + [fixed-size-sorters]: Fixed-size-sorters.md + [fixed-sorter-traits]: Sorter-traits.md#fixed_sorter_traits + [grailsort]: https://github.com/Mrrl/GrailSort + [grail-sorter]: Sorters.md#grail_sorter + [hybrid-adapter]: Sorter-adapters.md#hybrid_adapter + [is-always-stable]: Sorter-traits.md#is_always_stable + [is-projection]: Sorter-traits.md#is_projection-and-is_projection_iterator + [is-stable]: Sorter-traits.md#is_stable + [library-nomenclature]: Library-nomenclature.md + [radix-sort]: https://en.wikipedia.org/wiki/Radix_sort + [rebind-iterator-category]: Sorter-traits.md#rebind_iterator_category + [schwartz-adapter]: Sorter-adapters.md#schwartz_adapter + [selection-sort]: https://en.wikipedia.org/wiki/Selection_sort + [small-array-adapter]: Sorter-adapters.md#small_array_adapter + [sorter-facade]: Sorter-facade.md + [sorter-traits]: Sorter-traits.md#sorter_traits + [sorting-networks]: https://en.wikipedia.org/wiki/Sorting_network + [spread-sorter]: Sorters.md#spread_sorter + [sqrtsort]: https://github.com/Mrrl/SqrtSort + [stability]: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability + [stable-adapter]: Sorter-adapters.md#stable_adapter-make_stable-and-stable_t + [static-const]: Miscellaneous-utilities.md#static_const + [std-array]: https://en.cppreference.com/w/cpp/container/array + [std-greater-void]: https://en.cppreference.com/w/cpp/utility/functional/greater_void + [std-identity]: https://en.cppreference.com/w/cpp/utility/functional/identity + [std-integral-constant]: https://en.cppreference.com/w/cpp/types/integral_constant + [std-is-sorted]: https://en.cppreference.com/w/cpp/algorithm/is_sorted + [std-iterators]: https://en.cppreference.com/w/cpp/iterator + [std-iterator-tags]: https://en.cppreference.com/w/cpp/iterator/iterator_tags + [std-less-void]: https://en.cppreference.com/w/cpp/utility/functional/less_void + [std-negate-void]: https://en.cppreference.com/w/cpp/utility/functional/negate_void + [std-sort]: https://en.cppreference.com/w/cpp/algorithm/sort + [stlab]: https://stlab.adobe.com/ + [utility-as-function]: Miscellaneous-utilities.md#as_function + [utility-function-objects]: Miscellaneous-utilities.md#miscellaneous-function-objects + [utility-identity]: Miscellaneous-utilities.md#miscellaneous-function-objects + [verge-sorter]: Sorters.md#verge_sorter + [wiki-sorter]: Sorters.md#wiki_sorter + [writing-a-bubble-sorter]: Writing-a-bubble_sorter.md diff --git a/docs/_Sidebar.md b/docs/_Sidebar.md index 6f906b78..efdea090 100644 --- a/docs/_Sidebar.md +++ b/docs/_Sidebar.md @@ -1,23 +1,24 @@ -* [[Home]] +* [Home](Home.md) * Sorting library - * [[Library nomenclature]] - * [[Sorting functions]] - * [[Sorters]] - * [[Fixed-size sorters]] - * [[Sorter adapters]] - * [[Sorter facade]] - * [[Sorter traits]] - * [[Measures of presortedness]] -* [[Comparators and projections]] - * [[Comparators]] - * [[Chainable projections]] - * [[Refined functions]] -* [[Miscellaneous utilities]] + * [Library nomenclature](Library-nomenclature.md) + * [Sorting functions](Sorting-functions.md) + * [Sorters](Sorters.md) + * [Fixed-size sorters](Fixed-size-sorters.md) + * [Sorter adapters](Sorter-adapters.md) + * [Sorter facade](Sorter-facade.md) + * [Sorter traits](Sorter-traits.md) + * [Measures of presortedness](Measures-of-presortedness.md) +* [Comparators and projections](Comparators-and-projections.md) + * [Comparators](Comparators.md) + * [Comparator adapters](Comparator-adapters.md) + * [Chainable projections](Chainable-projections.md) + * [Refined functions](Refined-functions.md) +* [Miscellaneous utilities](Miscellaneous-utilities.md) * Tutorials - * [[Writing a sorter]] - * [Writing a `bubble_sorter`](https://github.com/Morwenn/cpp-sort/wiki/writing-a-bubble_sorter) - * [[Writing a container-aware algorithm]] -* [[Tooling]] -* [[Benchmarks]] -* [[Changelog]] -* [[Original research]] + * [Writing a sorter](Writing-a-sorter.md) + * [Writing a `bubble_sorter`](Writing-a-bubble_sorter.md) + * [Writing a container-aware algorithm](Writing-a-container-aware-algorithm.md) +* [Tooling](Tooling.md) +* [Benchmarks](Benchmarks.md) +* [Changelog](Changelog.md) +* [Original research](Original-research.md) diff --git a/docs/images/cpp-sort-logo.svg b/docs/images/cpp-sort-logo.svg new file mode 100644 index 00000000..47bb4d67 --- /dev/null +++ b/docs/images/cpp-sort-logo.svg @@ -0,0 +1,312 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cpp-sort + + + + + + + + + + + + + + + diff --git a/include/cpp-sort/adapters/indirect_adapter.h b/include/cpp-sort/adapters/indirect_adapter.h index 3cc03a5f..c7714e6c 100644 --- a/include/cpp-sort/adapters/indirect_adapter.h +++ b/include/cpp-sort/adapters/indirect_adapter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2021 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_ADAPTERS_INDIRECT_ADAPTER_H_ @@ -39,7 +39,9 @@ namespace cppsort ForwardIterator first, ForwardIterator last, difference_type_t size, Compare compare, Projection projection) - -> decltype(auto) + -> decltype(cppsort::detail::indiesort(std::forward(sorter), + first, last, size, + std::move(compare), std::move(projection))) { return cppsort::detail::indiesort(std::forward(sorter), first, last, size, @@ -51,7 +53,21 @@ namespace cppsort RandomAccessIterator first, RandomAccessIterator last, difference_type_t size, Compare compare, Projection projection) - -> decltype(auto) +#ifdef __cpp_lib_uncaught_exceptions + -> decltype(std::forward(sorter)( + (RandomAccessIterator*)0, (RandomAccessIterator*)0, + std::move(compare), indirect(projection) + )) +#else + -> std::enable_if_t< + has_comparison_projection_sort_iterator< + Sorter, + RandomAccessIterator*, + Compare, + indirect_t + >::value + > +#endif { using utility::iter_move; @@ -142,7 +158,11 @@ namespace cppsort > auto operator()(ForwardIterable&& iterable, Compare compare={}, Projection projection={}) const - -> decltype(auto) + -> decltype(sort_indirectly(iterator_category_t>{}, + this->get(), + std::begin(iterable), std::end(iterable), + cppsort::utility::size(iterable), + std::move(compare), std::move(projection))) { auto size = cppsort::utility::size(iterable); return sort_indirectly(iterator_category_t>{}, @@ -161,7 +181,10 @@ namespace cppsort > auto operator()(ForwardIterator first, ForwardIterator last, Compare compare={}, Projection projection={}) const - -> decltype(auto) + -> decltype(sort_indirectly(iterator_category_t{}, + this->get(), first, last, + std::distance(first, last), + std::move(compare), std::move(projection))) { auto size = std::distance(first, last); return sort_indirectly(iterator_category_t{}, diff --git a/include/cpp-sort/comparators/flip.h b/include/cpp-sort/comparators/flip.h new file mode 100644 index 00000000..f62f908b --- /dev/null +++ b/include/cpp-sort/comparators/flip.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2021-2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#ifndef CPPSORT_COMPARATORS_FLIP_H_ +#define CPPSORT_COMPARATORS_FLIP_H_ + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include "../detail/raw_checkers.h" + +namespace cppsort +{ + template + struct not_fn_t; + template + class projection_compare; + + //////////////////////////////////////////////////////////// + // flip_t + + template + struct flip_t: + detail::raw_check_is_transparent + { + private: + + F func; + + public: + + //////////////////////////////////////////////////////////// + // Construction + + flip_t() = default; + + explicit constexpr flip_t(const F& func): + func(func) + {} + + explicit constexpr flip_t(F&& func): + func(std::move(func)) + {} + + //////////////////////////////////////////////////////////// + // Call + + template + constexpr auto operator()(T1&& x, T2&& y) & + noexcept(noexcept(utility::as_function(func)(std::forward(y), std::forward(x)))) + -> decltype(utility::as_function(func)(std::forward(y), std::forward(x))) + { + return utility::as_function(func)(std::forward(y), std::forward(x)); + } + + template + constexpr auto operator()(T1&& x, T2&& y) const& + noexcept(noexcept(utility::as_function(func)(std::forward(y), std::forward(x)))) + -> decltype(utility::as_function(func)(std::forward(y), std::forward(x))) + { + return utility::as_function(func)(std::forward(y), std::forward(x)); + } + + template + constexpr auto operator()(T1&& x, T2&& y) && + noexcept(noexcept(utility::as_function(std::move(func))(std::forward(y), std::forward(x)))) + -> decltype(utility::as_function(std::move(func))(std::forward(y), std::forward(x))) + { + return utility::as_function(std::move(func))(std::forward(y), std::forward(x)); + } + + template + constexpr auto operator()(T1&& x, T2&& y) const&& + noexcept(noexcept(utility::as_function(std::move(func))(std::forward(y), std::forward(x)))) + -> decltype(utility::as_function(std::move(func))(std::forward(y), std::forward(x))) + { + return utility::as_function(std::move(func))(std::forward(y), std::forward(x)); + } + + //////////////////////////////////////////////////////////// + // Accessor + + constexpr auto base() const + -> F + { + return func; + } + }; + + //////////////////////////////////////////////////////////// + // Helper for flip_t construction + + namespace detail + { + template + struct flip_impl + { + using type = flip_t; + + static constexpr auto construct(const F& func) + -> type + { + return type(func); + } + + static constexpr auto construct(F&& func) + -> type + { + return type(std::move(func)); + } + }; + + template + struct flip_impl> + { + using type = F; + + static constexpr auto construct(const flip_t& func) + -> type + { + return func.base(); + } + + static constexpr auto construct(flip_t&& func) + -> type + { + return std::move(func).base(); + } + }; + + template + struct flip_impl>> + { + using type = not_fn_t; + + static constexpr auto construct(const not_fn_t>& func) + -> type + { + return type(func.base().base()); + } + + static constexpr auto construct(not_fn_t>&& func) + -> type + { + return type(std::move(func).base().base()); + } + }; + + template + struct flip_impl> + { + using type = projection_compare< + typename detail::flip_impl::type, F2 + >; + + static constexpr auto construct(const projection_compare& func) + -> type + { + return type( + detail::flip_impl::construct(func.comparison()), + func.projection() + ); + } + + static constexpr auto construct(projection_compare&& func) + -> type + { + return type( + detail::flip_impl::construct(std::move(func.comparison())), + std::move(func.projection()) + ); + } + }; + } + + //////////////////////////////////////////////////////////// + // flip + // + // Name taken from Haskell flip function from the Prelude + // module: it takes a binary Callable and returns another + // Callable with its arguments flipped. + + template + constexpr auto flip(F&& func) + -> typename detail::flip_impl>::type + { + return detail::flip_impl>::construct(std::forward(func)); + } + + //////////////////////////////////////////////////////////// + // Branchless traits + + namespace utility + { + template + struct is_probably_branchless_comparison, T>: + is_probably_branchless_comparison + {}; + } +} + +#endif // CPPSORT_COMPARATORS_FLIP_H_ diff --git a/include/cpp-sort/comparators/not_fn.h b/include/cpp-sort/comparators/not_fn.h new file mode 100644 index 00000000..1baa2da9 --- /dev/null +++ b/include/cpp-sort/comparators/not_fn.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2021-2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#ifndef CPPSORT_COMPARATORS_NOT_FN_H_ +#define CPPSORT_COMPARATORS_NOT_FN_H_ + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include "../detail/raw_checkers.h" + +namespace cppsort +{ + template + struct flip_t; + template + class projection_compare; + + //////////////////////////////////////////////////////////// + // not_fn_t + + template + struct not_fn_t: + detail::raw_check_is_transparent + { + private: + + F func; + + public: + + //////////////////////////////////////////////////////////// + // Construction + + not_fn_t() = default; + + explicit constexpr not_fn_t(const F& func): + func(func) + {} + + explicit constexpr not_fn_t(F&& func): + func(std::move(func)) + {} + + //////////////////////////////////////////////////////////// + // Call + + template + constexpr auto operator()(Args&&... args) & + noexcept(noexcept(not utility::as_function(func)(std::forward(args)...))) + -> decltype(not utility::as_function(func)(std::forward(args)...)) + { + return not utility::as_function(func)(std::forward(args)...); + } + + template + constexpr auto operator()(Args&&... args) const& + noexcept(noexcept(not utility::as_function(func)(std::forward(args)...))) + -> decltype(not utility::as_function(func)(std::forward(args)...)) + { + return not utility::as_function(func)(std::forward(args)...); + } + + template + constexpr auto operator()(Args&&... args) && + noexcept(noexcept(not utility::as_function(std::move(func))(std::forward(args)...))) + -> decltype(not utility::as_function(std::move(func))(std::forward(args)...)) + { + return not utility::as_function(std::move(func))(std::forward(args)...); + } + + template + constexpr auto operator()(Args&&... args) const&& + noexcept(noexcept(not utility::as_function(std::move(func))(std::forward(args)...))) + -> decltype(not utility::as_function(std::move(func))(std::forward(args)...)) + { + return not utility::as_function(std::move(func))(std::forward(args)...); + } + + //////////////////////////////////////////////////////////// + // Accessor + + constexpr auto base() const + -> F + { + return func; + } + }; + + //////////////////////////////////////////////////////////// + // Helper for not_fn_t construction + + namespace detail + { + template + struct not_fn_impl + { + using type = not_fn_t; + + static constexpr auto construct(const F& func) + -> type + { + return type(func); + } + + static constexpr auto construct(F&& func) + -> type + { + return type(std::move(func)); + } + }; + + template + struct not_fn_impl> + { + using type = F; + + static constexpr auto construct(const not_fn_t& func) + -> type + { + return func.base(); + } + + static constexpr auto construct(not_fn_t&& func) + -> type + { + return std::move(func).base(); + } + }; + + template + struct not_fn_impl>> + { + using type = flip_t; + + static constexpr auto construct(const flip_t>& func) + -> type + { + return type(func.base().base()); + } + + static constexpr auto construct(flip_t>&& func) + -> type + { + return type(std::move(func).base().base()); + } + }; + + template + struct not_fn_impl> + { + using type = projection_compare< + typename detail::not_fn_impl::type, F2 + >; + + static constexpr auto construct(const projection_compare& func) + -> type + { + return type( + detail::not_fn_impl::construct(func.comparison()), + func.projection() + ); + } + + static constexpr auto construct(projection_compare&& func) + -> type + { + return type( + detail::not_fn_impl::construct(std::move(func.comparison())), + std::move(func.projection()) + ); + } + }; + } + + //////////////////////////////////////////////////////////// + // C++17 std::not_fn equivalent + + template + constexpr auto not_fn(F&& func) + -> typename detail::not_fn_impl>::type + { + return detail::not_fn_impl>::construct(std::forward(func)); + } +} + +#endif // CPPSORT_COMPARATORS_NOT_FN_H_ diff --git a/include/cpp-sort/comparators/projection_compare.h b/include/cpp-sort/comparators/projection_compare.h index 63113cb0..219282a5 100644 --- a/include/cpp-sort/comparators/projection_compare.h +++ b/include/cpp-sort/comparators/projection_compare.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_COMPARATORS_PROJECTION_COMPARE_H_ @@ -12,59 +12,176 @@ #include #include #include +#include +#include "../detail/config.h" +#include "../detail/raw_checkers.h" #include "../detail/type_traits.h" namespace cppsort { template - class projection_compare + class projection_compare: + public detail::raw_check_is_transparent { private: - using compare_t = detail::remove_cvref_t< - decltype(utility::as_function(std::declval())) - >; - using projection_t = detail::remove_cvref_t< - decltype(utility::as_function(std::declval())) - >; - std::tuple data; + std::tuple data; public: + projection_compare() = default; + projection_compare(Compare compare, Projection projection): - data(utility::as_function(compare), utility::as_function(projection)) + data(std::move(compare), std::move(projection)) {} - template - constexpr auto operator()(T&& lhs, U&& rhs) - noexcept(noexcept(std::get<0>(data)(std::get<1>(data)(std::forward(lhs)), - std::get<1>(data)(std::forward(rhs))))) - -> decltype(std::get<0>(data)(std::get<1>(data)(std::forward(lhs)), - std::get<1>(data)(std::forward(rhs)))) + template + constexpr auto operator()(T1&& x, T2&& y) & + noexcept(noexcept(utility::as_function(std::get<0>(data))( + utility::as_function(std::get<1>(data))(std::forward(x)), + utility::as_function(std::get<1>(data))(std::forward(y)) + ))) + -> decltype(utility::as_function(std::get<0>(data))( + utility::as_function(std::get<1>(data))(std::forward(x)), + utility::as_function(std::get<1>(data))(std::forward(y)) + )) + { + auto&& comp = utility::as_function(std::get<0>(data)); + auto&& proj = utility::as_function(std::get<1>(data)); + return comp(proj(std::forward(x)), proj(std::forward(y))); + } + + template + constexpr auto operator()(T1&& x, T2&& y) const& + noexcept(noexcept(utility::as_function(std::get<0>(data))( + utility::as_function(std::get<1>(data))(std::forward(x)), + utility::as_function(std::get<1>(data))(std::forward(y)) + ))) + -> decltype(utility::as_function(std::get<0>(data))( + utility::as_function(std::get<1>(data))(std::forward(x)), + utility::as_function(std::get<1>(data))(std::forward(y)) + )) + { + auto&& comp = utility::as_function(std::get<0>(data)); + auto&& proj = utility::as_function(std::get<1>(data)); + return comp(proj(std::forward(x)), proj(std::forward(y))); + } + + template + constexpr auto operator()(T1&& x, T2&& y) && + noexcept(noexcept(utility::as_function(std::get<0>(data))( + utility::as_function(std::get<1>(data))(std::forward(x)), + utility::as_function(std::get<1>(data))(std::forward(y)) + ))) + -> decltype(utility::as_function(std::get<0>(data))( + utility::as_function(std::get<1>(data))(std::forward(x)), + utility::as_function(std::get<1>(data))(std::forward(y)) + )) + { + auto&& comp = utility::as_function(std::get<0>(data)); + auto&& proj = utility::as_function(std::get<1>(data)); + return comp(proj(std::forward(x)), proj(std::forward(y))); + } + + template + constexpr auto operator()(T1&& x, T2&& y) const&& + noexcept(noexcept(utility::as_function(std::get<0>(data))( + utility::as_function(std::get<1>(data))(std::forward(x)), + utility::as_function(std::get<1>(data))(std::forward(y)) + ))) + -> decltype(utility::as_function(std::get<0>(data))( + utility::as_function(std::get<1>(data))(std::forward(x)), + utility::as_function(std::get<1>(data))(std::forward(y)) + )) { - return std::get<0>(data)(std::get<1>(data)(std::forward(lhs)), - std::get<1>(data)(std::forward(rhs))); + auto&& comp = utility::as_function(std::get<0>(data)); + auto&& proj = utility::as_function(std::get<1>(data)); + return comp(proj(std::forward(x)), proj(std::forward(y))); } - template - constexpr auto operator()(T&& lhs, U&& rhs) const - noexcept(noexcept(std::get<0>(data)(std::get<1>(data)(std::forward(lhs)), - std::get<1>(data)(std::forward(rhs))))) - -> decltype(std::get<0>(data)(std::get<1>(data)(std::forward(lhs)), - std::get<1>(data)(std::forward(rhs)))) + //////////////////////////////////////////////////////////// + // Accessors + + constexpr auto comparison() const + -> Compare { - return std::get<0>(data)(std::get<1>(data)(std::forward(lhs)), - std::get<1>(data)(std::forward(rhs))); + return std::get<0>(data); } - using is_transparent = void; + constexpr auto projection() const + -> Projection + { + return std::get<1>(data); + } }; + //////////////////////////////////////////////////////////// + // Helper for projection_compare construction + + namespace detail + { + template + struct proj_comp_impl + { + using type = projection_compare; + + template + static constexpr auto construct(C&& comp, P&& proj) + -> type + { + return type(std::forward(comp), std::forward

(proj)); + } + }; + + template + struct proj_comp_impl + { + using type = Compare; + + static constexpr auto construct(const Compare& comp, const utility::identity&) + -> type + { + return comp; + } + + static constexpr auto construct(Compare&& comp, const utility::identity&) + -> type + { + return comp; + } + }; + +#if CPPSORT_STD_IDENTITY_AVAILABLE + template + struct proj_comp_impl + { + using type = Compare; + + static constexpr auto construct(const Compare& comp, const utility::identity&) + -> type + { + return comp; + } + + static constexpr auto construct(Compare&& comp, const utility::identity&) + -> type + { + return comp; + } + }; +#endif + } + + //////////////////////////////////////////////////////////// + // make_projection_compare + template - auto make_projection_compare(Compare compare, Projection projection) - -> projection_compare + constexpr auto make_projection_compare(Compare&& compare, Projection&& projection) + -> typename detail::proj_comp_impl, std::decay_t>::type { - return { std::move(compare), std::move(projection) }; + return detail::proj_comp_impl, std::decay_t>::construct( + std::forward(compare), std::forward(projection) + ); } namespace utility diff --git a/include/cpp-sort/detail/buffered_inplace_merge.h b/include/cpp-sort/detail/buffered_inplace_merge.h index 4037a305..a0ecb0c5 100644 --- a/include/cpp-sort/detail/buffered_inplace_merge.h +++ b/include/cpp-sort/detail/buffered_inplace_merge.h @@ -20,10 +20,10 @@ #include #include #include +#include #include #include #include "config.h" -#include "functional.h" #include "iterator_traits.h" #include "memory.h" #include "move.h" @@ -123,7 +123,7 @@ namespace detail half_inplace_merge(rv(ptr), rv(buff), rbi(middle), rbi(first), rbi(last), len2, - invert(compare), std::move(projection)); + cppsort::flip(compare), std::move(projection)); } } }} diff --git a/include/cpp-sort/detail/cartesian_tree_sort.h b/include/cpp-sort/detail/cartesian_tree_sort.h index a87ca939..7f41cfd4 100644 --- a/include/cpp-sort/detail/cartesian_tree_sort.h +++ b/include/cpp-sort/detail/cartesian_tree_sort.h @@ -12,10 +12,10 @@ #include #include #include +#include #include #include #include "../detail/heapsort.h" -#include "../detail/functional.h" #include "../detail/immovable_vector.h" #include "../detail/iterator_traits.h" #include "../detail/type_traits.h" @@ -153,7 +153,7 @@ namespace detail std::vector pq; // Priority queue pq.push_back(tree.root()); - auto&& comp = invert(compare); + auto&& comp = cppsort::flip(compare); auto proj_value = [proj=utility::as_function(projection)](auto* node) -> decltype(auto) { return proj(node->value); }; diff --git a/include/cpp-sort/detail/container_aware/mel_sort.h b/include/cpp-sort/detail/container_aware/mel_sort.h index f04b19d7..2b0b35c3 100644 --- a/include/cpp-sort/detail/container_aware/mel_sort.h +++ b/include/cpp-sort/detail/container_aware/mel_sort.h @@ -15,13 +15,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include "../functional.h" #include "../lower_bound.h" #include "../type_traits.h" @@ -54,7 +54,7 @@ namespace cppsort if (not comp(value, proj(last_list.back()))) { // Element belongs to the tails (bigger elements) auto insertion_point = detail::lower_bound( - lists.begin(), std::prev(lists.end()), value, invert(compare), + lists.begin(), std::prev(lists.end()), value, cppsort::flip(compare), [&proj](auto& list) -> decltype(auto) { return proj(list.back()); } ); insertion_point->splice(insertion_point->end(), collection, collection.begin()); @@ -141,7 +141,7 @@ namespace cppsort if (not comp(value, proj(*last_list.last))) { // Element belongs to the tails (bigger elements) auto insertion_point = detail::lower_bound( - lists.begin(), std::prev(lists.end()), value, invert(compare), + lists.begin(), std::prev(lists.end()), value, cppsort::flip(compare), [&proj](auto& list) -> decltype(auto) { return proj(*list.last); } ); insertion_point->list.splice_after(insertion_point->last, collection, diff --git a/include/cpp-sort/detail/functional.h b/include/cpp-sort/detail/functional.h index bc5bae08..7f4204d4 100644 --- a/include/cpp-sort/detail/functional.h +++ b/include/cpp-sort/detail/functional.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Morwenn + * Copyright (c) 2021-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_DETAIL_FUNCTIONAL_H_ @@ -11,101 +11,18 @@ #include #include #include -#include +#include namespace cppsort { namespace detail { - //////////////////////////////////////////////////////////// - // C++17 std::not_fn - - template - class not_fn_t - { - private: - - Predicate predicate; - - public: - - not_fn_t() = delete; - - explicit not_fn_t(Predicate predicate): - predicate(std::move(predicate)) - {} - - template - auto operator()(T1&& x, T2&& y) - -> bool - { - auto&& pred = utility::as_function(predicate); - return not pred(std::forward(x), std::forward(y)); - } - - template - auto operator()(T1&& x, T2&& y) const - -> bool - { - auto&& pred = utility::as_function(predicate); - return not pred(std::forward(x), std::forward(y)); - } - }; - - template - auto not_fn(Predicate&& pred) - -> not_fn_t> - { - return not_fn_t>(std::forward(pred)); - } - - //////////////////////////////////////////////////////////// - // invert - - template - class invert_t - { - private: - - Predicate predicate; - - public: - - invert_t() = delete; - - explicit invert_t(Predicate predicate): - predicate(std::move(predicate)) - {} - - template - auto operator()(T1&& x, T2&& y) - -> bool - { - auto&& pred = utility::as_function(predicate); - return pred(std::forward(y), std::forward(x)); - } - - template - auto operator()(T1&& x, T2&& y) const - -> bool - { - auto&& pred = utility::as_function(predicate); - return pred(std::forward(y), std::forward(x)); - } - }; - - template - auto invert(Predicate&& pred) - -> invert_t> - { - return invert_t>(std::forward(pred)); - } - //////////////////////////////////////////////////////////// // indirect template - class indirect_t + class indirect_t: + utility::projection_base { private: @@ -144,14 +61,4 @@ namespace detail } }} -namespace cppsort -{ -namespace utility -{ - template - struct is_probably_branchless_comparison, T>: - is_probably_branchless_comparison - {}; -}} - #endif // CPPSORT_DETAIL_FUNCTIONAL_H_ diff --git a/include/cpp-sort/detail/indiesort.h b/include/cpp-sort/detail/indiesort.h index e2d9aa5a..2192b284 100644 --- a/include/cpp-sort/detail/indiesort.h +++ b/include/cpp-sort/detail/indiesort.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2021 Morwenn + * Copyright (c) 2020-2022 Morwenn * SPDX-License-Identifier: MIT */ @@ -40,15 +40,15 @@ namespace cppsort { namespace detail { - template - struct pointer_index_tuple + template + struct it_and_index { - PointerType original_location; - SizeType original_index; + Iterator original_location; + difference_type_t original_index; - pointer_index_tuple() = default; + it_and_index() = default; - pointer_index_tuple(PointerType item, SizeType index) noexcept: + it_and_index(Iterator item, difference_type_t index) noexcept: original_location(item), original_index(index) {} @@ -58,17 +58,30 @@ namespace detail auto indiesort(Sorter&& sorter, ForwardIterator first, ForwardIterator last, difference_type_t size, Compare compare, Projection projection) - -> decltype(auto) +#ifdef __cpp_lib_uncaught_exceptions + -> decltype(std::forward(sorter)( + (it_and_index*)0, (it_and_index*)0, + std::move(compare), + &it_and_index::original_location | indirect(projection) + )) +#else + -> std::enable_if_t< + has_comparison_projection_sort_iterator< + Sorter, + it_and_index*, + Compare, + decltype(&it_and_index::original_location | indirect(projection)) + >::value + > +#endif { - using difference_type = difference_type_t; using utility::iter_move; - auto&& proj = utility::as_function(projection); - using item_index_tuple = pointer_index_tuple; + using item_index_tuple = it_and_index; immovable_vector storage(size); // Construct pointers to all elements in the sequence - difference_type index = 0; + difference_type_t index = 0; for (auto current_element = first; current_element != last; ++current_element) { storage.emplace_back(current_element, index); ++index; @@ -78,9 +91,7 @@ namespace detail // Sort the iterators on pointed values std::forward(sorter)( storage.begin(), storage.end(), std::move(compare), - [&proj](auto& elem) -> decltype(auto) { - return proj(*(elem.original_location)); - } + &item_index_tuple::original_location | indirect(projection) ); #else // Work around the sorters that return void @@ -93,8 +104,8 @@ namespace detail if (current_tuple->original_index != index) { auto end_value = iter_move(current_tuple->original_location); - difference_type destination_index = index; - difference_type source_index = current_tuple->original_index; + auto destination_index = index; + auto source_index = current_tuple->original_index; do { *(storage[destination_index].original_location) = iter_move(storage[source_index].original_location); @@ -117,9 +128,7 @@ namespace detail // Sort the iterators on pointed values return std::forward(sorter)( storage.begin(), storage.end(), std::move(compare), - [&proj](auto& elem) -> decltype(auto) { - return proj(*(elem.original_location)); - } + &item_index_tuple::original_location | indirect(projection) ); #endif } diff --git a/include/cpp-sort/detail/introselect.h b/include/cpp-sort/detail/introselect.h index 1e883d1b..94d3b23d 100644 --- a/include/cpp-sort/detail/introselect.h +++ b/include/cpp-sort/detail/introselect.h @@ -192,7 +192,7 @@ namespace detail ++medians_it; } - // Rest variables for the next iteration + // Reset variables for the next iteration last = medians_it; size = rounded_size == size ? size / 5 : size / 5 + 1; diff --git a/include/cpp-sort/detail/melsort.h b/include/cpp-sort/detail/melsort.h index 4ce883da..aeefe25d 100644 --- a/include/cpp-sort/detail/melsort.h +++ b/include/cpp-sort/detail/melsort.h @@ -11,10 +11,10 @@ #include #include #include +#include #include #include #include "fixed_size_list.h" -#include "functional.h" #include "iterator_traits.h" #include "lower_bound.h" #include "merge_move.h" @@ -165,7 +165,7 @@ namespace detail if (not comp(value, proj(last_list.back()))) { // Element belongs to the tails (bigger elements) auto insertion_point = detail::lower_bound( - lists.begin(), std::prev(lists.end()), value, invert(compare), + lists.begin(), std::prev(lists.end()), value, cppsort::flip(compare), [&proj](auto& list) -> decltype(auto) { return proj(list.back()); } ); insertion_point->push_back(iter_move(it)); diff --git a/include/cpp-sort/detail/pdqsort.h b/include/cpp-sort/detail/pdqsort.h index aa8f3cf0..39be5523 100644 --- a/include/cpp-sort/detail/pdqsort.h +++ b/include/cpp-sort/detail/pdqsort.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2021 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ @@ -436,6 +436,7 @@ namespace detail constexpr bool is_branchless = utility::is_probably_branchless_comparison_v && utility::is_probably_branchless_projection_v; + (void)is_branchless; // Silence a -Wunused-but-set-variable false positive auto&& comp = utility::as_function(compare); auto&& proj = utility::as_function(projection); diff --git a/include/cpp-sort/detail/raw_checkers.h b/include/cpp-sort/detail/raw_checkers.h index 30cbb340..31d4154c 100644 --- a/include/cpp-sort/detail/raw_checkers.h +++ b/include/cpp-sort/detail/raw_checkers.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_DETAIL_RAW_CHECKERS_H_ @@ -16,8 +16,12 @@ namespace cppsort { namespace detail { + // Raw checkers: type traits that check whether a specific type member + // exists within a type. Inheriting from the checker will give to the + // child type the same type member aliasing the same type. + //////////////////////////////////////////////////////////// - // Raw checkers (check with the type itself) + // iterator_category template struct has_iterator_category: @@ -48,6 +52,9 @@ namespace detail > {}; + //////////////////////////////////////////////////////////// + // is_always_stable + template struct has_is_always_stable: std::false_type @@ -77,6 +84,38 @@ namespace detail Sorters... > {}; + + //////////////////////////////////////////////////////////// + // is_transparent + + template + struct has_is_transparent: + std::false_type + {}; + + template + struct has_is_transparent>: + std::true_type + {}; + + template + constexpr bool has_is_transparent_v = has_is_transparent>::value; + + template + struct raw_check_is_transparent_impl {}; + + template<> + struct raw_check_is_transparent_impl + { + using is_transparent = void; + }; + + template + struct raw_check_is_transparent: + raw_check_is_transparent_impl< + all(has_is_transparent::value...) + > + {}; }} #endif // CPPSORT_DETAIL_RAW_CHECKERS_H_ diff --git a/include/cpp-sort/detail/slabsort.h b/include/cpp-sort/detail/slabsort.h index 9a9b3618..ac0bb690 100644 --- a/include/cpp-sort/detail/slabsort.h +++ b/include/cpp-sort/detail/slabsort.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include "bitops.h" @@ -151,7 +152,7 @@ namespace detail if (not comp(value, proj(*std::prev(last_list.end()).base()->it))) { // Element belongs to the tails (bigger elements) auto insertion_point = detail::lower_bound( - lists.begin(), std::prev(lists.end()), value, invert(compare), + lists.begin(), std::prev(lists.end()), value, cppsort::flip(compare), [&proj](auto& list) -> decltype(auto) { return proj(*std::prev(list.end()).base()->it); } diff --git a/include/cpp-sort/detail/sorting_network/sort21.h b/include/cpp-sort/detail/sorting_network/sort21.h index ad36e368..422fa47a 100644 --- a/include/cpp-sort/detail/sorting_network/sort21.h +++ b/include/cpp-sort/detail/sorting_network/sort21.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2021 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_DETAIL_SORTING_NETWORK_SORT21_H_ @@ -24,125 +24,128 @@ namespace detail Compare compare={}, Projection projection={}) const -> void { - iter_swap_if(first, first + 7u, compare, projection); - iter_swap_if(first + 1u, first + 10u, compare, projection); - iter_swap_if(first + 3u, first + 5u, compare, projection); - iter_swap_if(first + 4u, first + 8u, compare, projection); - iter_swap_if(first + 6u, first + 13u, compare, projection); - iter_swap_if(first + 9u, first + 19u, compare, projection); - iter_swap_if(first + 11u, first + 14u, compare, projection); - iter_swap_if(first + 12u, first + 17u, compare, projection); - iter_swap_if(first + 15u, first + 16u, compare, projection); - iter_swap_if(first + 18u, first + 20u, compare, projection); - iter_swap_if(first, first + 11u, compare, projection); - iter_swap_if(first + 1u, first + 15u, compare, projection); - iter_swap_if(first + 2u, first + 12u, compare, projection); - iter_swap_if(first + 3u, first + 4u, compare, projection); - iter_swap_if(first + 5u, first + 8u, compare, projection); - iter_swap_if(first + 6u, first + 9u, compare, projection); - iter_swap_if(first + 7u, first + 14u, compare, projection); - iter_swap_if(first + 10u, first + 16u, compare, projection); - iter_swap_if(first + 13u, first + 19u, compare, projection); - iter_swap_if(first + 17u, first + 20u, compare, projection); - iter_swap_if(first, first + 6u, compare, projection); - iter_swap_if(first + 1u, first + 3u, compare, projection); - iter_swap_if(first + 2u, first + 18u, compare, projection); - iter_swap_if(first + 4u, first + 15u, compare, projection); - iter_swap_if(first + 5u, first + 10u, compare, projection); - iter_swap_if(first + 8u, first + 16u, compare, projection); - iter_swap_if(first + 11u, first + 17u, compare, projection); + iter_swap_if(first + 0u, first + 1u, compare, projection); + iter_swap_if(first + 2u, first + 3u, compare, projection); + iter_swap_if(first + 4u, first + 5u, compare, projection); + iter_swap_if(first + 6u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 9u, compare, projection); + iter_swap_if(first + 10u, first + 11u, compare, projection); iter_swap_if(first + 12u, first + 13u, compare, projection); - iter_swap_if(first + 14u, first + 20u, compare, projection); - iter_swap_if(first + 2u, first + 6u, compare, projection); - iter_swap_if(first + 5u, first + 12u, compare, projection); - iter_swap_if(first + 7u, first + 18u, compare, projection); - iter_swap_if(first + 8u, first + 14u, compare, projection); + iter_swap_if(first + 14u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 17u, compare, projection); + iter_swap_if(first + 18u, first + 19u, compare, projection); + iter_swap_if(first + 0u, first + 2u, compare, projection); + iter_swap_if(first + 1u, first + 3u, compare, projection); + iter_swap_if(first + 4u, first + 6u, compare, projection); + iter_swap_if(first + 5u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 10u, compare, projection); iter_swap_if(first + 9u, first + 11u, compare, projection); - iter_swap_if(first + 10u, first + 17u, compare, projection); - iter_swap_if(first + 13u, first + 19u, compare, projection); - iter_swap_if(first + 16u, first + 20u, compare, projection); - iter_swap_if(first + 1u, first + 2u, compare, projection); - iter_swap_if(first + 4u, first + 7u, compare, projection); - iter_swap_if(first + 5u, first + 9u, compare, projection); - iter_swap_if(first + 6u, first + 17u, compare, projection); - iter_swap_if(first + 10u, first + 13u, compare, projection); - iter_swap_if(first + 11u, first + 12u, compare, projection); - iter_swap_if(first + 14u, first + 19u, compare, projection); - iter_swap_if(first + 15u, first + 18u, compare, projection); - iter_swap_if(first, first + 2u, compare, projection); + iter_swap_if(first + 12u, first + 14u, compare, projection); + iter_swap_if(first + 13u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 18u, compare, projection); + iter_swap_if(first + 17u, first + 19u, compare, projection); + iter_swap_if(first + 0u, first + 4u, compare, projection); + iter_swap_if(first + 1u, first + 5u, compare, projection); + iter_swap_if(first + 2u, first + 6u, compare, projection); + iter_swap_if(first + 3u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 12u, compare, projection); + iter_swap_if(first + 9u, first + 13u, compare, projection); + iter_swap_if(first + 10u, first + 14u, compare, projection); + iter_swap_if(first + 11u, first + 15u, compare, projection); + iter_swap_if(first + 0u, first + 8u, compare, projection); + iter_swap_if(first + 1u, first + 9u, compare, projection); + iter_swap_if(first + 2u, first + 10u, compare, projection); + iter_swap_if(first + 3u, first + 11u, compare, projection); + iter_swap_if(first + 4u, first + 12u, compare, projection); + iter_swap_if(first + 5u, first + 13u, compare, projection); + iter_swap_if(first + 6u, first + 14u, compare, projection); + iter_swap_if(first + 7u, first + 15u, compare, projection); + iter_swap_if(first + 3u, first + 18u, compare, projection); + iter_swap_if(first + 7u, first + 20u, compare, projection); + iter_swap_if(first + 2u, first + 7u, compare, projection); iter_swap_if(first + 3u, first + 6u, compare, projection); - iter_swap_if(first + 4u, first + 5u, compare, projection); - iter_swap_if(first + 7u, first + 10u, compare, projection); - iter_swap_if(first + 8u, first + 11u, compare, projection); - iter_swap_if(first + 9u, first + 15u, compare, projection); - iter_swap_if(first + 12u, first + 16u, compare, projection); - iter_swap_if(first + 13u, first + 18u, compare, projection); - iter_swap_if(first + 14u, first + 17u, compare, projection); + iter_swap_if(first + 14u, first + 18u, compare, projection); iter_swap_if(first + 19u, first + 20u, compare, projection); - iter_swap_if(first, first + 1u, compare, projection); + iter_swap_if(first + 2u, first + 16u, compare, projection); + iter_swap_if(first + 3u, first + 8u, compare, projection); + iter_swap_if(first + 6u, first + 14u, compare, projection); + iter_swap_if(first + 7u, first + 17u, compare, projection); + iter_swap_if(first + 11u, first + 19u, compare, projection); + iter_swap_if(first + 15u, first + 20u, compare, projection); + iter_swap_if(first + 0u, first + 2u, compare, projection); + iter_swap_if(first + 7u, first + 10u, compare, projection); + iter_swap_if(first + 9u, first + 16u, compare, projection); + iter_swap_if(first + 13u, first + 17u, compare, projection); + iter_swap_if(first + 15u, first + 19u, compare, projection); + iter_swap_if(first + 1u, first + 7u, compare, projection); iter_swap_if(first + 2u, first + 3u, compare, projection); - iter_swap_if(first + 5u, first + 9u, compare, projection); - iter_swap_if(first + 6u, first + 12u, compare, projection); - iter_swap_if(first + 7u, first + 8u, compare, projection); - iter_swap_if(first + 11u, first + 14u, compare, projection); - iter_swap_if(first + 13u, first + 15u, compare, projection); - iter_swap_if(first + 16u, first + 19u, compare, projection); + iter_swap_if(first + 4u, first + 9u, compare, projection); + iter_swap_if(first + 5u, first + 10u, compare, projection); + iter_swap_if(first + 11u, first + 16u, compare, projection); + iter_swap_if(first + 12u, first + 13u, compare, projection); iter_swap_if(first + 17u, first + 18u, compare, projection); - iter_swap_if(first + 1u, first + 2u, compare, projection); - iter_swap_if(first + 3u, first + 9u, compare, projection); - iter_swap_if(first + 6u, first + 13u, compare, projection); - iter_swap_if(first + 10u, first + 11u, compare, projection); - iter_swap_if(first + 12u, first + 15u, compare, projection); - iter_swap_if(first + 16u, first + 17u, compare, projection); - iter_swap_if(first + 18u, first + 19u, compare, projection); iter_swap_if(first + 1u, first + 4u, compare, projection); - iter_swap_if(first + 2u, first + 5u, compare, projection); - iter_swap_if(first + 3u, first + 7u, compare, projection); - iter_swap_if(first + 6u, first + 10u, compare, projection); - iter_swap_if(first + 8u, first + 9u, compare, projection); - iter_swap_if(first + 11u, first + 12u, compare, projection); - iter_swap_if(first + 13u, first + 14u, compare, projection); - iter_swap_if(first + 17u, first + 18u, compare, projection); - iter_swap_if(first + 2u, first + 4u, compare, projection); - iter_swap_if(first + 5u, first + 6u, compare, projection); + iter_swap_if(first + 5u, first + 11u, compare, projection); + iter_swap_if(first + 6u, first + 12u, compare, projection); iter_swap_if(first + 7u, first + 8u, compare, projection); - iter_swap_if(first + 9u, first + 11u, compare, projection); iter_swap_if(first + 10u, first + 13u, compare, projection); - iter_swap_if(first + 12u, first + 15u, compare, projection); iter_swap_if(first + 14u, first + 16u, compare, projection); + iter_swap_if(first + 15u, first + 17u, compare, projection); + iter_swap_if(first + 18u, first + 19u, compare, projection); + iter_swap_if(first + 1u, first + 2u, compare, projection); iter_swap_if(first + 3u, first + 4u, compare, projection); - iter_swap_if(first + 5u, first + 7u, compare, projection); - iter_swap_if(first + 6u, first + 8u, compare, projection); - iter_swap_if(first + 9u, first + 10u, compare, projection); - iter_swap_if(first + 11u, first + 13u, compare, projection); - iter_swap_if(first + 12u, first + 14u, compare, projection); - iter_swap_if(first + 15u, first + 16u, compare, projection); + iter_swap_if(first + 5u, first + 6u, compare, projection); + iter_swap_if(first + 10u, first + 14u, compare, projection); + iter_swap_if(first + 11u, first + 12u, compare, projection); + iter_swap_if(first + 13u, first + 16u, compare, projection); + iter_swap_if(first + 17u, first + 18u, compare, projection); + iter_swap_if(first + 2u, first + 3u, compare, projection); iter_swap_if(first + 4u, first + 5u, compare, projection); - iter_swap_if(first + 6u, first + 7u, compare, projection); - iter_swap_if(first + 8u, first + 9u, compare, projection); + iter_swap_if(first + 6u, first + 9u, compare, projection); iter_swap_if(first + 10u, first + 11u, compare, projection); iter_swap_if(first + 12u, first + 13u, compare, projection); iter_swap_if(first + 14u, first + 15u, compare, projection); iter_swap_if(first + 16u, first + 17u, compare, projection); + iter_swap_if(first + 6u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 9u, compare, projection); + iter_swap_if(first + 13u, first + 15u, compare, projection); + iter_swap_if(first + 4u, first + 6u, compare, projection); + iter_swap_if(first + 7u, first + 8u, compare, projection); + iter_swap_if(first + 9u, first + 12u, compare, projection); + iter_swap_if(first + 15u, first + 16u, compare, projection); + iter_swap_if(first + 3u, first + 4u, compare, projection); + iter_swap_if(first + 5u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 10u, compare, projection); + iter_swap_if(first + 9u, first + 11u, compare, projection); + iter_swap_if(first + 12u, first + 14u, compare, projection); + iter_swap_if(first + 5u, first + 6u, compare, projection); + iter_swap_if(first + 7u, first + 8u, compare, projection); + iter_swap_if(first + 9u, first + 10u, compare, projection); + iter_swap_if(first + 11u, first + 12u, compare, projection); + iter_swap_if(first + 13u, first + 14u, compare, projection); } template static constexpr auto index_pairs() - -> std::array, 100> + -> std::array, 99> { return {{ - {0, 7}, {1, 10}, {3, 5}, {4, 8}, {6, 13}, {9, 19}, {11, 14}, {12, 17}, {15, 16}, {18, 20}, - {0, 11}, {1, 15}, {2, 12}, {3, 4}, {5, 8}, {6, 9}, {7, 14}, {10, 16}, {13, 19}, {17, 20}, - {0, 6}, {1, 3}, {2, 18}, {4, 15}, {5, 10}, {8, 16}, {11, 17}, {12, 13}, {14, 20}, - {2, 6}, {5, 12}, {7, 18}, {8, 14}, {9, 11}, {10, 17}, {13, 19}, {16, 20}, - {1, 2}, {4, 7}, {5, 9}, {6, 17}, {10, 13}, {11, 12}, {14, 19}, {15, 18}, - {0, 2}, {3, 6}, {4, 5}, {7, 10}, {8, 11}, {9, 15}, {12, 16}, {13, 18}, {14, 17}, {19, 20}, - {0, 1}, {2, 3}, {5, 9}, {6, 12}, {7, 8}, {11, 14}, {13, 15}, {16, 19}, {17, 18}, - {1, 2}, {3, 9}, {6, 13}, {10, 11}, {12, 15}, {16, 17}, {18, 19}, - {1, 4}, {2, 5}, {3, 7}, {6, 10}, {8, 9}, {11, 12}, {13, 14}, {17, 18}, - {2, 4}, {5, 6}, {7, 8}, {9, 11}, {10, 13}, {12, 15}, {14, 16}, - {3, 4}, {5, 7}, {6, 8}, {9, 10}, {11, 13}, {12, 14}, {15, 16}, - {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}, {14, 15}, {16, 17}, + {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}, {14, 15}, {16, 17}, {18, 19}, + {0, 2}, {1, 3}, {4, 6}, {5, 7}, {8, 10}, {9, 11}, {12, 14}, {13, 15}, {16, 18}, {17, 19}, + {0, 4}, {1, 5}, {2, 6}, {3, 7}, {8, 12}, {9, 13}, {10, 14}, {11, 15}, + {0, 8}, {1, 9}, {2, 10}, {3, 11}, {4, 12}, {5, 13}, {6, 14}, {7, 15}, + {3, 18}, {7, 20}, + {2, 7}, {3, 6}, {14, 18}, {19, 20}, + {2, 16}, {3, 8}, {6, 14}, {7, 17}, {11, 19}, {15, 20}, + {0, 2}, {7, 10}, {9, 16}, {13, 17}, {15, 19}, + {1, 7}, {2, 3}, {4, 9}, {5, 10}, {11, 16}, {12, 13}, {17, 18}, + {1, 4}, {5, 11}, {6, 12}, {7, 8}, {10, 13}, {14, 16}, {15, 17}, {18, 19}, + {1, 2}, {3, 4}, {5, 6}, {10, 14}, {11, 12}, {13, 16}, {17, 18}, + {2, 3}, {4, 5}, {6, 9}, {10, 11}, {12, 13}, {14, 15}, {16, 17}, + {6, 7}, {8, 9}, {13, 15}, + {4, 6}, {7, 8}, {9, 12}, {15, 16}, + {3, 4}, {5, 7}, {8, 10}, {9, 11}, {12, 14}, + {5, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 14}, }}; } }; diff --git a/include/cpp-sort/detail/sorting_network/sort22.h b/include/cpp-sort/detail/sorting_network/sort22.h index 95ac0388..aaa7e020 100644 --- a/include/cpp-sort/detail/sorting_network/sort22.h +++ b/include/cpp-sort/detail/sorting_network/sort22.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2021 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_DETAIL_SORTING_NETWORK_SORT22_H_ @@ -24,7 +24,7 @@ namespace detail Compare compare={}, Projection projection={}) const -> void { - iter_swap_if(first, first + 1u, compare, projection); + iter_swap_if(first + 0u, first + 1u, compare, projection); iter_swap_if(first + 2u, first + 3u, compare, projection); iter_swap_if(first + 4u, first + 5u, compare, projection); iter_swap_if(first + 6u, first + 7u, compare, projection); @@ -35,122 +35,122 @@ namespace detail iter_swap_if(first + 16u, first + 17u, compare, projection); iter_swap_if(first + 18u, first + 19u, compare, projection); iter_swap_if(first + 20u, first + 21u, compare, projection); - iter_swap_if(first, first + 12u, compare, projection); - iter_swap_if(first + 1u, first + 13u, compare, projection); + iter_swap_if(first + 0u, first + 2u, compare, projection); + iter_swap_if(first + 1u, first + 3u, compare, projection); + iter_swap_if(first + 4u, first + 6u, compare, projection); + iter_swap_if(first + 5u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 10u, compare, projection); + iter_swap_if(first + 9u, first + 11u, compare, projection); + iter_swap_if(first + 12u, first + 14u, compare, projection); + iter_swap_if(first + 13u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 18u, compare, projection); + iter_swap_if(first + 17u, first + 19u, compare, projection); + iter_swap_if(first + 0u, first + 4u, compare, projection); + iter_swap_if(first + 1u, first + 5u, compare, projection); iter_swap_if(first + 2u, first + 6u, compare, projection); iter_swap_if(first + 3u, first + 7u, compare, projection); - iter_swap_if(first + 4u, first + 10u, compare, projection); - iter_swap_if(first + 8u, first + 20u, compare, projection); - iter_swap_if(first + 9u, first + 21u, compare, projection); - iter_swap_if(first + 11u, first + 17u, compare, projection); - iter_swap_if(first + 14u, first + 18u, compare, projection); - iter_swap_if(first + 15u, first + 19u, compare, projection); - iter_swap_if(first, first + 2u, compare, projection); - iter_swap_if(first + 1u, first + 6u, compare, projection); - iter_swap_if(first + 3u, first + 12u, compare, projection); - iter_swap_if(first + 4u, first + 16u, compare, projection); - iter_swap_if(first + 5u, first + 17u, compare, projection); - iter_swap_if(first + 7u, first + 13u, compare, projection); - iter_swap_if(first + 8u, first + 14u, compare, projection); - iter_swap_if(first + 9u, first + 18u, compare, projection); - iter_swap_if(first + 15u, first + 20u, compare, projection); - iter_swap_if(first + 19u, first + 21u, compare, projection); - iter_swap_if(first, first + 8u, compare, projection); - iter_swap_if(first + 1u, first + 15u, compare, projection); - iter_swap_if(first + 2u, first + 14u, compare, projection); - iter_swap_if(first + 3u, first + 9u, compare, projection); - iter_swap_if(first + 5u, first + 11u, compare, projection); - iter_swap_if(first + 6u, first + 20u, compare, projection); - iter_swap_if(first + 7u, first + 19u, compare, projection); - iter_swap_if(first + 10u, first + 16u, compare, projection); - iter_swap_if(first + 12u, first + 18u, compare, projection); - iter_swap_if(first + 13u, first + 21u, compare, projection); - iter_swap_if(first, first + 4u, compare, projection); - iter_swap_if(first + 1u, first + 10u, compare, projection); - iter_swap_if(first + 3u, first + 8u, compare, projection); - iter_swap_if(first + 5u, first + 9u, compare, projection); - iter_swap_if(first + 7u, first + 14u, compare, projection); - iter_swap_if(first + 11u, first + 20u, compare, projection); - iter_swap_if(first + 12u, first + 16u, compare, projection); - iter_swap_if(first + 13u, first + 18u, compare, projection); + iter_swap_if(first + 8u, first + 12u, compare, projection); + iter_swap_if(first + 9u, first + 13u, compare, projection); + iter_swap_if(first + 10u, first + 14u, compare, projection); + iter_swap_if(first + 11u, first + 15u, compare, projection); + iter_swap_if(first + 17u, first + 18u, compare, projection); + iter_swap_if(first + 0u, first + 8u, compare, projection); + iter_swap_if(first + 1u, first + 9u, compare, projection); + iter_swap_if(first + 2u, first + 10u, compare, projection); + iter_swap_if(first + 3u, first + 11u, compare, projection); + iter_swap_if(first + 4u, first + 12u, compare, projection); + iter_swap_if(first + 5u, first + 13u, compare, projection); + iter_swap_if(first + 6u, first + 14u, compare, projection); + iter_swap_if(first + 7u, first + 15u, compare, projection); iter_swap_if(first + 17u, first + 21u, compare, projection); - iter_swap_if(first + 1u, first + 3u, compare, projection); - iter_swap_if(first + 2u, first + 5u, compare, projection); - iter_swap_if(first + 4u, first + 8u, compare, projection); - iter_swap_if(first + 6u, first + 9u, compare, projection); - iter_swap_if(first + 7u, first + 10u, compare, projection); - iter_swap_if(first + 11u, first + 14u, compare, projection); - iter_swap_if(first + 12u, first + 15u, compare, projection); - iter_swap_if(first + 13u, first + 17u, compare, projection); - iter_swap_if(first + 16u, first + 19u, compare, projection); + iter_swap_if(first + 1u, first + 8u, compare, projection); + iter_swap_if(first + 6u, first + 20u, compare, projection); + iter_swap_if(first + 7u, first + 17u, compare, projection); + iter_swap_if(first + 19u, first + 21u, compare, projection); + iter_swap_if(first + 3u, first + 19u, compare, projection); + iter_swap_if(first + 4u, first + 7u, compare, projection); + iter_swap_if(first + 6u, first + 16u, compare, projection); + iter_swap_if(first + 14u, first + 21u, compare, projection); iter_swap_if(first + 18u, first + 20u, compare, projection); - iter_swap_if(first + 2u, first + 4u, compare, projection); + iter_swap_if(first + 0u, first + 6u, compare, projection); + iter_swap_if(first + 1u, first + 4u, compare, projection); iter_swap_if(first + 3u, first + 12u, compare, projection); - iter_swap_if(first + 5u, first + 8u, compare, projection); - iter_swap_if(first + 6u, first + 11u, compare, projection); - iter_swap_if(first + 9u, first + 18u, compare, projection); - iter_swap_if(first + 10u, first + 15u, compare, projection); - iter_swap_if(first + 13u, first + 16u, compare, projection); + iter_swap_if(first + 5u, first + 18u, compare, projection); + iter_swap_if(first + 7u, first + 10u, compare, projection); + iter_swap_if(first + 9u, first + 16u, compare, projection); + iter_swap_if(first + 11u, first + 20u, compare, projection); + iter_swap_if(first + 13u, first + 19u, compare, projection); + iter_swap_if(first + 14u, first + 17u, compare, projection); + iter_swap_if(first + 15u, first + 21u, compare, projection); + iter_swap_if(first + 2u, first + 5u, compare, projection); + iter_swap_if(first + 3u, first + 7u, compare, projection); + iter_swap_if(first + 6u, first + 8u, compare, projection); + iter_swap_if(first + 10u, first + 11u, compare, projection); + iter_swap_if(first + 12u, first + 13u, compare, projection); + iter_swap_if(first + 15u, first + 20u, compare, projection); + iter_swap_if(first + 16u, first + 18u, compare, projection); iter_swap_if(first + 17u, first + 19u, compare, projection); - iter_swap_if(first + 1u, first + 2u, compare, projection); - iter_swap_if(first + 3u, first + 4u, compare, projection); - iter_swap_if(first + 5u, first + 7u, compare, projection); - iter_swap_if(first + 6u, first + 12u, compare, projection); - iter_swap_if(first + 8u, first + 11u, compare, projection); - iter_swap_if(first + 9u, first + 15u, compare, projection); - iter_swap_if(first + 10u, first + 13u, compare, projection); + iter_swap_if(first + 5u, first + 8u, compare, projection); + iter_swap_if(first + 7u, first + 9u, compare, projection); + iter_swap_if(first + 10u, first + 12u, compare, projection); iter_swap_if(first + 14u, first + 16u, compare, projection); - iter_swap_if(first + 17u, first + 18u, compare, projection); + iter_swap_if(first + 15u, first + 17u, compare, projection); iter_swap_if(first + 19u, first + 20u, compare, projection); - iter_swap_if(first + 2u, first + 3u, compare, projection); - iter_swap_if(first + 4u, first + 5u, compare, projection); - iter_swap_if(first + 7u, first + 12u, compare, projection); - iter_swap_if(first + 8u, first + 10u, compare, projection); - iter_swap_if(first + 9u, first + 14u, compare, projection); + iter_swap_if(first + 2u, first + 7u, compare, projection); + iter_swap_if(first + 3u, first + 5u, compare, projection); + iter_swap_if(first + 8u, first + 9u, compare, projection); + iter_swap_if(first + 10u, first + 14u, compare, projection); + iter_swap_if(first + 11u, first + 16u, compare, projection); + iter_swap_if(first + 12u, first + 18u, compare, projection); + iter_swap_if(first + 17u, first + 19u, compare, projection); + iter_swap_if(first + 2u, first + 6u, compare, projection); + iter_swap_if(first + 4u, first + 7u, compare, projection); + iter_swap_if(first + 5u, first + 8u, compare, projection); iter_swap_if(first + 11u, first + 13u, compare, projection); - iter_swap_if(first + 16u, first + 17u, compare, projection); - iter_swap_if(first + 18u, first + 19u, compare, projection); + iter_swap_if(first + 12u, first + 14u, compare, projection); + iter_swap_if(first + 15u, first + 18u, compare, projection); + iter_swap_if(first + 1u, first + 2u, compare, projection); iter_swap_if(first + 4u, first + 6u, compare, projection); - iter_swap_if(first + 5u, first + 8u, compare, projection); + iter_swap_if(first + 7u, first + 10u, compare, projection); iter_swap_if(first + 9u, first + 11u, compare, projection); - iter_swap_if(first + 10u, first + 12u, compare, projection); iter_swap_if(first + 13u, first + 16u, compare, projection); - iter_swap_if(first + 15u, first + 17u, compare, projection); + iter_swap_if(first + 2u, first + 4u, compare, projection); + iter_swap_if(first + 3u, first + 6u, compare, projection); + iter_swap_if(first + 5u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 10u, compare, projection); + iter_swap_if(first + 9u, first + 12u, compare, projection); + iter_swap_if(first + 11u, first + 14u, compare, projection); + iter_swap_if(first + 13u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 18u, compare, projection); iter_swap_if(first + 3u, first + 4u, compare, projection); - iter_swap_if(first + 6u, first + 7u, compare, projection); - iter_swap_if(first + 9u, first + 10u, compare, projection); - iter_swap_if(first + 11u, first + 12u, compare, projection); - iter_swap_if(first + 14u, first + 15u, compare, projection); - iter_swap_if(first + 17u, first + 18u, compare, projection); iter_swap_if(first + 5u, first + 6u, compare, projection); iter_swap_if(first + 7u, first + 8u, compare, projection); - iter_swap_if(first + 10u, first + 11u, compare, projection); + iter_swap_if(first + 9u, first + 10u, compare, projection); + iter_swap_if(first + 11u, first + 12u, compare, projection); iter_swap_if(first + 13u, first + 14u, compare, projection); iter_swap_if(first + 15u, first + 16u, compare, projection); - iter_swap_if(first + 6u, first + 7u, compare, projection); - iter_swap_if(first + 8u, first + 9u, compare, projection); - iter_swap_if(first + 12u, first + 13u, compare, projection); - iter_swap_if(first + 14u, first + 15u, compare, projection); + iter_swap_if(first + 17u, first + 18u, compare, projection); } template static constexpr auto index_pairs() - -> std::array, 107> + -> std::array, 106> { return {{ {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}, {14, 15}, {16, 17}, {18, 19}, {20, 21}, - {0, 12}, {1, 13}, {2, 6}, {3, 7}, {4, 10}, {8, 20}, {9, 21}, {11, 17}, {14, 18}, {15, 19}, - {0, 2}, {1, 6}, {3, 12}, {4, 16}, {5, 17}, {7, 13}, {8, 14}, {9, 18}, {15, 20}, {19, 21}, - {0, 8}, {1, 15}, {2, 14}, {3, 9}, {5, 11}, {6, 20}, {7, 19}, {10, 16}, {12, 18}, {13, 21}, - {0, 4}, {1, 10}, {3, 8}, {5, 9}, {7, 14}, {11, 20}, {12, 16}, {13, 18}, {17, 21}, - {1, 3}, {2, 5}, {4, 8}, {6, 9}, {7, 10}, {11, 14}, {12, 15}, {13, 17}, {16, 19}, {18, 20}, - {2, 4}, {3, 12}, {5, 8}, {6, 11}, {9, 18}, {10, 15}, {13, 16}, {17, 19}, - {1, 2}, {3, 4}, {5, 7}, {6, 12}, {8, 11}, {9, 15}, {10, 13}, {14, 16}, {17, 18}, {19, 20}, - {2, 3}, {4, 5}, {7, 12}, {8, 10}, {9, 14}, {11, 13}, {16, 17}, {18, 19}, - {4, 6}, {5, 8}, {9, 11}, {10, 12}, {13, 16}, {15, 17}, - {3, 4}, {6, 7}, {9, 10}, {11, 12}, {14, 15}, {17, 18}, - {5, 6}, {7, 8}, {10, 11}, {13, 14}, {15, 16}, - {6, 7}, {8, 9}, {12, 13}, {14, 15}, + {0, 2}, {1, 3}, {4, 6}, {5, 7}, {8, 10}, {9, 11}, {12, 14}, {13, 15}, {16, 18}, {17, 19}, + {0, 4}, {1, 5}, {2, 6}, {3, 7}, {8, 12}, {9, 13}, {10, 14}, {11, 15}, {17, 18}, + {0, 8}, {1, 9}, {2, 10}, {3, 11}, {4, 12}, {5, 13}, {6, 14}, {7, 15}, {17, 21}, + {1, 8}, {6, 20}, {7, 17}, {19, 21}, + {3, 19}, {4, 7}, {6, 16}, {14, 21}, {18, 20}, + {0, 6}, {1, 4}, {3, 12}, {5, 18}, {7, 10}, {9, 16}, {11, 20}, {13, 19}, {14, 17}, {15, 21}, + {2, 5}, {3, 7}, {6, 8}, {10, 11}, {12, 13}, {15, 20}, {16, 18}, {17, 19}, + {5, 8}, {7, 9}, {10, 12}, {14, 16}, {15, 17}, {19, 20}, + {2, 7}, {3, 5}, {8, 9}, {10, 14}, {11, 16}, {12, 18}, {17, 19}, + {2, 6}, {4, 7}, {5, 8}, {11, 13}, {12, 14}, {15, 18}, + {1, 2}, {4, 6}, {7, 10}, {9, 11}, {13, 16}, + {2, 4}, {3, 6}, {5, 7}, {8, 10}, {9, 12}, {11, 14}, {13, 15}, {16, 18}, + {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 14}, {15, 16}, {17, 18}, }}; } }; diff --git a/include/cpp-sort/detail/sorting_network/sort23.h b/include/cpp-sort/detail/sorting_network/sort23.h index 4eeec33b..9f284af7 100644 --- a/include/cpp-sort/detail/sorting_network/sort23.h +++ b/include/cpp-sort/detail/sorting_network/sort23.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2021 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_DETAIL_SORTING_NETWORK_SORT23_H_ @@ -24,141 +24,141 @@ namespace detail Compare compare={}, Projection projection={}) const -> void { - iter_swap_if(first, first + 20u, compare, projection); - iter_swap_if(first + 1u, first + 12u, compare, projection); - iter_swap_if(first + 2u, first + 16u, compare, projection); - iter_swap_if(first + 4u, first + 6u, compare, projection); - iter_swap_if(first + 5u, first + 10u, compare, projection); - iter_swap_if(first + 7u, first + 21u, compare, projection); - iter_swap_if(first + 8u, first + 14u, compare, projection); - iter_swap_if(first + 9u, first + 15u, compare, projection); - iter_swap_if(first + 11u, first + 22u, compare, projection); - iter_swap_if(first + 13u, first + 18u, compare, projection); - iter_swap_if(first + 17u, first + 19u, compare, projection); - iter_swap_if(first, first + 3u, compare, projection); - iter_swap_if(first + 1u, first + 11u, compare, projection); - iter_swap_if(first + 2u, first + 7u, compare, projection); - iter_swap_if(first + 4u, first + 17u, compare, projection); - iter_swap_if(first + 5u, first + 13u, compare, projection); - iter_swap_if(first + 6u, first + 19u, compare, projection); - iter_swap_if(first + 8u, first + 9u, compare, projection); - iter_swap_if(first + 10u, first + 18u, compare, projection); - iter_swap_if(first + 12u, first + 22u, compare, projection); - iter_swap_if(first + 14u, first + 15u, compare, projection); - iter_swap_if(first + 16u, first + 21u, compare, projection); - iter_swap_if(first, first + 1u, compare, projection); - iter_swap_if(first + 2u, first + 4u, compare, projection); - iter_swap_if(first + 3u, first + 12u, compare, projection); - iter_swap_if(first + 5u, first + 8u, compare, projection); - iter_swap_if(first + 6u, first + 9u, compare, projection); - iter_swap_if(first + 7u, first + 10u, compare, projection); - iter_swap_if(first + 11u, first + 20u, compare, projection); - iter_swap_if(first + 13u, first + 16u, compare, projection); - iter_swap_if(first + 14u, first + 17u, compare, projection); - iter_swap_if(first + 15u, first + 18u, compare, projection); - iter_swap_if(first + 19u, first + 21u, compare, projection); - iter_swap_if(first + 2u, first + 5u, compare, projection); - iter_swap_if(first + 4u, first + 8u, compare, projection); - iter_swap_if(first + 6u, first + 11u, compare, projection); - iter_swap_if(first + 7u, first + 14u, compare, projection); - iter_swap_if(first + 9u, first + 16u, compare, projection); - iter_swap_if(first + 12u, first + 17u, compare, projection); - iter_swap_if(first + 15u, first + 19u, compare, projection); - iter_swap_if(first + 18u, first + 21u, compare, projection); - iter_swap_if(first + 1u, first + 8u, compare, projection); - iter_swap_if(first + 3u, first + 14u, compare, projection); - iter_swap_if(first + 4u, first + 7u, compare, projection); - iter_swap_if(first + 9u, first + 20u, compare, projection); - iter_swap_if(first + 10u, first + 12u, compare, projection); - iter_swap_if(first + 11u, first + 13u, compare, projection); - iter_swap_if(first + 15u, first + 22u, compare, projection); - iter_swap_if(first + 16u, first + 19u, compare, projection); - iter_swap_if(first, first + 7u, compare, projection); - iter_swap_if(first + 1u, first + 5u, compare, projection); - iter_swap_if(first + 3u, first + 4u, compare, projection); - iter_swap_if(first + 6u, first + 11u, compare, projection); - iter_swap_if(first + 8u, first + 15u, compare, projection); - iter_swap_if(first + 9u, first + 14u, compare, projection); - iter_swap_if(first + 10u, first + 13u, compare, projection); - iter_swap_if(first + 12u, first + 17u, compare, projection); - iter_swap_if(first + 18u, first + 22u, compare, projection); - iter_swap_if(first + 19u, first + 20u, compare, projection); - iter_swap_if(first, first + 2u, compare, projection); - iter_swap_if(first + 1u, first + 6u, compare, projection); - iter_swap_if(first + 4u, first + 7u, compare, projection); - iter_swap_if(first + 5u, first + 9u, compare, projection); - iter_swap_if(first + 8u, first + 10u, compare, projection); - iter_swap_if(first + 13u, first + 15u, compare, projection); - iter_swap_if(first + 14u, first + 18u, compare, projection); - iter_swap_if(first + 16u, first + 19u, compare, projection); - iter_swap_if(first + 17u, first + 22u, compare, projection); - iter_swap_if(first + 20u, first + 21u, compare, projection); + iter_swap_if(first + 0u, first + 1u, compare, projection); iter_swap_if(first + 2u, first + 3u, compare, projection); iter_swap_if(first + 4u, first + 5u, compare, projection); - iter_swap_if(first + 6u, first + 8u, compare, projection); - iter_swap_if(first + 7u, first + 9u, compare, projection); + iter_swap_if(first + 6u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 9u, compare, projection); iter_swap_if(first + 10u, first + 11u, compare, projection); iter_swap_if(first + 12u, first + 13u, compare, projection); - iter_swap_if(first + 14u, first + 16u, compare, projection); - iter_swap_if(first + 15u, first + 17u, compare, projection); + iter_swap_if(first + 14u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 17u, compare, projection); iter_swap_if(first + 18u, first + 19u, compare, projection); - iter_swap_if(first + 21u, first + 22u, compare, projection); - iter_swap_if(first + 1u, first + 2u, compare, projection); - iter_swap_if(first + 3u, first + 6u, compare, projection); - iter_swap_if(first + 4u, first + 10u, compare, projection); - iter_swap_if(first + 7u, first + 8u, compare, projection); + iter_swap_if(first + 20u, first + 21u, compare, projection); + iter_swap_if(first + 0u, first + 2u, compare, projection); + iter_swap_if(first + 1u, first + 3u, compare, projection); + iter_swap_if(first + 4u, first + 6u, compare, projection); + iter_swap_if(first + 5u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 10u, compare, projection); iter_swap_if(first + 9u, first + 11u, compare, projection); iter_swap_if(first + 12u, first + 14u, compare, projection); - iter_swap_if(first + 13u, first + 19u, compare, projection); - iter_swap_if(first + 15u, first + 16u, compare, projection); - iter_swap_if(first + 17u, first + 20u, compare, projection); - iter_swap_if(first + 2u, first + 3u, compare, projection); - iter_swap_if(first + 5u, first + 10u, compare, projection); + iter_swap_if(first + 13u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 18u, compare, projection); + iter_swap_if(first + 17u, first + 19u, compare, projection); + iter_swap_if(first + 21u, first + 22u, compare, projection); + iter_swap_if(first + 0u, first + 4u, compare, projection); + iter_swap_if(first + 1u, first + 5u, compare, projection); + iter_swap_if(first + 2u, first + 6u, compare, projection); + iter_swap_if(first + 3u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 12u, compare, projection); + iter_swap_if(first + 9u, first + 13u, compare, projection); + iter_swap_if(first + 10u, first + 14u, compare, projection); + iter_swap_if(first + 11u, first + 15u, compare, projection); + iter_swap_if(first + 17u, first + 21u, compare, projection); + iter_swap_if(first + 18u, first + 20u, compare, projection); + iter_swap_if(first + 19u, first + 22u, compare, projection); + iter_swap_if(first + 0u, first + 8u, compare, projection); + iter_swap_if(first + 1u, first + 9u, compare, projection); + iter_swap_if(first + 2u, first + 10u, compare, projection); + iter_swap_if(first + 3u, first + 11u, compare, projection); + iter_swap_if(first + 4u, first + 12u, compare, projection); + iter_swap_if(first + 5u, first + 13u, compare, projection); + iter_swap_if(first + 6u, first + 14u, compare, projection); + iter_swap_if(first + 7u, first + 15u, compare, projection); + iter_swap_if(first + 1u, first + 2u, compare, projection); + iter_swap_if(first + 5u, first + 18u, compare, projection); + iter_swap_if(first + 7u, first + 19u, compare, projection); + iter_swap_if(first + 9u, first + 16u, compare, projection); + iter_swap_if(first + 10u, first + 21u, compare, projection); + iter_swap_if(first + 12u, first + 20u, compare, projection); + iter_swap_if(first + 15u, first + 22u, compare, projection); + iter_swap_if(first + 5u, first + 9u, compare, projection); iter_swap_if(first + 6u, first + 7u, compare, projection); - iter_swap_if(first + 8u, first + 9u, compare, projection); - iter_swap_if(first + 13u, first + 18u, compare, projection); + iter_swap_if(first + 10u, first + 18u, compare, projection); + iter_swap_if(first + 11u, first + 21u, compare, projection); + iter_swap_if(first + 12u, first + 17u, compare, projection); + iter_swap_if(first + 13u, first + 20u, compare, projection); iter_swap_if(first + 14u, first + 15u, compare, projection); - iter_swap_if(first + 16u, first + 17u, compare, projection); + iter_swap_if(first + 3u, first + 17u, compare, projection); + iter_swap_if(first + 6u, first + 16u, compare, projection); + iter_swap_if(first + 7u, first + 14u, compare, projection); + iter_swap_if(first + 8u, first + 12u, compare, projection); + iter_swap_if(first + 15u, first + 19u, compare, projection); iter_swap_if(first + 20u, first + 21u, compare, projection); iter_swap_if(first + 3u, first + 4u, compare, projection); - iter_swap_if(first + 5u, first + 7u, compare, projection); + iter_swap_if(first + 5u, first + 8u, compare, projection); + iter_swap_if(first + 6u, first + 10u, compare, projection); + iter_swap_if(first + 9u, first + 12u, compare, projection); + iter_swap_if(first + 13u, first + 16u, compare, projection); + iter_swap_if(first + 14u, first + 15u, compare, projection); + iter_swap_if(first + 17u, first + 18u, compare, projection); + iter_swap_if(first + 19u, first + 21u, compare, projection); + iter_swap_if(first + 0u, first + 5u, compare, projection); + iter_swap_if(first + 1u, first + 8u, compare, projection); + iter_swap_if(first + 2u, first + 12u, compare, projection); + iter_swap_if(first + 3u, first + 9u, compare, projection); + iter_swap_if(first + 4u, first + 10u, compare, projection); + iter_swap_if(first + 7u, first + 13u, compare, projection); + iter_swap_if(first + 11u, first + 17u, compare, projection); + iter_swap_if(first + 14u, first + 16u, compare, projection); + iter_swap_if(first + 18u, first + 20u, compare, projection); + iter_swap_if(first + 2u, first + 6u, compare, projection); + iter_swap_if(first + 3u, first + 5u, compare, projection); + iter_swap_if(first + 4u, first + 8u, compare, projection); + iter_swap_if(first + 7u, first + 11u, compare, projection); iter_swap_if(first + 10u, first + 12u, compare, projection); + iter_swap_if(first + 13u, first + 18u, compare, projection); + iter_swap_if(first + 14u, first + 17u, compare, projection); + iter_swap_if(first + 15u, first + 20u, compare, projection); + iter_swap_if(first + 1u, first + 3u, compare, projection); + iter_swap_if(first + 2u, first + 5u, compare, projection); + iter_swap_if(first + 6u, first + 9u, compare, projection); + iter_swap_if(first + 7u, first + 10u, compare, projection); iter_swap_if(first + 11u, first + 13u, compare, projection); - iter_swap_if(first + 16u, first + 18u, compare, projection); + iter_swap_if(first + 12u, first + 14u, compare, projection); + iter_swap_if(first + 15u, first + 18u, compare, projection); + iter_swap_if(first + 16u, first + 17u, compare, projection); iter_swap_if(first + 19u, first + 20u, compare, projection); + iter_swap_if(first + 2u, first + 3u, compare, projection); iter_swap_if(first + 4u, first + 6u, compare, projection); - iter_swap_if(first + 8u, first + 10u, compare, projection); - iter_swap_if(first + 9u, first + 12u, compare, projection); - iter_swap_if(first + 11u, first + 14u, compare, projection); - iter_swap_if(first + 13u, first + 15u, compare, projection); + iter_swap_if(first + 8u, first + 9u, compare, projection); + iter_swap_if(first + 11u, first + 12u, compare, projection); + iter_swap_if(first + 13u, first + 14u, compare, projection); + iter_swap_if(first + 15u, first + 16u, compare, projection); iter_swap_if(first + 17u, first + 19u, compare, projection); + iter_swap_if(first + 3u, first + 4u, compare, projection); iter_swap_if(first + 5u, first + 6u, compare, projection); iter_swap_if(first + 7u, first + 8u, compare, projection); iter_swap_if(first + 9u, first + 10u, compare, projection); - iter_swap_if(first + 11u, first + 12u, compare, projection); - iter_swap_if(first + 13u, first + 14u, compare, projection); - iter_swap_if(first + 15u, first + 16u, compare, projection); + iter_swap_if(first + 12u, first + 13u, compare, projection); + iter_swap_if(first + 14u, first + 15u, compare, projection); iter_swap_if(first + 17u, first + 18u, compare, projection); + iter_swap_if(first + 4u, first + 5u, compare, projection); + iter_swap_if(first + 6u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 9u, compare, projection); + iter_swap_if(first + 10u, first + 11u, compare, projection); + iter_swap_if(first + 16u, first + 17u, compare, projection); } template static constexpr auto index_pairs() - -> std::array, 115> + -> std::array, 114> { return {{ - {0, 20}, {1, 12}, {2, 16}, {4, 6}, {5, 10}, {7, 21}, {8, 14}, {9, 15}, {11, 22}, {13, 18}, {17, 19}, - {0, 3}, {1, 11}, {2, 7}, {4, 17}, {5, 13}, {6, 19}, {8, 9}, {10, 18}, {12, 22}, {14, 15}, {16, 21}, - {0, 1}, {2, 4}, {3, 12}, {5, 8}, {6, 9}, {7, 10}, {11, 20}, {13, 16}, {14, 17}, {15, 18}, {19, 21}, - {2, 5}, {4, 8}, {6, 11}, {7, 14}, {9, 16}, {12, 17}, {15, 19}, {18, 21}, - {1, 8}, {3, 14}, {4, 7}, {9, 20}, {10, 12}, {11, 13}, {15, 22}, {16, 19}, - {0, 7}, {1, 5}, {3, 4}, {6, 11}, {8, 15}, {9, 14}, {10, 13}, {12, 17}, {18, 22}, {19, 20}, - {0, 2}, {1, 6}, {4, 7}, {5, 9}, {8, 10}, {13, 15}, {14, 18}, {16, 19}, {17, 22}, {20, 21}, - {2, 3}, {4, 5}, {6, 8}, {7, 9}, {10, 11}, {12, 13}, {14, 16}, {15, 17}, {18, 19}, {21, 22}, - {1, 2}, {3, 6}, {4, 10}, {7, 8}, {9, 11}, {12, 14}, {13, 19}, {15, 16}, {17, 20}, - {2, 3}, {5, 10}, {6, 7}, {8, 9}, {13, 18}, {14, 15}, {16, 17}, {20, 21}, - {3, 4}, {5, 7}, {10, 12}, {11, 13}, {16, 18}, {19, 20}, - {4, 6}, {8, 10}, {9, 12}, {11, 14}, {13, 15}, {17, 19}, - {5, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 14}, {15, 16}, {17, 18}, + {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}, {14, 15}, {16, 17}, {18, 19}, {20, 21}, + {0, 2}, {1, 3}, {4, 6}, {5, 7}, {8, 10}, {9, 11}, {12, 14}, {13, 15}, {16, 18}, {17, 19}, {21, 22}, + {0, 4}, {1, 5}, {2, 6}, {3, 7}, {8, 12}, {9, 13}, {10, 14}, {11, 15}, {17, 21}, {18, 20}, {19, 22}, + {0, 8}, {1, 9}, {2, 10}, {3, 11}, {4, 12}, {5, 13}, {6, 14}, {7, 15}, + {1, 2}, {5, 18}, {7, 19}, {9, 16}, {10, 21}, {12, 20}, {15, 22}, + {5, 9}, {6, 7}, {10, 18}, {11, 21}, {12, 17}, {13, 20}, {14, 15}, + {3, 17}, {6, 16}, {7, 14}, {8, 12}, {15, 19}, {20, 21}, + {3, 4}, {5, 8}, {6, 10}, {9, 12}, {13, 16}, {14, 15}, {17, 18}, {19, 21}, + {0, 5}, {1, 8}, {2, 12}, {3, 9}, {4, 10}, {7, 13}, {11, 17}, {14, 16}, {18, 20}, + {2, 6}, {3, 5}, {4, 8}, {7, 11}, {10, 12}, {13, 18}, {14, 17}, {15, 20}, + {1, 3}, {2, 5}, {6, 9}, {7, 10}, {11, 13}, {12, 14}, {15, 18}, {16, 17}, {19, 20}, + {2, 3}, {4, 6}, {8, 9}, {11, 12}, {13, 14}, {15, 16}, {17, 19}, + {3, 4}, {5, 6}, {7, 8}, {9, 10}, {12, 13}, {14, 15}, {17, 18}, + {4, 5}, {6, 7}, {8, 9}, {10, 11}, {16, 17}, }}; } }; diff --git a/include/cpp-sort/detail/sorting_network/sort25.h b/include/cpp-sort/detail/sorting_network/sort25.h index 53fc6fe5..6708c60b 100644 --- a/include/cpp-sort/detail/sorting_network/sort25.h +++ b/include/cpp-sort/detail/sorting_network/sort25.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2021 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_DETAIL_SORTING_NETWORK_SORT25_H_ @@ -24,160 +24,159 @@ namespace detail Compare compare={}, Projection projection={}) const -> void { - iter_swap_if(first, first + 2u, compare, projection); - iter_swap_if(first + 1u, first + 8u, compare, projection); - iter_swap_if(first + 3u, first + 18u, compare, projection); - iter_swap_if(first + 4u, first + 17u, compare, projection); - iter_swap_if(first + 5u, first + 20u, compare, projection); - iter_swap_if(first + 6u, first + 19u, compare, projection); - iter_swap_if(first + 7u, first + 9u, compare, projection); + iter_swap_if(first + 0u, first + 1u, compare, projection); + iter_swap_if(first + 2u, first + 3u, compare, projection); + iter_swap_if(first + 4u, first + 5u, compare, projection); + iter_swap_if(first + 6u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 9u, compare, projection); iter_swap_if(first + 10u, first + 11u, compare, projection); iter_swap_if(first + 12u, first + 13u, compare, projection); - iter_swap_if(first + 14u, first + 16u, compare, projection); - iter_swap_if(first + 15u, first + 22u, compare, projection); + iter_swap_if(first + 14u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 17u, compare, projection); + iter_swap_if(first + 18u, first + 19u, compare, projection); + iter_swap_if(first + 20u, first + 21u, compare, projection); + iter_swap_if(first + 22u, first + 23u, compare, projection); + iter_swap_if(first + 0u, first + 2u, compare, projection); + iter_swap_if(first + 1u, first + 3u, compare, projection); + iter_swap_if(first + 4u, first + 6u, compare, projection); + iter_swap_if(first + 5u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 10u, compare, projection); + iter_swap_if(first + 9u, first + 11u, compare, projection); + iter_swap_if(first + 12u, first + 14u, compare, projection); + iter_swap_if(first + 13u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 18u, compare, projection); + iter_swap_if(first + 17u, first + 19u, compare, projection); + iter_swap_if(first + 20u, first + 22u, compare, projection); iter_swap_if(first + 21u, first + 23u, compare, projection); - iter_swap_if(first, first + 3u, compare, projection); - iter_swap_if(first + 1u, first + 15u, compare, projection); - iter_swap_if(first + 2u, first + 18u, compare, projection); + iter_swap_if(first + 0u, first + 4u, compare, projection); + iter_swap_if(first + 1u, first + 5u, compare, projection); + iter_swap_if(first + 2u, first + 6u, compare, projection); + iter_swap_if(first + 3u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 12u, compare, projection); + iter_swap_if(first + 9u, first + 13u, compare, projection); + iter_swap_if(first + 10u, first + 14u, compare, projection); + iter_swap_if(first + 11u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 20u, compare, projection); + iter_swap_if(first + 17u, first + 21u, compare, projection); + iter_swap_if(first + 18u, first + 22u, compare, projection); + iter_swap_if(first + 19u, first + 23u, compare, projection); + iter_swap_if(first + 0u, first + 8u, compare, projection); + iter_swap_if(first + 1u, first + 9u, compare, projection); + iter_swap_if(first + 2u, first + 10u, compare, projection); + iter_swap_if(first + 3u, first + 11u, compare, projection); iter_swap_if(first + 4u, first + 12u, compare, projection); - iter_swap_if(first + 5u, first + 21u, compare, projection); - iter_swap_if(first + 6u, first + 10u, compare, projection); - iter_swap_if(first + 7u, first + 14u, compare, projection); - iter_swap_if(first + 8u, first + 22u, compare, projection); - iter_swap_if(first + 9u, first + 16u, compare, projection); - iter_swap_if(first + 11u, first + 19u, compare, projection); - iter_swap_if(first + 13u, first + 17u, compare, projection); - iter_swap_if(first + 20u, first + 23u, compare, projection); - iter_swap_if(first, first + 4u, compare, projection); - iter_swap_if(first + 1u, first + 7u, compare, projection); - iter_swap_if(first + 2u, first + 13u, compare, projection); - iter_swap_if(first + 3u, first + 12u, compare, projection); - iter_swap_if(first + 5u, first + 6u, compare, projection); - iter_swap_if(first + 8u, first + 14u, compare, projection); - iter_swap_if(first + 9u, first + 15u, compare, projection); - iter_swap_if(first + 10u, first + 21u, compare, projection); - iter_swap_if(first + 11u, first + 20u, compare, projection); - iter_swap_if(first + 16u, first + 22u, compare, projection); + iter_swap_if(first + 5u, first + 13u, compare, projection); + iter_swap_if(first + 6u, first + 14u, compare, projection); + iter_swap_if(first + 7u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 24u, compare, projection); iter_swap_if(first + 17u, first + 18u, compare, projection); - iter_swap_if(first + 19u, first + 23u, compare, projection); - iter_swap_if(first, first + 5u, compare, projection); - iter_swap_if(first + 2u, first + 11u, compare, projection); - iter_swap_if(first + 3u, first + 6u, compare, projection); - iter_swap_if(first + 4u, first + 10u, compare, projection); - iter_swap_if(first + 7u, first + 16u, compare, projection); - iter_swap_if(first + 8u, first + 9u, compare, projection); - iter_swap_if(first + 12u, first + 21u, compare, projection); - iter_swap_if(first + 13u, first + 19u, compare, projection); - iter_swap_if(first + 14u, first + 15u, compare, projection); - iter_swap_if(first + 17u, first + 20u, compare, projection); - iter_swap_if(first + 18u, first + 23u, compare, projection); - iter_swap_if(first + 2u, first + 7u, compare, projection); + iter_swap_if(first + 21u, first + 22u, compare, projection); + iter_swap_if(first + 0u, first + 16u, compare, projection); + iter_swap_if(first + 2u, first + 8u, compare, projection); + iter_swap_if(first + 3u, first + 12u, compare, projection); + iter_swap_if(first + 4u, first + 20u, compare, projection); + iter_swap_if(first + 5u, first + 19u, compare, projection); + iter_swap_if(first + 9u, first + 22u, compare, projection); + iter_swap_if(first + 10u, first + 24u, compare, projection); + iter_swap_if(first + 1u, first + 8u, compare, projection); iter_swap_if(first + 6u, first + 9u, compare, projection); - iter_swap_if(first + 8u, first + 11u, compare, projection); - iter_swap_if(first + 14u, first + 24u, compare, projection); - iter_swap_if(first + 18u, first + 21u, compare, projection); - iter_swap_if(first + 3u, first + 8u, compare, projection); - iter_swap_if(first + 7u, first + 10u, compare, projection); - iter_swap_if(first + 11u, first + 12u, compare, projection); - iter_swap_if(first + 13u, first + 14u, compare, projection); - iter_swap_if(first + 15u, first + 21u, compare, projection); + iter_swap_if(first + 7u, first + 22u, compare, projection); + iter_swap_if(first + 10u, first + 18u, compare, projection); + iter_swap_if(first + 14u, first + 19u, compare, projection); + iter_swap_if(first + 21u, first + 24u, compare, projection); + iter_swap_if(first + 1u, first + 17u, compare, projection); + iter_swap_if(first + 2u, first + 10u, compare, projection); + iter_swap_if(first + 5u, first + 21u, compare, projection); + iter_swap_if(first + 11u, first + 24u, compare, projection); iter_swap_if(first + 18u, first + 20u, compare, projection); - iter_swap_if(first + 22u, first + 24u, compare, projection); - iter_swap_if(first + 4u, first + 13u, compare, projection); - iter_swap_if(first + 10u, first + 16u, compare, projection); - iter_swap_if(first + 11u, first + 15u, compare, projection); - iter_swap_if(first + 18u, first + 24u, compare, projection); - iter_swap_if(first + 19u, first + 22u, compare, projection); iter_swap_if(first + 1u, first + 4u, compare, projection); - iter_swap_if(first + 8u, first + 11u, compare, projection); - iter_swap_if(first + 9u, first + 19u, compare, projection); - iter_swap_if(first + 13u, first + 17u, compare, projection); - iter_swap_if(first + 14u, first + 18u, compare, projection); - iter_swap_if(first + 16u, first + 20u, compare, projection); + iter_swap_if(first + 2u, first + 16u, compare, projection); + iter_swap_if(first + 3u, first + 21u, compare, projection); + iter_swap_if(first + 6u, first + 10u, compare, projection); + iter_swap_if(first + 8u, first + 18u, compare, projection); + iter_swap_if(first + 9u, first + 17u, compare, projection); + iter_swap_if(first + 11u, first + 14u, compare, projection); + iter_swap_if(first + 12u, first + 20u, compare, projection); iter_swap_if(first + 23u, first + 24u, compare, projection); - iter_swap_if(first, first + 1u, compare, projection); - iter_swap_if(first + 4u, first + 5u, compare, projection); - iter_swap_if(first + 6u, first + 13u, compare, projection); - iter_swap_if(first + 9u, first + 14u, compare, projection); - iter_swap_if(first + 10u, first + 17u, compare, projection); + iter_swap_if(first + 1u, first + 2u, compare, projection); + iter_swap_if(first + 3u, first + 5u, compare, projection); + iter_swap_if(first + 4u, first + 16u, compare, projection); + iter_swap_if(first + 12u, first + 18u, compare, projection); + iter_swap_if(first + 13u, first + 23u, compare, projection); + iter_swap_if(first + 14u, first + 19u, compare, projection); + iter_swap_if(first + 15u, first + 24u, compare, projection); + iter_swap_if(first + 17u, first + 21u, compare, projection); + iter_swap_if(first + 4u, first + 8u, compare, projection); + iter_swap_if(first + 7u, first + 13u, compare, projection); + iter_swap_if(first + 9u, first + 16u, compare, projection); + iter_swap_if(first + 10u, first + 12u, compare, projection); + iter_swap_if(first + 11u, first + 18u, compare, projection); + iter_swap_if(first + 14u, first + 20u, compare, projection); + iter_swap_if(first + 15u, first + 23u, compare, projection); + iter_swap_if(first + 19u, first + 22u, compare, projection); + iter_swap_if(first + 2u, first + 4u, compare, projection); + iter_swap_if(first + 3u, first + 8u, compare, projection); + iter_swap_if(first + 5u, first + 16u, compare, projection); + iter_swap_if(first + 6u, first + 9u, compare, projection); + iter_swap_if(first + 7u, first + 17u, compare, projection); + iter_swap_if(first + 13u, first + 21u, compare, projection); + iter_swap_if(first + 15u, first + 19u, compare, projection); + iter_swap_if(first + 22u, first + 23u, compare, projection); + iter_swap_if(first + 3u, first + 6u, compare, projection); + iter_swap_if(first + 5u, first + 10u, compare, projection); + iter_swap_if(first + 7u, first + 11u, compare, projection); + iter_swap_if(first + 8u, first + 9u, compare, projection); iter_swap_if(first + 12u, first + 16u, compare, projection); - iter_swap_if(first + 18u, first + 19u, compare, projection); + iter_swap_if(first + 13u, first + 18u, compare, projection); + iter_swap_if(first + 14u, first + 17u, compare, projection); + iter_swap_if(first + 19u, first + 22u, compare, projection); iter_swap_if(first + 20u, first + 21u, compare, projection); - iter_swap_if(first + 22u, first + 23u, compare, projection); - iter_swap_if(first + 2u, first + 6u, compare, projection); iter_swap_if(first + 3u, first + 4u, compare, projection); - iter_swap_if(first + 5u, first + 13u, compare, projection); + iter_swap_if(first + 6u, first + 8u, compare, projection); iter_swap_if(first + 7u, first + 9u, compare, projection); - iter_swap_if(first + 12u, first + 18u, compare, projection); + iter_swap_if(first + 10u, first + 12u, compare, projection); + iter_swap_if(first + 11u, first + 14u, compare, projection); + iter_swap_if(first + 13u, first + 16u, compare, projection); iter_swap_if(first + 15u, first + 17u, compare, projection); - iter_swap_if(first + 16u, first + 19u, compare, projection); - iter_swap_if(first + 20u, first + 22u, compare, projection); - iter_swap_if(first + 21u, first + 23u, compare, projection); - iter_swap_if(first + 1u, first + 2u, compare, projection); + iter_swap_if(first + 18u, first + 20u, compare, projection); + iter_swap_if(first + 19u, first + 21u, compare, projection); iter_swap_if(first + 5u, first + 8u, compare, projection); - iter_swap_if(first + 6u, first + 7u, compare, projection); - iter_swap_if(first + 9u, first + 10u, compare, projection); + iter_swap_if(first + 7u, first + 10u, compare, projection); + iter_swap_if(first + 9u, first + 12u, compare, projection); iter_swap_if(first + 11u, first + 13u, compare, projection); - iter_swap_if(first + 14u, first + 15u, compare, projection); + iter_swap_if(first + 14u, first + 16u, compare, projection); + iter_swap_if(first + 15u, first + 18u, compare, projection); iter_swap_if(first + 17u, first + 20u, compare, projection); - iter_swap_if(first + 21u, first + 22u, compare, projection); - iter_swap_if(first + 1u, first + 3u, compare, projection); - iter_swap_if(first + 2u, first + 4u, compare, projection); iter_swap_if(first + 5u, first + 6u, compare, projection); - iter_swap_if(first + 7u, first + 11u, compare, projection); - iter_swap_if(first + 8u, first + 9u, compare, projection); - iter_swap_if(first + 10u, first + 13u, compare, projection); - iter_swap_if(first + 12u, first + 14u, compare, projection); - iter_swap_if(first + 15u, first + 16u, compare, projection); - iter_swap_if(first + 17u, first + 18u, compare, projection); - iter_swap_if(first + 19u, first + 20u, compare, projection); - iter_swap_if(first + 2u, first + 3u, compare, projection); - iter_swap_if(first + 4u, first + 8u, compare, projection); - iter_swap_if(first + 6u, first + 7u, compare, projection); - iter_swap_if(first + 9u, first + 12u, compare, projection); - iter_swap_if(first + 10u, first + 11u, compare, projection); - iter_swap_if(first + 13u, first + 14u, compare, projection); - iter_swap_if(first + 15u, first + 17u, compare, projection); - iter_swap_if(first + 16u, first + 18u, compare, projection); - iter_swap_if(first + 20u, first + 21u, compare, projection); - iter_swap_if(first + 3u, first + 5u, compare, projection); - iter_swap_if(first + 4u, first + 6u, compare, projection); iter_swap_if(first + 7u, first + 8u, compare, projection); iter_swap_if(first + 9u, first + 10u, compare, projection); iter_swap_if(first + 11u, first + 12u, compare, projection); - iter_swap_if(first + 13u, first + 15u, compare, projection); - iter_swap_if(first + 14u, first + 17u, compare, projection); - iter_swap_if(first + 16u, first + 19u, compare, projection); - iter_swap_if(first + 4u, first + 5u, compare, projection); - iter_swap_if(first + 6u, first + 7u, compare, projection); - iter_swap_if(first + 8u, first + 9u, compare, projection); - iter_swap_if(first + 10u, first + 11u, compare, projection); - iter_swap_if(first + 12u, first + 13u, compare, projection); - iter_swap_if(first + 14u, first + 15u, compare, projection); - iter_swap_if(first + 16u, first + 17u, compare, projection); - iter_swap_if(first + 18u, first + 19u, compare, projection); + iter_swap_if(first + 13u, first + 14u, compare, projection); + iter_swap_if(first + 15u, first + 16u, compare, projection); + iter_swap_if(first + 17u, first + 18u, compare, projection); + iter_swap_if(first + 19u, first + 20u, compare, projection); } template static constexpr auto index_pairs() - -> std::array, 132> + -> std::array, 131> { return {{ - {0, 2}, {1, 8}, {3, 18}, {4, 17}, {5, 20}, {6, 19}, {7, 9}, {10, 11}, {12, 13}, {14, 16}, {15, 22}, {21, 23}, - {0, 3}, {1, 15}, {2, 18}, {4, 12}, {5, 21}, {6, 10}, {7, 14}, {8, 22}, {9, 16}, {11, 19}, {13, 17}, {20, 23}, - {0, 4}, {1, 7}, {2, 13}, {3, 12}, {5, 6}, {8, 14}, {9, 15}, {10, 21}, {11, 20}, {16, 22}, {17, 18}, {19, 23}, - {0, 5}, {2, 11}, {3, 6}, {4, 10}, {7, 16}, {8, 9}, {12, 21}, {13, 19}, {14, 15}, {17, 20}, {18, 23}, - {2, 7}, {6, 9}, {8, 11}, {14, 24}, {18, 21}, - {3, 8}, {7, 10}, {11, 12}, {13, 14}, {15, 21}, {18, 20}, {22, 24}, - {4, 13}, {10, 16}, {11, 15}, {18, 24}, {19, 22}, - {1, 4}, {8, 11}, {9, 19}, {13, 17}, {14, 18}, {16, 20}, {23, 24}, - {0, 1}, {4, 5}, {6, 13}, {9, 14}, {10, 17}, {12, 16}, {18, 19}, {20, 21}, {22, 23}, - {2, 6}, {3, 4}, {5, 13}, {7, 9}, {12, 18}, {15, 17}, {16, 19}, {20, 22}, {21, 23}, - {1, 2}, {5, 8}, {6, 7}, {9, 10}, {11, 13}, {14, 15}, {17, 20}, {21, 22}, - {1, 3}, {2, 4}, {5, 6}, {7, 11}, {8, 9}, {10, 13}, {12, 14}, {15, 16}, {17, 18}, {19, 20}, - {2, 3}, {4, 8}, {6, 7}, {9, 12}, {10, 11}, {13, 14}, {15, 17}, {16, 18}, {20, 21}, - {3, 5}, {4, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 15}, {14, 17}, {16, 19}, - {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}, {14, 15}, {16, 17}, {18, 19}, + {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}, {14, 15}, {16, 17}, {18, 19}, {20, 21}, {22, 23}, + {0, 2}, {1, 3}, {4, 6}, {5, 7}, {8, 10}, {9, 11}, {12, 14}, {13, 15}, {16, 18}, {17, 19}, {20, 22}, {21, 23}, + {0, 4}, {1, 5}, {2, 6}, {3, 7}, {8, 12}, {9, 13}, {10, 14}, {11, 15}, {16, 20}, {17, 21}, {18, 22}, {19, 23}, + {0, 8}, {1, 9}, {2, 10}, {3, 11}, {4, 12}, {5, 13}, {6, 14}, {7, 15}, {16, 24}, {17, 18}, {21, 22}, + {0, 16}, {2, 8}, {3, 12}, {4, 20}, {5, 19}, {9, 22}, {10, 24}, + {1, 8}, {6, 9}, {7, 22}, {10, 18}, {14, 19}, {21, 24}, + {1, 17}, {2, 10}, {5, 21}, {11, 24}, {18, 20}, + {1, 4}, {2, 16}, {3, 21}, {6, 10}, {8, 18}, {9, 17}, {11, 14}, {12, 20}, {23, 24}, + {1, 2}, {3, 5}, {4, 16}, {12, 18}, {13, 23}, {14, 19}, {15, 24}, {17, 21}, + {4, 8}, {7, 13}, {9, 16}, {10, 12}, {11, 18}, {14, 20}, {15, 23}, {19, 22}, + {2, 4}, {3, 8}, {5, 16}, {6, 9}, {7, 17}, {13, 21}, {15, 19}, {22, 23}, + {3, 6}, {5, 10}, {7, 11}, {8, 9}, {12, 16}, {13, 18}, {14, 17}, {19, 22}, {20, 21}, + {3, 4}, {6, 8}, {7, 9}, {10, 12}, {11, 14}, {13, 16}, {15, 17}, {18, 20}, {19, 21}, + {5, 8}, {7, 10}, {9, 12}, {11, 13}, {14, 16}, {15, 18}, {17, 20}, + {5, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 14}, {15, 16}, {17, 18}, {19, 20}, }}; } }; diff --git a/include/cpp-sort/detail/sorting_network/sort27.h b/include/cpp-sort/detail/sorting_network/sort27.h index 6896fd63..eddcad59 100644 --- a/include/cpp-sort/detail/sorting_network/sort27.h +++ b/include/cpp-sort/detail/sorting_network/sort27.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2021 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_DETAIL_SORTING_NETWORK_SORT27_H_ @@ -24,144 +24,144 @@ namespace detail Compare compare={}, Projection projection={}) const -> void { - iter_swap_if(first, first + 2u, compare, projection); + iter_swap_if(first + 0u, first + 1u, compare, projection); + iter_swap_if(first + 2u, first + 3u, compare, projection); + iter_swap_if(first + 4u, first + 5u, compare, projection); + iter_swap_if(first + 6u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 9u, compare, projection); + iter_swap_if(first + 10u, first + 11u, compare, projection); + iter_swap_if(first + 12u, first + 13u, compare, projection); + iter_swap_if(first + 14u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 17u, compare, projection); + iter_swap_if(first + 18u, first + 19u, compare, projection); + iter_swap_if(first + 20u, first + 21u, compare, projection); + iter_swap_if(first + 22u, first + 23u, compare, projection); + iter_swap_if(first + 24u, first + 25u, compare, projection); + iter_swap_if(first + 0u, first + 2u, compare, projection); + iter_swap_if(first + 1u, first + 3u, compare, projection); iter_swap_if(first + 4u, first + 6u, compare, projection); + iter_swap_if(first + 5u, first + 7u, compare, projection); iter_swap_if(first + 8u, first + 10u, compare, projection); + iter_swap_if(first + 9u, first + 11u, compare, projection); iter_swap_if(first + 12u, first + 14u, compare, projection); + iter_swap_if(first + 13u, first + 15u, compare, projection); iter_swap_if(first + 16u, first + 18u, compare, projection); + iter_swap_if(first + 17u, first + 19u, compare, projection); iter_swap_if(first + 20u, first + 22u, compare, projection); + iter_swap_if(first + 21u, first + 23u, compare, projection); iter_swap_if(first + 24u, first + 26u, compare, projection); - iter_swap_if(first, first + 4u, compare, projection); - iter_swap_if(first + 8u, first + 12u, compare, projection); - iter_swap_if(first + 16u, first + 20u, compare, projection); + iter_swap_if(first + 0u, first + 4u, compare, projection); + iter_swap_if(first + 1u, first + 5u, compare, projection); iter_swap_if(first + 2u, first + 6u, compare, projection); + iter_swap_if(first + 3u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 12u, compare, projection); + iter_swap_if(first + 9u, first + 13u, compare, projection); iter_swap_if(first + 10u, first + 14u, compare, projection); + iter_swap_if(first + 11u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 20u, compare, projection); + iter_swap_if(first + 17u, first + 21u, compare, projection); iter_swap_if(first + 18u, first + 22u, compare, projection); - iter_swap_if(first, first + 8u, compare, projection); - iter_swap_if(first + 16u, first + 24u, compare, projection); + iter_swap_if(first + 19u, first + 23u, compare, projection); + iter_swap_if(first + 25u, first + 26u, compare, projection); + iter_swap_if(first + 0u, first + 8u, compare, projection); + iter_swap_if(first + 1u, first + 9u, compare, projection); iter_swap_if(first + 2u, first + 10u, compare, projection); - iter_swap_if(first + 18u, first + 26u, compare, projection); + iter_swap_if(first + 3u, first + 11u, compare, projection); iter_swap_if(first + 4u, first + 12u, compare, projection); + iter_swap_if(first + 5u, first + 13u, compare, projection); iter_swap_if(first + 6u, first + 14u, compare, projection); - iter_swap_if(first, first + 16u, compare, projection); - iter_swap_if(first + 2u, first + 18u, compare, projection); - iter_swap_if(first + 4u, first + 20u, compare, projection); - iter_swap_if(first + 6u, first + 22u, compare, projection); - iter_swap_if(first + 8u, first + 24u, compare, projection); - iter_swap_if(first + 10u, first + 26u, compare, projection); + iter_swap_if(first + 7u, first + 15u, compare, projection); + iter_swap_if(first + 18u, first + 24u, compare, projection); + iter_swap_if(first + 20u, first + 26u, compare, projection); + iter_swap_if(first + 22u, first + 25u, compare, projection); + iter_swap_if(first + 2u, first + 8u, compare, projection); + iter_swap_if(first + 3u, first + 12u, compare, projection); + iter_swap_if(first + 5u, first + 10u, compare, projection); + iter_swap_if(first + 6u, first + 9u, compare, projection); + iter_swap_if(first + 7u, first + 13u, compare, projection); + iter_swap_if(first + 11u, first + 14u, compare, projection); + iter_swap_if(first + 16u, first + 18u, compare, projection); + iter_swap_if(first + 17u, first + 22u, compare, projection); + iter_swap_if(first + 19u, first + 26u, compare, projection); + iter_swap_if(first + 21u, first + 25u, compare, projection); + iter_swap_if(first + 0u, first + 16u, compare, projection); + iter_swap_if(first + 1u, first + 8u, compare, projection); + iter_swap_if(first + 5u, first + 22u, compare, projection); + iter_swap_if(first + 10u, first + 24u, compare, projection); + iter_swap_if(first + 11u, first + 25u, compare, projection); + iter_swap_if(first + 23u, first + 26u, compare, projection); + iter_swap_if(first + 1u, first + 18u, compare, projection); + iter_swap_if(first + 4u, first + 8u, compare, projection); + iter_swap_if(first + 5u, first + 19u, compare, projection); + iter_swap_if(first + 9u, first + 26u, compare, projection); iter_swap_if(first + 10u, first + 20u, compare, projection); + iter_swap_if(first + 12u, first + 23u, compare, projection); + iter_swap_if(first + 21u, first + 24u, compare, projection); + iter_swap_if(first + 2u, first + 10u, compare, projection); + iter_swap_if(first + 3u, first + 21u, compare, projection); + iter_swap_if(first + 4u, first + 17u, compare, projection); + iter_swap_if(first + 6u, first + 20u, compare, projection); + iter_swap_if(first + 7u, first + 24u, compare, projection); + iter_swap_if(first + 8u, first + 19u, compare, projection); iter_swap_if(first + 12u, first + 18u, compare, projection); - iter_swap_if(first + 6u, first + 24u, compare, projection); - iter_swap_if(first + 14u, first + 22u, compare, projection); + iter_swap_if(first + 14u, first + 23u, compare, projection); + iter_swap_if(first + 15u, first + 26u, compare, projection); iter_swap_if(first + 2u, first + 4u, compare, projection); - iter_swap_if(first + 8u, first + 16u, compare, projection); - iter_swap_if(first + 2u, first + 8u, compare, projection); - iter_swap_if(first + 14u, first + 26u, compare, projection); - iter_swap_if(first + 4u, first + 16u, compare, projection); - iter_swap_if(first + 4u, first + 8u, compare, projection); - iter_swap_if(first + 10u, first + 12u, compare, projection); - iter_swap_if(first + 18u, first + 20u, compare, projection); - iter_swap_if(first + 22u, first + 26u, compare, projection); - iter_swap_if(first + 6u, first + 16u, compare, projection); - iter_swap_if(first + 14u, first + 24u, compare, projection); - iter_swap_if(first + 12u, first + 16u, compare, projection); - iter_swap_if(first + 20u, first + 24u, compare, projection); iter_swap_if(first + 6u, first + 10u, compare, projection); - iter_swap_if(first + 14u, first + 18u, compare, projection); - iter_swap_if(first + 6u, first + 8u, compare, projection); - iter_swap_if(first + 10u, first + 12u, compare, projection); - iter_swap_if(first + 14u, first + 16u, compare, projection); - iter_swap_if(first + 18u, first + 20u, compare, projection); - iter_swap_if(first + 22u, first + 24u, compare, projection); - iter_swap_if(first + 12u, first + 14u, compare, projection); - iter_swap_if(first + 16u, first + 18u, compare, projection); - iter_swap_if(first + 3u, first + 15u, compare, projection); - iter_swap_if(first + 19u, first + 23u, compare, projection); - iter_swap_if(first + 7u, first + 9u, compare, projection); - iter_swap_if(first + 11u, first + 17u, compare, projection); - iter_swap_if(first + 1u, first + 25u, compare, projection); - iter_swap_if(first + 5u, first + 13u, compare, projection); - iter_swap_if(first + 1u, first + 3u, compare, projection); - iter_swap_if(first + 5u, first + 7u, compare, projection); - iter_swap_if(first + 9u, first + 13u, compare, projection); - iter_swap_if(first + 17u, first + 23u, compare, projection); - iter_swap_if(first + 15u, first + 25u, compare, projection); - iter_swap_if(first + 11u, first + 19u, compare, projection); - iter_swap_if(first + 1u, first + 5u, compare, projection); - iter_swap_if(first + 7u, first + 15u, compare, projection); - iter_swap_if(first + 21u, first + 23u, compare, projection); - iter_swap_if(first + 3u, first + 9u, compare, projection); - iter_swap_if(first + 13u, first + 25u, compare, projection); - iter_swap_if(first + 15u, first + 17u, compare, projection); - iter_swap_if(first + 23u, first + 25u, compare, projection); - iter_swap_if(first + 9u, first + 19u, compare, projection); - iter_swap_if(first + 13u, first + 21u, compare, projection); - iter_swap_if(first + 7u, first + 9u, compare, projection); - iter_swap_if(first + 11u, first + 13u, compare, projection); - iter_swap_if(first + 17u, first + 19u, compare, projection); - iter_swap_if(first + 21u, first + 23u, compare, projection); - iter_swap_if(first + 3u, first + 15u, compare, projection); - iter_swap_if(first + 5u, first + 13u, compare, projection); - iter_swap_if(first + 19u, first + 23u, compare, projection); - iter_swap_if(first + 3u, first + 7u, compare, projection); - iter_swap_if(first + 9u, first + 15u, compare, projection); - iter_swap_if(first + 17u, first + 21u, compare, projection); - iter_swap_if(first + 1u, first + 11u, compare, projection); - iter_swap_if(first + 5u, first + 11u, compare, projection); - iter_swap_if(first + 13u, first + 17u, compare, projection); - iter_swap_if(first + 19u, first + 21u, compare, projection); - iter_swap_if(first + 3u, first + 5u, compare, projection); iter_swap_if(first + 7u, first + 11u, compare, projection); - iter_swap_if(first + 15u, first + 17u, compare, projection); - iter_swap_if(first + 9u, first + 13u, compare, projection); - iter_swap_if(first + 5u, first + 7u, compare, projection); - iter_swap_if(first + 9u, first + 11u, compare, projection); - iter_swap_if(first + 13u, first + 15u, compare, projection); - iter_swap_if(first + 17u, first + 19u, compare, projection); - iter_swap_if(first + 7u, first + 9u, compare, projection); - iter_swap_if(first + 11u, first + 13u, compare, projection); - iter_swap_if(first, first + 1u, compare, projection); - iter_swap_if(first + 2u, first + 3u, compare, projection); - iter_swap_if(first + 4u, first + 5u, compare, projection); - iter_swap_if(first + 6u, first + 7u, compare, projection); - iter_swap_if(first + 8u, first + 9u, compare, projection); - iter_swap_if(first + 10u, first + 11u, compare, projection); - iter_swap_if(first + 12u, first + 13u, compare, projection); - iter_swap_if(first + 14u, first + 15u, compare, projection); - iter_swap_if(first + 16u, first + 17u, compare, projection); - iter_swap_if(first + 18u, first + 19u, compare, projection); + iter_swap_if(first + 8u, first + 16u, compare, projection); + iter_swap_if(first + 9u, first + 17u, compare, projection); + iter_swap_if(first + 13u, first + 19u, compare, projection); + iter_swap_if(first + 14u, first + 22u, compare, projection); + iter_swap_if(first + 15u, first + 23u, compare, projection); iter_swap_if(first + 20u, first + 21u, compare, projection); - iter_swap_if(first + 22u, first + 23u, compare, projection); - iter_swap_if(first + 24u, first + 25u, compare, projection); - iter_swap_if(first + 1u, first + 16u, compare, projection); - iter_swap_if(first + 3u, first + 18u, compare, projection); - iter_swap_if(first + 5u, first + 20u, compare, projection); - iter_swap_if(first + 7u, first + 22u, compare, projection); - iter_swap_if(first + 9u, first + 24u, compare, projection); - iter_swap_if(first + 11u, first + 26u, compare, projection); iter_swap_if(first + 1u, first + 8u, compare, projection); iter_swap_if(first + 3u, first + 10u, compare, projection); - iter_swap_if(first + 5u, first + 12u, compare, projection); - iter_swap_if(first + 7u, first + 14u, compare, projection); + iter_swap_if(first + 5u, first + 9u, compare, projection); + iter_swap_if(first + 12u, first + 16u, compare, projection); + iter_swap_if(first + 13u, first + 18u, compare, projection); + iter_swap_if(first + 14u, first + 17u, compare, projection); + iter_swap_if(first + 15u, first + 24u, compare, projection); + iter_swap_if(first + 19u, first + 25u, compare, projection); + iter_swap_if(first + 1u, first + 2u, compare, projection); + iter_swap_if(first + 3u, first + 12u, compare, projection); + iter_swap_if(first + 4u, first + 8u, compare, projection); + iter_swap_if(first + 7u, first + 13u, compare, projection); iter_swap_if(first + 9u, first + 16u, compare, projection); iter_swap_if(first + 11u, first + 18u, compare, projection); + iter_swap_if(first + 14u, first + 20u, compare, projection); + iter_swap_if(first + 17u, first + 21u, compare, projection); + iter_swap_if(first + 19u, first + 22u, compare, projection); + iter_swap_if(first + 23u, first + 25u, compare, projection); + iter_swap_if(first + 2u, first + 4u, compare, projection); + iter_swap_if(first + 3u, first + 8u, compare, projection); + iter_swap_if(first + 5u, first + 12u, compare, projection); + iter_swap_if(first + 6u, first + 9u, compare, projection); + iter_swap_if(first + 7u, first + 14u, compare, projection); + iter_swap_if(first + 10u, first + 16u, compare, projection); + iter_swap_if(first + 11u, first + 17u, compare, projection); iter_swap_if(first + 13u, first + 20u, compare, projection); - iter_swap_if(first + 15u, first + 22u, compare, projection); - iter_swap_if(first + 17u, first + 24u, compare, projection); - iter_swap_if(first + 19u, first + 26u, compare, projection); - iter_swap_if(first + 1u, first + 4u, compare, projection); - iter_swap_if(first + 3u, first + 6u, compare, projection); - iter_swap_if(first + 5u, first + 8u, compare, projection); + iter_swap_if(first + 15u, first + 19u, compare, projection); + iter_swap_if(first + 18u, first + 21u, compare, projection); + iter_swap_if(first + 23u, first + 24u, compare, projection); + iter_swap_if(first + 5u, first + 6u, compare, projection); iter_swap_if(first + 7u, first + 10u, compare, projection); iter_swap_if(first + 9u, first + 12u, compare, projection); - iter_swap_if(first + 11u, first + 14u, compare, projection); - iter_swap_if(first + 13u, first + 16u, compare, projection); + iter_swap_if(first + 11u, first + 13u, compare, projection); + iter_swap_if(first + 14u, first + 16u, compare, projection); iter_swap_if(first + 15u, first + 18u, compare, projection); iter_swap_if(first + 17u, first + 20u, compare, projection); - iter_swap_if(first + 19u, first + 22u, compare, projection); - iter_swap_if(first + 21u, first + 24u, compare, projection); - iter_swap_if(first + 23u, first + 26u, compare, projection); - iter_swap_if(first + 1u, first + 2u, compare, projection); + iter_swap_if(first + 21u, first + 22u, compare, projection); + iter_swap_if(first + 3u, first + 5u, compare, projection); + iter_swap_if(first + 6u, first + 8u, compare, projection); + iter_swap_if(first + 7u, first + 9u, compare, projection); + iter_swap_if(first + 10u, first + 12u, compare, projection); + iter_swap_if(first + 11u, first + 14u, compare, projection); + iter_swap_if(first + 13u, first + 16u, compare, projection); + iter_swap_if(first + 15u, first + 17u, compare, projection); + iter_swap_if(first + 18u, first + 20u, compare, projection); + iter_swap_if(first + 19u, first + 21u, compare, projection); + iter_swap_if(first + 22u, first + 23u, compare, projection); iter_swap_if(first + 3u, first + 4u, compare, projection); iter_swap_if(first + 5u, first + 6u, compare, projection); iter_swap_if(first + 7u, first + 8u, compare, projection); @@ -172,30 +172,28 @@ namespace detail iter_swap_if(first + 17u, first + 18u, compare, projection); iter_swap_if(first + 19u, first + 20u, compare, projection); iter_swap_if(first + 21u, first + 22u, compare, projection); - iter_swap_if(first + 23u, first + 24u, compare, projection); - iter_swap_if(first + 25u, first + 26u, compare, projection); } template static constexpr auto index_pairs() - -> std::array, 150> + -> std::array, 148> { return {{ - {0, 9}, {1, 6}, {2, 4}, {3, 7}, {5, 8}, {11, 24}, {12, 23}, {13, 26}, {14, 25}, {15, 19}, {16, 17}, {18, 22}, {20, 21}, - {0, 1}, {3, 5}, {4, 10}, {6, 9}, {7, 8}, {11, 16}, {12, 18}, {13, 20}, {14, 15}, {17, 24}, {19, 25}, {21, 26}, {22, 23}, - {1, 3}, {2, 5}, {4, 7}, {8, 10}, {11, 12}, {13, 14}, {15, 16}, {17, 19}, {18, 20}, {21, 22}, {23, 24}, {25, 26}, - {0, 4}, {1, 2}, {3, 7}, {5, 9}, {6, 8}, {11, 13}, {12, 14}, {15, 21}, {16, 22}, {17, 18}, {19, 20}, {23, 25}, {24, 26}, - {0, 1}, {2, 6}, {4, 5}, {7, 8}, {9, 10}, {12, 13}, {14, 23}, {15, 17}, {16, 18}, {19, 21}, {20, 22}, {24, 25}, - {0, 11}, {2, 4}, {3, 6}, {5, 7}, {8, 9}, {12, 15}, {13, 17}, {16, 19}, {18, 21}, {20, 24}, {22, 25}, - {1, 2}, {3, 4}, {5, 6}, {7, 8}, {13, 15}, {14, 17}, {20, 23}, {22, 24}, - {1, 12}, {2, 3}, {4, 5}, {6, 7}, {14, 16}, {17, 19}, {18, 20}, {21, 23}, - {2, 13}, {14, 15}, {16, 17}, {18, 19}, {20, 21}, {22, 23}, - {3, 14}, {4, 15}, {5, 16}, {10, 21}, {17, 18}, {19, 20}, - {6, 17}, {7, 18}, {8, 19}, {9, 20}, {10, 13}, {14, 22}, {15, 23}, {16, 24}, - {6, 10}, {7, 14}, {8, 11}, {9, 12}, {17, 25}, {18, 26}, {19, 23}, {20, 24}, - {4, 8}, {5, 9}, {11, 15}, {12, 16}, {13, 17}, {18, 22}, {21, 25}, {24, 26}, - {2, 4}, {3, 5}, {6, 8}, {7, 9}, {10, 11}, {12, 14}, {13, 15}, {16, 18}, {17, 19}, {20, 22}, {21, 23}, {25, 26}, - {1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 14}, {15, 16}, {17, 18}, {19, 20}, {21, 22}, {23, 24}, + {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}, {14, 15}, {16, 17}, {18, 19}, {20, 21}, {22, 23}, {24, 25}, + {0, 2}, {1, 3}, {4, 6}, {5, 7}, {8, 10}, {9, 11}, {12, 14}, {13, 15}, {16, 18}, {17, 19}, {20, 22}, {21, 23}, {24, 26}, + {0, 4}, {1, 5}, {2, 6}, {3, 7}, {8, 12}, {9, 13}, {10, 14}, {11, 15}, {16, 20}, {17, 21}, {18, 22}, {19, 23}, {25, 26}, + {0, 8}, {1, 9}, {2, 10}, {3, 11}, {4, 12}, {5, 13}, {6, 14}, {7, 15}, {18, 24}, {20, 26}, {22, 25}, + {2, 8}, {3, 12}, {5, 10}, {6, 9}, {7, 13}, {11, 14}, {16, 18}, {17, 22}, {19, 26}, {21, 25}, + {0, 16}, {1, 8}, {5, 22}, {10, 24}, {11, 25}, {23, 26}, + {1, 18}, {4, 8}, {5, 19}, {9, 26}, {10, 20}, {12, 23}, {21, 24}, + {2, 10}, {3, 21}, {4, 17}, {6, 20}, {7, 24}, {8, 19}, {12, 18}, {14, 23}, {15, 26}, + {2, 4}, {6, 10}, {7, 11}, {8, 16}, {9, 17}, {13, 19}, {14, 22}, {15, 23}, {20, 21}, + {1, 8}, {3, 10}, {5, 9}, {12, 16}, {13, 18}, {14, 17}, {15, 24}, {19, 25}, + {1, 2}, {3, 12}, {4, 8}, {7, 13}, {9, 16}, {11, 18}, {14, 20}, {17, 21}, {19, 22}, {23, 25}, + {2, 4}, {3, 8}, {5, 12}, {6, 9}, {7, 14}, {10, 16}, {11, 17}, {13, 20}, {15, 19}, {18, 21}, {23, 24}, + {5, 6}, {7, 10}, {9, 12}, {11, 13}, {14, 16}, {15, 18}, {17, 20}, {21, 22}, + {3, 5}, {6, 8}, {7, 9}, {10, 12}, {11, 14}, {13, 16}, {15, 17}, {18, 20}, {19, 21}, {22, 23}, + {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 14}, {15, 16}, {17, 18}, {19, 20}, {21, 22}, }}; } }; diff --git a/include/cpp-sort/detail/sorting_network/sort29.h b/include/cpp-sort/detail/sorting_network/sort29.h index 785f8768..b46680dc 100644 --- a/include/cpp-sort/detail/sorting_network/sort29.h +++ b/include/cpp-sort/detail/sorting_network/sort29.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2021 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_DETAIL_SORTING_NETWORK_SORT29_H_ @@ -24,58 +24,153 @@ namespace detail Compare compare={}, Projection projection={}) const -> void { - sorting_network_sorter<16u>{}(first, first+16u, compare, projection); - sorting_network_sorter<13u>{}(first+16u, first+29u, compare, projection); - - iter_swap_if(first, first + 16u, compare, projection); - iter_swap_if(first + 8u, first + 24u, compare, projection); - iter_swap_if(first + 8u, first + 16u, compare, projection); - iter_swap_if(first + 4u, first + 20u, compare, projection); - iter_swap_if(first + 12u, first + 28u, compare, projection); - iter_swap_if(first + 12u, first + 20u, compare, projection); - iter_swap_if(first + 4u, first + 8u, compare, projection); - iter_swap_if(first + 12u, first + 16u, compare, projection); - iter_swap_if(first + 20u, first + 24u, compare, projection); - iter_swap_if(first + 2u, first + 18u, compare, projection); - iter_swap_if(first + 10u, first + 26u, compare, projection); - iter_swap_if(first + 10u, first + 18u, compare, projection); - iter_swap_if(first + 6u, first + 22u, compare, projection); - iter_swap_if(first + 14u, first + 22u, compare, projection); - iter_swap_if(first + 6u, first + 10u, compare, projection); - iter_swap_if(first + 14u, first + 18u, compare, projection); - iter_swap_if(first + 22u, first + 26u, compare, projection); - iter_swap_if(first + 2u, first + 4u, compare, projection); - iter_swap_if(first + 6u, first + 8u, compare, projection); - iter_swap_if(first + 10u, first + 12u, compare, projection); - iter_swap_if(first + 14u, first + 16u, compare, projection); - iter_swap_if(first + 18u, first + 20u, compare, projection); + iter_swap_if(first + 0u, first + 1u, compare, projection); + iter_swap_if(first + 2u, first + 3u, compare, projection); + iter_swap_if(first + 4u, first + 5u, compare, projection); + iter_swap_if(first + 6u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 9u, compare, projection); + iter_swap_if(first + 10u, first + 11u, compare, projection); + iter_swap_if(first + 12u, first + 13u, compare, projection); + iter_swap_if(first + 14u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 28u, compare, projection); + iter_swap_if(first + 17u, first + 26u, compare, projection); + iter_swap_if(first + 18u, first + 25u, compare, projection); + iter_swap_if(first + 19u, first + 23u, compare, projection); + iter_swap_if(first + 21u, first + 27u, compare, projection); iter_swap_if(first + 22u, first + 24u, compare, projection); + iter_swap_if(first + 0u, first + 2u, compare, projection); + iter_swap_if(first + 1u, first + 3u, compare, projection); + iter_swap_if(first + 4u, first + 6u, compare, projection); + iter_swap_if(first + 5u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 10u, compare, projection); + iter_swap_if(first + 9u, first + 11u, compare, projection); + iter_swap_if(first + 12u, first + 14u, compare, projection); + iter_swap_if(first + 13u, first + 15u, compare, projection); + iter_swap_if(first + 17u, first + 22u, compare, projection); + iter_swap_if(first + 18u, first + 19u, compare, projection); + iter_swap_if(first + 20u, first + 27u, compare, projection); + iter_swap_if(first + 23u, first + 25u, compare, projection); + iter_swap_if(first + 24u, first + 26u, compare, projection); + iter_swap_if(first + 0u, first + 4u, compare, projection); + iter_swap_if(first + 1u, first + 5u, compare, projection); + iter_swap_if(first + 2u, first + 6u, compare, projection); + iter_swap_if(first + 3u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 12u, compare, projection); + iter_swap_if(first + 9u, first + 13u, compare, projection); + iter_swap_if(first + 10u, first + 14u, compare, projection); + iter_swap_if(first + 11u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 20u, compare, projection); + iter_swap_if(first + 17u, first + 18u, compare, projection); + iter_swap_if(first + 19u, first + 22u, compare, projection); + iter_swap_if(first + 23u, first + 24u, compare, projection); + iter_swap_if(first + 25u, first + 26u, compare, projection); + iter_swap_if(first + 27u, first + 28u, compare, projection); + iter_swap_if(first + 0u, first + 8u, compare, projection); + iter_swap_if(first + 1u, first + 9u, compare, projection); + iter_swap_if(first + 2u, first + 10u, compare, projection); + iter_swap_if(first + 3u, first + 11u, compare, projection); + iter_swap_if(first + 4u, first + 12u, compare, projection); + iter_swap_if(first + 5u, first + 13u, compare, projection); + iter_swap_if(first + 6u, first + 14u, compare, projection); + iter_swap_if(first + 7u, first + 15u, compare, projection); + iter_swap_if(first + 20u, first + 22u, compare, projection); + iter_swap_if(first + 21u, first + 25u, compare, projection); + iter_swap_if(first + 24u, first + 27u, compare, projection); iter_swap_if(first + 26u, first + 28u, compare, projection); + iter_swap_if(first + 3u, first + 20u, compare, projection); + iter_swap_if(first + 5u, first + 24u, compare, projection); + iter_swap_if(first + 6u, first + 21u, compare, projection); + iter_swap_if(first + 7u, first + 26u, compare, projection); + iter_swap_if(first + 10u, first + 23u, compare, projection); + iter_swap_if(first + 11u, first + 13u, compare, projection); + iter_swap_if(first + 12u, first + 19u, compare, projection); + iter_swap_if(first + 14u, first + 25u, compare, projection); + iter_swap_if(first + 15u, first + 28u, compare, projection); + iter_swap_if(first + 22u, first + 27u, compare, projection); + iter_swap_if(first + 2u, first + 5u, compare, projection); + iter_swap_if(first + 3u, first + 10u, compare, projection); + iter_swap_if(first + 6u, first + 16u, compare, projection); + iter_swap_if(first + 7u, first + 14u, compare, projection); + iter_swap_if(first + 11u, first + 22u, compare, projection); + iter_swap_if(first + 13u, first + 27u, compare, projection); + iter_swap_if(first + 15u, first + 25u, compare, projection); + iter_swap_if(first + 19u, first + 23u, compare, projection); + iter_swap_if(first + 20u, first + 24u, compare, projection); + iter_swap_if(first + 2u, first + 12u, compare, projection); + iter_swap_if(first + 6u, first + 17u, compare, projection); + iter_swap_if(first + 11u, first + 20u, compare, projection); + iter_swap_if(first + 13u, first + 24u, compare, projection); + iter_swap_if(first + 14u, first + 21u, compare, projection); + iter_swap_if(first + 15u, first + 26u, compare, projection); + iter_swap_if(first + 16u, first + 18u, compare, projection); + iter_swap_if(first + 0u, first + 6u, compare, projection); iter_swap_if(first + 1u, first + 17u, compare, projection); - iter_swap_if(first + 9u, first + 25u, compare, projection); - iter_swap_if(first + 9u, first + 17u, compare, projection); - iter_swap_if(first + 5u, first + 21u, compare, projection); - iter_swap_if(first + 13u, first + 21u, compare, projection); + iter_swap_if(first + 5u, first + 12u, compare, projection); + iter_swap_if(first + 7u, first + 20u, compare, projection); + iter_swap_if(first + 8u, first + 16u, compare, projection); + iter_swap_if(first + 9u, first + 18u, compare, projection); + iter_swap_if(first + 13u, first + 14u, compare, projection); + iter_swap_if(first + 15u, first + 21u, compare, projection); + iter_swap_if(first + 25u, first + 26u, compare, projection); + iter_swap_if(first + 1u, first + 2u, compare, projection); + iter_swap_if(first + 6u, first + 8u, compare, projection); + iter_swap_if(first + 15u, first + 22u, compare, projection); + iter_swap_if(first + 16u, first + 17u, compare, projection); + iter_swap_if(first + 18u, first + 19u, compare, projection); + iter_swap_if(first + 26u, first + 27u, compare, projection); + iter_swap_if(first + 1u, first + 6u, compare, projection); + iter_swap_if(first + 2u, first + 8u, compare, projection); + iter_swap_if(first + 4u, first + 17u, compare, projection); + iter_swap_if(first + 9u, first + 16u, compare, projection); + iter_swap_if(first + 11u, first + 18u, compare, projection); + iter_swap_if(first + 19u, first + 23u, compare, projection); + iter_swap_if(first + 22u, first + 25u, compare, projection); + iter_swap_if(first + 3u, first + 4u, compare, projection); + iter_swap_if(first + 5u, first + 16u, compare, projection); + iter_swap_if(first + 10u, first + 17u, compare, projection); + iter_swap_if(first + 13u, first + 18u, compare, projection); + iter_swap_if(first + 14u, first + 19u, compare, projection); + iter_swap_if(first + 23u, first + 24u, compare, projection); + iter_swap_if(first + 25u, first + 26u, compare, projection); + iter_swap_if(first + 3u, first + 6u, compare, projection); + iter_swap_if(first + 4u, first + 10u, compare, projection); iter_swap_if(first + 5u, first + 9u, compare, projection); - iter_swap_if(first + 13u, first + 17u, compare, projection); - iter_swap_if(first + 21u, first + 25u, compare, projection); - iter_swap_if(first + 3u, first + 19u, compare, projection); - iter_swap_if(first + 11u, first + 27u, compare, projection); - iter_swap_if(first + 11u, first + 19u, compare, projection); - iter_swap_if(first + 7u, first + 23u, compare, projection); + iter_swap_if(first + 7u, first + 13u, compare, projection); + iter_swap_if(first + 12u, first + 16u, compare, projection); + iter_swap_if(first + 14u, first + 17u, compare, projection); iter_swap_if(first + 15u, first + 23u, compare, projection); - iter_swap_if(first + 7u, first + 11u, compare, projection); - iter_swap_if(first + 15u, first + 19u, compare, projection); - iter_swap_if(first + 23u, first + 27u, compare, projection); - iter_swap_if(first + 3u, first + 5u, compare, projection); - iter_swap_if(first + 7u, first + 9u, compare, projection); - iter_swap_if(first + 11u, first + 13u, compare, projection); - iter_swap_if(first + 15u, first + 17u, compare, projection); - iter_swap_if(first + 19u, first + 21u, compare, projection); - iter_swap_if(first + 23u, first + 25u, compare, projection); + iter_swap_if(first + 18u, first + 20u, compare, projection); + iter_swap_if(first + 21u, first + 24u, compare, projection); + iter_swap_if(first + 2u, first + 3u, compare, projection); + iter_swap_if(first + 4u, first + 9u, compare, projection); + iter_swap_if(first + 5u, first + 6u, compare, projection); + iter_swap_if(first + 7u, first + 12u, compare, projection); + iter_swap_if(first + 10u, first + 11u, compare, projection); + iter_swap_if(first + 13u, first + 16u, compare, projection); + iter_swap_if(first + 15u, first + 18u, compare, projection); + iter_swap_if(first + 19u, first + 23u, compare, projection); + iter_swap_if(first + 20u, first + 21u, compare, projection); + iter_swap_if(first + 24u, first + 25u, compare, projection); iter_swap_if(first + 1u, first + 2u, compare, projection); iter_swap_if(first + 3u, first + 4u, compare, projection); - iter_swap_if(first + 5u, first + 6u, compare, projection); + iter_swap_if(first + 7u, first + 10u, compare, projection); + iter_swap_if(first + 8u, first + 9u, compare, projection); + iter_swap_if(first + 11u, first + 13u, compare, projection); + iter_swap_if(first + 12u, first + 14u, compare, projection); + iter_swap_if(first + 16u, first + 17u, compare, projection); + iter_swap_if(first + 18u, first + 19u, compare, projection); + iter_swap_if(first + 21u, first + 23u, compare, projection); + iter_swap_if(first + 22u, first + 24u, compare, projection); + iter_swap_if(first + 3u, first + 5u, compare, projection); + iter_swap_if(first + 4u, first + 7u, compare, projection); + iter_swap_if(first + 6u, first + 8u, compare, projection); + iter_swap_if(first + 9u, first + 12u, compare, projection); + iter_swap_if(first + 10u, first + 11u, compare, projection); + iter_swap_if(first + 13u, first + 16u, compare, projection); + iter_swap_if(first + 14u, first + 15u, compare, projection); + iter_swap_if(first + 17u, first + 20u, compare, projection); + iter_swap_if(first + 22u, first + 23u, compare, projection); + iter_swap_if(first + 4u, first + 6u, compare, projection); iter_swap_if(first + 7u, first + 8u, compare, projection); iter_swap_if(first + 9u, first + 10u, compare, projection); iter_swap_if(first + 11u, first + 12u, compare, projection); @@ -84,31 +179,39 @@ namespace detail iter_swap_if(first + 17u, first + 18u, compare, projection); iter_swap_if(first + 19u, first + 20u, compare, projection); iter_swap_if(first + 21u, first + 22u, compare, projection); - iter_swap_if(first + 23u, first + 24u, compare, projection); - iter_swap_if(first + 25u, first + 26u, compare, projection); - iter_swap_if(first + 27u, first + 28u, compare, projection); + iter_swap_if(first + 4u, first + 5u, compare, projection); + iter_swap_if(first + 6u, first + 7u, compare, projection); + iter_swap_if(first + 8u, first + 9u, compare, projection); + iter_swap_if(first + 10u, first + 11u, compare, projection); + iter_swap_if(first + 12u, first + 13u, compare, projection); + iter_swap_if(first + 14u, first + 15u, compare, projection); + iter_swap_if(first + 16u, first + 17u, compare, projection); + iter_swap_if(first + 18u, first + 19u, compare, projection); + iter_swap_if(first + 20u, first + 21u, compare, projection); } template static constexpr auto index_pairs() - -> std::array, 165> + -> std::array, 164> { return {{ - {0, 12}, {1, 10}, {2, 9}, {3, 7}, {5, 11}, {6, 8}, {13, 26}, {14, 25}, {15, 28}, {16, 27}, {17, 21}, {18, 19}, {20, 24}, {22, 23}, - {1, 6}, {2, 3}, {4, 11}, {7, 9}, {8, 10}, {13, 18}, {14, 20}, {15, 22}, {16, 17}, {19, 26}, {21, 27}, {23, 28}, {24, 25}, - {0, 4}, {1, 2}, {3, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 14}, {15, 16}, {17, 18}, {19, 21}, {20, 22}, {23, 24}, {25, 26}, {27, 28}, - {4, 6}, {5, 9}, {8, 11}, {10, 12}, {13, 15}, {14, 16}, {17, 23}, {18, 24}, {19, 20}, {21, 22}, {25, 27}, {26, 28}, - {0, 5}, {3, 8}, {4, 7}, {6, 11}, {9, 10}, {14, 15}, {16, 25}, {17, 19}, {18, 20}, {21, 23}, {22, 24}, {26, 27}, - {0, 1}, {2, 5}, {6, 9}, {7, 8}, {10, 11}, {14, 17}, {15, 19}, {18, 21}, {20, 23}, {22, 26}, {24, 27}, - {0, 13}, {1, 3}, {2, 4}, {5, 6}, {9, 10}, {15, 17}, {16, 19}, {22, 25}, {24, 26}, - {1, 2}, {3, 4}, {5, 7}, {6, 8}, {16, 18}, {19, 21}, {20, 22}, {23, 25}, - {1, 14}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {16, 17}, {18, 19}, {20, 21}, {22, 23}, {24, 25}, - {2, 15}, {3, 4}, {5, 6}, {10, 23}, {11, 24}, {12, 25}, {19, 20}, {21, 22}, - {3, 16}, {4, 17}, {5, 18}, {6, 19}, {7, 20}, {8, 21}, {9, 22}, {10, 15}, - {6, 10}, {8, 13}, {9, 14}, {11, 16}, {12, 17}, {18, 26}, {19, 27}, {20, 28}, - {4, 8}, {5, 9}, {7, 11}, {12, 13}, {14, 18}, {15, 19}, {16, 20}, {17, 21}, {22, 26}, {23, 27}, {24, 28}, - {2, 4}, {3, 5}, {6, 8}, {7, 9}, {10, 12}, {11, 14}, {13, 15}, {16, 18}, {17, 19}, {20, 22}, {21, 23}, {24, 26}, {25, 27}, - {1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 14}, {15, 16}, {17, 18}, {19, 20}, {21, 22}, {23, 24}, {25, 26}, {27, 28}, + {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}, {14, 15}, {16, 28}, {17, 26}, {18, 25}, {19, 23}, {21, 27}, {22, 24}, + {0, 2}, {1, 3}, {4, 6}, {5, 7}, {8, 10}, {9, 11}, {12, 14}, {13, 15}, {17, 22}, {18, 19}, {20, 27}, {23, 25}, {24, 26}, + {0, 4}, {1, 5}, {2, 6}, {3, 7}, {8, 12}, {9, 13}, {10, 14}, {11, 15}, {16, 20}, {17, 18}, {19, 22}, {23, 24}, {25, 26}, {27, 28}, + {0, 8}, {1, 9}, {2, 10}, {3, 11}, {4, 12}, {5, 13}, {6, 14}, {7, 15}, {20, 22}, {21, 25}, {24, 27}, {26, 28}, + {3, 20}, {5, 24}, {6, 21}, {7, 26}, {10, 23}, {11, 13}, {12, 19}, {14, 25}, {15, 28}, {22, 27}, + {2, 5}, {3, 10}, {6, 16}, {7, 14}, {11, 22}, {13, 27}, {15, 25}, {19, 23}, {20, 24}, + {2, 12}, {6, 17}, {11, 20}, {13, 24}, {14, 21}, {15, 26}, {16, 18}, + {0, 6}, {1, 17}, {5, 12}, {7, 20}, {8, 16}, {9, 18}, {13, 14}, {15, 21}, {25, 26}, + {1, 2}, {6, 8}, {15, 22}, {16, 17}, {18, 19}, {26, 27}, + {1, 6}, {2, 8}, {4, 17}, {9, 16}, {11, 18}, {19, 23}, {22, 25}, + {3, 4}, {5, 16}, {10, 17}, {13, 18}, {14, 19}, {23, 24}, {25, 26}, + {3, 6}, {4, 10}, {5, 9}, {7, 13}, {12, 16}, {14, 17}, {15, 23}, {18, 20}, {21, 24}, + {2, 3}, {4, 9}, {5, 6}, {7, 12}, {10, 11}, {13, 16}, {15, 18}, {19, 23}, {20, 21}, {24, 25}, + {1, 2}, {3, 4}, {7, 10}, {8, 9}, {11, 13}, {12, 14}, {16, 17}, {18, 19}, {21, 23}, {22, 24}, + {3, 5}, {4, 7}, {6, 8}, {9, 12}, {10, 11}, {13, 16}, {14, 15}, {17, 20}, {22, 23}, + {4, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 14}, {15, 16}, {17, 18}, {19, 20}, {21, 22}, + {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}, {14, 15}, {16, 17}, {18, 19}, {20, 21}, }}; } }; diff --git a/include/cpp-sort/detail/spinsort.h b/include/cpp-sort/detail/spinsort.h index 9968f86b..e68abe48 100644 --- a/include/cpp-sort/detail/spinsort.h +++ b/include/cpp-sort/detail/spinsort.h @@ -24,13 +24,13 @@ #include #include #include +#include #include #include #include "boost_common/util/merge.h" #include "boost_common/range.h" #include "bitops.h" #include "config.h" -#include "functional.h" #include "immovable_vector.h" #include "insertion_sort.h" #include "is_sorted_until.h" @@ -162,7 +162,7 @@ namespace detail return false; } - it = detail::is_sorted_until(rng_data.first, rng_data.last, detail::not_fn(compare), projection); + it = detail::is_sorted_until(rng_data.first, rng_data.last, cppsort::not_fn(compare), projection); if (rng_data.last - it >= min_insert_partial_sort) { return false; } diff --git a/include/cpp-sort/detail/timsort.h b/include/cpp-sort/detail/timsort.h index a38587f7..c761a9be 100644 --- a/include/cpp-sort/detail/timsort.h +++ b/include/cpp-sort/detail/timsort.h @@ -6,7 +6,8 @@ * - http://cr.openjdk.java.net/~martin/webrevs/openjdk7/timsort/raw_files/new/src/share/classes/java/util/TimSort.java * * Copyright (c) 2011 Fuji, Goro (gfx) . - * Copyright (c) 2015-2021 Morwenn. + * Copyright (c) 2015-2022 Morwenn. + * Copyright (c) 2021 Igor Kushnir . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -33,6 +34,7 @@ // Headers //////////////////////////////////////////////////////////// #include +#include #include #include #include @@ -69,8 +71,13 @@ namespace detail {} }; - template - class TimSort + template< + typename ChildClass, + typename RandomAccessIterator, + typename Compare, + typename Projection + > + struct TimSortBase { using iterator = RandomAccessIterator; using rvalue_type = rvalue_type_t; @@ -86,7 +93,7 @@ namespace detail std::ptrdiff_t buffer_size = 0; // Silence GCC -Winline warning - ~TimSort() noexcept {} + ~TimSortBase() noexcept {} std::vector> pending_; @@ -106,7 +113,7 @@ namespace detail return; } - TimSort ts{}; + ChildClass ts{}; difference_type const minRun = minRunLength(nRemaining); iterator cur = lo; do { @@ -717,14 +724,53 @@ namespace detail detail::move(buffer.get(), buffer.get() + len2, dest - (len2 - 1)); } } + }; + + template + struct TimSort: + TimSortBase< + TimSort, + RandomAccessIterator, + Compare, + Projection + > + {}; + + template + struct AdaptiveShiversSort: + TimSortBase< + AdaptiveShiversSort, + RandomAccessIterator, + Compare, + Projection + > + { + using base = TimSortBase< + AdaptiveShiversSort, + RandomAccessIterator, + Compare, + Projection + >; + using difference_type = typename base::difference_type; + + AdaptiveShiversSort() = default; - // the only interface is the friend timsort() function - template - friend void timsort(IterT, IterT, LessT, Proj); + auto mergeCollapse(Compare compare, Projection projection) + -> void + { + while (this->pending_.size() > 1) { + difference_type n = this->pending_.size() - 3; + auto x = this->pending_[n + 1].len | this->pending_[n + 2].len; + if (n < 0 || x <= (this->pending_[n].len & ~x)) { + break; + } + base::mergeAt(n, compare, projection); + } + } }; template - auto timsort(RandomAccessIterator const first, RandomAccessIterator const last, + auto timsort(RandomAccessIterator first, RandomAccessIterator last, Compare compare, Projection projection) -> void { @@ -732,6 +778,16 @@ namespace detail std::move(first), std::move(last), std::move(compare), std::move(projection)); } + + template + auto adaptive_shivers_sort(RandomAccessIterator first, RandomAccessIterator last, + Compare compare, Projection projection) + -> void + { + AdaptiveShiversSort::sort( + std::move(first), std::move(last), + std::move(compare), std::move(projection)); + } }} #endif // CPPSORT_DETAIL_TIMSORT_H_ diff --git a/include/cpp-sort/detail/upper_bound.h b/include/cpp-sort/detail/upper_bound.h index 58cb5fd7..cf2f275c 100644 --- a/include/cpp-sort/detail/upper_bound.h +++ b/include/cpp-sort/detail/upper_bound.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_DETAIL_UPPER_BOUND_H_ @@ -10,9 +10,10 @@ //////////////////////////////////////////////////////////// #include #include -#include -#include "bitops.h" +#include +#include #include "iterator_traits.h" +#include "lower_bound.h" namespace cppsort { @@ -24,20 +25,12 @@ namespace detail T&& value, Compare compare, Projection projection) -> ForwardIterator { - auto&& comp = utility::as_function(compare); - auto&& proj = utility::as_function(projection); - - while (size > 0) { - ForwardIterator it = first; - std::advance(it, half(size)); - if (not comp(value, proj(*it))) { - first = ++it; - size -= half(size) + 1; - } else { - size = half(size); - } - } - return first; + return lower_bound_n( + first, size, + std::forward(value), + cppsort::not_fn(cppsort::flip(std::move(compare))), + std::move(projection) + ); } template ForwardIterator { - return upper_bound_n(first, std::distance(first, last), - std::forward(value), - std::move(compare), std::move(projection)); + return lower_bound_n( + first, std::distance(first, last), + std::forward(value), + cppsort::not_fn(cppsort::flip(std::move(compare))), + std::move(projection) + ); } }} diff --git a/include/cpp-sort/fwd.h b/include/cpp-sort/fwd.h index d720f73b..058b1660 100644 --- a/include/cpp-sort/fwd.h +++ b/include/cpp-sort/fwd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_FWD_H_ @@ -24,6 +24,7 @@ namespace cppsort //////////////////////////////////////////////////////////// // Sorters + struct adaptive_shivers_sorter; template struct block_sorter; struct cartesian_tree_sorter; diff --git a/include/cpp-sort/probes/enc.h b/include/cpp-sort/probes/enc.h index 76cc4ff0..c7a65cfc 100644 --- a/include/cpp-sort/probes/enc.h +++ b/include/cpp-sort/probes/enc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_PROBES_ENC_H_ @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -42,19 +43,17 @@ namespace probe utility::is_probably_branchless_comparison_v && utility::is_probably_branchless_projection_v; - auto proj = [&projection, &accessor](const auto& list) -> decltype(auto) { - return projection(*(list.*accessor)); - }; - if (can_optimize) { return cppsort::detail::lower_monobound_n( lists.begin(), lists.size() - 1, value, - std::move(compare), proj + std::move(compare), + accessor | cppsort::detail::indirect(projection) ); } else { return cppsort::detail::lower_bound_n( lists.begin(), lists.size() - 1, value, - std::move(compare), proj + std::move(compare), + accessor | cppsort::detail::indirect(projection) ); } } @@ -95,7 +94,7 @@ namespace probe if (not comp(value, proj(*last_list.second))) { // Element belongs to the tails (bigger elements) auto insertion_point = enc_lower_bound( - lists, value, cppsort::detail::invert(compare), proj, + lists, value, cppsort::flip(compare), proj, &std::pair::second ); insertion_point->second = first; diff --git a/include/cpp-sort/probes/sus.h b/include/cpp-sort/probes/sus.h index 4fbe0953..6702705e 100644 --- a/include/cpp-sort/probes/sus.h +++ b/include/cpp-sort/probes/sus.h @@ -12,12 +12,12 @@ #include #include #include +#include #include #include #include #include #include -#include "../detail/functional.h" #include "../detail/longest_non_descending_subsequence.h" #include "../detail/type_traits.h" @@ -46,7 +46,7 @@ namespace probe auto res = cppsort::detail::longest_non_descending_subsequence( first, last, 0, // Dummy value, not useful here - cppsort::detail::not_fn(compare), std::move(projection) + cppsort::not_fn(compare), std::move(projection) ); return res.first > 0 ? res.first - 1 : 0; } diff --git a/include/cpp-sort/sorters.h b/include/cpp-sort/sorters.h index 3aed709b..82428feb 100644 --- a/include/cpp-sort/sorters.h +++ b/include/cpp-sort/sorters.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2021 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_SORTERS_H_ @@ -8,6 +8,7 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// +#include #include #include #include diff --git a/include/cpp-sort/sorters/adaptive_shivers_sorter.h b/include/cpp-sort/sorters/adaptive_shivers_sorter.h new file mode 100644 index 00000000..972d0945 --- /dev/null +++ b/include/cpp-sort/sorters/adaptive_shivers_sorter.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#ifndef CPPSORT_SORTERS_ADAPTIVE_SHIVERS_SORTER_H_ +#define CPPSORT_SORTERS_ADAPTIVE_SHIVERS_SORTER_H_ + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include "../detail/iterator_traits.h" +#include "../detail/timsort.h" +#include "../detail/type_traits.h" + +namespace cppsort +{ + //////////////////////////////////////////////////////////// + // Sorter + + namespace detail + { + struct adaptive_shivers_sorter_impl + { + template< + typename RandomAccessIterator, + typename Compare = std::less<>, + typename Projection = utility::identity, + typename = detail::enable_if_t< + is_projection_iterator_v + > + > + auto operator()(RandomAccessIterator first, RandomAccessIterator last, + Compare compare={}, Projection projection={}) const + -> void + { + static_assert( + std::is_base_of< + iterator_category, + iterator_category_t + >::value, + "adaptive_shivers_sorter requires at least random-access iterators" + ); + + adaptive_shivers_sort(std::move(first), std::move(last), + std::move(compare), std::move(projection)); + } + + //////////////////////////////////////////////////////////// + // Sorter traits + + using iterator_category = std::random_access_iterator_tag; + using is_always_stable = std::true_type; + }; + } + + struct adaptive_shivers_sorter: + sorter_facade + {}; + + //////////////////////////////////////////////////////////// + // Sort function + + namespace + { + constexpr auto&& adaptive_shivers_sort + = utility::static_const::value; + } +} + +#endif // CPPSORT_SORTERS_ADAPTIVE_SHIVERS_SORTER_H_ diff --git a/include/cpp-sort/utility/as_function.h b/include/cpp-sort/utility/as_function.h index 6b88bab1..a85a4955 100644 --- a/include/cpp-sort/utility/as_function.h +++ b/include/cpp-sort/utility/as_function.h @@ -46,7 +46,7 @@ namespace utility } template - constexpr auto operator()(T && t) const + constexpr auto operator()(T&& t) const noexcept(std::is_nothrow_constructible::value) -> cppsort::detail::enable_if_t< not std::is_member_pointer>::value, diff --git a/include/cpp-sort/utility/functional.h b/include/cpp-sort/utility/functional.h index 013bb54f..42396cd6 100644 --- a/include/cpp-sort/utility/functional.h +++ b/include/cpp-sort/utility/functional.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2021 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_UTILITY_FUNCTIONAL_H_ @@ -13,6 +13,7 @@ #include #include #include +#include "../detail/raw_checkers.h" #include "../detail/type_traits.h" namespace cppsort @@ -30,7 +31,8 @@ namespace utility { template struct projection_base_pipe_result: - projection_base + projection_base, + cppsort::detail::raw_check_is_transparent { T lhs; U rhs; @@ -106,7 +108,8 @@ namespace utility { template struct as_projection_fn: - projection_base + projection_base, + cppsort::detail::raw_check_is_transparent { private: @@ -114,7 +117,7 @@ namespace utility public: - as_projection_fn() = delete; + as_projection_fn() = default; as_projection_fn(const as_projection_fn&) = default; as_projection_fn(as_projection_fn&&) = default; @@ -172,7 +175,8 @@ namespace utility {}; template - struct as_comparison_fn + struct as_comparison_fn: + cppsort::detail::raw_check_is_transparent { private: @@ -180,7 +184,7 @@ namespace utility public: - as_comparison_fn() = delete; + as_comparison_fn() = default; as_comparison_fn(const as_comparison_fn&) = default; as_comparison_fn(as_comparison_fn&&) = default; @@ -281,7 +285,8 @@ namespace utility //////////////////////////////////////////////////////////// // Math functions (mostly useful for buffer providers) - struct half + struct half: + projection_base { template constexpr auto operator()(T&& value) const @@ -289,9 +294,12 @@ namespace utility { return std::forward(value) / 2; } + + using is_transparent = void; }; - struct log + struct log: + projection_base { template constexpr auto operator()(T&& value) const @@ -300,9 +308,12 @@ namespace utility using std::log; return log(std::forward(value)); } + + using is_transparent = void; }; - struct sqrt + struct sqrt: + projection_base { template constexpr auto operator()(T&& value) const @@ -311,6 +322,8 @@ namespace utility using std::sqrt; return sqrt(std::forward(value)); } + + using is_transparent = void; }; //////////////////////////////////////////////////////////// diff --git a/include/cpp-sort/version.h b/include/cpp-sort/version.h index 234660a8..ee66059c 100644 --- a/include/cpp-sort/version.h +++ b/include/cpp-sort/version.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2021 Morwenn + * Copyright (c) 2018-2022 Morwenn * SPDX-License-Identifier: MIT */ #ifndef CPPSORT_VERSION_H_ @@ -8,7 +8,7 @@ // Semantic versioning macros #define CPPSORT_VERSION_MAJOR 1 -#define CPPSORT_VERSION_MINOR 12 -#define CPPSORT_VERSION_PATCH 1 +#define CPPSORT_VERSION_MINOR 13 +#define CPPSORT_VERSION_PATCH 0 #endif // CPPSORT_VERSION_H_ diff --git a/testsuite/CMakeLists.txt b/tests/CMakeLists.txt similarity index 86% rename from testsuite/CMakeLists.txt rename to tests/CMakeLists.txt index 87eaee9c..da3a53fc 100644 --- a/testsuite/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2021 Morwenn +# Copyright (c) 2015-2022 Morwenn # SPDX-License-Identifier: MIT include(cpp-sort-utils) @@ -13,12 +13,13 @@ set(SANITIZE "" CACHE STRING "Comma-separated list of options to pass to -fsanit option(CPPSORT_USE_VALGRIND "Whether to run the tests with Valgrind" ${USE_VALGRIND}) option(CPPSORT_ENABLE_COVERAGE "Whether to produce code coverage" ${ENABLE_COVERAGE}) set(CPPSORT_SANITIZE ${SANITIZE} CACHE STRING "Comma-separated list of options to pass to -fsanitize") +option(CPPSORT_STATIC_TESTS "Whether to turn some tests into static assertions" OFF) ######################################## # Find or download Catch2 -message(STATUS "Looking for Catch2 2.6.0+") -find_package(Catch2 2.6.0 QUIET) +message(STATUS "Looking for Catch2 3.0.0+") +find_package(Catch2 3.0.0 QUIET) if (TARGET Catch2::Catch2) get_target_property(Catch2_INCLUDE_DIRECTORY Catch2::Catch2 INTERFACE_INCLUDE_DIRECTORIES) message(STATUS "Catch2 found: ${Catch2_INCLUDE_DIRECTORY}") @@ -26,11 +27,11 @@ else() message(STATUS "Catch2 not found") download_project(PROJ Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2 - GIT_TAG v2.13.7 + GIT_TAG v3.0.0-preview4 UPDATE_DISCONNECTED 1 ) add_subdirectory(${Catch2_SOURCE_DIR} ${Catch2_BINARY_DIR}) - list(APPEND CMAKE_MODULE_PATH ${Catch2_SOURCE_DIR}/contrib) + list(APPEND CMAKE_MODULE_PATH ${Catch2_SOURCE_DIR}/extras) endif() include(Catch) @@ -52,18 +53,19 @@ macro(configure_tests target) target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(${target} PRIVATE - Catch2::Catch2 + Catch2::Catch2WithMain cpp-sort::cpp-sort ) target_compile_definitions(${target} PRIVATE # Somewhat speed up Catch2 compile times CATCH_CONFIG_FAST_COMPILE - CATCH_CONFIG_DISABLE_MATCHERS # Enable assertions for more thorough tests CPPSORT_ENABLE_ASSERTIONS # We test deprecated code but we don't want it to warn CPPSORT_DISABLE_DEPRECATION_WARNINGS + # Conditionally turn some tests into static assertions + $<$>:CATCH_CONFIG_RUNTIME_STATIC_REQUIRE> ) # More warnings and settings @@ -104,23 +106,9 @@ endmacro() add_executable(main-tests # Tooling - main.cpp testing-tools/random.cpp - # General tests - every_instantiated_sorter.cpp - every_sorter.cpp - every_sorter_internal_compare.cpp - every_sorter_long_string.cpp - every_sorter_move_compare_projection.cpp - every_sorter_move_only.cpp - every_sorter_no_post_iterator.cpp - every_sorter_non_const_compare.cpp - every_sorter_rvalue_projection.cpp - every_sorter_small_collections.cpp - every_sorter_span.cpp - every_sorter_throwing_moves.cpp - every_sorter_tricky_difference_type.cpp + # General utilities tests is_stable.cpp rebind_iterator_category.cpp sort_array.cpp @@ -162,7 +150,9 @@ add_executable(main-tests # Comparators tests comparators/case_insensitive_less.cpp + comparators/flip_not.cpp comparators/natural_less.cpp + comparators/projection_compare.cpp comparators/total_less.cpp comparators/transparent_comparators.cpp @@ -202,6 +192,19 @@ add_executable(main-tests sorters/default_sorter.cpp $<$>:sorters/default_sorter_fptr.cpp> sorters/default_sorter_projection.cpp + sorters/every_instantiated_sorter.cpp + sorters/every_sorter.cpp + sorters/every_sorter_internal_compare.cpp + sorters/every_sorter_long_string.cpp + sorters/every_sorter_move_compare_projection.cpp + sorters/every_sorter_move_only.cpp + sorters/every_sorter_no_post_iterator.cpp + sorters/every_sorter_non_const_compare.cpp + sorters/every_sorter_rvalue_projection.cpp + sorters/every_sorter_small_collections.cpp + sorters/every_sorter_span.cpp + sorters/every_sorter_throwing_moves.cpp + sorters/every_sorter_tricky_difference_type.cpp sorters/merge_insertion_sorter_projection.cpp sorters/merge_sorter.cpp sorters/merge_sorter_projection.cpp @@ -216,6 +219,7 @@ add_executable(main-tests # Utilities tests utility/adapter_storage.cpp + utility/as_comparison.cpp utility/as_projection.cpp utility/as_projection_iterable.cpp utility/branchless_traits.cpp @@ -235,11 +239,10 @@ if (NOT "${CPPSORT_SANITIZE}" MATCHES "address|memory") # the global [de]allocation functions in order to test the # algorithms that have a fallback when heap exhaustion occurs, # which isn't something we want for the main tests - main.cpp testing-tools/new_delete.cpp testing-tools/random.cpp - heap_memory_exhaustion.cpp probes/every_probe_heap_memory_exhaustion.cpp + sorters/every_sorter_heap_memory_exhaustion.cpp ) configure_tests(heap-memory-exhaustion-tests) endif() @@ -257,7 +260,7 @@ endif() include(CTest) -string(RANDOM LENGTH 5 ALPHABET 0123456789 RNG_SEED) +string(RANDOM LENGTH 6 ALPHABET 123456789 RNG_SEED) catch_discover_tests(main-tests EXTRA_ARGS --rng-seed ${RNG_SEED}) if (NOT "${CPPSORT_SANITIZE}" MATCHES "address|memory") catch_discover_tests(heap-memory-exhaustion-tests EXTRA_ARGS --rng-seed ${RNG_SEED}) diff --git a/testsuite/adapters/container_aware_adapter.cpp b/tests/adapters/container_aware_adapter.cpp similarity index 61% rename from testsuite/adapters/container_aware_adapter.cpp rename to tests/adapters/container_aware_adapter.cpp index 750b82e9..d828b442 100644 --- a/testsuite/adapters/container_aware_adapter.cpp +++ b/tests/adapters/container_aware_adapter.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2016-2020 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include @@ -47,26 +47,27 @@ TEST_CASE( "basic tests with container_aware_adapter", SECTION( "with comparison" ) { CHECK( sorter(collection, std::greater<>{}) ); - CHECK( not cppsort::is_stable&, std::greater<>)>::value ); + STATIC_CHECK( not cppsort::is_stable&, std::greater<>)>::value ); } SECTION( "with projection" ) { CHECK( sorter(collection, std::negate<>{}) ); - CHECK( not cppsort::is_stable&, std::negate<>)>::value ); + STATIC_CHECK( not cppsort::is_stable&, std::negate<>)>::value ); } SECTION( "with automagic comparison-projection" ) { CHECK( sorter(collection, std::greater<>{}, std::negate<>{}) ); - CHECK( not cppsort::is_stable&, std::greater<>, std::negate<>)>::value ); + STATIC_CHECK( not cppsort::is_stable&, + std::greater<>, std::negate<>)>::value ); } SECTION( "more about stability" ) { - CHECK( cppsort::is_stable&)>::value ); - CHECK( cppsort::is_stable::iterator, std::list::iterator)>::value ); - CHECK( cppsort::is_stable::iterator, - foobar::cool_list::iterator)>::value ); + STATIC_CHECK( cppsort::is_stable&)>::value ); + STATIC_CHECK( cppsort::is_stable::iterator, std::list::iterator)>::value ); + STATIC_CHECK( cppsort::is_stable::iterator, + foobar::cool_list::iterator)>::value ); } } diff --git a/testsuite/adapters/container_aware_adapter_forward_list.cpp b/tests/adapters/container_aware_adapter_forward_list.cpp similarity index 62% rename from testsuite/adapters/container_aware_adapter_forward_list.cpp rename to tests/adapters/container_aware_adapter_forward_list.cpp index 5a7be4e0..3bd30b99 100644 --- a/testsuite/adapters/container_aware_adapter_forward_list.cpp +++ b/tests/adapters/container_aware_adapter_forward_list.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -30,25 +30,25 @@ TEST_CASE( "container_aware_adapter and std::forward_list", cppsort::container_aware_adapter< cppsort::insertion_sorter > sorter; - std::forward_list collection(std::begin(vec), std::end(vec)); + std::forward_list collection(vec.begin(), vec.end()); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::greater<>{}, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); // Make sure that the generic overload is also called when needed auto vec_copy = vec; sorter(vec_copy); - CHECK( std::is_sorted(std::begin(vec_copy), std::end(vec_copy)) ); + CHECK( std::is_sorted(vec_copy.begin(), vec_copy.end()) ); } SECTION( "merge_sorter" ) @@ -56,25 +56,25 @@ TEST_CASE( "container_aware_adapter and std::forward_list", cppsort::container_aware_adapter< cppsort::merge_sorter > sorter; - std::forward_list collection(std::begin(vec), std::end(vec)); + std::forward_list collection(vec.begin(), vec.end()); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::greater<>{}, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); // Make sure that the generic overload is also called when needed auto vec_copy = vec; sorter(vec_copy); - CHECK( std::is_sorted(std::begin(vec_copy), std::end(vec_copy)) ); + CHECK( std::is_sorted(vec_copy.begin(), vec_copy.end()) ); } SECTION( "mel_sorter" ) @@ -108,24 +108,24 @@ TEST_CASE( "container_aware_adapter and std::forward_list", cppsort::container_aware_adapter< cppsort::selection_sorter > sorter; - std::forward_list collection(std::begin(vec), std::end(vec)); + std::forward_list collection(vec.begin(), vec.end()); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::greater<>{}, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); // Make sure that the generic overload is also called when needed auto vec_copy = vec; sorter(vec_copy); - CHECK( std::is_sorted(std::begin(vec_copy), std::end(vec_copy)) ); + CHECK( std::is_sorted(vec_copy.begin(), vec_copy.end()) ); } } diff --git a/testsuite/adapters/container_aware_adapter_list.cpp b/tests/adapters/container_aware_adapter_list.cpp similarity index 62% rename from testsuite/adapters/container_aware_adapter_list.cpp rename to tests/adapters/container_aware_adapter_list.cpp index e088b501..72f4a621 100644 --- a/testsuite/adapters/container_aware_adapter_list.cpp +++ b/tests/adapters/container_aware_adapter_list.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -30,25 +30,25 @@ TEST_CASE( "container_aware_adapter and std::list", cppsort::container_aware_adapter< cppsort::insertion_sorter > sorter; - std::list collection(std::begin(vec), std::end(vec)); + std::list collection(vec.begin(), vec.end()); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::greater<>{}, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); // Make sure that the generic overload is also called when needed auto vec_copy = vec; sorter(vec_copy); - CHECK( std::is_sorted(std::begin(vec_copy), std::end(vec_copy)) ); + CHECK( std::is_sorted(vec_copy.begin(), vec_copy.end()) ); } SECTION( "merge_sorter" ) @@ -56,25 +56,25 @@ TEST_CASE( "container_aware_adapter and std::list", cppsort::container_aware_adapter< cppsort::merge_sorter > sorter; - std::list collection(std::begin(vec), std::end(vec)); + std::list collection(vec.begin(), vec.end()); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::greater<>{}, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); // Make sure that the generic overload is also called when needed auto vec_copy = vec; sorter(vec_copy); - CHECK( std::is_sorted(std::begin(vec_copy), std::end(vec_copy)) ); + CHECK( std::is_sorted(vec_copy.begin(), vec_copy.end()) ); } SECTION( "mel_sorter" ) @@ -108,24 +108,24 @@ TEST_CASE( "container_aware_adapter and std::list", cppsort::container_aware_adapter< cppsort::selection_sorter > sorter; - std::list collection(std::begin(vec), std::end(vec)); + std::list collection(vec.begin(), vec.end()); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); - collection = { std::begin(vec), std::end(vec) }; + collection = { vec.begin(), vec.end() }; sorter(collection, std::greater<>{}, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); // Make sure that the generic overload is also called when needed auto vec_copy = vec; sorter(vec_copy); - CHECK( std::is_sorted(std::begin(vec_copy), std::end(vec_copy)) ); + CHECK( std::is_sorted(vec_copy.begin(), vec_copy.end()) ); } } diff --git a/testsuite/adapters/counting_adapter.cpp b/tests/adapters/counting_adapter.cpp similarity index 97% rename from testsuite/adapters/counting_adapter.cpp rename to tests/adapters/counting_adapter.cpp index 46a2753e..67e80ec0 100644 --- a/testsuite/adapters/counting_adapter.cpp +++ b/tests/adapters/counting_adapter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/testsuite/adapters/every_adapter_fptr.cpp b/tests/adapters/every_adapter_fptr.cpp similarity index 76% rename from testsuite/adapters/every_adapter_fptr.cpp rename to tests/adapters/every_adapter_fptr.cpp index b9839a82..9d6465b1 100644 --- a/testsuite/adapters/every_adapter_fptr.cpp +++ b/tests/adapters/every_adapter_fptr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2021 Morwenn + * Copyright (c) 2018-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -38,10 +38,10 @@ TEST_CASE( "function pointer test for every adapter", constexpr void(*sort_it2)(std::list&, std::greater<>) = sorter{}; sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); sort_it2(li, std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); } SECTION( "counting_adapter" ) @@ -53,7 +53,7 @@ TEST_CASE( "function pointer test for every adapter", std::size_t res = sort_it(collection, std::greater<>{}); CHECK( res == 2080 ); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } SECTION( "hybrid_adapter" ) @@ -65,7 +65,7 @@ TEST_CASE( "function pointer test for every adapter", constexpr void(*sort_it)(std::vector&, std::greater<>) = sorter{}; sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } SECTION( "indirect_adapter" ) @@ -76,7 +76,7 @@ TEST_CASE( "function pointer test for every adapter", constexpr void(*sort_it)(std::vector&, std::greater<>) = sorter{}; sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } SECTION( "out_of_place_adapter" ) @@ -89,13 +89,13 @@ TEST_CASE( "function pointer test for every adapter", constexpr void(*sort_it3)(std::forward_list&, std::greater<>) = sorter{}; sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); sort_it2(li, std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); sort_it3(fli, std::greater<>{}); - CHECK( std::is_sorted(std::begin(fli), std::end(fli), std::greater<>{}) ); + CHECK( std::is_sorted(fli.begin(), fli.end(), std::greater<>{}) ); } SECTION( "schwartz_adapter" ) @@ -106,7 +106,7 @@ TEST_CASE( "function pointer test for every adapter", constexpr void(*sort_it)(std::vector&, std::greater<>) = sorter{}; sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } SECTION( "schwartz_adapter" ) @@ -118,7 +118,7 @@ TEST_CASE( "function pointer test for every adapter", std::array arr = {{ 4, 3, 2, 5, 6, 1 }}; sort_it(arr, std::greater<>{}); - CHECK( std::is_sorted(std::begin(arr), std::end(arr), std::greater<>{}) ); + CHECK( std::is_sorted(arr.begin(), arr.end(), std::greater<>{}) ); } SECTION( "self_sort_adapter" ) @@ -130,10 +130,10 @@ TEST_CASE( "function pointer test for every adapter", constexpr void(*sort_it2)(std::list&, std::greater<>) = sorter{}; sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); sort_it2(li, std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); } SECTION( "stable_adapter" ) @@ -145,10 +145,10 @@ TEST_CASE( "function pointer test for every adapter", constexpr void(*sort_it2)(std::list&, std::greater<>) = sorter{}; sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); sort_it2(li, std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); } SECTION( "small_array_adapter" ) @@ -166,15 +166,15 @@ TEST_CASE( "function pointer test for every adapter", auto to_sort = arr; sort_it1(to_sort, std::greater<>{}); - CHECK( std::is_sorted(std::begin(to_sort), std::end(to_sort), std::greater<>{}) ); + CHECK( std::is_sorted(to_sort.begin(), to_sort.end(), std::greater<>{}) ); to_sort = arr; sort_it2(to_sort, std::greater<>{}); - CHECK( std::is_sorted(std::begin(to_sort), std::end(to_sort), std::greater<>{}) ); + CHECK( std::is_sorted(to_sort.begin(), to_sort.end(), std::greater<>{}) ); to_sort = arr; sort_it3(to_sort, std::greater<>{}); - CHECK( std::is_sorted(std::begin(to_sort), std::end(to_sort), std::greater<>{}) ); + CHECK( std::is_sorted(to_sort.begin(), to_sort.end(), std::greater<>{}) ); } SECTION( "stable_adapter" ) @@ -185,7 +185,7 @@ TEST_CASE( "function pointer test for every adapter", constexpr void(*sort_it)(std::vector&, std::greater<>) = sorter{}; sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } SECTION( "verge_adapter" ) @@ -196,6 +196,6 @@ TEST_CASE( "function pointer test for every adapter", constexpr void(*sort_it)(std::vector&, std::greater<>) = sorter{}; sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } } diff --git a/testsuite/adapters/every_adapter_internal_compare.cpp b/tests/adapters/every_adapter_internal_compare.cpp similarity index 76% rename from testsuite/adapters/every_adapter_internal_compare.cpp rename to tests/adapters/every_adapter_internal_compare.cpp index fc316223..12aa1af4 100644 --- a/testsuite/adapters/every_adapter_internal_compare.cpp +++ b/tests/adapters/every_adapter_internal_compare.cpp @@ -1,12 +1,12 @@ /* - * Copyright (c) 2017-2018 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include #include -#include +#include #include #include #include @@ -33,7 +33,7 @@ TEST_CASE( "test most adapters with a pointer to member function comparison", // Sort and check it's sorted std::size_t res = sorter{}(collection, &internal_compare::compare_to); CHECK( res == 2080 ); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "hybrid_adapter" ) @@ -44,7 +44,7 @@ TEST_CASE( "test most adapters with a pointer to member function comparison", >; sorter{}(collection, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "indirect_adapter" ) @@ -54,7 +54,7 @@ TEST_CASE( "test most adapters with a pointer to member function comparison", >; sorter{}(collection, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "out_of_place_adapter" ) @@ -64,13 +64,13 @@ TEST_CASE( "test most adapters with a pointer to member function comparison", >; sorter{}(collection, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); std::list> li; distribution(std::back_inserter(li), 65, 0); sorter{}(li, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + CHECK( std::is_sorted(li.begin(), li.end()) ); } SECTION( "schwartz_adapter" ) @@ -80,7 +80,7 @@ TEST_CASE( "test most adapters with a pointer to member function comparison", >; sorter{}(collection, &internal_compare::compare_to, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } SECTION( "self_sort_adapter" ) @@ -90,13 +90,13 @@ TEST_CASE( "test most adapters with a pointer to member function comparison", >; sorter{}(collection, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); std::list> li; distribution(std::back_inserter(li), 65, 0); sorter{}(li, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + CHECK( std::is_sorted(li.begin(), li.end()) ); } SECTION( "stable_adapter" ) @@ -106,13 +106,13 @@ TEST_CASE( "test most adapters with a pointer to member function comparison", >; sorter{}(collection, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); std::list> li; distribution(std::back_inserter(li), 65, 0); sorter{}(li, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + CHECK( std::is_sorted(li.begin(), li.end()) ); } SECTION( "small_array_adapter" ) @@ -123,15 +123,15 @@ TEST_CASE( "test most adapters with a pointer to member function comparison", auto to_sort = arr; small_array_adapter{}(to_sort, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(to_sort), std::end(to_sort)) ); + CHECK( std::is_sorted(to_sort.begin(), to_sort.end()) ); to_sort = arr; small_array_adapter{}(to_sort, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(to_sort), std::end(to_sort)) ); + CHECK( std::is_sorted(to_sort.begin(), to_sort.end()) ); to_sort = arr; small_array_adapter{}(to_sort, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(to_sort), std::end(to_sort)) ); + CHECK( std::is_sorted(to_sort.begin(), to_sort.end()) ); } SECTION( "stable_adapter" ) @@ -141,7 +141,7 @@ TEST_CASE( "test most adapters with a pointer to member function comparison", >; sorter{}(collection, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "verge_adapter" ) @@ -151,6 +151,6 @@ TEST_CASE( "test most adapters with a pointer to member function comparison", >; sorter{}(collection, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } } diff --git a/testsuite/adapters/every_adapter_non_const_compare.cpp b/tests/adapters/every_adapter_non_const_compare.cpp similarity index 76% rename from testsuite/adapters/every_adapter_non_const_compare.cpp rename to tests/adapters/every_adapter_non_const_compare.cpp index 3294b695..406cd58e 100644 --- a/testsuite/adapters/every_adapter_non_const_compare.cpp +++ b/tests/adapters/every_adapter_non_const_compare.cpp @@ -1,11 +1,12 @@ /* - * Copyright (c) 2020 Morwenn + * Copyright (c) 2020-2022 Morwenn * SPDX-License-Identifier: MIT */ #include +#include #include #include -#include +#include #include #include #include @@ -48,7 +49,7 @@ TEST_CASE( "test adapters extended compatibility with LWG 3031", "[adapters]" ) // Sort and check it's sorted std::size_t res = sorter{}(vec, non_const_compare); CHECK( res == 2080 ); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } SECTION( "hybrid_adapter" ) @@ -59,7 +60,7 @@ TEST_CASE( "test adapters extended compatibility with LWG 3031", "[adapters]" ) >; sorter{}(vec, non_const_compare); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } SECTION( "indirect_adapter" ) @@ -69,7 +70,7 @@ TEST_CASE( "test adapters extended compatibility with LWG 3031", "[adapters]" ) >; sorter{}(vec, non_const_compare); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } SECTION( "out_of_place_adapter" ) @@ -79,10 +80,10 @@ TEST_CASE( "test adapters extended compatibility with LWG 3031", "[adapters]" ) >; sorter{}(vec, non_const_compare); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); sorter{}(li, non_const_compare); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + CHECK( std::is_sorted(li.begin(), li.end()) ); } SECTION( "schwartz_adapter" ) @@ -92,7 +93,7 @@ TEST_CASE( "test adapters extended compatibility with LWG 3031", "[adapters]" ) >; sorter{}(vec, non_const_compare, fake_identity{}); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } SECTION( "self_sort_adapter" ) @@ -102,10 +103,10 @@ TEST_CASE( "test adapters extended compatibility with LWG 3031", "[adapters]" ) >; sorter{}(vec, non_const_compare); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); sorter{}(li, non_const_compare); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + CHECK( std::is_sorted(li.begin(), li.end()) ); } SECTION( "stable_adapter" ) @@ -115,10 +116,10 @@ TEST_CASE( "test adapters extended compatibility with LWG 3031", "[adapters]" ) >; sorter{}(vec, non_const_compare); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); sorter{}(li, non_const_compare); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + CHECK( std::is_sorted(li.begin(), li.end()) ); } SECTION( "small_array_adapter" ) @@ -129,15 +130,15 @@ TEST_CASE( "test adapters extended compatibility with LWG 3031", "[adapters]" ) auto to_sort = arr; small_array_adapter{}(to_sort, non_const_compare); - CHECK( std::is_sorted(std::begin(to_sort), std::end(to_sort)) ); + CHECK( std::is_sorted(to_sort.begin(), to_sort.end()) ); to_sort = arr; small_array_adapter{}(to_sort, non_const_compare); - CHECK( std::is_sorted(std::begin(to_sort), std::end(to_sort)) ); + CHECK( std::is_sorted(to_sort.begin(), to_sort.end()) ); to_sort = arr; small_array_adapter{}(to_sort, non_const_compare); - CHECK( std::is_sorted(std::begin(to_sort), std::end(to_sort)) ); + CHECK( std::is_sorted(to_sort.begin(), to_sort.end()) ); } SECTION( "stable_adapter" ) @@ -147,7 +148,7 @@ TEST_CASE( "test adapters extended compatibility with LWG 3031", "[adapters]" ) >; sorter{}(vec, non_const_compare); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } SECTION( "verge_adapter" ) @@ -157,6 +158,6 @@ TEST_CASE( "test adapters extended compatibility with LWG 3031", "[adapters]" ) >; sorter{}(vec, non_const_compare); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } } diff --git a/testsuite/adapters/every_adapter_stateful_sorter.cpp b/tests/adapters/every_adapter_stateful_sorter.cpp similarity index 76% rename from testsuite/adapters/every_adapter_stateful_sorter.cpp rename to tests/adapters/every_adapter_stateful_sorter.cpp index 21e59523..8c19d566 100644 --- a/testsuite/adapters/every_adapter_stateful_sorter.cpp +++ b/tests/adapters/every_adapter_stateful_sorter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 Morwenn + * Copyright (c) 2019-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -83,10 +83,10 @@ TEST_CASE( "test stateful sorters with every adapter", cppsort::container_aware_adapter> sort_it(sorter); sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); sort_it(li, std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); } SECTION( "counting_adapter" ) @@ -95,7 +95,7 @@ TEST_CASE( "test stateful sorters with every adapter", cppsort::counting_adapter> sort_it(sorter); sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } SECTION( "hybrid_adapter" ) @@ -111,15 +111,15 @@ TEST_CASE( "test stateful sorters with every adapter", int res1 = sort_it(fli, std::greater<>{}); CHECK( res1 == 1 ); - CHECK( std::is_sorted(std::begin(fli), std::end(fli), std::greater<>{}) ); + CHECK( std::is_sorted(fli.begin(), fli.end(), std::greater<>{}) ); int res2 = sort_it(li, std::greater<>{}); CHECK( res2 == 2 ); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); int res3 = sort_it(collection, std::greater<>{}); CHECK( res3 == 3 ); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } SECTION( "indirect_adapter" ) @@ -128,7 +128,7 @@ TEST_CASE( "test stateful sorters with every adapter", cppsort::indirect_adapter> sort_it(sorter); sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } SECTION( "out_of_place_adapter" ) @@ -137,13 +137,13 @@ TEST_CASE( "test stateful sorters with every adapter", cppsort::out_of_place_adapter> sort_it(sorter); sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); sort_it(li, std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); sort_it(fli, std::greater<>{}); - CHECK( std::is_sorted(std::begin(fli), std::end(fli), std::greater<>{}) ); + CHECK( std::is_sorted(fli.begin(), fli.end(), std::greater<>{}) ); } SECTION( "schwartz_adapter" ) @@ -152,7 +152,7 @@ TEST_CASE( "test stateful sorters with every adapter", cppsort::schwartz_adapter> sort_it(sorter); sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } SECTION( "self_sort_adapter" ) @@ -161,10 +161,10 @@ TEST_CASE( "test stateful sorters with every adapter", cppsort::self_sort_adapter> sort_it(sorter); sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); sort_it(li, std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); } SECTION( "stable_adapter" ) @@ -175,10 +175,10 @@ TEST_CASE( "test stateful sorters with every adapter", >(cppsort::self_sort_adapter>(sorter)); sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); sort_it(li, std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); } SECTION( "stable_adapter" ) @@ -187,7 +187,7 @@ TEST_CASE( "test stateful sorters with every adapter", cppsort::stable_adapter> sort_it(sorter); sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } SECTION( "verge_adapter" ) @@ -196,6 +196,6 @@ TEST_CASE( "test stateful sorters with every adapter", cppsort::verge_adapter> sort_it(sorter); sort_it(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } } diff --git a/testsuite/adapters/every_adapter_tricky_difference_type.cpp b/tests/adapters/every_adapter_tricky_difference_type.cpp similarity index 93% rename from testsuite/adapters/every_adapter_tricky_difference_type.cpp rename to tests/adapters/every_adapter_tricky_difference_type.cpp index 33c44d47..7deb5a2a 100644 --- a/testsuite/adapters/every_adapter_tricky_difference_type.cpp +++ b/tests/adapters/every_adapter_tricky_difference_type.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2021 Morwenn + * Copyright (c) 2021-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include diff --git a/tests/adapters/hybrid_adapter_is_stable.cpp b/tests/adapters/hybrid_adapter_is_stable.cpp new file mode 100644 index 00000000..f8288ad1 --- /dev/null +++ b/tests/adapters/hybrid_adapter_is_stable.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2016-2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TEST_CASE( "hybrid_adapter stability checks", + "[hybrid_adapter][is_stable]" ) +{ + SECTION( "simple sorters" ) + { + using sorter = cppsort::hybrid_adapter< + cppsort::selection_sorter, + cppsort::rebind_iterator_category< + cppsort::merge_sorter, + std::bidirectional_iterator_tag + >, + cppsort::pdq_sorter + >; + + STATIC_CHECK( not cppsort::is_stable&)>::value ); + STATIC_CHECK( not cppsort::is_stable::iterator, + std::vector::iterator)>::value ); + + STATIC_CHECK( cppsort::is_stable&)>::value ); + STATIC_CHECK( cppsort::is_stable::iterator, + std::list::iterator)>::value ); + + STATIC_CHECK( not cppsort::is_stable&)>::value ); + STATIC_CHECK( not cppsort::is_stable::iterator, + std::forward_list::iterator)>::value ); + } + + SECTION( "nested hybrid_adapter" ) + { + using sorter = cppsort::hybrid_adapter< + cppsort::selection_sorter, + cppsort::hybrid_adapter< + cppsort::rebind_iterator_category< + cppsort::merge_sorter, + std::bidirectional_iterator_tag + > + >, + cppsort::pdq_sorter + >; + + STATIC_CHECK( not cppsort::is_stable&)>::value ); + STATIC_CHECK( not cppsort::is_stable::iterator, + std::vector::iterator)>::value ); + + STATIC_CHECK( cppsort::is_stable&)>::value ); + STATIC_CHECK( cppsort::is_stable::iterator, + std::list::iterator)>::value ); + + STATIC_CHECK( not cppsort::is_stable&)>::value ); + STATIC_CHECK( not cppsort::is_stable::iterator, + std::forward_list::iterator)>::value ); + } + + SECTION( "with small_array_adapter" ) + { + using sorter = cppsort::hybrid_adapter< + cppsort::small_array_adapter< + cppsort::sorting_network_sorter, + std::make_index_sequence<14u> + >, + cppsort::merge_sorter + >; + + STATIC_CHECK( cppsort::is_stable&)>::value ); + STATIC_CHECK( cppsort::is_stable::iterator, + std::vector::iterator)>::value ); + + STATIC_CHECK( cppsort::is_stable&)>::value ); + STATIC_CHECK( cppsort::is_stable::iterator, + std::list::iterator)>::value ); + + STATIC_CHECK( cppsort::is_stable&)>::value ); + STATIC_CHECK( cppsort::is_stable::iterator, + std::forward_list::iterator)>::value ); + + STATIC_CHECK( not cppsort::is_stable&)>::value ); + STATIC_CHECK( cppsort::is_stable::iterator, + std::array::iterator)>::value ); + + STATIC_CHECK( cppsort::is_stable&)>::value ); + STATIC_CHECK( cppsort::is_stable::iterator, + std::array::iterator)>::value ); + + STATIC_CHECK( not cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable::value ); + } +} diff --git a/testsuite/adapters/hybrid_adapter_many_sorters.cpp b/tests/adapters/hybrid_adapter_many_sorters.cpp similarity index 96% rename from testsuite/adapters/hybrid_adapter_many_sorters.cpp rename to tests/adapters/hybrid_adapter_many_sorters.cpp index 19c1fb7b..24be7d2c 100644 --- a/testsuite/adapters/hybrid_adapter_many_sorters.cpp +++ b/tests/adapters/hybrid_adapter_many_sorters.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2018 Morwenn + * Copyright (c) 2018-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include diff --git a/testsuite/adapters/hybrid_adapter_nested.cpp b/tests/adapters/hybrid_adapter_nested.cpp similarity index 97% rename from testsuite/adapters/hybrid_adapter_nested.cpp rename to tests/adapters/hybrid_adapter_nested.cpp index 9824ac9e..fcb42489 100644 --- a/testsuite/adapters/hybrid_adapter_nested.cpp +++ b/tests/adapters/hybrid_adapter_nested.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -8,7 +8,7 @@ #include #include #include -#include +#include namespace { diff --git a/testsuite/adapters/hybrid_adapter_partial_compare.cpp b/tests/adapters/hybrid_adapter_partial_compare.cpp similarity index 85% rename from testsuite/adapters/hybrid_adapter_partial_compare.cpp rename to tests/adapters/hybrid_adapter_partial_compare.cpp index e483043a..b189f0d0 100644 --- a/testsuite/adapters/hybrid_adapter_partial_compare.cpp +++ b/tests/adapters/hybrid_adapter_partial_compare.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2015-2020 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include @@ -61,7 +61,7 @@ namespace } TEST_CASE( "hybrid_adapter over partial comparison sorter", - "[hybrid_adapter][compare]" ) + "[hybrid_adapter][comparison]" ) { // Check that hybrid_adapter works as expected even // with partial comparison sorters @@ -79,7 +79,7 @@ TEST_CASE( "hybrid_adapter over partial comparison sorter", sorter_type res1 = sorter(vec); CHECK( res1 == sorter_type::ascending ); - sorter_type res2 = sorter(std::begin(vec), std::end(vec)); + sorter_type res2 = sorter(vec.begin(), vec.end()); CHECK( res2 == sorter_type::ascending ); } @@ -88,7 +88,7 @@ TEST_CASE( "hybrid_adapter over partial comparison sorter", sorter_type res1 = sorter(vec, std::less<>{}); CHECK( res1 == sorter_type::ascending ); - sorter_type res2 = sorter(std::begin(vec), std::end(vec), std::less<>{}); + sorter_type res2 = sorter(vec.begin(), vec.end(), std::less<>{}); CHECK( res2 == sorter_type::ascending ); } @@ -97,7 +97,7 @@ TEST_CASE( "hybrid_adapter over partial comparison sorter", sorter_type res1 = sorter(vec, std::greater<>{}); CHECK( res1 == sorter_type::descending ); - sorter_type res2 = sorter(std::begin(vec), std::end(vec), std::greater<>{}); + sorter_type res2 = sorter(vec.begin(), vec.end(), std::greater<>{}); CHECK( res2 == sorter_type::descending ); } @@ -106,7 +106,7 @@ TEST_CASE( "hybrid_adapter over partial comparison sorter", sorter_type res1 = sorter(vec, std::less_equal<>{}); CHECK( res1 == sorter_type::generic ); - sorter_type res2 = sorter(std::begin(vec), std::end(vec), std::less_equal<>{}); + sorter_type res2 = sorter(vec.begin(), vec.end(), std::less_equal<>{}); CHECK( res2 == sorter_type::generic ); } } diff --git a/testsuite/adapters/hybrid_adapter_sfinae.cpp b/tests/adapters/hybrid_adapter_sfinae.cpp similarity index 90% rename from testsuite/adapters/hybrid_adapter_sfinae.cpp rename to tests/adapters/hybrid_adapter_sfinae.cpp index 9cbda141..abe969f2 100644 --- a/testsuite/adapters/hybrid_adapter_sfinae.cpp +++ b/tests/adapters/hybrid_adapter_sfinae.cpp @@ -1,12 +1,12 @@ /* - * Copyright (c) 2015-2020 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include #include -#include +#include #include #include #include @@ -100,13 +100,13 @@ TEST_CASE( "sfinae forwarding in hybrid_adapter", SECTION( "with iterators" ) { - sorter_type res1 = sorter(std::begin(vec1), std::end(vec1)); + sorter_type res1 = sorter(vec1.begin(), vec1.end()); CHECK( res1 == sorter_type::integer ); - sorter_type res2 = sorter(std::begin(vec2), std::end(vec2)); + sorter_type res2 = sorter(vec2.begin(), vec2.end()); CHECK( res2 == sorter_type::floating_point ); - sorter_type res3 = sorter(std::begin(vec3), std::end(vec3)); + sorter_type res3 = sorter(vec3.begin(), vec3.end()); CHECK( res3 == sorter_type::generic ); } @@ -157,13 +157,13 @@ TEST_CASE( "sfinae forwarding in nested hybrid_adapter", SECTION( "with iterators" ) { - sorter_type res1 = sorter(std::begin(vec1), std::end(vec1)); + sorter_type res1 = sorter(vec1.begin(), vec1.end()); CHECK( res1 == sorter_type::integer ); - sorter_type res2 = sorter(std::begin(vec2), std::end(vec2)); + sorter_type res2 = sorter(vec2.begin(), vec2.end()); CHECK( res2 == sorter_type::floating_point ); - sorter_type res3 = sorter(std::begin(vec3), std::end(vec3)); + sorter_type res3 = sorter(vec3.begin(), vec3.end()); CHECK( res3 == sorter_type::generic ); } diff --git a/testsuite/adapters/indirect_adapter.cpp b/tests/adapters/indirect_adapter.cpp similarity index 56% rename from testsuite/adapters/indirect_adapter.cpp rename to tests/adapters/indirect_adapter.cpp index 3312f67b..671ed92b 100644 --- a/testsuite/adapters/indirect_adapter.cpp +++ b/tests/adapters/indirect_adapter.cpp @@ -1,14 +1,15 @@ /* - * Copyright (c) 2016-2020 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include #include -#include +#include #include #include +#include #include #include #include @@ -30,33 +31,33 @@ TEST_CASE( "basic tests with indirect_adapter", SECTION( "with comparison" ) { sorter(collection, std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); collection = vec; - sorter(std::begin(collection), std::end(collection), std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + sorter(collection.begin(), collection.end(), std::greater<>{}); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } SECTION( "with projection" ) { sorter(collection, std::negate<>{}); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, std::negate<>{}) ); collection = vec; - sorter(std::begin(collection), std::end(collection), std::negate<>{}); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + sorter(collection.begin(), collection.end(), std::negate<>{}); + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, std::negate<>{}) ); } SECTION( "with comparison and projection" ) { sorter(collection, std::greater<>{}, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); collection = vec; - sorter(std::begin(collection), std::end(collection), std::greater<>{}, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + sorter(collection.begin(), collection.end(), std::greater<>{}, std::negate<>{}); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } } @@ -74,19 +75,32 @@ TEST_CASE( "indirect_adapter with temporary span", SECTION( "with comparison" ) { sorter(make_span(collection), std::greater<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection), std::greater<>{}) ); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); } SECTION( "with projection" ) { sorter(make_span(collection), std::negate<>{}); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, std::negate<>{}) ); } SECTION( "with comparison and projection" ) { sorter(make_span(collection), std::greater<>{}, std::negate<>{}); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } } + + +TEST_CASE( "indirect_adapter over non-comparison sorter", + "[indirect_adapter][spread_sorter]" ) +{ + std::vector collection; collection.reserve(221); + auto distribution = dist::shuffled{}; + distribution(std::back_inserter(collection), 221, -32); + + cppsort::indirect_adapter sorter; + sorter(collection, std::negate<>{}); + CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) ); +} diff --git a/testsuite/adapters/indirect_adapter_every_sorter.cpp b/tests/adapters/indirect_adapter_every_sorter.cpp similarity index 90% rename from testsuite/adapters/indirect_adapter_every_sorter.cpp rename to tests/adapters/indirect_adapter_every_sorter.cpp index 7c9c93b7..4449cbc0 100644 --- a/testsuite/adapters/indirect_adapter_every_sorter.cpp +++ b/tests/adapters/indirect_adapter_every_sorter.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "every random-access sorter with indirect adapter", "[indirect_adapter]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::default_sorter, cppsort::drop_merge_sorter, @@ -44,7 +45,7 @@ TEMPLATE_TEST_CASE( "every random-access sorter with indirect adapter", "[indire cppsort::indirect_adapter sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } TEMPLATE_TEST_CASE( "every bidirectional sorter with indirect_adapter", "[indirect_adapter]", @@ -66,7 +67,7 @@ TEMPLATE_TEST_CASE( "every bidirectional sorter with indirect_adapter", "[indire cppsort::indirect_adapter sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } TEMPLATE_TEST_CASE( "every forward sorter with with indirect_adapter", "[indirect_adapter]", @@ -84,5 +85,5 @@ TEMPLATE_TEST_CASE( "every forward sorter with with indirect_adapter", "[indirec cppsort::indirect_adapter sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/adapters/mixed_adapters.cpp b/tests/adapters/mixed_adapters.cpp similarity index 62% rename from testsuite/adapters/mixed_adapters.cpp rename to tests/adapters/mixed_adapters.cpp index 8bf4aee5..8140d8c0 100644 --- a/testsuite/adapters/mixed_adapters.cpp +++ b/tests/adapters/mixed_adapters.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include @@ -105,7 +105,7 @@ TEST_CASE( "indirect sort with Schwartzian transform", > sorter; sorter(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); } @@ -118,7 +118,7 @@ TEST_CASE( "indirect sort with Schwartzian transform", > sorter; sorter(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); } @@ -131,7 +131,7 @@ TEST_CASE( "indirect sort with Schwartzian transform", > sorter; sorter(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); } @@ -144,7 +144,7 @@ TEST_CASE( "indirect sort with Schwartzian transform", > sorter; sorter(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); } } @@ -168,41 +168,41 @@ TEST_CASE( "stability of counting_adapter over self_sort_adapter", SECTION( "is_always_stable" ) { - CHECK( not cppsort::is_always_stable::value ); - CHECK( not cppsort::is_always_stable::value ); + STATIC_CHECK( not cppsort::is_always_stable::value ); + STATIC_CHECK( not cppsort::is_always_stable::value ); } SECTION( "is_stable" ) { using cppsort::is_stable; - CHECK( is_stable&)>::value ); - CHECK( not is_stable&)>::value ); - CHECK( is_stable&, std::greater<>)>::value ); - CHECK( not is_stable&, std::greater<>)>::value ); - CHECK( not is_stable&, std::negate<>)>::value ); - CHECK( not is_stable&, std::negate<>)>::value ); - - CHECK( not is_stable::iterator, std::list::iterator)>::value ); - CHECK( not is_stable::iterator, std::vector::iterator)>::value ); - CHECK( not is_stable::iterator, std::list::iterator, std::greater<>)>::value ); - CHECK( not is_stable::iterator, std::vector::iterator, std::greater<>)>::value ); - CHECK( not is_stable::iterator, std::list::iterator, std::negate<>)>::value ); - CHECK( not is_stable::iterator, std::vector::iterator, std::negate<>)>::value ); - - CHECK( is_stable&)>::value ); - CHECK( is_stable&)>::value ); - CHECK( is_stable&, std::greater<>)>::value ); - CHECK( is_stable&, std::greater<>)>::value ); - CHECK( is_stable&, std::negate<>)>::value ); - CHECK( is_stable&, std::negate<>)>::value ); - - CHECK( is_stable::iterator, std::list::iterator)>::value ); - CHECK( is_stable::iterator, std::vector::iterator)>::value ); - CHECK( is_stable::iterator, std::list::iterator, std::greater<>)>::value ); - CHECK( is_stable::iterator, std::vector::iterator, std::greater<>)>::value ); - CHECK( is_stable::iterator, std::list::iterator, std::negate<>)>::value ); - CHECK( is_stable::iterator, std::vector::iterator, std::negate<>)>::value ); + STATIC_CHECK( is_stable&)>::value ); + STATIC_CHECK( not is_stable&)>::value ); + STATIC_CHECK( is_stable&, std::greater<>)>::value ); + STATIC_CHECK( not is_stable&, std::greater<>)>::value ); + STATIC_CHECK( not is_stable&, std::negate<>)>::value ); + STATIC_CHECK( not is_stable&, std::negate<>)>::value ); + + STATIC_CHECK( not is_stable::iterator, std::list::iterator)>::value ); + STATIC_CHECK( not is_stable::iterator, std::vector::iterator)>::value ); + STATIC_CHECK( not is_stable::iterator, std::list::iterator, std::greater<>)>::value ); + STATIC_CHECK( not is_stable::iterator, std::vector::iterator, std::greater<>)>::value ); + STATIC_CHECK( not is_stable::iterator, std::list::iterator, std::negate<>)>::value ); + STATIC_CHECK( not is_stable::iterator, std::vector::iterator, std::negate<>)>::value ); + + STATIC_CHECK( is_stable&)>::value ); + STATIC_CHECK( is_stable&)>::value ); + STATIC_CHECK( is_stable&, std::greater<>)>::value ); + STATIC_CHECK( is_stable&, std::greater<>)>::value ); + STATIC_CHECK( is_stable&, std::negate<>)>::value ); + STATIC_CHECK( is_stable&, std::negate<>)>::value ); + + STATIC_CHECK( is_stable::iterator, std::list::iterator)>::value ); + STATIC_CHECK( is_stable::iterator, std::vector::iterator)>::value ); + STATIC_CHECK( is_stable::iterator, std::list::iterator, std::greater<>)>::value ); + STATIC_CHECK( is_stable::iterator, std::vector::iterator, std::greater<>)>::value ); + STATIC_CHECK( is_stable::iterator, std::list::iterator, std::negate<>)>::value ); + STATIC_CHECK( is_stable::iterator, std::vector::iterator, std::negate<>)>::value ); } } @@ -218,9 +218,9 @@ TEST_CASE( "stable_adapter over stable_adapter", "[stable_adapter]" ) using nested2 = cppsort::stable_adapter; using nested3 = cppsort::stable_adapter; - CHECK( std::is_same, sorter>::value ); - CHECK( std::is_same, sorter>::value ); - CHECK( std::is_same, sorter>::value ); + STATIC_CHECK( std::is_same, sorter>::value ); + STATIC_CHECK( std::is_same, sorter>::value ); + STATIC_CHECK( std::is_same, sorter>::value ); } SECTION( "over stable sorter" ) @@ -231,8 +231,8 @@ TEST_CASE( "stable_adapter over stable_adapter", "[stable_adapter]" ) using nested2 = cppsort::stable_adapter; using nested3 = cppsort::stable_adapter; - CHECK( std::is_same, sorter>::value ); - CHECK( std::is_same, sorter>::value ); - CHECK( std::is_same, sorter>::value ); + STATIC_CHECK( std::is_same, sorter>::value ); + STATIC_CHECK( std::is_same, sorter>::value ); + STATIC_CHECK( std::is_same, sorter>::value ); } } diff --git a/testsuite/adapters/return_forwarding.cpp b/tests/adapters/return_forwarding.cpp similarity index 97% rename from testsuite/adapters/return_forwarding.cpp rename to tests/adapters/return_forwarding.cpp index f2064c97..00d3badc 100644 --- a/testsuite/adapters/return_forwarding.cpp +++ b/tests/adapters/return_forwarding.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020 Morwenn + * Copyright (c) 2018-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/testsuite/adapters/schwartz_adapter_every_sorter.cpp b/tests/adapters/schwartz_adapter_every_sorter.cpp similarity index 97% rename from testsuite/adapters/schwartz_adapter_every_sorter.cpp rename to tests/adapters/schwartz_adapter_every_sorter.cpp index b46118cf..6a88e56d 100644 --- a/testsuite/adapters/schwartz_adapter_every_sorter.cpp +++ b/tests/adapters/schwartz_adapter_every_sorter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -24,6 +24,7 @@ template using wrapper = generic_wrapper; TEMPLATE_TEST_CASE( "every random-access sorter with Schwartzian transform adapter", "[schwartz_adapter]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::default_sorter, cppsort::drop_merge_sorter, diff --git a/testsuite/adapters/schwartz_adapter_every_sorter_reversed.cpp b/tests/adapters/schwartz_adapter_every_sorter_reversed.cpp similarity index 97% rename from testsuite/adapters/schwartz_adapter_every_sorter_reversed.cpp rename to tests/adapters/schwartz_adapter_every_sorter_reversed.cpp index 00ceeef4..33678413 100644 --- a/testsuite/adapters/schwartz_adapter_every_sorter_reversed.cpp +++ b/tests/adapters/schwartz_adapter_every_sorter_reversed.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -24,6 +24,7 @@ using wrapper = generic_wrapper; TEMPLATE_TEST_CASE( "every sorter with Schwartzian transform adapter and reverse iterators", "[schwartz_adapter][reverse_iterator]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::default_sorter, cppsort::drop_merge_sorter, diff --git a/testsuite/adapters/schwartz_adapter_fixed_sorters.cpp b/tests/adapters/schwartz_adapter_fixed_sorters.cpp similarity index 64% rename from testsuite/adapters/schwartz_adapter_fixed_sorters.cpp rename to tests/adapters/schwartz_adapter_fixed_sorters.cpp index 1b14f498..16d9c459 100644 --- a/testsuite/adapters/schwartz_adapter_fixed_sorters.cpp +++ b/tests/adapters/schwartz_adapter_fixed_sorters.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include @@ -69,140 +69,140 @@ TEST_CASE( "Schwartzian transform adapter with fixed-size sorters", SECTION( "size 2" ) { std::array collection; - helpers::iota(std::begin(collection), std::end(collection), -10.0, &wrapper::value); + helpers::iota(collection.begin(), collection.end(), -10.0, &wrapper::value); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); low_comparisons_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); low_moves_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); merge_exchange_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); odd_even_merge_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); sorting_network_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); } SECTION( "size 3" ) { std::array collection; - helpers::iota(std::begin(collection), std::end(collection), -10.0, &wrapper::value); + helpers::iota(collection.begin(), collection.end(), -10.0, &wrapper::value); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); low_comparisons_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); low_moves_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); merge_exchange_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); sorting_network_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); } SECTION( "size 4" ) { std::array collection; - helpers::iota(std::begin(collection), std::end(collection), -10.0, &wrapper::value); + helpers::iota(collection.begin(), collection.end(), -10.0, &wrapper::value); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); low_comparisons_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); low_moves_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); merge_exchange_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); odd_even_merge_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); sorting_network_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); } SECTION( "size 5" ) { std::array collection; - helpers::iota(std::begin(collection), std::end(collection), -10.0, &wrapper::value); + helpers::iota(collection.begin(), collection.end(), -10.0, &wrapper::value); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); low_comparisons_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); low_moves_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); merge_exchange_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); sorting_network_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); } SECTION( "size 6" ) { std::array collection; - helpers::iota(std::begin(collection), std::end(collection), -10.0, &wrapper::value); + helpers::iota(collection.begin(), collection.end(), -10.0, &wrapper::value); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); low_comparisons_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); low_moves_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); merge_exchange_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); - std::shuffle(std::begin(collection), std::end(collection), hasard::engine()); + std::shuffle(collection.begin(), collection.end(), hasard::engine()); sorting_network_sort(collection, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(collection), std::end(collection), + CHECK( helpers::is_sorted(collection.begin(), collection.end(), std::less<>{}, &wrapper::value) ); } @@ -266,7 +266,7 @@ TEST_CASE( "stability of Schwartzian transform adapter with fixed-size sorters", SECTION( "is_always_stable" ) { - CHECK( not is_always_stable>::value ); - CHECK( not is_always_stable::value ); + STATIC_CHECK( not is_always_stable>::value ); + STATIC_CHECK( not is_always_stable::value ); } } diff --git a/testsuite/adapters/self_sort_adapter.cpp b/tests/adapters/self_sort_adapter.cpp similarity index 64% rename from testsuite/adapters/self_sort_adapter.cpp rename to tests/adapters/self_sort_adapter.cpp index 7f13b033..9d045090 100644 --- a/testsuite/adapters/self_sort_adapter.cpp +++ b/tests/adapters/self_sort_adapter.cpp @@ -1,9 +1,9 @@ /* - * Copyright (c) 2015-2018 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #include -#include +#include #include #include #include @@ -184,26 +184,28 @@ TEST_CASE( "stability of self_sort_adapter", SECTION( "is_always_stable" ) { - CHECK( not cppsort::is_always_stable::value ); - CHECK( not cppsort::is_always_stable::value ); + STATIC_CHECK( not cppsort::is_always_stable::value ); + STATIC_CHECK( not cppsort::is_always_stable::value ); - CHECK( cppsort::is_always_stable::value ); - CHECK( not cppsort::is_always_stable::value ); + STATIC_CHECK( cppsort::is_always_stable::value ); + STATIC_CHECK( not cppsort::is_always_stable::value ); } SECTION( "is_stable" ) { - CHECK( not cppsort::is_stable::value ); - CHECK( not cppsort::is_stable::value ); - CHECK( cppsort::is_stable::value ); - CHECK( not cppsort::is_stable::value ); - CHECK( not cppsort::is_stable::value ); - - CHECK( cppsort::is_stable::value ); - CHECK( not cppsort::is_stable::value ); - CHECK( cppsort::is_stable::value ); - CHECK( not cppsort::is_stable::value ); - CHECK( cppsort::is_stable::value ); + STATIC_CHECK( not cppsort::is_stable::value ); + STATIC_CHECK( not cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable::value ); + STATIC_CHECK( not cppsort::is_stable::value ); + STATIC_CHECK( not cppsort::is_stable::value ); + + STATIC_CHECK( cppsort::is_stable::value ); + STATIC_CHECK( not cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable::value ); + STATIC_CHECK( not cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable::value ); } } @@ -220,23 +222,25 @@ TEST_CASE( "stability of stable_adapter", SECTION( "is_always_stable" ) { - CHECK( cppsort::is_always_stable::value ); - CHECK( cppsort::is_always_stable::value ); + STATIC_CHECK( cppsort::is_always_stable::value ); + STATIC_CHECK( cppsort::is_always_stable::value ); } SECTION( "is_stable" ) { - CHECK( cppsort::is_stable::value ); - CHECK( cppsort::is_stable::value ); - CHECK( cppsort::is_stable::value ); - CHECK( cppsort::is_stable::value ); - CHECK( cppsort::is_stable::value ); - - CHECK( cppsort::is_stable::value ); - CHECK( cppsort::is_stable::value ); - CHECK( cppsort::is_stable::value ); - CHECK( cppsort::is_stable::value ); - CHECK( cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable::value ); + + STATIC_CHECK( cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable::value ); } } diff --git a/testsuite/adapters/self_sort_adapter_no_compare.cpp b/tests/adapters/self_sort_adapter_no_compare.cpp similarity index 88% rename from testsuite/adapters/self_sort_adapter_no_compare.cpp rename to tests/adapters/self_sort_adapter_no_compare.cpp index b440d7d3..dad8ee26 100644 --- a/testsuite/adapters/self_sort_adapter_no_compare.cpp +++ b/tests/adapters/self_sort_adapter_no_compare.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -83,12 +83,12 @@ TEST_CASE( "self-sortable object without comparison", std::vector tmp; tmp.reserve(size); auto distribution = dist::shuffled{}; distribution(std::back_inserter(tmp), size, 0); - std::copy(std::begin(tmp), std::end(tmp), std::begin(collection)); + std::copy(tmp.begin(), tmp.end(), collection.begin()); // Sort and check it's sorted auto res = sorter(collection); CHECK( res == sorter_type::self_sortable ); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "with a comparator" ) @@ -104,11 +104,11 @@ TEST_CASE( "self-sortable object without comparison", std::vector tmp; tmp.reserve(size); auto distribution = dist::shuffled{}; distribution(std::back_inserter(tmp), size, 0); - std::copy(std::begin(tmp), std::end(tmp), std::begin(collection)); + std::copy(tmp.begin(), tmp.end(), collection.begin()); // Sort and check it's sorted auto res = sorter(collection, std::less<>{}); CHECK( res == sorter_type::dummy_sorter ); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } } diff --git a/testsuite/adapters/small_array_adapter.cpp b/tests/adapters/small_array_adapter.cpp similarity index 98% rename from testsuite/adapters/small_array_adapter.cpp rename to tests/adapters/small_array_adapter.cpp index fa748721..68a1d34a 100644 --- a/testsuite/adapters/small_array_adapter.cpp +++ b/tests/adapters/small_array_adapter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/testsuite/adapters/small_array_adapter_is_stable.cpp b/tests/adapters/small_array_adapter_is_stable.cpp similarity index 64% rename from testsuite/adapters/small_array_adapter_is_stable.cpp rename to tests/adapters/small_array_adapter_is_stable.cpp index c0535276..9d4e0d00 100644 --- a/testsuite/adapters/small_array_adapter_is_stable.cpp +++ b/tests/adapters/small_array_adapter_is_stable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -90,20 +90,20 @@ TEST_CASE( "small_array_adapter stability", SECTION( "is_always_stable" ) { - CHECK( not cppsort::is_always_stable::value ); - CHECK( cppsort::is_always_stable::value ); + STATIC_CHECK( not cppsort::is_always_stable::value ); + STATIC_CHECK( cppsort::is_always_stable::value ); } SECTION( "is_stable" ) { - CHECK( not cppsort::is_stable::value ); - CHECK( not cppsort::is_stable::value ); - CHECK( not cppsort::is_stable)>::value ); - CHECK( not cppsort::is_stable)>::value ); - - CHECK( cppsort::is_stable::value ); - CHECK( cppsort::is_stable)>::value ); - CHECK( cppsort::is_stable)>::value ); + STATIC_CHECK( not cppsort::is_stable::value ); + STATIC_CHECK( not cppsort::is_stable::value ); + STATIC_CHECK( not cppsort::is_stable)>::value ); + STATIC_CHECK( not cppsort::is_stable)>::value ); + + STATIC_CHECK( cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable)>::value ); + STATIC_CHECK( cppsort::is_stable)>::value ); } SECTION( "is_stable with schwartz_adapter" ) @@ -111,13 +111,13 @@ TEST_CASE( "small_array_adapter stability", using sorter3 = cppsort::schwartz_adapter; using sorter4 = cppsort::schwartz_adapter; - CHECK( not cppsort::is_stable::value ); - CHECK( not cppsort::is_stable::value ); - CHECK( not cppsort::is_stable)>::value ); - CHECK( not cppsort::is_stable)>::value ); + STATIC_CHECK( not cppsort::is_stable::value ); + STATIC_CHECK( not cppsort::is_stable::value ); + STATIC_CHECK( not cppsort::is_stable)>::value ); + STATIC_CHECK( not cppsort::is_stable)>::value ); - CHECK( cppsort::is_stable::value ); - CHECK( cppsort::is_stable)>::value ); - CHECK( cppsort::is_stable)>::value ); + STATIC_CHECK( cppsort::is_stable::value ); + STATIC_CHECK( cppsort::is_stable)>::value ); + STATIC_CHECK( cppsort::is_stable)>::value ); } } diff --git a/testsuite/adapters/stable_adapter_every_sorter.cpp b/tests/adapters/stable_adapter_every_sorter.cpp similarity index 97% rename from testsuite/adapters/stable_adapter_every_sorter.cpp rename to tests/adapters/stable_adapter_every_sorter.cpp index ff8625c9..a7fb5411 100644 --- a/testsuite/adapters/stable_adapter_every_sorter.cpp +++ b/tests/adapters/stable_adapter_every_sorter.cpp @@ -1,12 +1,12 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include #include -#include +#include #include #include #include @@ -27,6 +27,7 @@ using wrapper = generic_stable_wrapper; // are also in ascending order TEMPLATE_TEST_CASE( "every random-access sorter with stable_adapter", "[stable_adapter]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::default_sorter, cppsort::drop_merge_sorter, diff --git a/testsuite/adapters/verge_adapter_every_sorter.cpp b/tests/adapters/verge_adapter_every_sorter.cpp similarity index 94% rename from testsuite/adapters/verge_adapter_every_sorter.cpp rename to tests/adapters/verge_adapter_every_sorter.cpp index a5776d7d..5088a7ac 100644 --- a/testsuite/adapters/verge_adapter_every_sorter.cpp +++ b/tests/adapters/verge_adapter_every_sorter.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include @@ -15,6 +15,7 @@ #include TEMPLATE_TEST_CASE( "every sorter with verge_adapter", "[verge_adapter]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::default_sorter, cppsort::drop_merge_sorter, @@ -49,6 +50,7 @@ TEMPLATE_TEST_CASE( "every sorter with verge_adapter", "[verge_adapter]", } TEMPLATE_TEST_CASE( "every sorter with stable verge_adapter", "[verge_adapter][stable_adapter]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::default_sorter, cppsort::drop_merge_sorter, diff --git a/testsuite/comparators/case_insensitive_less.cpp b/tests/comparators/case_insensitive_less.cpp similarity index 95% rename from testsuite/comparators/case_insensitive_less.cpp rename to tests/comparators/case_insensitive_less.cpp index b015683a..c6794c5e 100644 --- a/testsuite/comparators/case_insensitive_less.cpp +++ b/tests/comparators/case_insensitive_less.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2016-2020 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include @@ -33,7 +33,7 @@ namespace sub } } -TEST_CASE( "case-insensitive string comparison with case_insensitive_less" ) +TEST_CASE( "case-insensitive string comparison with case_insensitive_less", "[comparison]" ) { std::array array = { "awry", diff --git a/tests/comparators/flip_not.cpp b/tests/comparators/flip_not.cpp new file mode 100644 index 00000000..d7ca10be --- /dev/null +++ b/tests/comparators/flip_not.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2021-2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include +#include + +TEST_CASE( "flip", "[comparison]" ) +{ + SECTION( "flip" ) + { + constexpr auto cmp = cppsort::flip(std::less<>{}); + STATIC_CHECK_FALSE( cmp(1, 2) ); + STATIC_CHECK( cmp(2, 1) ); + STATIC_CHECK_FALSE( cmp(2, 2) ); + } + + SECTION( "flip(flip)" ) + { + constexpr auto cmp = cppsort::flip(cppsort::flip(std::less<>{})); + STATIC_CHECK( cmp(1, 2) ); + STATIC_CHECK_FALSE( cmp(2, 1) ); + STATIC_CHECK_FALSE( cmp(2, 2) ); + } +} + +TEST_CASE( "not_fn", "[comparison]" ) +{ + SECTION( "not_fn" ) + { + constexpr auto cmp = cppsort::not_fn(std::less<>{}); + STATIC_CHECK_FALSE( cmp(1, 2) ); + STATIC_CHECK( cmp(2, 1) ); + STATIC_CHECK( cmp(2, 2) ); + } + + SECTION( "not_fn(not_fn)" ) + { + constexpr auto cmp = cppsort::not_fn(cppsort::not_fn(std::less<>{})); + STATIC_CHECK( cmp(1, 2) ); + STATIC_CHECK_FALSE( cmp(2, 1) ); + STATIC_CHECK_FALSE( cmp(2, 2) ); + } +} + +TEST_CASE( "mixed flip and not_fn", "[comparison]" ) +{ + SECTION( "not_fn(flip)" ) + { + constexpr auto cmp = cppsort::not_fn(cppsort::flip(std::less<>{})); + STATIC_CHECK( cmp(1, 2) ); + STATIC_CHECK_FALSE( cmp(2, 1) ); + STATIC_CHECK( cmp(2, 2) ); + } + + SECTION( "flip(not_fn)" ) + { + constexpr auto cmp = cppsort::flip(cppsort::not_fn(std::less<>{})); + STATIC_CHECK( cmp(1, 2) ); + STATIC_CHECK_FALSE( cmp(2, 1) ); + STATIC_CHECK( cmp(2, 2) ); + } + + SECTION( "not_fn(flip(not_fn))" ) + { + constexpr auto cmp = cppsort::not_fn(cppsort::flip(cppsort::not_fn(std::less<>{}))); + STATIC_CHECK_FALSE( cmp(1, 2) ); + STATIC_CHECK( cmp(2, 1) ); + STATIC_CHECK_FALSE( cmp(2, 2) ); + } + + SECTION( "flip(not_fn(flip))" ) + { + constexpr auto cmp = cppsort::flip(cppsort::not_fn(cppsort::flip(std::less<>{}))); + STATIC_CHECK_FALSE( cmp(1, 2) ); + STATIC_CHECK( cmp(2, 1) ); + STATIC_CHECK( cmp(2, 2) ); + } +} + +TEST_CASE( "is_transparent over flip", "[comparison][is_transparent]" ) +{ + using cmp1 = cppsort::flip_t>; + using cmp2 = cppsort::flip_t>; + + STATIC_CHECK_FALSE( cppsort::detail::has_is_transparent_v ); + STATIC_CHECK( cppsort::detail::has_is_transparent_v ); + + std::map mapping1 = { + {1, 1}, + {2, 2}, + {3, 3}, + }; + CHECK_THROWS( mapping1.find(is_transparent_helper_compared(2)) ); + + std::map mapping2 = { + {1, 1}, + {2, 2}, + {3, 3}, + }; + CHECK_NOTHROW( mapping2.find(is_transparent_helper_compared(2)) ); +} + +TEST_CASE( "is_transparent over not_fn", "[comparison][is_transparent]" ) +{ + using cmp1 = cppsort::not_fn_t>; + using cmp2 = cppsort::not_fn_t>; + + STATIC_CHECK_FALSE( cppsort::detail::has_is_transparent_v ); + STATIC_CHECK( cppsort::detail::has_is_transparent_v ); + + std::map mapping1 = { + {1, 1}, + {2, 2}, + {3, 3}, + }; + CHECK_THROWS( mapping1.find(is_transparent_helper_compared(2)) ); + + std::map mapping2 = { + {1, 1}, + {2, 2}, + {3, 3}, + }; + CHECK_NOTHROW( mapping2.find(is_transparent_helper_compared(2)) ); +} diff --git a/testsuite/comparators/natural_less.cpp b/tests/comparators/natural_less.cpp similarity index 81% rename from testsuite/comparators/natural_less.cpp rename to tests/comparators/natural_less.cpp index 6add8b00..8c19c3f8 100644 --- a/testsuite/comparators/natural_less.cpp +++ b/tests/comparators/natural_less.cpp @@ -1,14 +1,14 @@ /* - * Copyright (c) 2016-2020 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include -#include +#include #include #include -TEST_CASE( "string natural sort with natural_less" ) +TEST_CASE( "string natural sort with natural_less", "[comparison]" ) { std::array array = { "Yay", diff --git a/tests/comparators/projection_compare.cpp b/tests/comparators/projection_compare.cpp new file mode 100644 index 00000000..b69a721c --- /dev/null +++ b/tests/comparators/projection_compare.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include +#include + +namespace +{ + // identity-like, but avoids special cases + + struct fake_identity + { + template + constexpr auto operator()(T&& value) const noexcept + -> T&& + { + return std::forward(value); + } + }; + + struct fake_identity_transparent + { + template + constexpr auto operator()(T&& value) const noexcept + -> T&& + { + return std::forward(value); + } + + using is_transparent = void; + }; +} + +TEST_CASE( "is_transparent over projection_compare", "[comparison][is_transparent]" ) +{ + using cmp1 = cppsort::projection_compare, fake_identity>; + using cmp2 = cppsort::projection_compare, fake_identity_transparent>; + using cmp3 = cppsort::projection_compare, fake_identity>; + using cmp4 = cppsort::projection_compare, fake_identity_transparent>; + + STATIC_CHECK_FALSE( cppsort::detail::has_is_transparent_v ); + STATIC_CHECK_FALSE( cppsort::detail::has_is_transparent_v ); + STATIC_CHECK_FALSE( cppsort::detail::has_is_transparent_v ); + STATIC_CHECK( cppsort::detail::has_is_transparent_v ); + + std::map mapping1 = { + {1, 1}, + {2, 2}, + {3, 3}, + }; + CHECK_THROWS( mapping1.find(is_transparent_helper_compared(2)) ); + + std::map mapping2 = { + {1, 1}, + {2, 2}, + {3, 3}, + }; + CHECK_THROWS( mapping2.find(is_transparent_helper_compared(2)) ); + + std::map mapping3 = { + {1, 1}, + {2, 2}, + {3, 3}, + }; + CHECK_THROWS( mapping3.find(is_transparent_helper_compared(2)) ); + + std::map mapping4 = { + {1, 1}, + {2, 2}, + {3, 3}, + }; + CHECK_NOTHROW( mapping4.find(is_transparent_helper_compared(2)) ); +} diff --git a/testsuite/comparators/total_less.cpp b/tests/comparators/total_less.cpp similarity index 87% rename from testsuite/comparators/total_less.cpp rename to tests/comparators/total_less.cpp index b932ef0a..a661dd0a 100644 --- a/testsuite/comparators/total_less.cpp +++ b/tests/comparators/total_less.cpp @@ -1,14 +1,14 @@ /* - * Copyright (c) 2016-2020 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include -#include +#include #include #include -TEST_CASE( "IEEE 754 totalOrder implementation" ) +TEST_CASE( "IEEE 754 totalOrder implementation", "[comparison]" ) { static constexpr double nan = std::numeric_limits::quiet_NaN(); static constexpr double inf = std::numeric_limits::infinity(); diff --git a/testsuite/comparators/transparent_comparators.cpp b/tests/comparators/transparent_comparators.cpp similarity index 96% rename from testsuite/comparators/transparent_comparators.cpp rename to tests/comparators/transparent_comparators.cpp index ae08bf17..e151dec2 100644 --- a/testsuite/comparators/transparent_comparators.cpp +++ b/tests/comparators/transparent_comparators.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Morwenn + * Copyright (c) 2019-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -96,7 +96,8 @@ namespace } } -TEST_CASE( "Check that comparators work as transparent comparators" ) +TEST_CASE( "Check that comparators work as transparent comparators", + "[comparison][is_transparent]" ) { using namespace std::string_literals; diff --git a/testsuite/distributions/all_equal.cpp b/tests/distributions/all_equal.cpp similarity index 89% rename from testsuite/distributions/all_equal.cpp rename to tests/distributions/all_equal.cpp index 5ab6cfdc..507c29f3 100644 --- a/testsuite/distributions/all_equal.cpp +++ b/tests/distributions/all_equal.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test random-access sorters with all_equal distribution", "[distributions]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, @@ -46,5 +47,5 @@ TEMPLATE_TEST_CASE( "test random-access sorters with all_equal distribution", "[ TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/distributions/alternating.cpp b/tests/distributions/alternating.cpp similarity index 89% rename from testsuite/distributions/alternating.cpp rename to tests/distributions/alternating.cpp index eedd67a1..d31f73ee 100644 --- a/testsuite/distributions/alternating.cpp +++ b/tests/distributions/alternating.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test sorter with alternating distribution", "[distributions]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, @@ -46,5 +47,5 @@ TEMPLATE_TEST_CASE( "test sorter with alternating distribution", "[distributions TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/distributions/ascending.cpp b/tests/distributions/ascending.cpp similarity index 91% rename from testsuite/distributions/ascending.cpp rename to tests/distributions/ascending.cpp index 6bc39996..76f93acc 100644 --- a/testsuite/distributions/ascending.cpp +++ b/tests/distributions/ascending.cpp @@ -1,23 +1,24 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test sorter with ascending distribution", "[distributions]", + cppsort::adaptive_shivers_sorter, + cppsort::cartesian_tree_sorter, // While counting_sort shouldn't be affected by patterns, its // underlying minmax_element_and_is_sorted function had a bug // that could specifically appear with an ascending distribution, // so here is the dedicated test (see issue #103) cppsort::counting_sorter, - cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, cppsort::grail_sorter< @@ -51,5 +52,5 @@ TEMPLATE_TEST_CASE( "test sorter with ascending distribution", "[distributions]" TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/distributions/ascending_sawtooth.cpp b/tests/distributions/ascending_sawtooth.cpp similarity index 89% rename from testsuite/distributions/ascending_sawtooth.cpp rename to tests/distributions/ascending_sawtooth.cpp index 08363da1..7eed81a1 100644 --- a/testsuite/distributions/ascending_sawtooth.cpp +++ b/tests/distributions/ascending_sawtooth.cpp @@ -1,18 +1,19 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test random-access sorters with ascending_sawtooth distribution", "[distributions]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, @@ -47,7 +48,7 @@ TEMPLATE_TEST_CASE( "test random-access sorters with ascending_sawtooth distribu TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } TEMPLATE_TEST_CASE( "test bidirectional sorters with ascending_sawtooth distribution", "[distributions]", @@ -65,5 +66,5 @@ TEMPLATE_TEST_CASE( "test bidirectional sorters with ascending_sawtooth distribu TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/distributions/descending.cpp b/tests/distributions/descending.cpp similarity index 89% rename from testsuite/distributions/descending.cpp rename to tests/distributions/descending.cpp index 44f41d39..e4d2dfc9 100644 --- a/testsuite/distributions/descending.cpp +++ b/tests/distributions/descending.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test sorter with descending distribution", "[distributions]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, @@ -46,5 +47,5 @@ TEMPLATE_TEST_CASE( "test sorter with descending distribution", "[distributions] TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/distributions/descending_sawtooth.cpp b/tests/distributions/descending_sawtooth.cpp similarity index 89% rename from testsuite/distributions/descending_sawtooth.cpp rename to tests/distributions/descending_sawtooth.cpp index b8c4abf2..00d48185 100644 --- a/testsuite/distributions/descending_sawtooth.cpp +++ b/tests/distributions/descending_sawtooth.cpp @@ -1,18 +1,19 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test random-access sorters with descending_sawtooth distribution", "[distributions]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, @@ -47,7 +48,7 @@ TEMPLATE_TEST_CASE( "test random-access sorters with descending_sawtooth distrib TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } TEMPLATE_TEST_CASE( "test bidirectional sorters with descending_sawtooth distribution", "[distributions]", @@ -65,5 +66,5 @@ TEMPLATE_TEST_CASE( "test bidirectional sorters with descending_sawtooth distrib TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/distributions/median_of_3_killer.cpp b/tests/distributions/median_of_3_killer.cpp similarity index 94% rename from testsuite/distributions/median_of_3_killer.cpp rename to tests/distributions/median_of_3_killer.cpp index 73e690fa..67bc4bff 100644 --- a/testsuite/distributions/median_of_3_killer.cpp +++ b/tests/distributions/median_of_3_killer.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2020-2021 Morwenn + * Copyright (c) 2020-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test random-access sorters with median_of_3_killer distribution", "[distributions]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, diff --git a/testsuite/distributions/pipe_organ.cpp b/tests/distributions/pipe_organ.cpp similarity index 89% rename from testsuite/distributions/pipe_organ.cpp rename to tests/distributions/pipe_organ.cpp index e21d47c6..bd2d6398 100644 --- a/testsuite/distributions/pipe_organ.cpp +++ b/tests/distributions/pipe_organ.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test sorter with pipe_organ distribution", "[distributions]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, @@ -46,5 +47,5 @@ TEMPLATE_TEST_CASE( "test sorter with pipe_organ distribution", "[distributions] TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/distributions/push_front.cpp b/tests/distributions/push_front.cpp similarity index 89% rename from testsuite/distributions/push_front.cpp rename to tests/distributions/push_front.cpp index c815361c..9260511f 100644 --- a/testsuite/distributions/push_front.cpp +++ b/tests/distributions/push_front.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test sorter with push_front distribution", "[distributions]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, @@ -46,5 +47,5 @@ TEMPLATE_TEST_CASE( "test sorter with push_front distribution", "[distributions] TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/distributions/push_middle.cpp b/tests/distributions/push_middle.cpp similarity index 89% rename from testsuite/distributions/push_middle.cpp rename to tests/distributions/push_middle.cpp index 71c9b407..a0fd01a2 100644 --- a/testsuite/distributions/push_middle.cpp +++ b/tests/distributions/push_middle.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test sorter with push_middle distribution", "[distributions]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, @@ -46,5 +47,5 @@ TEMPLATE_TEST_CASE( "test sorter with push_middle distribution", "[distributions TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/distributions/shuffled.cpp b/tests/distributions/shuffled.cpp similarity index 89% rename from testsuite/distributions/shuffled.cpp rename to tests/distributions/shuffled.cpp index 3509e41c..039c8f63 100644 --- a/testsuite/distributions/shuffled.cpp +++ b/tests/distributions/shuffled.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test sorter with shuffled distribution", "[distributions]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, @@ -46,5 +47,5 @@ TEMPLATE_TEST_CASE( "test sorter with shuffled distribution", "[distributions]", TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/distributions/shuffled_16_values.cpp b/tests/distributions/shuffled_16_values.cpp similarity index 89% rename from testsuite/distributions/shuffled_16_values.cpp rename to tests/distributions/shuffled_16_values.cpp index ac8a5097..911cc069 100644 --- a/testsuite/distributions/shuffled_16_values.cpp +++ b/tests/distributions/shuffled_16_values.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test sorter with shuffled_16_values distribution", "[distributions]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, @@ -46,5 +47,5 @@ TEMPLATE_TEST_CASE( "test sorter with shuffled_16_values distribution", "[distri TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/tests/is_stable.cpp b/tests/is_stable.cpp new file mode 100644 index 00000000..85b38e69 --- /dev/null +++ b/tests/is_stable.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2016-2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include +#include +#include +#include + +TEST_CASE( "test is_stable with raw sorters", + "[is_stable]" ) +{ + // Exhaustive test for every scenario where is_sorter is + // supposed to trivially fall back to is_always_stable + + using cppsort::is_stable; + using cppsort::utility::identity; + + SECTION( "merge_sorter" ) + { + using sorter = cppsort::merge_sorter; + + STATIC_CHECK( is_stable&)>::value ); + STATIC_CHECK( is_stable::iterator, std::vector::iterator)>::value ); + + STATIC_CHECK( is_stable&, std::less<>)>::value ); + STATIC_CHECK( is_stable::iterator, std::vector::iterator, + std::less<>)>::value ); + + STATIC_CHECK( is_stable&, std::greater<>)>::value ); + STATIC_CHECK( is_stable::iterator, std::vector::iterator, + std::greater<>)>::value ); + + STATIC_CHECK( is_stable&, identity)>::value ); + STATIC_CHECK( is_stable::iterator, std::vector::iterator, + identity)>::value ); + + STATIC_CHECK( is_stable&, std::negate<>)>::value ); + STATIC_CHECK( is_stable::iterator, std::vector::iterator, + std::negate<>)>::value ); + + STATIC_CHECK( is_stable&, std::less<>, identity)>::value ); + STATIC_CHECK( is_stable::iterator, std::vector::iterator, + std::less<>, identity)>::value ); + + STATIC_CHECK( is_stable&, std::greater<>, identity)>::value ); + STATIC_CHECK( is_stable::iterator, std::vector::iterator, + std::greater<>, identity)>::value ); + + STATIC_CHECK( is_stable&, std::less<>, std::negate<>)>::value ); + STATIC_CHECK( is_stable::iterator, std::vector::iterator, + std::less<>, std::negate<>)>::value ); + + STATIC_CHECK( is_stable&, std::greater<>, std::negate<>)>::value ); + STATIC_CHECK( is_stable::iterator, std::vector::iterator, + std::greater<>, std::negate<>)>::value ); + } + + SECTION( "quick_sorter" ) + { + using sorter = cppsort::quick_sorter; + + STATIC_CHECK( not is_stable&)>::value ); + STATIC_CHECK( not is_stable::iterator, std::vector::iterator)>::value ); + + STATIC_CHECK( not is_stable&, std::less<>)>::value ); + STATIC_CHECK( not is_stable::iterator, std::vector::iterator, + std::less<>)>::value ); + + STATIC_CHECK( not is_stable&, std::greater<>)>::value ); + STATIC_CHECK( not is_stable::iterator, std::vector::iterator, + std::greater<>)>::value ); + + STATIC_CHECK( not is_stable&, identity)>::value ); + STATIC_CHECK( not is_stable::iterator, std::vector::iterator, + identity)>::value ); + + STATIC_CHECK( not is_stable&, std::negate<>)>::value ); + STATIC_CHECK( not is_stable::iterator, std::vector::iterator, + std::negate<>)>::value ); + + STATIC_CHECK( not is_stable&, std::less<>, identity)>::value ); + STATIC_CHECK( not is_stable::iterator, std::vector::iterator, + std::less<>, identity)>::value ); + + STATIC_CHECK( not is_stable&, std::greater<>, identity)>::value ); + STATIC_CHECK( not is_stable::iterator, std::vector::iterator, + std::greater<>, identity)>::value ); + + STATIC_CHECK( not is_stable&, std::less<>, std::negate<>)>::value ); + STATIC_CHECK( not is_stable::iterator, std::vector::iterator, + std::less<>, std::negate<>)>::value ); + + STATIC_CHECK( not is_stable&, std::greater<>, std::negate<>)>::value ); + STATIC_CHECK( not is_stable::iterator, std::vector::iterator, + std::greater<>, std::negate<>)>::value ); + } + + SECTION( "low_comparisons_sorter" ) + { + // Many fixed-size sorters define is_always_stable through + // sorter_traits, which makes this test interesting + using sorter = cppsort::low_comparisons_sorter<8>; + STATIC_CHECK( not is_stable::value ); + } +} diff --git a/testsuite/probes/block.cpp b/tests/probes/block.cpp similarity index 93% rename from testsuite/probes/block.cpp rename to tests/probes/block.cpp index db1f0db9..976622d3 100644 --- a/testsuite/probes/block.cpp +++ b/tests/probes/block.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2021 Morwenn + * Copyright (c) 2021-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include diff --git a/testsuite/probes/dis.cpp b/tests/probes/dis.cpp similarity index 96% rename from testsuite/probes/dis.cpp rename to tests/probes/dis.cpp index 26b841c3..ca77623f 100644 --- a/testsuite/probes/dis.cpp +++ b/tests/probes/dis.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include -#include +#include #include #include #include diff --git a/testsuite/probes/enc.cpp b/tests/probes/enc.cpp similarity index 93% rename from testsuite/probes/enc.cpp rename to tests/probes/enc.cpp index 4dc0643c..a45d00e2 100644 --- a/testsuite/probes/enc.cpp +++ b/tests/probes/enc.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include -#include +#include #include #include #include diff --git a/testsuite/probes/every_probe_common.cpp b/tests/probes/every_probe_common.cpp similarity index 97% rename from testsuite/probes/every_probe_common.cpp rename to tests/probes/every_probe_common.cpp index 33d55fac..37b2f0fd 100644 --- a/testsuite/probes/every_probe_common.cpp +++ b/tests/probes/every_probe_common.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2021 Morwenn + * Copyright (c) 2021-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include // diff --git a/testsuite/probes/every_probe_heap_memory_exhaustion.cpp b/tests/probes/every_probe_heap_memory_exhaustion.cpp similarity index 96% rename from testsuite/probes/every_probe_heap_memory_exhaustion.cpp rename to tests/probes/every_probe_heap_memory_exhaustion.cpp index 1e6764de..2006dbdc 100644 --- a/testsuite/probes/every_probe_heap_memory_exhaustion.cpp +++ b/tests/probes/every_probe_heap_memory_exhaustion.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2021 Morwenn + * Copyright (c) 2020-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/testsuite/probes/every_probe_move_compare_projection.cpp b/tests/probes/every_probe_move_compare_projection.cpp similarity index 96% rename from testsuite/probes/every_probe_move_compare_projection.cpp rename to tests/probes/every_probe_move_compare_projection.cpp index 1708ee2a..5a703d49 100644 --- a/testsuite/probes/every_probe_move_compare_projection.cpp +++ b/tests/probes/every_probe_move_compare_projection.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2020-2021 Morwenn + * Copyright (c) 2020-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include -#include +#include #include #include #include diff --git a/testsuite/probes/exc.cpp b/tests/probes/exc.cpp similarity index 95% rename from testsuite/probes/exc.cpp rename to tests/probes/exc.cpp index 93bdc8f0..e264ff2d 100644 --- a/testsuite/probes/exc.cpp +++ b/tests/probes/exc.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include diff --git a/testsuite/probes/ham.cpp b/tests/probes/ham.cpp similarity index 94% rename from testsuite/probes/ham.cpp rename to tests/probes/ham.cpp index 4a3ce7ca..f612008f 100644 --- a/testsuite/probes/ham.cpp +++ b/tests/probes/ham.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include diff --git a/testsuite/probes/inv.cpp b/tests/probes/inv.cpp similarity index 93% rename from testsuite/probes/inv.cpp rename to tests/probes/inv.cpp index 8894361a..db177cfb 100644 --- a/testsuite/probes/inv.cpp +++ b/tests/probes/inv.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include -#include +#include #include #include #include diff --git a/testsuite/probes/max.cpp b/tests/probes/max.cpp similarity index 94% rename from testsuite/probes/max.cpp rename to tests/probes/max.cpp index f866f3a0..3f0ef70d 100644 --- a/testsuite/probes/max.cpp +++ b/tests/probes/max.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include diff --git a/testsuite/probes/mono.cpp b/tests/probes/mono.cpp similarity index 95% rename from testsuite/probes/mono.cpp rename to tests/probes/mono.cpp index 4539f58c..fc1385c4 100644 --- a/testsuite/probes/mono.cpp +++ b/tests/probes/mono.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2018-2021 Morwenn + * Copyright (c) 2018-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include -#include +#include #include #include #include diff --git a/testsuite/probes/osc.cpp b/tests/probes/osc.cpp similarity index 95% rename from testsuite/probes/osc.cpp rename to tests/probes/osc.cpp index bceb0e25..c650a299 100644 --- a/testsuite/probes/osc.cpp +++ b/tests/probes/osc.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include -#include +#include #include #include #include diff --git a/testsuite/probes/relations.cpp b/tests/probes/relations.cpp similarity index 93% rename from testsuite/probes/relations.cpp rename to tests/probes/relations.cpp index 993e9dbd..367ca678 100644 --- a/testsuite/probes/relations.cpp +++ b/tests/probes/relations.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include -#include +#include #include #include @@ -40,6 +40,10 @@ TEST_CASE( "relations between measures of presortedness", "[probe]" ) // by Heikki Mannila CHECK( exc <= inv ); + // Splitsort - an adaptive sorting algorithm + // by Christos Levcopoulos and Ola Petersson + CHECK( rem <= inv ); + // A framework for adaptive sorting // by Ola Petersson and Alistair Moffat CHECK( runs <= rem + 1 ); diff --git a/testsuite/probes/rem.cpp b/tests/probes/rem.cpp similarity index 94% rename from testsuite/probes/rem.cpp rename to tests/probes/rem.cpp index f29d011e..895c1504 100644 --- a/testsuite/probes/rem.cpp +++ b/tests/probes/rem.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include -#include +#include #include #include #include diff --git a/testsuite/probes/runs.cpp b/tests/probes/runs.cpp similarity index 94% rename from testsuite/probes/runs.cpp rename to tests/probes/runs.cpp index e2742965..bd811441 100644 --- a/testsuite/probes/runs.cpp +++ b/tests/probes/runs.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include -#include +#include #include #include #include diff --git a/testsuite/probes/sus.cpp b/tests/probes/sus.cpp similarity index 93% rename from testsuite/probes/sus.cpp rename to tests/probes/sus.cpp index 9ddbebfa..17c43a09 100644 --- a/testsuite/probes/sus.cpp +++ b/tests/probes/sus.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2021 Morwenn + * Copyright (c) 2021-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include -#include +#include #include #include #include diff --git a/testsuite/rebind_iterator_category.cpp b/tests/rebind_iterator_category.cpp similarity index 85% rename from testsuite/rebind_iterator_category.cpp rename to tests/rebind_iterator_category.cpp index 3411835d..1e7f01f9 100644 --- a/testsuite/rebind_iterator_category.cpp +++ b/tests/rebind_iterator_category.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -68,8 +68,10 @@ TEST_CASE( "iterator category rebinder", std::random_access_iterator_tag >; - CHECK( (std::is_same, std::bidirectional_iterator_tag>::value) ); - CHECK( (std::is_same, std::random_access_iterator_tag>::value) ); + STATIC_CHECK( std::is_same, + std::bidirectional_iterator_tag>::value ); + STATIC_CHECK( std::is_same, + std::random_access_iterator_tag>::value ); } SECTION( "with hybrid_adapter" ) diff --git a/testsuite/sort_array.cpp b/tests/sort_array.cpp similarity index 96% rename from testsuite/sort_array.cpp rename to tests/sort_array.cpp index 13c8b317..e46e1c0c 100644 --- a/testsuite/sort_array.cpp +++ b/tests/sort_array.cpp @@ -1,9 +1,9 @@ /* - * Copyright (c) 2018 Morwenn + * Copyright (c) 2018-2022 Morwenn * SPDX-License-Identifier: MIT */ #include -#include +#include #include #include #include diff --git a/testsuite/sorter_facade.cpp b/tests/sorter_facade.cpp similarity index 72% rename from testsuite/sorter_facade.cpp rename to tests/sorter_facade.cpp index c75649a2..f54fe77e 100644 --- a/testsuite/sorter_facade.cpp +++ b/tests/sorter_facade.cpp @@ -1,12 +1,11 @@ /* - * Copyright (c) 2015-2020 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #include -#include #include #include -#include +#include #include #include #include @@ -65,7 +64,7 @@ namespace } TEST_CASE( "sorter_facade miscellaneous checks", - "[sorter_facade][compare][projection]" ) + "[sorter_facade][comparison][projection]" ) { // Some checks to make sure that sorter_facade always // forwards the value correctly in the most common cases @@ -79,42 +78,41 @@ TEST_CASE( "sorter_facade miscellaneous checks", SECTION( "with comparison only" ) { CHECK( comparison_sorter{}(vec, std::less<>{}) ); - CHECK( comparison_sorter{}(std::begin(vec), std::end(vec), std::less<>{}) ); + CHECK( comparison_sorter{}(vec.begin(), vec.end(), std::less<>{}) ); CHECK( comparison_sorter{}(vec, std::greater<>{}) ); - CHECK( comparison_sorter{}(std::begin(vec), std::end(vec), std::greater<>{}) ); + CHECK( comparison_sorter{}(vec.begin(), vec.end(), std::greater<>{}) ); } SECTION( "with projection only" ) { CHECK( projection_sorter{}(vec, cppsort::utility::identity{}) ); - CHECK( projection_sorter{}(std::begin(vec), std::end(vec), cppsort::utility::identity{}) ); + CHECK( projection_sorter{}(vec.begin(), vec.end(), cppsort::utility::identity{}) ); CHECK( projection_sorter{}(vec_wrap, &wrapper::value) ); - CHECK( projection_sorter{}(std::begin(vec_wrap), std::end(vec_wrap), &wrapper::value) ); + CHECK( projection_sorter{}(vec_wrap.begin(), vec_wrap.end(), &wrapper::value) ); } SECTION( "with both comparison and projection" ) { CHECK( comparison_projection_sorter{}(vec, std::less<>{}) ); - CHECK( comparison_projection_sorter{}(std::begin(vec), std::end(vec), std::less<>{}) ); + CHECK( comparison_projection_sorter{}(vec.begin(), vec.end(), std::less<>{}) ); CHECK( comparison_projection_sorter{}(vec, std::greater<>{}) ); - CHECK( comparison_projection_sorter{}(std::begin(vec), std::end(vec), std::greater<>{}) ); + CHECK( comparison_projection_sorter{}(vec.begin(), vec.end(), std::greater<>{}) ); CHECK( comparison_projection_sorter{}(vec, cppsort::utility::identity{}) ); - CHECK( comparison_projection_sorter{}(std::begin(vec), std::end(vec), - cppsort::utility::identity{}) ); + CHECK( comparison_projection_sorter{}(vec.begin(), vec.end(), cppsort::utility::identity{}) ); CHECK( comparison_projection_sorter{}(vec_wrap, &wrapper::value) ); - CHECK( comparison_projection_sorter{}(std::begin(vec_wrap), std::end(vec_wrap), &wrapper::value) ); + CHECK( comparison_projection_sorter{}(vec_wrap.begin(), vec_wrap.end(), &wrapper::value) ); CHECK( comparison_projection_sorter{}(vec, std::greater<>{}, cppsort::utility::identity{}) ); - CHECK( comparison_projection_sorter{}(std::begin(vec), std::end(vec), + CHECK( comparison_projection_sorter{}(vec.begin(), vec.end(), std::greater<>{}, cppsort::utility::identity{}) ); CHECK( comparison_projection_sorter{}(vec_wrap, std::greater<>{}, &wrapper::value) ); - CHECK( comparison_projection_sorter{}(std::begin(vec_wrap), std::end(vec_wrap), + CHECK( comparison_projection_sorter{}(vec_wrap.begin(), vec_wrap.end(), std::greater<>{}, &wrapper::value) ); } } diff --git a/testsuite/sorter_facade_constexpr.cpp b/tests/sorter_facade_constexpr.cpp similarity index 96% rename from testsuite/sorter_facade_constexpr.cpp rename to tests/sorter_facade_constexpr.cpp index 463394fe..d4dfc26f 100644 --- a/testsuite/sorter_facade_constexpr.cpp +++ b/tests/sorter_facade_constexpr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Morwenn + * Copyright (c) 2021-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -79,5 +79,5 @@ TEST_CASE( "test basic constexpr support", "[sorter_facade][constexpr]" ) // Check that sorter_facade can be useful in a constexpr constext // if the sorter implementation is constexpr-friendly itself constexpr bool is_sorted = test_sorter(); - CHECK( is_sorted ); + STATIC_CHECK( is_sorted ); } diff --git a/testsuite/sorter_facade_defaults.cpp b/tests/sorter_facade_defaults.cpp similarity index 78% rename from testsuite/sorter_facade_defaults.cpp rename to tests/sorter_facade_defaults.cpp index 10bf2e0d..78147d7d 100644 --- a/testsuite/sorter_facade_defaults.cpp +++ b/tests/sorter_facade_defaults.cpp @@ -1,11 +1,10 @@ /* - * Copyright (c) 2015-2020 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #include -#include #include -#include +#include #include #include @@ -83,7 +82,7 @@ namespace } TEST_CASE( "std::less<> forwarding to sorters", - "[sorter_facade][compare]" ) + "[sorter_facade][comparison]" ) { // Check that sorter_facade only creates the overloads for // std::less when the original sorter does not support @@ -101,27 +100,27 @@ TEST_CASE( "std::less<> forwarding to sorters", SECTION( "with std::less<>" ) { CHECK( comparison_sorter{}(vec, std::less<>{}) ); - CHECK( comparison_sorter{}(std::begin(vec), std::end(vec), std::less<>{}) ); + CHECK( comparison_sorter{}(vec.begin(), vec.end(), std::less<>{}) ); CHECK( non_comparison_sorter{}(vec, std::less<>{}) ); - CHECK( non_comparison_sorter{}(std::begin(vec), std::end(vec), std::less<>{}) ); + CHECK( non_comparison_sorter{}(vec.begin(), vec.end(), std::less<>{}) ); CHECK( not non_comparison_iterable_sorter{}(vec, std::less<>{}) ); - CHECK( non_comparison_iterable_sorter{}(std::begin(vec), std::end(vec), std::less<>{}) ); + CHECK( non_comparison_iterable_sorter{}(vec.begin(), vec.end(), std::less<>{}) ); } SECTION( "with utility::identity" ) { CHECK( comparison_sorter{}(vec, cppsort::utility::identity{}) ); - CHECK( comparison_sorter{}(std::begin(vec), std::end(vec), cppsort::utility::identity{}) ); + CHECK( comparison_sorter{}(vec.begin(), vec.end(), cppsort::utility::identity{}) ); CHECK( non_comparison_sorter{}(vec, cppsort::utility::identity{}) ); - CHECK( non_comparison_sorter{}(std::begin(vec), std::end(vec), cppsort::utility::identity{}) ); + CHECK( non_comparison_sorter{}(vec.begin(), vec.end(), cppsort::utility::identity{}) ); CHECK( not non_comparison_iterable_sorter{}(vec, cppsort::utility::identity{}) ); - CHECK( non_comparison_iterable_sorter{}(std::begin(vec), std::end(vec), cppsort::utility::identity{}) ); + CHECK( non_comparison_iterable_sorter{}(vec.begin(), vec.end(), cppsort::utility::identity{}) ); CHECK( comparison_projection_sorter{}(vec, cppsort::utility::identity{}) ); - CHECK( comparison_projection_sorter{}(std::begin(vec), std::end(vec), cppsort::utility::identity{}) ); + CHECK( comparison_projection_sorter{}(vec.begin(), vec.end(), cppsort::utility::identity{}) ); } } diff --git a/testsuite/sorter_facade_fptr.cpp b/tests/sorter_facade_fptr.cpp similarity index 97% rename from testsuite/sorter_facade_fptr.cpp rename to tests/sorter_facade_fptr.cpp index bf750a78..1fc039f1 100644 --- a/testsuite/sorter_facade_fptr.cpp +++ b/tests/sorter_facade_fptr.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2021 Morwenn + * Copyright (c) 2021-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include diff --git a/testsuite/sorter_facade_iterable.cpp b/tests/sorter_facade_iterable.cpp similarity index 81% rename from testsuite/sorter_facade_iterable.cpp rename to tests/sorter_facade_iterable.cpp index 02aa23e1..becce9b5 100644 --- a/testsuite/sorter_facade_iterable.cpp +++ b/tests/sorter_facade_iterable.cpp @@ -1,12 +1,11 @@ /* - * Copyright (c) 2015-2020 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #include -#include #include #include -#include +#include #include #include #include @@ -99,7 +98,7 @@ namespace } TEST_CASE( "sorter_facade with sorters overloaded for iterables", - "[sorter_facade][compare][projection]" ) + "[sorter_facade][comparison][projection]" ) { // Some sorters can optimize the computations a bit by adding // overloaded operator() that take a full iteratable instead @@ -116,12 +115,12 @@ TEST_CASE( "sorter_facade with sorters overloaded for iterables", { call res1 = comparison_sorter{}(vec, std::less<>{}); CHECK( res1 == call::iterable ); - call res2 = comparison_sorter{}(std::begin(vec), std::end(vec), std::less<>{}); + call res2 = comparison_sorter{}(vec.begin(), vec.end(), std::less<>{}); CHECK( res2 == call::iterator ); call res3 = comparison_sorter{}(vec, std::greater<>{}); CHECK( res3 == call::iterable ); - call res4 = comparison_sorter{}(std::begin(vec), std::end(vec), std::greater<>{}); + call res4 = comparison_sorter{}(vec.begin(), vec.end(), std::greater<>{}); CHECK( res4 == call::iterator ); } @@ -129,12 +128,12 @@ TEST_CASE( "sorter_facade with sorters overloaded for iterables", { call res1 = projection_sorter{}(vec, cppsort::utility::identity{}); CHECK( res1 == call::iterable ); - call res2 = projection_sorter{}(std::begin(vec), std::end(vec), cppsort::utility::identity{}); + call res2 = projection_sorter{}(vec.begin(), vec.end(), cppsort::utility::identity{}); CHECK( res2 == call::iterator ); call res3 = projection_sorter{}(vec_wrap, &wrapper::value); CHECK( res3 == call::iterable ); - call res4 = projection_sorter{}(std::begin(vec_wrap), std::end(vec_wrap), &wrapper::value); + call res4 = projection_sorter{}(vec_wrap.begin(), vec_wrap.end(), &wrapper::value); CHECK( res4 == call::iterator ); } @@ -142,35 +141,34 @@ TEST_CASE( "sorter_facade with sorters overloaded for iterables", { call res1 = comparison_projection_sorter{}(vec, std::less<>{}); CHECK( res1 == call::iterable ); - call res2 = comparison_projection_sorter{}(std::begin(vec), std::end(vec), std::less<>{}); + call res2 = comparison_projection_sorter{}(vec.begin(), vec.end(), std::less<>{}); CHECK( res2 == call::iterator ); call res3 = comparison_projection_sorter{}(vec, std::greater<>{}); CHECK( res3 == call::iterable ); - call res4 = comparison_projection_sorter{}(std::begin(vec), std::end(vec), std::greater<>{}); + call res4 = comparison_projection_sorter{}(vec.begin(), vec.end(), std::greater<>{}); CHECK( res4 == call::iterator ); call res5 = comparison_projection_sorter{}(vec, cppsort::utility::identity{}); CHECK( res5 == call::iterable ); - call res6 = comparison_projection_sorter{}(std::begin(vec), std::end(vec), + call res6 = comparison_projection_sorter{}(vec.begin(), vec.end(), cppsort::utility::identity{}); CHECK( res6 == call::iterator ); call res7 = comparison_projection_sorter{}(vec_wrap, &wrapper::value); CHECK( res7 == call::iterable ); - call res8 = comparison_projection_sorter{}(std::begin(vec_wrap), std::end(vec_wrap), - &wrapper::value); + call res8 = comparison_projection_sorter{}(vec_wrap.begin(), vec_wrap.end(), &wrapper::value); CHECK( res8 == call::iterator ); call res9 = comparison_projection_sorter{}(vec, std::greater<>{}, cppsort::utility::identity{}); CHECK( res9 == call::iterable ); - call res10 = comparison_projection_sorter{}(std::begin(vec), std::end(vec), + call res10 = comparison_projection_sorter{}(vec.begin(), vec.end(), std::greater<>{}, cppsort::utility::identity{}); CHECK( res10 == call::iterator ); call res11 = comparison_projection_sorter{}(vec_wrap, std::greater<>{}, &wrapper::value); CHECK( res11 == call::iterable ); - call res12 = comparison_projection_sorter{}(std::begin(vec_wrap), std::end(vec_wrap), + call res12 = comparison_projection_sorter{}(vec_wrap.begin(), vec_wrap.end(), std::greater<>{}, &wrapper::value); CHECK( res12 == call::iterator ); } diff --git a/testsuite/sorters/counting_sorter.cpp b/tests/sorters/counting_sorter.cpp similarity index 74% rename from testsuite/sorters/counting_sorter.cpp rename to tests/sorters/counting_sorter.cpp index 79a2cc37..91f3c949 100644 --- a/testsuite/sorters/counting_sorter.cpp +++ b/tests/sorters/counting_sorter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -23,15 +23,15 @@ TEST_CASE( "counting_sorter tests", "[counting_sorter]" ) std::vector vec; vec.reserve(size); distribution(std::back_inserter(vec), size, -1568); cppsort::counting_sort(vec); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } SECTION( "sort with unsigned int iterators" ) { std::list li; distribution(std::back_inserter(li), size, 0u); - cppsort::counting_sort(std::begin(li), std::end(li)); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + cppsort::counting_sort(li.begin(), li.end()); + CHECK( std::is_sorted(li.begin(), li.end()) ); } SECTION( "reverse sort with long long iterable" ) @@ -39,15 +39,15 @@ TEST_CASE( "counting_sorter tests", "[counting_sorter]" ) std::vector vec; vec.reserve(size); distribution(std::back_inserter(vec), size, 1568); cppsort::counting_sort(vec); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } SECTION( "reverse sort with unsigned long long iterators" ) { std::forward_list li; distribution(std::front_inserter(li), size, 0ULL); - cppsort::counting_sort(std::begin(li), std::end(li)); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + cppsort::counting_sort(li.begin(), li.end()); + CHECK( std::is_sorted(li.begin(), li.end()) ); } #ifdef __SIZEOF_INT128__ @@ -55,8 +55,8 @@ TEST_CASE( "counting_sorter tests", "[counting_sorter]" ) { std::list<__uint128_t> li;; distribution(std::back_inserter(li), size, __uint128_t(0)); - cppsort::counting_sort(std::begin(li), std::end(li)); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + cppsort::counting_sort(li.begin(), li.end()); + CHECK( std::is_sorted(li.begin(), li.end()) ); } #endif @@ -69,6 +69,6 @@ TEST_CASE( "counting_sorter tests", "[counting_sorter]" ) std::vector vec = { -47, -46, -45, -44, -43, -42, -41, -39, -40, -38 }; cppsort::counting_sort(vec); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } } diff --git a/tests/sorters/default_sorter.cpp b/tests/sorters/default_sorter.cpp new file mode 100644 index 00000000..fa61a470 --- /dev/null +++ b/tests/sorters/default_sorter.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015-2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TEST_CASE( "default sorter tests", "[default_sorter]" ) +{ + // Collection to sort + std::vector vec; vec.reserve(80); + auto distribution = dist::shuffled{}; + distribution(std::back_inserter(vec), 80, 0); + + SECTION( "sort with random-access iterable" ) + { + cppsort::sort(vec); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); + } + + SECTION( "sort with random-access iterable and compare" ) + { + cppsort::sort(vec, std::greater<>{}); + CHECK( std::is_sorted(vec.begin(), vec.end(), std::greater<>{}) ); + } + + SECTION( "sort with random-access iterators" ) + { + cppsort::sort(vec.begin(), vec.end()); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); + } + + SECTION( "sort with random-access iterators and compare" ) + { + cppsort::sort(vec.begin(), vec.end(), std::greater<>{}); + CHECK( std::is_sorted(vec.begin(), vec.end(), std::greater<>{}) ); + } + + SECTION( "sort with bidirectional iterators" ) + { + std::list li(vec.begin(), vec.end()); + cppsort::sort(li.begin(), li.end()); + CHECK( std::is_sorted(li.begin(), li.end()) ); + } + + SECTION( "sort with bidirectional iterators and compare" ) + { + std::list li(vec.begin(), vec.end()); + cppsort::sort(li.begin(), li.end(), std::greater<>{}); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); + } + + SECTION( "sort with forward iterators" ) + { + std::forward_list li(vec.begin(), vec.end()); + cppsort::sort(li.begin(), li.end()); + CHECK( std::is_sorted(li.begin(), li.end()) ); + } + + SECTION( "sort with forward iterators and compare" ) + { + std::forward_list li(vec.begin(), vec.end()); + cppsort::sort(li.begin(), li.end(), std::greater<>{}); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); + } + + SECTION( "sort with self-sortable iterable" ) + { + std::list li(vec.begin(), vec.end()); + cppsort::sort(li); + CHECK( std::is_sorted(li.begin(), li.end()) ); + } + + SECTION( "sort with self-sortable iterable and compare" ) + { + std::forward_list li(vec.begin(), vec.end()); + cppsort::sort(li, std::greater<>{}); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); + } +} diff --git a/testsuite/sorters/default_sorter_fptr.cpp b/tests/sorters/default_sorter_fptr.cpp similarity index 66% rename from testsuite/sorters/default_sorter_fptr.cpp rename to tests/sorters/default_sorter_fptr.cpp index 82453043..9970f288 100644 --- a/testsuite/sorters/default_sorter_fptr.cpp +++ b/tests/sorters/default_sorter_fptr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2021 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -28,7 +28,7 @@ TEST_CASE( "default sorter function pointer tests", constexpr void(*sorter)(std::vector&) = cppsort::default_sorter(); sorter(vec); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } SECTION( "sort with random-access iterable and compare" ) @@ -36,7 +36,7 @@ TEST_CASE( "default sorter function pointer tests", constexpr void(*sorter)(std::vector&, std::greater<>) = cppsort::default_sorter(); sorter(vec, std::greater<>{}); - CHECK( std::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}) ); + CHECK( std::is_sorted(vec.begin(), vec.end(), std::greater<>{}) ); } SECTION( "sort with random-access iterable and projection" ) @@ -44,7 +44,7 @@ TEST_CASE( "default sorter function pointer tests", constexpr void(*sorter)(std::vector&, decltype(projection)) = cppsort::default_sorter(); sorter(vec, projection); - CHECK( std::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}) ); + CHECK( std::is_sorted(vec.begin(), vec.end(), std::greater<>{}) ); } SECTION( "sort with random-access iterable, compare and projection" ) @@ -55,7 +55,7 @@ TEST_CASE( "default sorter function pointer tests", = cppsort::default_sorter(); sorter(vec, std::greater<>{}, projection); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } SECTION( "sort with random-access iterators" ) @@ -64,8 +64,8 @@ TEST_CASE( "default sorter function pointer tests", std::vector::iterator) = cppsort::default_sorter(); - sorter(std::begin(vec), std::end(vec)); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + sorter(vec.begin(), vec.end()); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } SECTION( "sort with random-access iterators and compare" ) @@ -75,8 +75,8 @@ TEST_CASE( "default sorter function pointer tests", std::greater<>) = cppsort::default_sorter(); - sorter(std::begin(vec), std::end(vec), std::greater<>{}); - CHECK( std::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}) ); + sorter(vec.begin(), vec.end(), std::greater<>{}); + CHECK( std::is_sorted(vec.begin(), vec.end(), std::greater<>{}) ); } SECTION( "sort with random-access iterators and projection" ) @@ -86,8 +86,8 @@ TEST_CASE( "default sorter function pointer tests", decltype(projection)) = cppsort::default_sorter(); - sorter(std::begin(vec), std::end(vec), projection); - CHECK( std::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}) ); + sorter(vec.begin(), vec.end(), projection); + CHECK( std::is_sorted(vec.begin(), vec.end(), std::greater<>{}) ); } SECTION( "sort with random-access iterators, compare and projection" ) @@ -98,8 +98,8 @@ TEST_CASE( "default sorter function pointer tests", decltype(projection)) = cppsort::default_sorter(); - sorter(std::begin(vec), std::end(vec), std::greater<>{}, projection); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + sorter(vec.begin(), vec.end(), std::greater<>{}, projection); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } SECTION( "sort with bidirectional iterators" ) @@ -108,9 +108,9 @@ TEST_CASE( "default sorter function pointer tests", std::list::iterator) = cppsort::default_sorter(); - std::list li(std::begin(vec), std::end(vec)); - sorter(std::begin(li), std::end(li)); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + std::list li(vec.begin(), vec.end()); + sorter(li.begin(), li.end()); + CHECK( std::is_sorted(li.begin(), li.end()) ); } SECTION( "sort with bidirectional iterators and compare" ) @@ -120,9 +120,9 @@ TEST_CASE( "default sorter function pointer tests", std::greater<>) = cppsort::default_sorter(); - std::list li(std::begin(vec), std::end(vec)); - sorter(std::begin(li), std::end(li), std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + std::list li(vec.begin(), vec.end()); + sorter(li.begin(), li.end(), std::greater<>{}); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); } SECTION( "sort with bidirectional iterators and projection" ) @@ -132,9 +132,9 @@ TEST_CASE( "default sorter function pointer tests", decltype(projection)) = cppsort::default_sorter(); - std::list li(std::begin(vec), std::end(vec)); - sorter(std::begin(li), std::end(li), projection); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + std::list li(vec.begin(), vec.end()); + sorter(li.begin(), li.end(), projection); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); } SECTION( "sort with bidirectional iterators, compare and projection" ) @@ -145,9 +145,9 @@ TEST_CASE( "default sorter function pointer tests", decltype(projection)) = cppsort::default_sorter(); - std::list li(std::begin(vec), std::end(vec)); - sorter(std::begin(li), std::end(li), std::greater<>{}, projection); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + std::list li(vec.begin(), vec.end()); + sorter(li.begin(), li.end(), std::greater<>{}, projection); + CHECK( std::is_sorted(li.begin(), li.end()) ); } SECTION( "sort with forward iterators" ) @@ -156,9 +156,9 @@ TEST_CASE( "default sorter function pointer tests", std::forward_list::iterator) = cppsort::default_sorter(); - std::forward_list li(std::begin(vec), std::end(vec)); - sorter(std::begin(li), std::end(li)); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + std::forward_list li(vec.begin(), vec.end()); + sorter(li.begin(), li.end()); + CHECK( std::is_sorted(li.begin(), li.end()) ); } SECTION( "sort with forward iterators and compare" ) @@ -168,9 +168,9 @@ TEST_CASE( "default sorter function pointer tests", std::greater<>) = cppsort::default_sorter(); - std::forward_list li(std::begin(vec), std::end(vec)); - sorter(std::begin(li), std::end(li), std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + std::forward_list li(vec.begin(), vec.end()); + sorter(li.begin(), li.end(), std::greater<>{}); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); } SECTION( "sort with forward iterators and projection" ) @@ -180,9 +180,9 @@ TEST_CASE( "default sorter function pointer tests", decltype(projection)) = cppsort::default_sorter(); - std::forward_list li(std::begin(vec), std::end(vec)); - sorter(std::begin(li), std::end(li), projection); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + std::forward_list li(vec.begin(), vec.end()); + sorter(li.begin(), li.end(), projection); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); } SECTION( "sort with forward iterators and projection" ) @@ -193,26 +193,26 @@ TEST_CASE( "default sorter function pointer tests", decltype(projection)) = cppsort::default_sorter(); - std::forward_list li(std::begin(vec), std::end(vec)); - sorter(std::begin(li), std::end(li), std::greater<>{}, projection); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + std::forward_list li(vec.begin(), vec.end()); + sorter(li.begin(), li.end(), std::greater<>{}, projection); + CHECK( std::is_sorted(li.begin(), li.end()) ); } SECTION( "sort with self-sortable iterable" ) { constexpr void(*sorter)(std::list&) = cppsort::default_sorter(); - std::list li(std::begin(vec), std::end(vec)); + std::list li(vec.begin(), vec.end()); sorter(li); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + CHECK( std::is_sorted(li.begin(), li.end()) ); } SECTION( "sort with self-sortable iterable and compare" ) { constexpr void(*sorter)(std::forward_list&, std::greater<>) = cppsort::default_sorter(); - std::forward_list li(std::begin(vec), std::end(vec)); + std::forward_list li(vec.begin(), vec.end()); sorter(li, std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); } } diff --git a/tests/sorters/default_sorter_projection.cpp b/tests/sorters/default_sorter_projection.cpp new file mode 100644 index 00000000..66dc53cc --- /dev/null +++ b/tests/sorters/default_sorter_projection.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015-2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TEST_CASE( "default sorter tests with projections", + "[default_sorter][projection]" ) +{ + // Wrapper to hide the integer + using wrapper = generic_wrapper; + + // Collection to sort + std::vector vec; + auto distribution = dist::shuffled{}; + distribution(std::back_inserter(vec), 80); + + SECTION( "sort with random-access iterable" ) + { + cppsort::sort(vec, &wrapper::value); + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &wrapper::value) ); + } + + SECTION( "sort with random-access iterable and compare" ) + { + cppsort::sort(vec, std::greater<>{}, &wrapper::value); + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::greater<>{}, &wrapper::value) ); + } + + SECTION( "sort with random-access iterators" ) + { + cppsort::sort(vec.begin(), vec.end(), &wrapper::value); + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &wrapper::value) ); + } + + SECTION( "sort with random-access iterators and compare" ) + { + cppsort::sort(vec.begin(), vec.end(), std::greater<>{}, &wrapper::value); + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::greater<>{}, &wrapper::value) ); + } + + SECTION( "sort with bidirectional iterators" ) + { + std::list li(vec.begin(), vec.end()); + cppsort::sort(li.begin(), li.end(), &wrapper::value); + CHECK( helpers::is_sorted(li.begin(), li.end(), std::less<>{}, &wrapper::value) ); + } + + SECTION( "sort with bidirectional iterators and compare" ) + { + std::list li(vec.begin(), vec.end()); + cppsort::sort(li.begin(), li.end(), std::greater<>{}, &wrapper::value); + CHECK( helpers::is_sorted(li.begin(), li.end(), std::greater<>{}, &wrapper::value) ); + } + + SECTION( "sort with forward iterators" ) + { + std::forward_list li(vec.begin(), vec.end()); + cppsort::sort(li.begin(), li.end(), &wrapper::value); + CHECK( helpers::is_sorted(li.begin(), li.end(), std::less<>{}, &wrapper::value) ); + } + + SECTION( "sort with forward iterators and compare" ) + { + std::forward_list li(vec.begin(), vec.end()); + cppsort::sort(li.begin(), li.end(), std::greater<>{}, &wrapper::value); + CHECK( helpers::is_sorted(li.begin(), li.end(), std::greater<>{}, &wrapper::value) ); + } +} diff --git a/testsuite/every_instantiated_sorter.cpp b/tests/sorters/every_instantiated_sorter.cpp similarity index 56% rename from testsuite/every_instantiated_sorter.cpp rename to tests/sorters/every_instantiated_sorter.cpp index 117b6a9f..f638d0a9 100644 --- a/testsuite/every_instantiated_sorter.cpp +++ b/tests/sorters/every_instantiated_sorter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -25,156 +25,162 @@ TEST_CASE( "test every instantiated sorter", "[sorters]" ) auto distribution = dist::shuffled{}; distribution(std::back_inserter(collection), 35, -47); - std::list li(std::begin(collection), std::end(collection)); - std::forward_list fli(std::begin(collection), std::end(collection)); + std::list li(collection.begin(), collection.end()); + std::forward_list fli(collection.begin(), collection.end()); + + SECTION( "adaptive_shivers_sort" ) + { + cppsort::adaptive_shivers_sort(collection); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); + } SECTION( "cartesian_tree_sort" ) { cppsort::cartesian_tree_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "counting_sort" ) { cppsort::counting_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "drop_merge_sort" ) { cppsort::drop_merge_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "grail_sorter" ) { cppsort::grail_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "heap_sorter" ) { cppsort::heap_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "insertion_sorter" ) { cppsort::insertion_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "mel_sorter" ) { cppsort::mel_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "merge_insertion_sorter" ) { cppsort::merge_insertion_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "merge_sorter" ) { cppsort::merge_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "pdq_sorter" ) { cppsort::pdq_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "poplar_sorter" ) { cppsort::poplar_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "quick_merge_sorter" ) { cppsort::quick_merge_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); cppsort::quick_merge_sort(li); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); + CHECK( std::is_sorted(li.begin(), li.end()) ); cppsort::quick_merge_sort(fli); - CHECK( std::is_sorted(std::begin(fli), std::end(fli)) ); + CHECK( std::is_sorted(fli.begin(), fli.end()) ); } SECTION( "quick_sorter" ) { cppsort::quick_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "selection_sorter" ) { cppsort::selection_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "ska_sorter" ) { cppsort::ska_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "slab_sorter" ) { cppsort::slab_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "smooth_sorter" ) { cppsort::smooth_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "spin_sorter" ) { cppsort::spin_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "split_sorter" ) { cppsort::split_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "spread_sorter" ) { cppsort::spread_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "std_sorter" ) { cppsort::std_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "tim_sorter" ) { cppsort::tim_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "verge_sorter" ) { cppsort::verge_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "wiki_sort" ) { cppsort::wiki_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } } diff --git a/testsuite/every_sorter.cpp b/tests/sorters/every_sorter.cpp similarity index 96% rename from testsuite/every_sorter.cpp rename to tests/sorters/every_sorter.cpp index a45a5231..d8a07c82 100644 --- a/testsuite/every_sorter.cpp +++ b/tests/sorters/every_sorter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -8,13 +8,14 @@ #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test every random-access sorter", "[sorters]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::counting_sorter, cppsort::drop_merge_sorter, diff --git a/testsuite/heap_memory_exhaustion.cpp b/tests/sorters/every_sorter_heap_memory_exhaustion.cpp similarity index 89% rename from testsuite/heap_memory_exhaustion.cpp rename to tests/sorters/every_sorter_heap_memory_exhaustion.cpp index 659f4681..66ffb4dc 100644 --- a/testsuite/heap_memory_exhaustion.cpp +++ b/tests/sorters/every_sorter_heap_memory_exhaustion.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 Morwenn + * Copyright (c) 2019-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -43,7 +43,7 @@ TEMPLATE_TEST_CASE( "heap exhaustion for random-access sorters", "[sorters][heap scoped_memory_exhaustion _; sorter{}(collection); } - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } TEMPLATE_TEST_CASE( "heap exhaustion for bidirectional sorters", "[sorters][heap_exhaustion]", @@ -62,7 +62,7 @@ TEMPLATE_TEST_CASE( "heap exhaustion for bidirectional sorters", "[sorters][heap scoped_memory_exhaustion _; sorter{}(collection); } - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } TEMPLATE_TEST_CASE( "heap exhaustion for forward sorters", "[sorters][heap_exhaustion]", @@ -80,5 +80,5 @@ TEMPLATE_TEST_CASE( "heap exhaustion for forward sorters", "[sorters][heap_exhau scoped_memory_exhaustion _; sorter{}(collection); } - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/every_sorter_internal_compare.cpp b/tests/sorters/every_sorter_internal_compare.cpp similarity index 88% rename from testsuite/every_sorter_internal_compare.cpp rename to tests/sorters/every_sorter_internal_compare.cpp index 404f1626..afe05794 100644 --- a/testsuite/every_sorter_internal_compare.cpp +++ b/tests/sorters/every_sorter_internal_compare.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include TEMPLATE_TEST_CASE( "test every sorter with a pointer to member function comparison", "[sorters][as_function]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, @@ -41,5 +42,5 @@ TEMPLATE_TEST_CASE( "test every sorter with a pointer to member function compari using sorter = TestType; sorter{}(collection, &internal_compare::compare_to); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/every_sorter_long_string.cpp b/tests/sorters/every_sorter_long_string.cpp similarity index 89% rename from testsuite/every_sorter_long_string.cpp rename to tests/sorters/every_sorter_long_string.cpp index 9bfd2e78..8189cbff 100644 --- a/testsuite/every_sorter_long_string.cpp +++ b/tests/sorters/every_sorter_long_string.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 Morwenn + * Copyright (c) 2019-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -31,13 +31,14 @@ namespace auto s = std::to_string(i); vec.push_back(std::string(100 - s.size(), '0') + std::move(s)); } - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); - std::move(std::begin(vec), std::end(vec), out); + std::shuffle(vec.begin(), vec.end(), hasard::engine()); + std::move(vec.begin(), vec.end(), out); } }; } TEMPLATE_TEST_CASE( "test every sorter with long std::string", "[sorters]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::default_sorter, cppsort::drop_merge_sorter, @@ -83,10 +84,10 @@ TEMPLATE_TEST_CASE( "test every sorter with long std::string", "[sorters]", distribution(std::back_inserter(collection), 491, -125); auto copy = collection; - std::sort(std::begin(copy), std::end(copy)); + std::sort(copy.begin(), copy.end()); TestType sorter; sorter(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); CHECK( bool(collection == copy) ); } diff --git a/testsuite/every_sorter_move_compare_projection.cpp b/tests/sorters/every_sorter_move_compare_projection.cpp similarity index 94% rename from testsuite/every_sorter_move_compare_projection.cpp rename to tests/sorters/every_sorter_move_compare_projection.cpp index c1f48eda..7fd971bd 100644 --- a/testsuite/every_sorter_move_compare_projection.cpp +++ b/tests/sorters/every_sorter_move_compare_projection.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2020-2021 Morwenn + * Copyright (c) 2020-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include @@ -13,6 +13,7 @@ #include TEMPLATE_TEST_CASE( "every sorter with comparison function altered by move", "[sorters]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, @@ -52,6 +53,7 @@ TEMPLATE_TEST_CASE( "every sorter with comparison function altered by move", "[s } TEMPLATE_TEST_CASE( "every sorter with projection function altered by move", "[sorters][projection]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, diff --git a/testsuite/every_sorter_move_only.cpp b/tests/sorters/every_sorter_move_only.cpp similarity index 93% rename from testsuite/every_sorter_move_only.cpp rename to tests/sorters/every_sorter_move_only.cpp index 597d96e2..5f28aa48 100644 --- a/testsuite/every_sorter_move_only.cpp +++ b/tests/sorters/every_sorter_move_only.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include #include TEMPLATE_TEST_CASE( "test every sorter with move-only types", "[sorters]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::default_sorter, cppsort::drop_merge_sorter, diff --git a/testsuite/every_sorter_no_post_iterator.cpp b/tests/sorters/every_sorter_no_post_iterator.cpp similarity index 96% rename from testsuite/every_sorter_no_post_iterator.cpp rename to tests/sorters/every_sorter_no_post_iterator.cpp index 41231f9a..32149889 100644 --- a/testsuite/every_sorter_no_post_iterator.cpp +++ b/tests/sorters/every_sorter_no_post_iterator.cpp @@ -1,12 +1,12 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include #include -#include +#include #include #include #include @@ -14,6 +14,7 @@ #include TEMPLATE_TEST_CASE( "test most sorters with no_post_iterator", "[sorters]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::counting_sorter, cppsort::default_sorter, diff --git a/testsuite/every_sorter_non_const_compare.cpp b/tests/sorters/every_sorter_non_const_compare.cpp similarity index 89% rename from testsuite/every_sorter_non_const_compare.cpp rename to tests/sorters/every_sorter_non_const_compare.cpp index 27dc1f6d..02a25b41 100644 --- a/testsuite/every_sorter_non_const_compare.cpp +++ b/tests/sorters/every_sorter_non_const_compare.cpp @@ -1,16 +1,17 @@ /* - * Copyright (c) 2020-2021 Morwenn + * Copyright (c) 2020-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include TEMPLATE_TEST_CASE( "test extended compatibility with LWG 3031", "[sorters]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::default_sorter, cppsort::drop_merge_sorter, @@ -45,5 +46,5 @@ TEMPLATE_TEST_CASE( "test extended compatibility with LWG 3031", "[sorters]", TestType sorter; sorter(collection, [](int& lhs, int& rhs) { return lhs < rhs; }); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/every_sorter_rvalue_projection.cpp b/tests/sorters/every_sorter_rvalue_projection.cpp similarity index 96% rename from testsuite/every_sorter_rvalue_projection.cpp rename to tests/sorters/every_sorter_rvalue_projection.cpp index 92ad4a11..7e243f3b 100644 --- a/testsuite/every_sorter_rvalue_projection.cpp +++ b/tests/sorters/every_sorter_rvalue_projection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Morwenn + * Copyright (c) 2021-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -9,11 +9,12 @@ #include #include #include -#include +#include #include #include TEMPLATE_TEST_CASE( "random-access sorters with a projection returning an rvalue", "[sorters][projection]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, diff --git a/testsuite/every_sorter_small_collections.cpp b/tests/sorters/every_sorter_small_collections.cpp similarity index 93% rename from testsuite/every_sorter_small_collections.cpp rename to tests/sorters/every_sorter_small_collections.cpp index c9dfd989..517df11d 100644 --- a/testsuite/every_sorter_small_collections.cpp +++ b/tests/sorters/every_sorter_small_collections.cpp @@ -1,12 +1,14 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ +#include #include -#include +#include #include TEMPLATE_TEST_CASE( "test every sorter with small collections", "[sorters]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::counting_sorter, cppsort::drop_merge_sorter, diff --git a/testsuite/every_sorter_span.cpp b/tests/sorters/every_sorter_span.cpp similarity index 91% rename from testsuite/every_sorter_span.cpp rename to tests/sorters/every_sorter_span.cpp index 9447bd11..f67d6e51 100644 --- a/testsuite/every_sorter_span.cpp +++ b/tests/sorters/every_sorter_span.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include @@ -13,6 +13,7 @@ #include TEMPLATE_TEST_CASE( "test every sorter with temporary span", "[sorters][span]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::counting_sorter, cppsort::default_sorter, @@ -55,5 +56,5 @@ TEMPLATE_TEST_CASE( "test every sorter with temporary span", "[sorters][span]", TestType sorter; sorter(make_span(collection)); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } diff --git a/testsuite/every_sorter_throwing_moves.cpp b/tests/sorters/every_sorter_throwing_moves.cpp similarity index 97% rename from testsuite/every_sorter_throwing_moves.cpp rename to tests/sorters/every_sorter_throwing_moves.cpp index 9bd0dc59..fe0fd328 100644 --- a/testsuite/every_sorter_throwing_moves.cpp +++ b/tests/sorters/every_sorter_throwing_moves.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Morwenn + * Copyright (c) 2021-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include @@ -77,6 +77,7 @@ namespace } TEMPLATE_TEST_CASE( "random-access sorters against throwing move operations", "[sorters][throwing_moves]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::drop_merge_sorter, cppsort::grail_sorter<>, diff --git a/testsuite/every_sorter_tricky_difference_type.cpp b/tests/sorters/every_sorter_tricky_difference_type.cpp similarity index 93% rename from testsuite/every_sorter_tricky_difference_type.cpp rename to tests/sorters/every_sorter_tricky_difference_type.cpp index 283ade84..f03c1800 100644 --- a/testsuite/every_sorter_tricky_difference_type.cpp +++ b/tests/sorters/every_sorter_tricky_difference_type.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2021 Morwenn + * Copyright (c) 2021-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include @@ -13,6 +13,7 @@ #include TEMPLATE_TEST_CASE( "test every sorter with an int8_t difference_type", "[sorters]", + cppsort::adaptive_shivers_sorter, cppsort::cartesian_tree_sorter, cppsort::counting_sorter, cppsort::drop_merge_sorter, diff --git a/testsuite/sorters/merge_insertion_sorter_projection.cpp b/tests/sorters/merge_insertion_sorter_projection.cpp similarity index 63% rename from testsuite/sorters/merge_insertion_sorter_projection.cpp rename to tests/sorters/merge_insertion_sorter_projection.cpp index 1d983ccf..c72ee45b 100644 --- a/testsuite/sorters/merge_insertion_sorter_projection.cpp +++ b/tests/sorters/merge_insertion_sorter_projection.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2016-2020 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include #include @@ -25,25 +25,25 @@ TEST_CASE( "merge_insertion_sorter tests with projections", SECTION( "sort with random-access iterable" ) { cppsort::merge_insertion_sort(vec, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), std::less<>{}, &wrapper::value) ); + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &wrapper::value) ); } SECTION( "sort with random-access iterable and compare" ) { cppsort::merge_insertion_sort(vec, std::greater<>{}, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}, &wrapper::value) ); + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::greater<>{}, &wrapper::value) ); } SECTION( "sort with random-access iterators" ) { - cppsort::merge_insertion_sort(std::begin(vec), std::end(vec), &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), std::less<>{}, &wrapper::value) ); + cppsort::merge_insertion_sort(vec.begin(), vec.end(), &wrapper::value); + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &wrapper::value) ); } SECTION( "sort with random-access iterators and compare" ) { - cppsort::merge_insertion_sort(std::begin(vec), std::end(vec), + cppsort::merge_insertion_sort(vec.begin(), vec.end(), std::greater<>{}, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}, &wrapper::value) ); + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::greater<>{}, &wrapper::value) ); } } diff --git a/tests/sorters/merge_sorter.cpp b/tests/sorters/merge_sorter.cpp new file mode 100644 index 00000000..2b129404 --- /dev/null +++ b/tests/sorters/merge_sorter.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015-2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TEST_CASE( "merge_sorter tests", "[merge_sorter]" ) +{ + // Collection to sort + std::vector vec; vec.reserve(80); + auto distribution = dist::shuffled{}; + distribution(std::back_inserter(vec), 80, 0); + + SECTION( "sort with random-access iterable" ) + { + cppsort::merge_sort(vec); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); + } + + SECTION( "sort with random-access iterable and compare" ) + { + cppsort::merge_sort(vec, std::greater<>{}); + CHECK( std::is_sorted(vec.begin(), vec.end(), std::greater<>{}) ); + } + + SECTION( "sort with random-access iterators" ) + { + cppsort::merge_sort(vec.begin(), vec.end()); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); + } + + SECTION( "sort with random-access iterators and compare" ) + { + cppsort::merge_sort(vec.begin(), vec.end(), std::greater<>{}); + CHECK( std::is_sorted(vec.begin(), vec.end(), std::greater<>{}) ); + } + + SECTION( "sort with bidirectional iterators" ) + { + std::list li(vec.begin(), vec.end()); + cppsort::merge_sort(li.begin(), li.end()); + CHECK( std::is_sorted(li.begin(), li.end()) ); + } + + SECTION( "sort with bidirectional iterators and compare" ) + { + std::list li(vec.begin(), vec.end()); + cppsort::merge_sort(li.begin(), li.end(), std::greater<>{}); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); + } + + SECTION( "sort with forward iterators" ) + { + std::forward_list li(vec.begin(), vec.end()); + cppsort::merge_sort(li.begin(), li.end()); + CHECK( std::is_sorted(li.begin(), li.end()) ); + } + + SECTION( "sort with forward iterators and compare" ) + { + std::forward_list li(vec.begin(), vec.end()); + cppsort::merge_sort(li.begin(), li.end(), std::greater<>{}); + CHECK( std::is_sorted(li.begin(), li.end(), std::greater<>{}) ); + } +} diff --git a/tests/sorters/merge_sorter_projection.cpp b/tests/sorters/merge_sorter_projection.cpp new file mode 100644 index 00000000..e6532a1b --- /dev/null +++ b/tests/sorters/merge_sorter_projection.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015-2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TEST_CASE( "merge_sorter tests with projections", + "[merge_sorter][projection]" ) +{ + // Wrapper to hide the integer + using wrapper = generic_wrapper; + + // Collection to sort + std::vector vec; + auto distribution = dist::shuffled{}; + distribution(std::back_inserter(vec), 80); + + SECTION( "sort with random-access iterable" ) + { + cppsort::merge_sort(vec, &wrapper::value); + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &wrapper::value) ); + } + + SECTION( "sort with random-access iterable and compare" ) + { + cppsort::merge_sort(vec, std::greater<>{}, &wrapper::value); + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::greater<>{}, &wrapper::value) ); + } + + SECTION( "sort with random-access iterators" ) + { + cppsort::merge_sort(vec.begin(), vec.end(), &wrapper::value); + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &wrapper::value) ); + } + + SECTION( "sort with random-access iterators and compare" ) + { + cppsort::merge_sort(vec.begin(), vec.end(), std::greater<>{}, &wrapper::value); + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::greater<>{}, &wrapper::value) ); + } + + SECTION( "sort with bidirectional iterators" ) + { + std::list li(vec.begin(), vec.end()); + cppsort::merge_sort(li.begin(), li.end(), &wrapper::value); + CHECK( helpers::is_sorted(li.begin(), li.end(), std::less<>{}, &wrapper::value) ); + } + + SECTION( "sort with bidirectional iterators and compare" ) + { + std::list li(vec.begin(), vec.end()); + cppsort::merge_sort(li.begin(), li.end(), std::greater<>{}, &wrapper::value); + CHECK( helpers::is_sorted(li.begin(), li.end(), std::greater<>{}, &wrapper::value) ); + } + + SECTION( "sort with forward iterators" ) + { + std::forward_list li(vec.begin(), vec.end()); + cppsort::merge_sort(li.begin(), li.end(), &wrapper::value); + CHECK( helpers::is_sorted(li.begin(), li.end(), std::less<>{}, &wrapper::value) ); + } + + SECTION( "sort with forward iterators and compare" ) + { + std::forward_list li(vec.begin(), vec.end()); + cppsort::merge_sort(li.begin(), li.end(), std::greater<>{}, &wrapper::value); + CHECK( helpers::is_sorted(li.begin(), li.end(), std::greater<>{}, &wrapper::value) ); + } +} diff --git a/testsuite/sorters/poplar_sorter.cpp b/tests/sorters/poplar_sorter.cpp similarity index 86% rename from testsuite/sorters/poplar_sorter.cpp rename to tests/sorters/poplar_sorter.cpp index 51bb1062..1d0709e8 100644 --- a/testsuite/sorters/poplar_sorter.cpp +++ b/tests/sorters/poplar_sorter.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2017-2018 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include @@ -25,6 +25,6 @@ TEST_CASE( "poplar_sorter tests", "[poplar_sorter]" ) std::vector vec; vec.reserve(size); distribution(std::back_inserter(vec), size, -1568); cppsort::poplar_sort(vec); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); } } diff --git a/testsuite/sorters/ska_sorter.cpp b/tests/sorters/ska_sorter.cpp similarity index 55% rename from testsuite/sorters/ska_sorter.cpp rename to tests/sorters/ska_sorter.cpp index c5b18062..4abb624c 100644 --- a/testsuite/sorters/ska_sorter.cpp +++ b/tests/sorters/ska_sorter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -101,62 +101,62 @@ TEST_CASE( "is_ska_sortable", "[ska_sorter]" ) SECTION( "built-in integral types" ) { - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); } SECTION( "built-in floating point types" ) { - CHECK(( is_ska_sortable || - sizeof(float) != sizeof(std::uint32_t) || - not std::numeric_limits::is_iec559 )); + STATIC_CHECK(( is_ska_sortable || + sizeof(float) != sizeof(std::uint32_t) || + not std::numeric_limits::is_iec559 )); - CHECK(( is_ska_sortable || - sizeof(double) != sizeof(std::uint64_t) || - not std::numeric_limits::is_iec559 )); + STATIC_CHECK(( is_ska_sortable || + sizeof(double) != sizeof(std::uint64_t) || + not std::numeric_limits::is_iec559 )); - CHECK_FALSE( is_ska_sortable ); + STATIC_CHECK_FALSE( is_ska_sortable ); } SECTION( "standard collections" ) { // Srings - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable ); - CHECK( is_ska_sortable> ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable ); + STATIC_CHECK( is_ska_sortable> ); // Other collections - CHECK( is_ska_sortable> ); - CHECK( is_ska_sortable> ); - CHECK( is_ska_sortable>> ); - CHECK( is_ska_sortable>> ); - CHECK_FALSE( is_ska_sortable> ); + STATIC_CHECK( is_ska_sortable> ); + STATIC_CHECK( is_ska_sortable> ); + STATIC_CHECK( is_ska_sortable>> ); + STATIC_CHECK( is_ska_sortable>> ); + STATIC_CHECK_FALSE( is_ska_sortable> ); } SECTION( "pairs and tuples" ) { // std::pair - CHECK( is_ska_sortable> ); - CHECK( is_ska_sortable>> ); - CHECK( is_ska_sortable>, std::deque>> ); - CHECK_FALSE( is_ska_sortable>, std::deque>> ); + STATIC_CHECK( is_ska_sortable> ); + STATIC_CHECK( is_ska_sortable>> ); + STATIC_CHECK( is_ska_sortable>, std::deque>> ); + STATIC_CHECK_FALSE( is_ska_sortable>, std::deque>> ); // std::tuple - CHECK( is_ska_sortable> ); - CHECK( is_ska_sortable>> ); - CHECK_FALSE( is_ska_sortable, std::deque>> ); + STATIC_CHECK( is_ska_sortable> ); + STATIC_CHECK( is_ska_sortable>> ); + STATIC_CHECK_FALSE( is_ska_sortable, std::deque>> ); } } diff --git a/testsuite/sorters/ska_sorter_projection.cpp b/tests/sorters/ska_sorter_projection.cpp similarity index 74% rename from testsuite/sorters/ska_sorter_projection.cpp rename to tests/sorters/ska_sorter_projection.cpp index 371eeb6c..89c244dc 100644 --- a/testsuite/sorters/ska_sorter_projection.cpp +++ b/tests/sorters/ska_sorter_projection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2021 Morwenn + * Copyright (c) 2017-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -22,9 +22,9 @@ TEST_CASE( "ska_sorter tests with projections", for (int i = 0 ; i < 100'000 ; ++i) { vec.emplace_back(i, float(i)); } - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); + std::shuffle(vec.begin(), vec.end(), hasard::engine()); cppsort::ska_sort(vec, &std::pair::first); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &std::pair::second) ); } @@ -34,9 +34,9 @@ TEST_CASE( "ska_sorter tests with projections", for (int i = 0 ; i < 100'000 ; ++i) { vec.emplace_back(i, float(i)); } - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); + std::shuffle(vec.begin(), vec.end(), hasard::engine()); cppsort::ska_sort(vec, &std::pair::first); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &std::pair::second) ); } @@ -46,9 +46,9 @@ TEST_CASE( "ska_sorter tests with projections", for (int i = 0 ; i < 100'000 ; ++i) { vec.emplace_back(i, float(i)); } - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); + std::shuffle(vec.begin(), vec.end(), hasard::engine()); cppsort::ska_sort(vec, &std::pair::second); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &std::pair::first) ); } @@ -58,9 +58,9 @@ TEST_CASE( "ska_sorter tests with projections", for (int i = 0 ; i < 100'000 ; ++i) { vec.emplace_back(i, double(i)); } - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); + std::shuffle(vec.begin(), vec.end(), hasard::engine()); cppsort::ska_sort(vec, &std::pair::second); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &std::pair::first) ); } @@ -72,9 +72,9 @@ TEST_CASE( "ska_sorter tests with projections", for (int i = 0 ; i < 100'000 ; ++i) { vec.emplace_back(std::to_string(i)); } - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); + std::shuffle(vec.begin(), vec.end(), hasard::engine()); cppsort::ska_sort(vec, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &wrapper::value) ); } } diff --git a/testsuite/sorters/spin_sorter.cpp b/tests/sorters/spin_sorter.cpp similarity index 82% rename from testsuite/sorters/spin_sorter.cpp rename to tests/sorters/spin_sorter.cpp index db2a26d0..2b0e139f 100644 --- a/testsuite/sorters/spin_sorter.cpp +++ b/tests/sorters/spin_sorter.cpp @@ -1,11 +1,11 @@ /* - * Copyright (c) 2019 Morwenn + * Copyright (c) 2019-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include -#include +#include #include #include @@ -27,7 +27,7 @@ TEST_CASE( "spin_sorter tests", "[spin_sorter]" ) collection.reserve(size); distribution(std::back_inserter(collection), size, 0); cppsort::spin_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } SECTION( "odd number of levels" ) @@ -36,6 +36,6 @@ TEST_CASE( "spin_sorter tests", "[spin_sorter]" ) collection.reserve(size); distribution(std::back_inserter(collection), size, 0); cppsort::spin_sort(collection); - CHECK( std::is_sorted(std::begin(collection), std::end(collection)) ); + CHECK( std::is_sorted(collection.begin(), collection.end()) ); } } diff --git a/testsuite/sorters/spread_sorter.cpp b/tests/sorters/spread_sorter.cpp similarity index 97% rename from testsuite/sorters/spread_sorter.cpp rename to tests/sorters/spread_sorter.cpp index 8879f374..1ce7f39c 100644 --- a/testsuite/sorters/spread_sorter.cpp +++ b/tests/sorters/spread_sorter.cpp @@ -1,12 +1,12 @@ /* - * Copyright (c) 2015-2021 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include #include -#include +#include #include #include #include diff --git a/tests/sorters/spread_sorter_defaults.cpp b/tests/sorters/spread_sorter_defaults.cpp new file mode 100644 index 00000000..83fc844e --- /dev/null +++ b/tests/sorters/spread_sorter_defaults.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015-2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TEST_CASE( "spread_sorter generate overloads", + "[spread_sorter][sorter_facade]" ) +{ + // These tests use spread_sorter as a real-world Guinea pig + // to make sure that sorter_facade generates the expected + // operator() overloads for non-comparison sorters + + SECTION( "default operator() with std::less<>" ) + { + std::vector vec(100'000); + std::iota(vec.begin(), vec.end(), 0); + + std::shuffle(vec.begin(), vec.end(), hasard::engine()); + cppsort::spread_sort(vec, std::less<>{}); + CHECK( std::is_sorted(vec.begin(), vec.end(), std::less<>{}) ); + + std::shuffle(vec.begin(), vec.end(), hasard::engine()); + cppsort::spread_sort(vec.begin(), vec.end(), std::less<>{}); + CHECK( std::is_sorted(vec.begin(), vec.end(), std::less<>{}) ); + } + + SECTION( "default operator() with utility::identity" ) + { + std::vector vec(100'000); + std::iota(vec.begin(), vec.end(), 0); + + std::shuffle(vec.begin(), vec.end(), hasard::engine()); + cppsort::spread_sort(vec, cppsort::utility::identity{}); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); + + std::shuffle(vec.begin(), vec.end(), hasard::engine()); + cppsort::spread_sort(vec.begin(), vec.end(), cppsort::utility::identity{}); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); + } + + SECTION( "default operator() with both" ) + { + std::vector vec(100'000); + std::iota(vec.begin(), vec.end(), 0); + + std::shuffle(vec.begin(), vec.end(), hasard::engine()); + cppsort::spread_sort(vec, std::less<>{}, cppsort::utility::identity{}); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); + + std::shuffle(vec.begin(), vec.end(), hasard::engine()); + cppsort::spread_sort(vec.begin(), vec.end(), std::less<>{}, cppsort::utility::identity{}); + CHECK( std::is_sorted(vec.begin(), vec.end()) ); + } +} diff --git a/testsuite/sorters/spread_sorter_projection.cpp b/tests/sorters/spread_sorter_projection.cpp similarity index 74% rename from testsuite/sorters/spread_sorter_projection.cpp rename to tests/sorters/spread_sorter_projection.cpp index cf33f9cf..1e523d27 100644 --- a/testsuite/sorters/spread_sorter_projection.cpp +++ b/tests/sorters/spread_sorter_projection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2021 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -22,9 +22,9 @@ TEST_CASE( "spread_sorter tests with projections", for (int i = 0 ; i < 100'000 ; ++i) { vec.emplace_back(i, float(i)); } - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); + std::shuffle(vec.begin(), vec.end(), hasard::engine()); cppsort::spread_sort(vec, &std::pair::first); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &std::pair::second) ); } @@ -34,9 +34,9 @@ TEST_CASE( "spread_sorter tests with projections", for (int i = 0 ; i < 100'000 ; ++i) { vec.emplace_back(i, float(i)); } - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); + std::shuffle(vec.begin(), vec.end(), hasard::engine()); cppsort::spread_sort(vec, &std::pair::first); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &std::pair::second) ); } @@ -46,9 +46,9 @@ TEST_CASE( "spread_sorter tests with projections", for (int i = 0 ; i < 100'000 ; ++i) { vec.emplace_back(i, float(i)); } - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); + std::shuffle(vec.begin(), vec.end(), hasard::engine()); cppsort::spread_sort(vec, &std::pair::second); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &std::pair::first) ); } @@ -58,9 +58,9 @@ TEST_CASE( "spread_sorter tests with projections", for (int i = 0 ; i < 100'000 ; ++i) { vec.emplace_back(i, double(i)); } - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); + std::shuffle(vec.begin(), vec.end(), hasard::engine()); cppsort::spread_sort(vec, &std::pair::second); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &std::pair::first) ); } @@ -72,9 +72,9 @@ TEST_CASE( "spread_sorter tests with projections", for (int i = 0 ; i < 100'000 ; ++i) { vec.emplace_back(std::to_string(i)); } - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); + std::shuffle(vec.begin(), vec.end(), hasard::engine()); cppsort::spread_sort(vec, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::less<>{}, &wrapper::value) ); } @@ -86,9 +86,9 @@ TEST_CASE( "spread_sorter tests with projections", for (int i = 0 ; i < 100'000 ; ++i) { vec.emplace_back(std::to_string(i)); } - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); + std::shuffle(vec.begin(), vec.end(), hasard::engine()); cppsort::spread_sort(vec, std::greater<>{}, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), + CHECK( helpers::is_sorted(vec.begin(), vec.end(), std::greater<>{}, &wrapper::value) ); } } diff --git a/testsuite/sorters/std_sorter.cpp b/tests/sorters/std_sorter.cpp similarity index 97% rename from testsuite/sorters/std_sorter.cpp rename to tests/sorters/std_sorter.cpp index 5062a519..25976644 100644 --- a/testsuite/sorters/std_sorter.cpp +++ b/tests/sorters/std_sorter.cpp @@ -1,12 +1,12 @@ /* - * Copyright (c) 2016-2020 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include #include -#include +#include #include #include #include diff --git a/testsuite/stable_sort_array.cpp b/tests/stable_sort_array.cpp similarity index 96% rename from testsuite/stable_sort_array.cpp rename to tests/stable_sort_array.cpp index 7b0e6aff..4293eaed 100644 --- a/testsuite/stable_sort_array.cpp +++ b/tests/stable_sort_array.cpp @@ -1,9 +1,9 @@ /* - * Copyright (c) 2018 Morwenn + * Copyright (c) 2018-2022 Morwenn * SPDX-License-Identifier: MIT */ #include -#include +#include #include #include #include diff --git a/testsuite/testing-tools/algorithm.h b/tests/testing-tools/algorithm.h similarity index 100% rename from testsuite/testing-tools/algorithm.h rename to tests/testing-tools/algorithm.h diff --git a/tests/testing-tools/catch_rng_seed.h b/tests/testing-tools/catch_rng_seed.h new file mode 100644 index 00000000..3b08c27f --- /dev/null +++ b/tests/testing-tools/catch_rng_seed.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#ifndef CPPSORT_TESTSUITE_CATCH_RNG_SEED_H_ +#define CPPSORT_TESTSUITE_CATCH_RNG_SEED_H_ + +namespace Catch +{ + // This functions is only available in an internal header that + // drags a lot of dependencies, it's cheaper to just declare + // it ourselves in this wrapper + unsigned int rngSeed(); +} + +#endif // CPPSORT_TESTSUITE_CATCH_RNG_SEED_H_ diff --git a/testsuite/testing-tools/distributions.h b/tests/testing-tools/distributions.h similarity index 100% rename from testsuite/testing-tools/distributions.h rename to tests/testing-tools/distributions.h diff --git a/testsuite/testing-tools/functional_checks.h b/tests/testing-tools/functional_checks.h similarity index 100% rename from testsuite/testing-tools/functional_checks.h rename to tests/testing-tools/functional_checks.h diff --git a/testsuite/testing-tools/internal_compare.h b/tests/testing-tools/internal_compare.h similarity index 100% rename from testsuite/testing-tools/internal_compare.h rename to tests/testing-tools/internal_compare.h diff --git a/tests/testing-tools/is_transparent.h b/tests/testing-tools/is_transparent.h new file mode 100644 index 00000000..cbf62a05 --- /dev/null +++ b/tests/testing-tools/is_transparent.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#ifndef CPPSORT_TESTSUITE_IS_TRANSPARENT_H_ +#define CPPSORT_TESTSUITE_IS_TRANSPARENT_H_ + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + +//////////////////////////////////////////////////////////// +// Couple of types to ensure that transparent comparators +// fulfill their promises + +struct is_transparent_helper_compared +{ + int value = 0; + + is_transparent_helper_compared(const is_transparent_helper_compared&) = default; + is_transparent_helper_compared(is_transparent_helper_compared&&) = default; + is_transparent_helper_compared& operator=(const is_transparent_helper_compared&) = default; + is_transparent_helper_compared& operator=(is_transparent_helper_compared&&) = default; + + is_transparent_helper_compared(int value): + value(value) + {} + + friend auto operator<(const is_transparent_helper_compared& lhs, const is_transparent_helper_compared& rhs) + -> bool + { + return lhs.value < rhs.value; + } +}; + +struct is_transparent_helper_stored +{ + int value = 0; + + is_transparent_helper_stored(const is_transparent_helper_stored&) = default; + is_transparent_helper_stored(is_transparent_helper_stored&&) = default; + is_transparent_helper_stored& operator=(const is_transparent_helper_stored&) = default; + is_transparent_helper_stored& operator=(is_transparent_helper_stored&&) = default; + + is_transparent_helper_stored(int value): + value(value) + {} + + is_transparent_helper_stored(const is_transparent_helper_compared&) + { + throw std::runtime_error("is_transparent_helper_stored constructed from is_transparent_helper_compared"); + } + + friend auto operator<(const is_transparent_helper_stored& lhs, const is_transparent_helper_stored& rhs) + -> bool + { + return lhs.value < rhs.value; + } +}; + +inline auto operator<(const is_transparent_helper_stored& lhs, const is_transparent_helper_compared& rhs) + -> bool +{ + return lhs.value < rhs.value; +} + +inline auto operator<(const is_transparent_helper_compared& lhs, const is_transparent_helper_stored& rhs) + -> bool +{ + return lhs.value < rhs.value; +} + +#endif // CPPSORT_TESTSUITE_IS_TRANSPARENT_H_ diff --git a/testsuite/testing-tools/memory_exhaustion.h b/tests/testing-tools/memory_exhaustion.h similarity index 100% rename from testsuite/testing-tools/memory_exhaustion.h rename to tests/testing-tools/memory_exhaustion.h diff --git a/testsuite/testing-tools/move_only.h b/tests/testing-tools/move_only.h similarity index 100% rename from testsuite/testing-tools/move_only.h rename to tests/testing-tools/move_only.h diff --git a/testsuite/testing-tools/new_delete.cpp b/tests/testing-tools/new_delete.cpp similarity index 100% rename from testsuite/testing-tools/new_delete.cpp rename to tests/testing-tools/new_delete.cpp diff --git a/testsuite/testing-tools/no_post_iterator.h b/tests/testing-tools/no_post_iterator.h similarity index 100% rename from testsuite/testing-tools/no_post_iterator.h rename to tests/testing-tools/no_post_iterator.h diff --git a/testsuite/testing-tools/random.cpp b/tests/testing-tools/random.cpp similarity index 80% rename from testsuite/testing-tools/random.cpp rename to tests/testing-tools/random.cpp index 0f7f2677..0073e791 100644 --- a/testsuite/testing-tools/random.cpp +++ b/tests/testing-tools/random.cpp @@ -1,8 +1,9 @@ /* - * Copyright (c) 2021 Morwenn + * Copyright (c) 2021-2022 Morwenn * SPDX-License-Identifier: MIT */ -#include +#include +#include "catch_rng_seed.h" #include "random.h" namespace hasard diff --git a/testsuite/testing-tools/random.h b/tests/testing-tools/random.h similarity index 100% rename from testsuite/testing-tools/random.h rename to tests/testing-tools/random.h diff --git a/testsuite/testing-tools/span.h b/tests/testing-tools/span.h similarity index 100% rename from testsuite/testing-tools/span.h rename to tests/testing-tools/span.h diff --git a/testsuite/testing-tools/test_vector.h b/tests/testing-tools/test_vector.h similarity index 100% rename from testsuite/testing-tools/test_vector.h rename to tests/testing-tools/test_vector.h diff --git a/testsuite/testing-tools/wrapper.h b/tests/testing-tools/wrapper.h similarity index 100% rename from testsuite/testing-tools/wrapper.h rename to tests/testing-tools/wrapper.h diff --git a/testsuite/utility/adapter_storage.cpp b/tests/utility/adapter_storage.cpp similarity index 94% rename from testsuite/utility/adapter_storage.cpp rename to tests/utility/adapter_storage.cpp index feca1b7d..75d929d1 100644 --- a/testsuite/utility/adapter_storage.cpp +++ b/tests/utility/adapter_storage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2021 Morwenn + * Copyright (c) 2018-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -104,7 +104,7 @@ TEST_CASE( "test correct adapter_storage behavior", "[adapter_storage]" ) auto adapted_sorter = dummy_adapter(original_sorter); adapted_sorter(arr); - CHECK( std::is_sorted(std::begin(arr), std::end(arr)) ); + CHECK( std::is_sorted(arr.begin(), arr.end()) ); } SECTION( "with an immutable non-empty sorter" ) @@ -113,6 +113,6 @@ TEST_CASE( "test correct adapter_storage behavior", "[adapter_storage]" ) auto adapted_sorter = dummy_adapter(original_sorter); adapted_sorter(arr); - CHECK( std::is_sorted(std::begin(arr), std::end(arr)) ); + CHECK( std::is_sorted(arr.begin(), arr.end()) ); } } diff --git a/tests/utility/as_comparison.cpp b/tests/utility/as_comparison.cpp new file mode 100644 index 00000000..b548e48b --- /dev/null +++ b/tests/utility/as_comparison.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include + +TEST_CASE( "is_transparent over as_projection", "[utility][comparison][is_transparent]" ) +{ + using cmp1 = cppsort::utility::detail::as_comparison_fn>; + using cmp2 = cppsort::utility::detail::as_comparison_fn>; + + STATIC_CHECK_FALSE( cppsort::detail::has_is_transparent_v ); + STATIC_CHECK( cppsort::detail::has_is_transparent_v ); + + std::map mapping1 = { + {1, 1}, + {2, 2}, + {3, 3}, + }; + CHECK_THROWS( mapping1.find(is_transparent_helper_compared(2)) ); + + std::map mapping2 = { + {1, 1}, + {2, 2}, + {3, 3}, + }; + CHECK_NOTHROW( mapping2.find(is_transparent_helper_compared(2)) ); +} diff --git a/testsuite/utility/as_projection.cpp b/tests/utility/as_projection.cpp similarity index 98% rename from testsuite/utility/as_projection.cpp rename to tests/utility/as_projection.cpp index 1e7413c0..e788cf46 100644 --- a/testsuite/utility/as_projection.cpp +++ b/tests/utility/as_projection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/testsuite/utility/as_projection_iterable.cpp b/tests/utility/as_projection_iterable.cpp similarity index 97% rename from testsuite/utility/as_projection_iterable.cpp rename to tests/utility/as_projection_iterable.cpp index dccf6bae..6fcff56d 100644 --- a/testsuite/utility/as_projection_iterable.cpp +++ b/tests/utility/as_projection_iterable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -116,7 +116,7 @@ namespace } TEST_CASE( "sorter_facade with sorters overloaded for iterables and mixed comparison/projection", - "[sorter_facade][compare][projection][as_projection]" ) + "[sorter_facade][comparison][projection][as_projection]" ) { // Test the intersection between mixed comparison/projection functions, // as_projection, as_comparison and some additional sorter_facade diff --git a/tests/utility/branchless_traits.cpp b/tests/utility/branchless_traits.cpp new file mode 100644 index 00000000..576e2350 --- /dev/null +++ b/tests/utility/branchless_traits.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2017-2022 Morwenn + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include +#include +#include +#include + +TEST_CASE( "test that some specific comparisons are branchless", + "[utility][branchless][comparison]" ) +{ + using namespace cppsort::utility; + + SECTION( "standard library function objects" ) + { + STATIC_CHECK( is_probably_branchless_comparison_v, int> ); + STATIC_CHECK( is_probably_branchless_comparison_v, int> ); + STATIC_CHECK( is_probably_branchless_comparison_v, long double> ); +#ifdef __cpp_lib_ranges + STATIC_CHECK( is_probably_branchless_comparison_v ); + STATIC_CHECK( is_probably_branchless_comparison_v ); +#endif + + STATIC_CHECK( is_probably_branchless_comparison_v, int> ); + STATIC_CHECK( is_probably_branchless_comparison_v, int> ); + STATIC_CHECK( is_probably_branchless_comparison_v, long double> ); +#ifdef __cpp_lib_ranges + STATIC_CHECK( is_probably_branchless_comparison_v ); + STATIC_CHECK( is_probably_branchless_comparison_v ); +#endif + + STATIC_CHECK_FALSE( is_probably_branchless_comparison_v, std::string> ); + STATIC_CHECK_FALSE( is_probably_branchless_comparison_v, std::string> ); +#ifdef __cpp_lib_ranges + STATIC_CHECK_FALSE( is_probably_branchless_comparison_v ); +#endif + + STATIC_CHECK_FALSE( is_probably_branchless_comparison_v, std::string> ); + STATIC_CHECK_FALSE( is_probably_branchless_comparison_v, std::string> ); +#ifdef __cpp_lib_ranges + STATIC_CHECK_FALSE( is_probably_branchless_comparison_v ); +#endif + } + + SECTION( "partial/weak/less function objects" ) + { + using partial_t = decltype(cppsort::partial_less); + using weak_t = decltype(cppsort::weak_less); + using total_t = decltype(cppsort::total_less); + + STATIC_CHECK( is_probably_branchless_comparison_v ); + STATIC_CHECK( is_probably_branchless_comparison_v ); + STATIC_CHECK( is_probably_branchless_comparison_v ); + + STATIC_CHECK( is_probably_branchless_comparison_v ); + STATIC_CHECK_FALSE( is_probably_branchless_comparison_v ); + STATIC_CHECK_FALSE( is_probably_branchless_comparison_v ); + + STATIC_CHECK_FALSE( is_probably_branchless_comparison_v ); + STATIC_CHECK_FALSE( is_probably_branchless_comparison_v ); + STATIC_CHECK_FALSE( is_probably_branchless_comparison_v ); + } + + SECTION( "cv-qualified and reference-qualified types" ) + { + STATIC_CHECK( is_probably_branchless_comparison_v, const int> ); + STATIC_CHECK( is_probably_branchless_comparison_v&, int> ); + STATIC_CHECK( is_probably_branchless_comparison_v, int&&> ); +#ifdef __cpp_lib_ranges + STATIC_CHECK( is_probably_branchless_comparison_v ); +#endif + } +} + +TEST_CASE( "test that some specific projections are branchless", + "[utility][branchless][projection]" ) +{ + using namespace cppsort::utility; + + struct foobar + { + int foo; + int bar() { return 0; } + }; + + STATIC_CHECK( is_probably_branchless_projection_v ); +#if CPPSORT_STD_IDENTITY_AVAILABLE + STATIC_CHECK( is_probably_branchless_projection_v ); +#endif + + STATIC_CHECK( is_probably_branchless_projection_v ); + STATIC_CHECK_FALSE( is_probably_branchless_projection_v ); + +#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) + STATIC_CHECK( is_probably_branchless_projection_v ); +#endif + STATIC_CHECK_FALSE( is_probably_branchless_projection_v ); +} diff --git a/testsuite/utility/buffer.cpp b/tests/utility/buffer.cpp similarity index 94% rename from testsuite/utility/buffer.cpp rename to tests/utility/buffer.cpp index daddf1d9..678d761a 100644 --- a/testsuite/utility/buffer.cpp +++ b/tests/utility/buffer.cpp @@ -1,8 +1,8 @@ /* - * Copyright (c) 2015-2018 Morwenn + * Copyright (c) 2015-2022 Morwenn * SPDX-License-Identifier: MIT */ -#include +#include #include #include diff --git a/testsuite/utility/chainable_projections.cpp b/tests/utility/chainable_projections.cpp similarity index 94% rename from testsuite/utility/chainable_projections.cpp rename to tests/utility/chainable_projections.cpp index 70b64b66..86807ea0 100644 --- a/testsuite/utility/chainable_projections.cpp +++ b/tests/utility/chainable_projections.cpp @@ -1,12 +1,12 @@ /* - * Copyright (c) 2020 Morwenn + * Copyright (c) 2020-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include #include -#include +#include #include #include #include @@ -87,7 +87,7 @@ TEST_CASE( "Pipe a projection_base several times", CHECK( std::is_sorted(vec.begin(), vec.end()) ); cppsort::spin_sort(vec2, projection2 | projection1 | projection2); - CHECK( std::is_sorted(std::begin(vec2), std::end(vec2), std::greater<>{}) ); + CHECK( std::is_sorted(vec2.begin(), vec2.end(), std::greater<>{}) ); } TEST_CASE( "Pipe a projection with as_projection", diff --git a/testsuite/utility/iter_swap.cpp b/tests/utility/iter_swap.cpp similarity index 98% rename from testsuite/utility/iter_swap.cpp rename to tests/utility/iter_swap.cpp index 3f495531..6294d86b 100644 --- a/testsuite/utility/iter_swap.cpp +++ b/tests/utility/iter_swap.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2016-2018 Morwenn + * Copyright (c) 2016-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include -#include +#include #include namespace diff --git a/testsuite/utility/sorting_networks.cpp b/tests/utility/sorting_networks.cpp similarity index 96% rename from testsuite/utility/sorting_networks.cpp rename to tests/utility/sorting_networks.cpp index 200f3c0a..08c38cd7 100644 --- a/testsuite/utility/sorting_networks.cpp +++ b/tests/utility/sorting_networks.cpp @@ -1,12 +1,12 @@ /* - * Copyright (c) 2021 Morwenn + * Copyright (c) 2021-2022 Morwenn * SPDX-License-Identifier: MIT */ #include #include #include #include -#include +#include #include #include #include diff --git a/testsuite/adapters/hybrid_adapter_is_stable.cpp b/testsuite/adapters/hybrid_adapter_is_stable.cpp deleted file mode 100644 index be978811..00000000 --- a/testsuite/adapters/hybrid_adapter_is_stable.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2016-2021 Morwenn - * SPDX-License-Identifier: MIT - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -TEST_CASE( "hybrid_adapter stability checks", - "[hybrid_adapter][is_stable]" ) -{ - SECTION( "simple sorters" ) - { - using sorter = cppsort::hybrid_adapter< - cppsort::selection_sorter, - cppsort::rebind_iterator_category< - cppsort::merge_sorter, - std::bidirectional_iterator_tag - >, - cppsort::pdq_sorter - >; - - CHECK( not cppsort::is_stable&)>::value ); - CHECK( not cppsort::is_stable::iterator, - std::vector::iterator)>::value ); - - CHECK( cppsort::is_stable&)>::value ); - CHECK( cppsort::is_stable::iterator, - std::list::iterator)>::value ); - - CHECK( not cppsort::is_stable&)>::value ); - CHECK( not cppsort::is_stable::iterator, - std::forward_list::iterator)>::value ); - } - - SECTION( "nested hybrid_adapter" ) - { - using sorter = cppsort::hybrid_adapter< - cppsort::selection_sorter, - cppsort::hybrid_adapter< - cppsort::rebind_iterator_category< - cppsort::merge_sorter, - std::bidirectional_iterator_tag - > - >, - cppsort::pdq_sorter - >; - - CHECK( not cppsort::is_stable&)>::value ); - CHECK( not cppsort::is_stable::iterator, - std::vector::iterator)>::value ); - - CHECK( cppsort::is_stable&)>::value ); - CHECK( cppsort::is_stable::iterator, - std::list::iterator)>::value ); - - CHECK( not cppsort::is_stable&)>::value ); - CHECK( not cppsort::is_stable::iterator, - std::forward_list::iterator)>::value ); - } - - SECTION( "with small_array_adapter" ) - { - using sorter = cppsort::hybrid_adapter< - cppsort::small_array_adapter< - cppsort::sorting_network_sorter, - std::make_index_sequence<14u> - >, - cppsort::merge_sorter - >; - - CHECK( cppsort::is_stable&)>::value ); - CHECK( cppsort::is_stable::iterator, - std::vector::iterator)>::value ); - - CHECK( cppsort::is_stable&)>::value ); - CHECK( cppsort::is_stable::iterator, - std::list::iterator)>::value ); - - CHECK( cppsort::is_stable&)>::value ); - CHECK( cppsort::is_stable::iterator, - std::forward_list::iterator)>::value ); - - CHECK( not cppsort::is_stable&)>::value ); - CHECK( cppsort::is_stable::iterator, - std::array::iterator)>::value ); - - CHECK( cppsort::is_stable&)>::value ); - CHECK( cppsort::is_stable::iterator, - std::array::iterator)>::value ); - - CHECK( not cppsort::is_stable::value ); - CHECK( cppsort::is_stable::value ); - } -} diff --git a/testsuite/is_stable.cpp b/testsuite/is_stable.cpp deleted file mode 100644 index 8ac53e45..00000000 --- a/testsuite/is_stable.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2016-2021 Morwenn - * SPDX-License-Identifier: MIT - */ -#include -#include -#include -#include -#include -#include -#include -#include - -TEST_CASE( "test is_stable with raw sorters", - "[is_stable]" ) -{ - // Exhaustive test for every scenario where is_sorter is - // supposed to trivially fall back to is_always_stable - - using cppsort::is_stable; - using cppsort::utility::identity; - - SECTION( "merge_sorter" ) - { - using sorter = cppsort::merge_sorter; - - CHECK( is_stable&)>::value ); - CHECK( is_stable::iterator, std::vector::iterator)>::value ); - - CHECK( is_stable&, std::less<>)>::value ); - CHECK( is_stable::iterator, std::vector::iterator, - std::less<>)>::value ); - - CHECK( is_stable&, std::greater<>)>::value ); - CHECK( is_stable::iterator, std::vector::iterator, - std::greater<>)>::value ); - - CHECK( is_stable&, identity)>::value ); - CHECK( is_stable::iterator, std::vector::iterator, - identity)>::value ); - - CHECK( is_stable&, std::negate<>)>::value ); - CHECK( is_stable::iterator, std::vector::iterator, - std::negate<>)>::value ); - - CHECK( is_stable&, std::less<>, identity)>::value ); - CHECK( is_stable::iterator, std::vector::iterator, - std::less<>, identity)>::value ); - - CHECK( is_stable&, std::greater<>, identity)>::value ); - CHECK( is_stable::iterator, std::vector::iterator, - std::greater<>, identity)>::value ); - - CHECK( is_stable&, std::less<>, std::negate<>)>::value ); - CHECK( is_stable::iterator, std::vector::iterator, - std::less<>, std::negate<>)>::value ); - - CHECK( is_stable&, std::greater<>, std::negate<>)>::value ); - CHECK( is_stable::iterator, std::vector::iterator, - std::greater<>, std::negate<>)>::value ); - } - - SECTION( "quick_sorter" ) - { - using sorter = cppsort::quick_sorter; - - CHECK( not is_stable&)>::value ); - CHECK( not is_stable::iterator, std::vector::iterator)>::value ); - - CHECK( not is_stable&, std::less<>)>::value ); - CHECK( not is_stable::iterator, std::vector::iterator, - std::less<>)>::value ); - - CHECK( not is_stable&, std::greater<>)>::value ); - CHECK( not is_stable::iterator, std::vector::iterator, - std::greater<>)>::value ); - - CHECK( not is_stable&, identity)>::value ); - CHECK( not is_stable::iterator, std::vector::iterator, - identity)>::value ); - - CHECK( not is_stable&, std::negate<>)>::value ); - CHECK( not is_stable::iterator, std::vector::iterator, - std::negate<>)>::value ); - - CHECK( not is_stable&, std::less<>, identity)>::value ); - CHECK( not is_stable::iterator, std::vector::iterator, - std::less<>, identity)>::value ); - - CHECK( not is_stable&, std::greater<>, identity)>::value ); - CHECK( not is_stable::iterator, std::vector::iterator, - std::greater<>, identity)>::value ); - - CHECK( not is_stable&, std::less<>, std::negate<>)>::value ); - CHECK( not is_stable::iterator, std::vector::iterator, - std::less<>, std::negate<>)>::value ); - - CHECK( not is_stable&, std::greater<>, std::negate<>)>::value ); - CHECK( not is_stable::iterator, std::vector::iterator, - std::greater<>, std::negate<>)>::value ); - } - - SECTION( "low_comparisons_sorter" ) - { - // Many fixed-size sorters define is_always_stable through - // sorter_traits, which makes this test interesting - using sorter = cppsort::low_comparisons_sorter<8>; - CHECK( not is_stable::value ); - } -} diff --git a/testsuite/main.cpp b/testsuite/main.cpp deleted file mode 100644 index e5c805ba..00000000 --- a/testsuite/main.cpp +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright (c) 2015-2021 Morwenn - * SPDX-License-Identifier: MIT - */ -#define CATCH_CONFIG_MAIN -#include diff --git a/testsuite/sorters/default_sorter.cpp b/testsuite/sorters/default_sorter.cpp deleted file mode 100644 index f5ff723c..00000000 --- a/testsuite/sorters/default_sorter.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2015-2018 Morwenn - * SPDX-License-Identifier: MIT - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -TEST_CASE( "default sorter tests", "[default_sorter]" ) -{ - // Collection to sort - std::vector vec; vec.reserve(80); - auto distribution = dist::shuffled{}; - distribution(std::back_inserter(vec), 80, 0); - - SECTION( "sort with random-access iterable" ) - { - cppsort::sort(vec); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); - } - - SECTION( "sort with random-access iterable and compare" ) - { - cppsort::sort(vec, std::greater<>{}); - CHECK( std::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}) ); - } - - SECTION( "sort with random-access iterators" ) - { - cppsort::sort(std::begin(vec), std::end(vec)); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); - } - - SECTION( "sort with random-access iterators and compare" ) - { - cppsort::sort(std::begin(vec), std::end(vec), std::greater<>{}); - CHECK( std::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}) ); - } - - SECTION( "sort with bidirectional iterators" ) - { - std::list li(std::begin(vec), std::end(vec)); - cppsort::sort(std::begin(li), std::end(li)); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); - } - - SECTION( "sort with bidirectional iterators and compare" ) - { - std::list li(std::begin(vec), std::end(vec)); - cppsort::sort(std::begin(li), std::end(li), std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); - } - - SECTION( "sort with forward iterators" ) - { - std::forward_list li(std::begin(vec), std::end(vec)); - cppsort::sort(std::begin(li), std::end(li)); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); - } - - SECTION( "sort with forward iterators and compare" ) - { - std::forward_list li(std::begin(vec), std::end(vec)); - cppsort::sort(std::begin(li), std::end(li), std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); - } - - SECTION( "sort with self-sortable iterable" ) - { - std::list li(std::begin(vec), std::end(vec)); - cppsort::sort(li); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); - } - - SECTION( "sort with self-sortable iterable and compare" ) - { - std::forward_list li(std::begin(vec), std::end(vec)); - cppsort::sort(li, std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); - } -} diff --git a/testsuite/sorters/default_sorter_projection.cpp b/testsuite/sorters/default_sorter_projection.cpp deleted file mode 100644 index 1c61846a..00000000 --- a/testsuite/sorters/default_sorter_projection.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2015-2020 Morwenn - * SPDX-License-Identifier: MIT - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -TEST_CASE( "default sorter tests with projections", - "[default_sorter][projection]" ) -{ - // Wrapper to hide the integer - using wrapper = generic_wrapper; - - // Collection to sort - std::vector vec; - auto distribution = dist::shuffled{}; - distribution(std::back_inserter(vec), 80); - - SECTION( "sort with random-access iterable" ) - { - cppsort::sort(vec, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), std::less<>{}, &wrapper::value) ); - } - - SECTION( "sort with random-access iterable and compare" ) - { - cppsort::sort(vec, std::greater<>{}, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}, &wrapper::value) ); - } - - SECTION( "sort with random-access iterators" ) - { - cppsort::sort(std::begin(vec), std::end(vec), &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), std::less<>{}, &wrapper::value) ); - } - - SECTION( "sort with random-access iterators and compare" ) - { - cppsort::sort(std::begin(vec), std::end(vec), std::greater<>{}, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}, &wrapper::value) ); - } - - SECTION( "sort with bidirectional iterators" ) - { - std::list li(std::begin(vec), std::end(vec)); - cppsort::sort(std::begin(li), std::end(li), &wrapper::value); - CHECK( helpers::is_sorted(std::begin(li), std::end(li), std::less<>{}, &wrapper::value) ); - } - - SECTION( "sort with bidirectional iterators and compare" ) - { - std::list li(std::begin(vec), std::end(vec)); - cppsort::sort(std::begin(li), std::end(li), std::greater<>{}, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(li), std::end(li), std::greater<>{}, &wrapper::value) ); - } - - SECTION( "sort with forward iterators" ) - { - std::forward_list li(std::begin(vec), std::end(vec)); - cppsort::sort(std::begin(li), std::end(li), &wrapper::value); - CHECK( helpers::is_sorted(std::begin(li), std::end(li), std::less<>{}, &wrapper::value) ); - } - - SECTION( "sort with forward iterators and compare" ) - { - std::forward_list li(std::begin(vec), std::end(vec)); - cppsort::sort(std::begin(li), std::end(li), std::greater<>{}, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(li), std::end(li), std::greater<>{}, &wrapper::value) ); - } -} diff --git a/testsuite/sorters/merge_sorter.cpp b/testsuite/sorters/merge_sorter.cpp deleted file mode 100644 index 95bde873..00000000 --- a/testsuite/sorters/merge_sorter.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2015-2020 Morwenn - * SPDX-License-Identifier: MIT - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -TEST_CASE( "merge_sorter tests", "[merge_sorter]" ) -{ - // Collection to sort - std::vector vec; vec.reserve(80); - auto distribution = dist::shuffled{}; - distribution(std::back_inserter(vec), 80, 0); - - SECTION( "sort with random-access iterable" ) - { - cppsort::merge_sort(vec); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); - } - - SECTION( "sort with random-access iterable and compare" ) - { - cppsort::merge_sort(vec, std::greater<>{}); - CHECK( std::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}) ); - } - - SECTION( "sort with random-access iterators" ) - { - cppsort::merge_sort(std::begin(vec), std::end(vec)); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); - } - - SECTION( "sort with random-access iterators and compare" ) - { - cppsort::merge_sort(std::begin(vec), std::end(vec), std::greater<>{}); - CHECK( std::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}) ); - } - - SECTION( "sort with bidirectional iterators" ) - { - std::list li(std::begin(vec), std::end(vec)); - cppsort::merge_sort(std::begin(li), std::end(li)); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); - } - - SECTION( "sort with bidirectional iterators and compare" ) - { - std::list li(std::begin(vec), std::end(vec)); - cppsort::merge_sort(std::begin(li), std::end(li), std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); - } - - SECTION( "sort with forward iterators" ) - { - std::forward_list li(std::begin(vec), std::end(vec)); - cppsort::merge_sort(std::begin(li), std::end(li)); - CHECK( std::is_sorted(std::begin(li), std::end(li)) ); - } - - SECTION( "sort with forward iterators and compare" ) - { - std::forward_list li(std::begin(vec), std::end(vec)); - cppsort::merge_sort(std::begin(li), std::end(li), std::greater<>{}); - CHECK( std::is_sorted(std::begin(li), std::end(li), std::greater<>{}) ); - } -} diff --git a/testsuite/sorters/merge_sorter_projection.cpp b/testsuite/sorters/merge_sorter_projection.cpp deleted file mode 100644 index 9b914871..00000000 --- a/testsuite/sorters/merge_sorter_projection.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2015-2020 Morwenn - * SPDX-License-Identifier: MIT - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -TEST_CASE( "merge_sorter tests with projections", - "[merge_sorter][projection]" ) -{ - // Wrapper to hide the integer - using wrapper = generic_wrapper; - - // Collection to sort - std::vector vec; - auto distribution = dist::shuffled{}; - distribution(std::back_inserter(vec), 80); - - SECTION( "sort with random-access iterable" ) - { - cppsort::merge_sort(vec, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), std::less<>{}, &wrapper::value) ); - } - - SECTION( "sort with random-access iterable and compare" ) - { - cppsort::merge_sort(vec, std::greater<>{}, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}, &wrapper::value) ); - } - - SECTION( "sort with random-access iterators" ) - { - cppsort::merge_sort(std::begin(vec), std::end(vec), &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), std::less<>{}, &wrapper::value) ); - } - - SECTION( "sort with random-access iterators and compare" ) - { - cppsort::merge_sort(std::begin(vec), std::end(vec), std::greater<>{}, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(vec), std::end(vec), std::greater<>{}, &wrapper::value) ); - } - - SECTION( "sort with bidirectional iterators" ) - { - std::list li(std::begin(vec), std::end(vec)); - cppsort::merge_sort(std::begin(li), std::end(li), &wrapper::value); - CHECK( helpers::is_sorted(std::begin(li), std::end(li), std::less<>{}, &wrapper::value) ); - } - - SECTION( "sort with bidirectional iterators and compare" ) - { - std::list li(std::begin(vec), std::end(vec)); - cppsort::merge_sort(std::begin(li), std::end(li), std::greater<>{}, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(li), std::end(li), std::greater<>{}, &wrapper::value) ); - } - - SECTION( "sort with forward iterators" ) - { - std::forward_list li(std::begin(vec), std::end(vec)); - cppsort::merge_sort(std::begin(li), std::end(li), &wrapper::value); - CHECK( helpers::is_sorted(std::begin(li), std::end(li), std::less<>{}, &wrapper::value) ); - } - - SECTION( "sort with forward iterators and compare" ) - { - std::forward_list li(std::begin(vec), std::end(vec)); - cppsort::merge_sort(std::begin(li), std::end(li), std::greater<>{}, &wrapper::value); - CHECK( helpers::is_sorted(std::begin(li), std::end(li), std::greater<>{}, &wrapper::value) ); - } -} diff --git a/testsuite/sorters/spread_sorter_defaults.cpp b/testsuite/sorters/spread_sorter_defaults.cpp deleted file mode 100644 index b317b198..00000000 --- a/testsuite/sorters/spread_sorter_defaults.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2015-2021 Morwenn - * SPDX-License-Identifier: MIT - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -TEST_CASE( "spread_sorter generate overloads", - "[spread_sorter][sorter_facade]" ) -{ - // These tests use spread_sorter as a real-world Guinea pig - // to make sure that sorter_facade generates the expected - // operator() overloads for non-comparison sorters - - SECTION( "default operator() with std::less<>" ) - { - std::vector vec(100'000); - std::iota(std::begin(vec), std::end(vec), 0); - - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); - cppsort::spread_sort(vec, std::less<>{}); - CHECK( std::is_sorted(std::begin(vec), std::end(vec), std::less<>{}) ); - - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); - cppsort::spread_sort(std::begin(vec), std::end(vec), std::less<>{}); - CHECK( std::is_sorted(std::begin(vec), std::end(vec), std::less<>{}) ); - } - - SECTION( "default operator() with utility::identity" ) - { - std::vector vec(100'000); - std::iota(std::begin(vec), std::end(vec), 0); - - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); - cppsort::spread_sort(vec, cppsort::utility::identity{}); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); - - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); - cppsort::spread_sort(std::begin(vec), std::end(vec), cppsort::utility::identity{}); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); - } - - SECTION( "default operator() with both" ) - { - std::vector vec(100'000); - std::iota(std::begin(vec), std::end(vec), 0); - - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); - cppsort::spread_sort(vec, std::less<>{}, cppsort::utility::identity{}); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); - - std::shuffle(std::begin(vec), std::end(vec), hasard::engine()); - cppsort::spread_sort(std::begin(vec), std::end(vec), std::less<>{}, cppsort::utility::identity{}); - CHECK( std::is_sorted(std::begin(vec), std::end(vec)) ); - } -} diff --git a/testsuite/utility/branchless_traits.cpp b/testsuite/utility/branchless_traits.cpp deleted file mode 100644 index 00010ed3..00000000 --- a/testsuite/utility/branchless_traits.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2017-2021 Morwenn - * SPDX-License-Identifier: MIT - */ -#include -#include -#include -#include -#include -#include -#include -#include - -TEST_CASE( "test that some specific comparisons are branchless", - "[utility][branchless][comparison]" ) -{ - using namespace cppsort::utility; - - SECTION( "standard library function objects" ) - { - CHECK( is_probably_branchless_comparison_v, int> ); - CHECK( is_probably_branchless_comparison_v, int> ); - CHECK( is_probably_branchless_comparison_v, long double> ); -#ifdef __cpp_lib_ranges - CHECK( is_probably_branchless_comparison_v ); - CHECK( is_probably_branchless_comparison_v ); -#endif - - CHECK( is_probably_branchless_comparison_v, int> ); - CHECK( is_probably_branchless_comparison_v, int> ); - CHECK( is_probably_branchless_comparison_v, long double> ); -#ifdef __cpp_lib_ranges - CHECK( is_probably_branchless_comparison_v ); - CHECK( is_probably_branchless_comparison_v ); -#endif - - CHECK_FALSE( is_probably_branchless_comparison_v, std::string> ); - CHECK_FALSE( is_probably_branchless_comparison_v, std::string> ); -#ifdef __cpp_lib_ranges - CHECK_FALSE( is_probably_branchless_comparison_v ); -#endif - - CHECK_FALSE( is_probably_branchless_comparison_v, std::string> ); - CHECK_FALSE( is_probably_branchless_comparison_v, std::string> ); -#ifdef __cpp_lib_ranges - CHECK_FALSE( is_probably_branchless_comparison_v ); -#endif - } - - SECTION( "partial/weak/less function objects" ) - { - using partial_t = decltype(cppsort::partial_less); - using weak_t = decltype(cppsort::weak_less); - using total_t = decltype(cppsort::total_less); - - CHECK( is_probably_branchless_comparison_v ); - CHECK( is_probably_branchless_comparison_v ); - CHECK( is_probably_branchless_comparison_v ); - - CHECK( is_probably_branchless_comparison_v ); - CHECK_FALSE( is_probably_branchless_comparison_v ); - CHECK_FALSE( is_probably_branchless_comparison_v ); - - CHECK_FALSE( is_probably_branchless_comparison_v ); - CHECK_FALSE( is_probably_branchless_comparison_v ); - CHECK_FALSE( is_probably_branchless_comparison_v ); - } - - SECTION( "cv-qualified and reference-qualified types" ) - { - CHECK( is_probably_branchless_comparison_v, const int> ); - CHECK( is_probably_branchless_comparison_v&, int> ); - CHECK( is_probably_branchless_comparison_v, int&&> ); -#ifdef __cpp_lib_ranges - CHECK( is_probably_branchless_comparison_v ); -#endif - } -} - -TEST_CASE( "test that some specific projections are branchless", - "[utility][branchless][projection]" ) -{ - using namespace cppsort::utility; - - struct foobar - { - int foo; - int bar() { return 0; } - }; - - CHECK( is_probably_branchless_projection_v ); -#if CPPSORT_STD_IDENTITY_AVAILABLE - CHECK( is_probably_branchless_projection_v ); -#endif - - CHECK( is_probably_branchless_projection_v ); - CHECK_FALSE( is_probably_branchless_projection_v ); - -#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) - CHECK( is_probably_branchless_projection_v ); -#endif - CHECK_FALSE( is_probably_branchless_projection_v ); -} diff --git a/tools/generate.py b/tools/generate.py index d8e8965e..1f59b0c1 100644 --- a/tools/generate.py +++ b/tools/generate.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2015-2020 Morwenn +# Copyright (c) 2015-2022 Morwenn # SPDX-License-Identifier: MIT import sys def transform(line): - line = line.strip('[],\nSWAP();') + line = line.strip('[],\nSWAP();{}') if line: x, y = map(int, line.split(',')) return 'iter_swap_if(first + {0}u, first + {1}u, compare, projection);'.format(x, y) diff --git a/tools/test_failing_sorter.cpp b/tools/test_failing_sorter.cpp index 24b16010..9c179450 100644 --- a/tools/test_failing_sorter.cpp +++ b/tools/test_failing_sorter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 Morwenn + * Copyright (c) 2019-2022 Morwenn * SPDX-License-Identifier: MIT */ #include @@ -19,8 +19,8 @@ #include #include #include "../benchmarks/benchmarking-tools/distributions.h" -#include "../testsuite/testing-tools/algorithm.h" -#include "../testsuite/testing-tools/wrapper.h" +#include "../tests/testing-tools/algorithm.h" +#include "../tests/testing-tools/wrapper.h" template void test(const char* name)