Skip to content

Commit

Permalink
Add experimental support for libassert
Browse files Browse the repository at this point in the history
  • Loading branch information
Morwenn committed Dec 19, 2023
1 parent 88576c0 commit 2d3dcc1
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 17 deletions.
25 changes: 22 additions & 3 deletions CMakeLists.txt
@@ -1,4 +1,4 @@
# Copyright (c) 2015-2022 Morwenn
# Copyright (c) 2015-2023 Morwenn
# SPDX-License-Identifier: MIT

cmake_minimum_required(VERSION 3.14.5)
Expand All @@ -13,19 +13,38 @@ include(GNUInstallDirs)
# Project options
option(CPPSORT_BUILD_TESTING "Build the cpp-sort test suite" ON)
option(CPPSORT_BUILD_EXAMPLES "Build the cpp-sort examples" OFF)
option(CPPSORT_USE_LIBASSERT "Use libassert for assertions (experimental)" OFF)

# Optionally use libassert for assertions
if (CPPSORT_USE_LIBASSERT)
include(FetchContent)
FetchContent_Declare(
assert
GIT_REPOSITORY https://github.com/jeremy-rifkin/libassert
GIT_TAG v1.2.2
FIND_PACKAGE_ARGS 1.2
)
FetchContent_MakeAvailable(assert)
endif()

# Create cpp-sort library and configure it
add_library(cpp-sort INTERFACE)
target_include_directories(cpp-sort INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)

target_compile_features(cpp-sort INTERFACE cxx_std_20)

# MSVC won't work without a stricter standard compliance
if (MSVC)
target_compile_options(cpp-sort INTERFACE /permissive-)
target_compile_options(cpp-sort INTERFACE /permissive- /Zc:preprocessor)
endif()

# Optionally link to libassert
if (CPPSORT_USE_LIBASSERT)
target_link_libraries(cpp-sort INTERFACE assert)
target_compile_definitions(cpp-sort INTERFACE CPPSORT_USE_LIBASSERT)
endif()

