Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .forgejo/workflows/do-nothing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (c) 2026 Morwenn
# SPDX-License-Identifier: MIT

# Codeberg seems to run the repository's GitHub actions when
# there is no Forgejo workflow: the goa of this file is to
# skip that callback
name: Do Nothing

on:
workflow_dispatch:
2 changes: 1 addition & 1 deletion .github/workflows/build-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
sanitize: address,undefined

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- name: Configure CMake
working-directory: ${{runner.workspace}}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build-mingw.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2021-2025 Morwenn
# Copyright (c) 2021-2026 Morwenn
# SPDX-License-Identifier: MIT

name: MinGW-w64 Builds
Expand Down Expand Up @@ -31,7 +31,7 @@ jobs:
build_type: [Debug, Release]

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- name: Configure CMake
shell: pwsh
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/build-msvc.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2021-2025 Morwenn
# Copyright (c) 2021-2026 Morwenn
# SPDX-License-Identifier: MIT

name: MSVC Builds
Expand Down Expand Up @@ -36,15 +36,14 @@ jobs:
build_tools: '-T ClangCL'

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- name: Configure CMake
shell: pwsh
working-directory: ${{runner.workspace}}
run: |
cmake -H${{github.event.repository.name}} -Bbuild `
-DCMAKE_CONFIGURATION_TYPES=${{matrix.config.build_type}} `
-DCMAKE_BUILD_TYPE=${{matrix.config.build_type}} `
-G"Visual Studio 17 2022" -A x64 ${{matrix.config.build_tools}} `
-DCPPSORT_BUILD_EXAMPLES=ON

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build-ubuntu.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2021-2025 Morwenn
# Copyright (c) 2021-2026 Morwenn
# SPDX-License-Identifier: MIT

name: Ubuntu Builds
Expand Down Expand Up @@ -41,7 +41,7 @@ jobs:
sanitize: address,undefined

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- name: Install GCC
if: ${{matrix.cxx == 'g++-9'}}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/code-coverage.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2020-2025 Morwenn
# Copyright (c) 2020-2026 Morwenn
# SPDX-License-Identifier: MIT

name: Coverage Upload to Codecov
Expand All @@ -23,7 +23,7 @@ jobs:

steps:
- name: Checkout project
uses: actions/checkout@v4
uses: actions/checkout@v7

- name: Install LCOV
run: sudo apt-get install -y lcov
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/mirror-to-codeberg.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2025 Morwenn
# Copyright (c) 2025-2026 Morwenn
# SPDX-License-Identifier: MIT

name: Mirror Commits to Codeberg
Expand All @@ -13,7 +13,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v7
with:
fetch-depth: 0

Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.17.2 LANGUAGES CXX)
project(cpp-sort VERSION 1.17.3 LANGUAGES CXX)

include(CMakePackageConfigHelpers)
include(cpp-sort-utils)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
![cpp-sort logo](docs/images/cpp-sort-logo.svg)