add_library(cpp-sort::cpp-sort ALIAS cpp-sort)
Expand Down
9 changes: 9 additions & 0 deletions docs/Home.md
Expand Up @@ -70,6 +70,14 @@ Some algorithms have assertions to guard against accidental logic issues (mostly

A similar `CPPSORT_ENABLE_AUDITS` macro can be defined to enable audits: those are expensive assertions which are not enabled by `CPPSORT_ENABLE_ASSERTIONS` because they are too expensive, to the point that they might even change the complexity of some algorithms. When turning on audits, internal calls to `__assume` or equivalent statements will also be turned into assertions to provided additional checks.

#### Rich assertions with libassert (experimental)

When defined, the macro `CPPSORT_USE_LIBASSERT` makes internal assertions use [libassert][libassert] instead of the standard `assert` macro. This allows assertions to provide additional information when an assertion fires, notably by displaying a full stack trace, and optionally to decompose the asserted expressions. See the library's README for more information.

This option can be enabled from CMake by setting the `CPPSORT_USE_LIBASSERT` to `ON`. See [the Tooling page][tooling-cmake] for more information.

*Note: the support for libassert is still experimental and has not been tested on all supported platforms. Errors are to be expected.*

## 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.
Expand All @@ -82,6 +90,7 @@ Hope you have fun!


[benchmarks]: Benchmarks.md
[libassert]: https://github.com/jeremy-rifkin/libassert
[original-research]: Original-research.md
[quickstart]: Quickstart.md
[swappable]: https://en.cppreference.com/w/cpp/concepts/swappable
4 changes: 3 additions & 1 deletion docs/Tooling.md
Expand Up @@ -24,11 +24,12 @@ target_link_libraries(my-target PRIVATE cpp-sort::cpp-sort)

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_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` flags of compilers that supports them, default to empty string.
* `CPPSORT_STATIC_TESTS`: when `ON`, some tests are executed at compile time instead of runtime, defaults to `OFF`.
* `CPPSORT_USE_LIBASSERT` (experimental): when `ON`, internal assertions use [libassert][libassert] instead of the standard `assert` macro, providing additional information about the errors. Defaults to `OFF`.

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.

Expand Down Expand Up @@ -68,3 +69,4 @@ Due to slight markup differences, some pages might not fully render correctly bu
[conan]: https://conan.io/
[conan-center]: https://conan.io/center/cpp-sort
[gollum]: https://github.com/gollum/gollum
[libassert]: https://github.com/jeremy-rifkin/libassert
33 changes: 23 additions & 10 deletions include/cpp-sort/detail/config.h
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 Morwenn
* Copyright (c) 2016-2023 Morwenn
* SPDX-License-Identifier: MIT
*/
#ifndef CPPSORT_DETAIL_CONFIG_H_
Expand All @@ -10,6 +10,9 @@

#if defined(CPPSORT_ENABLE_ASSERTIONS) || defined(CPPSORT_ENABLE_AUDITS)
# include <cassert>
# if defined(CPPSORT_USE_LIBASSERT)
# include <assert.hpp>
# endif
#endif

////////////////////////////////////////////////////////////
Expand All @@ -19,12 +22,22 @@
// than just relying on NDEBUG, so assertions have to be
// explicitly enabled in cpp-sort

#ifndef CPPSORT_ASSERT
# ifdef CPPSORT_ENABLE_ASSERTIONS
# define CPPSORT_ASSERT(...) assert((__VA_ARGS__))
# else
# define CPPSORT_ASSERT(...)
#if !defined(NDEBUG) && defined(CPPSORT_ENABLE_ASSERTIONS)
# if !defined(CPPSORT_ASSERT)
# if defined(CPPSORT_USE_LIBASSERT)
# define CPPSORT_ASSERT(...) ASSERT(__VA_ARGS__)
# else
# define CPPSORT_ARG2(_0, _1, _2, ...) _2
# define CPPSORT_NARG2(...) CPPSORT_ARG2(__VA_ARGS__, 2, 1, 0)
# define CPPSORT_ONE_OR_TWO_ARGS_1(condition) assert(condition)
# define CPPSORT_ONE_OR_TWO_ARGS_2(condition, message) assert(condition && message)
# define CPPSORT_ONE_OR_TWO_ARGS_N(N, ...) CPPSORT_ONE_OR_TWO_ARGS_##N(__VA_ARGS__)
# define CPPSORT_ONE_OR_TWO_ARGS(N, ...) CPPSORT_ONE_OR_TWO_ARGS_N(N, __VA_ARGS__)
# define CPPSORT_ASSERT(...) CPPSORT_ONE_OR_TWO_ARGS(CPPSORT_NARG2(__VA_ARGS__), __VA_ARGS__)
# endif
# endif
#else
# define CPPSORT_ASSERT(...) ((void)0)
#endif

////////////////////////////////////////////////////////////
Expand All @@ -38,7 +51,7 @@
# ifdef CPPSORT_ENABLE_AUDITS
# define CPPSORT_AUDIT(...) assert((__VA_ARGS__))
# else
# define CPPSORT_AUDIT(...)
# define CPPSORT_AUDIT(...) ((void)0)
# endif
#endif

Expand All @@ -60,7 +73,7 @@
#elif defined(_MSC_VER)
# define CPPSORT_ASSUME(expression) __assume(expression)
#else
# define CPPSORT_ASSUME(cond)
# define CPPSORT_ASSUME(cond) ((void)0)
#endif

////////////////////////////////////////////////////////////
Expand All @@ -71,13 +84,13 @@
// reached

#if defined(CPPSORT_ENABLE_AUDITS)
# define CPPSORT_UNREACHABLE CPPSORT_ASSERT("unreachable", false);
# define CPPSORT_UNREACHABLE CPPSORT_ASSERT(false, "unreachable");
#elif defined(__GNUC__) || defined(__clang__)
# define CPPSORT_UNREACHABLE __builtin_unreachable()
#elif defined(_MSC_VER)
# define CPPSORT_UNREACHABLE __assume(false)
#else
# define CPPSORT_UNREACHABLE
# define CPPSORT_UNREACHABLE ((void)0)
#endif

////////////////////////////////////////////////////////////
Expand Down
6 changes: 3 additions & 3 deletions include/cpp-sort/detail/timsort.h
Expand Up @@ -6,7 +6,7 @@
* - 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) <gfuji@cpan.org>.
* Copyright (c) 2015-2022 Morwenn.
* Copyright (c) 2015-2023 Morwenn.
* Copyright (c) 2021 Igor Kushnir <igorkuo@gmail.com>.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
Expand Down Expand Up @@ -560,7 +560,7 @@ namespace cppsort::detail
dest[len2] = mstd::iter_move(cursor1);
}
else {
CPPSORT_ASSERT(len1 != 0 && "comparison function violates its general contract");
CPPSORT_ASSERT(len1 != 0, "comparison function violates its general contract");
CPPSORT_ASSERT(len2 == 0);
CPPSORT_ASSERT(len1 > 1);
detail::move(cursor1, cursor1 + len1, dest);
Expand Down Expand Up @@ -709,7 +709,7 @@ namespace cppsort::detail
detail::move_backward(cursor1 - len1, cursor1, dest + (1 + len1));
*dest = mstd::iter_move(cursor2);
} else {
CPPSORT_ASSERT(len2 != 0 && "comparison function violates its general contract");
CPPSORT_ASSERT(len2 != 0, "comparison function violates its general contract");
CPPSORT_ASSERT(len1 == 0);
CPPSORT_ASSERT(len2 > 1);
detail::move(buffer.get(), buffer.get() + len2, dest - (len2 - 1));
Expand Down

0 comments on commit 2d3dcc1

Please sign in to comment.