[![Latest Release](https://img.shields.io/badge/release-1.17.2-blue.svg)](https://github.com/Morwenn/cpp-sort/releases/tag/1.17.2)
[![Conan Package](https://img.shields.io/badge/conan-cpp--sort%2F1.17.2-blue.svg)](https://conan.io/center/recipes/cpp-sort?version=1.17.2)
[![Latest Release](https://img.shields.io/badge/release-1.17.3-blue.svg)](https://github.com/Morwenn/cpp-sort/releases/tag/1.17.3)
[![Conan Package](https://img.shields.io/badge/conan-cpp--sort%2F1.17.3-blue.svg)](https://conan.io/center/recipes/cpp-sort?version=1.17.3)
[![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)

Expand Down
2 changes: 1 addition & 1 deletion conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

class CppSortConan(ConanFile):
name = "cpp-sort"
version = "1.17.2"
version = "1.17.3"
description = "Sorting algorithms & related tools"
license = "MIT"
url = "https://github.com/Morwenn/cpp-sort"
Expand Down
7 changes: 7 additions & 0 deletions docs/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ When compiled with C++17, **cpp-sort** might gain a few additional features depe

When compiled with C++20, **cpp-sort** might gain a few additional features depending on the level of C++20 support provided by the compiler. The availability of those features depends on the presence of corresponding [feature-testing macros][feature-test-macros] when possible, even though some checks are more granular. Don't hesitate to open an issue if your compiler and standard library supports one of those features but it doesn't seem to work in **cpp-sort**.

**Correctness improvements:**
* When possible, the total order predicates [`total_less` and `total_greater`][total-greater-less] use [`std::strong_order`][std-strong-order] to compare floating-point numbers, leading to a supposedly correct implementation of the IEEE *totalOrder* operator. In C++17 and earlier, those comparators don't actually implement a proper total order: they are unable to differentiate between quiet and signaling NaNs, and connot read NaN payloads.

The feature-test macro `__cpp_lib_three_way_comparison` can be used to check whether `std::strong_order` is available.

**New features:**
* When available, [`std::identity`][std-identity] benefits from dedicated support wherever [`utility::identity`][cpp-sort-function-objects] is supported, with equivalent semantics.

Expand Down Expand Up @@ -110,5 +115,7 @@ 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
[std-strong-order]: https://en.cppreference.com/w/cpp/utility/compare/strong_order
[std-swap]: https://en.cppreference.com/w/cpp/algorithm/swap
[total-greater-less]: Comparators.md#total-order-comparators
[utility-iter-move]: Miscellaneous-utilities.md#iter_move-and-iter_swap
8 changes: 6 additions & 2 deletions docs/Comparators.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Every non-refined comparator described below is also a [transparent comparator][
#include <cpp-sort/comparators/total_less.h>
```

The comparators `total_less` and `total_order` are [customization points][custom-point] implementing a [total order][total-order], inspired by the similar functions described in [P0100][P0100]. The provided functions handle built-in integer out of the box (using the built-in relational operators) and implement IEEE 754's `totalOrder` for floating point numbers (from lesser to greater):
The comparators `total_less` and `total_order` are [customization points][custom-point] implementing a [total order][total-order], inspired by the similar functions described in [P0100][P0100]. The provided functions handle built-in integer types out of the box (using the built-in relational operators) and attempt to implement IEEE 754's `totalOrder` for floating point numbers (from lesser to greater):
* positive quiet NaNs
* positive signaling NaNs
* positive infinity
Expand All @@ -23,14 +23,18 @@ The comparators `total_less` and `total_order` are [customization points][custom
* negative signaling NaNs
* negative quiet NaNs

That said, the comparators are currently unable to discriminate between quiet and signaling NaNs, so they are considered to be *equivalent*. When it doesn't handle a type natively and ADL doesn't find any suitable `total_less` function in a class namespace, `cppsort::total_less` does *not* fall back to `operator<`; see [P0100][P0100] for the rationale (it applies to the whole `total_*` family of customization points).
That said, the comparators are unable to discriminate between quiet and signaling NaNs, and have no way to inspect the bit patterns of NaNs to compare them. All NaNs that share a same sign are therefore considered to be *equivalent* in C++17. In C++20 however, the comparators rely on [`std::strong_order`][std-strong-order] when available, which correctly implements `totalOrder` for IEEE 754 floating point numbers.

When it doesn't handle a type natively and ADL doesn't find any suitable `total_less` function in a class namespace, `cppsort::total_less` does *not* fall back to `operator<`; see [P0100][P0100] for the rationale (it applies to the whole `total_*` family of customization points).

Total order comparators are considered as [generating branchless code][branchless-traits] when comparing instances of a type that satisfies [`std::is_integral`][std-is-integral].

*Changed in version 1.5.0:* `total_greater` and `total_less` are respectively of type `total_greater_t` and `total_less_t`.

*Changed in version 1.13.1:* support for `[un]signed __int128`.

*Changed in version 1.17.3:* `total_less` and `total_greater` now correctly implement IEEE 754 `totalOrder` in C++20 mode, when the feature-test macro `__cpp_lib_three_way_comparison` is defined.

### Weak order comparators

```cpp
Expand Down
2 changes: 1 addition & 1 deletion docs/Fixed-size-sorters.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,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 | 99 | 106 | 114 | 120 | 130 | 139 | 147 | 155 | 164 | 172 | 180 | 185
**CEs** | 71 | 77 | 85 | 91 | 99 | 106 | 114 | 120 | 130 | 138 | 147 | 155 | 164 | 172 | 180 | 185
**Size** | **33** | **34** | **35** | **36** | **37** | **38** | **39** | **40** | **41** | **42** | **43** | **44** | **45** | **46** | **47** | **48**
**CEs** | 199 | 209 | 220 | 227 | 240 | 250 | 259 | 265 | 282 | 291 | 303 | 309 | 324 | 332 | 340 | 346
**Size** | **49** | **50** | **51** | **52** | **53** | **54** | **55** | **56** | **57** | **58** | **59** | **60** | **61** | **62** | **63** | **64**
Expand Down
2 changes: 1 addition & 1 deletion docs/Home.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
![cpp-sort logo](images/cpp-sort-logo.svg)

Welcome to the **cpp-sort 1.17.2** documentation!
Welcome to the **cpp-sort 1.17.3** documentation!

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, as well as a few tutorials about writing 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.

Expand Down
4 changes: 2 additions & 2 deletions docs/Tooling.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ Note: when `CPPSORT_ENABLE_AUDITS` is `ON`, assertions in the library are enable
conan search cpp-sort --remote=conancenter
```

And then install any version to your local cache as follows (here with version 1.17.2):
And then install any version to your local cache as follows (here with version 1.17.3):

```sh
conan install --requires=cpp-sort/1.17.2
conan install --requires=cpp-sort/1.17.3
```

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 create your own package with the `conanfile.py` available in this repository.
Expand Down
9 changes: 6 additions & 3 deletions include/cpp-sort/comparators/partial_greater.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2021 Morwenn
* Copyright (c) 2016-2026 Morwenn
* SPDX-License-Identifier: MIT
*/
#ifndef CPPSORT_COMPARATORS_PARTIAL_GREATER_H_
Expand Down Expand Up @@ -33,9 +33,12 @@ namespace cppsort
// Generic overload: a weak order is also a partial order

template<typename T>
auto partial_greater(const T& lhs, const T& rhs)
constexpr auto partial_greater(const T& lhs, const T& rhs)
noexcept(noexcept(cppsort::weak_greater(lhs, rhs)))
-> decltype(cppsort::weak_greater(lhs, rhs))
-> detail::enable_if_t<
not std::is_floating_point<T>::value,
decltype(cppsort::weak_greater(lhs, rhs))
>
{
return cppsort::weak_greater(lhs, rhs);
}
Expand Down
9 changes: 6 additions & 3 deletions include/cpp-sort/comparators/partial_less.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2021 Morwenn
* Copyright (c) 2016-2026 Morwenn
* SPDX-License-Identifier: MIT
*/
#ifndef CPPSORT_COMPARATORS_PARTIAL_LESS_H_
Expand Down Expand Up @@ -33,9 +33,12 @@ namespace cppsort
// Generic overload: a weak order is also a partial order

template<typename T>
auto partial_less(const T& lhs, const T& rhs)
constexpr auto partial_less(const T& lhs, const T& rhs)
noexcept(noexcept(cppsort::weak_less(lhs, rhs)))
-> decltype(cppsort::weak_less(lhs, rhs))
-> detail::enable_if_t<
not std::is_floating_point<T>::value,
decltype(cppsort::weak_less(lhs, rhs))
>
{
return cppsort::weak_less(lhs, rhs);
}
Expand Down
17 changes: 14 additions & 3 deletions include/cpp-sort/comparators/total_greater.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 Morwenn
* Copyright (c) 2016-2026 Morwenn
* SPDX-License-Identifier: MIT
*/
#ifndef CPPSORT_COMPARATORS_TOTAL_GREATER_H_
Expand All @@ -8,14 +8,19 @@
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <cmath>
#include <type_traits>
#include <utility>
#include <cpp-sort/utility/branchless_traits.h>
#include <cpp-sort/utility/static_const.h>
#include "../detail/floating_point_weight.h"
#include "../detail/type_traits.h"

#if defined(__cpp_lib_three_way_comparison)
# include <compare>
#else
# include <cmath>
# include "../detail/floating_point_weight.h"
#endif

namespace cppsort
{
namespace detail
Expand All @@ -37,6 +42,11 @@ namespace cppsort
auto total_greater(T lhs, T rhs)
-> detail::enable_if_t<std::is_floating_point<T>::value, bool>
{
#if defined(__cpp_lib_three_way_comparison)
// Full implementation of totalOrder
return std::is_gt(std::strong_order(lhs, rhs));
#else
// Approximation, unable to differentiate NaNs
if (std::isfinite(lhs) && std::isfinite(rhs)) {
if (lhs == 0 && rhs == 0) {
return std::signbit(rhs) && not std::signbit(lhs);
Expand All @@ -47,6 +57,7 @@ namespace cppsort
int lhs_weight = total_weight(lhs);
int rhs_weight = total_weight(rhs);
return lhs_weight > rhs_weight;
#endif
}

////////////////////////////////////////////////////////////
Expand Down
18 changes: 15 additions & 3 deletions include/cpp-sort/comparators/total_less.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 Morwenn
* Copyright (c) 2016-2026 Morwenn
* SPDX-License-Identifier: MIT
*/
#ifndef CPPSORT_COMPARATORS_TOTAL_LESS_H_
Expand All @@ -8,14 +8,20 @@
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <cmath>
#include <type_traits>
#include <utility>
#include <version>
#include <cpp-sort/utility/branchless_traits.h>
#include <cpp-sort/utility/static_const.h>
#include "../detail/floating_point_weight.h"
#include "../detail/type_traits.h"

#if defined(__cpp_lib_three_way_comparison)
# include <compare>
#else
# include <cmath>
# include "../detail/floating_point_weight.h"
#endif

namespace cppsort
{
namespace detail
Expand All @@ -37,6 +43,11 @@ namespace cppsort
auto total_less(T lhs, T rhs)
-> detail::enable_if_t<std::is_floating_point<T>::value, bool>
{
#if defined(__cpp_lib_three_way_comparison)
// Full implementation of totalOrder
return std::is_lt(std::strong_order(lhs, rhs));
#else
// Approximation, unable to differentiate NaNs
if (std::isfinite(lhs) && std::isfinite(rhs)) {
if (lhs == 0 && rhs == 0) {
return std::signbit(lhs) && not std::signbit(rhs);
Expand All @@ -47,6 +58,7 @@ namespace cppsort
int lhs_weight = total_weight(lhs);
int rhs_weight = total_weight(rhs);
return lhs_weight < rhs_weight;
#endif
}

////////////////////////////////////////////////////////////
Expand Down
9 changes: 6 additions & 3 deletions include/cpp-sort/comparators/weak_greater.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2021 Morwenn
* Copyright (c) 2016-2026 Morwenn
* SPDX-License-Identifier: MIT
*/
#ifndef CPPSORT_COMPARATORS_WEAK_GREATER_H_
Expand Down Expand Up @@ -41,9 +41,12 @@ namespace cppsort
// Generic overload: a total order is also a weak order

template<typename T>
auto weak_greater(const T& lhs, const T& rhs)
constexpr auto weak_greater(const T& lhs, const T& rhs)
noexcept(noexcept(cppsort::total_greater(lhs, rhs)))
-> decltype(cppsort::total_greater(lhs, rhs))
-> detail::enable_if_t<
not std::is_floating_point<T>::value,
decltype(cppsort::total_greater(lhs, rhs))
>
{
return cppsort::total_greater(lhs, rhs);
}
Expand Down
9 changes: 6 additions & 3 deletions include/cpp-sort/comparators/weak_less.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2021 Morwenn
* Copyright (c) 2016-2026 Morwenn
* SPDX-License-Identifier: MIT
*/
#ifndef CPPSORT_COMPARATORS_WEAK_LESS_H_
Expand Down Expand Up @@ -41,9 +41,12 @@ namespace cppsort
// Generic overload: a total order is also a weak order

template<typename T>
auto weak_less(const T& lhs, const T& rhs)
constexpr auto weak_less(const T& lhs, const T& rhs)
noexcept(noexcept(cppsort::total_less(lhs, rhs)))
-> decltype(cppsort::total_less(lhs, rhs))
-> detail::enable_if_t<
not std::is_floating_point<T>::value,
decltype(cppsort::total_less(lhs, rhs))
>
{
return cppsort::total_less(lhs, rhs);
}
Expand Down
Loading
Loading