2#ifndef LIBSBX_UTILITY_ASSERT_HPP_
3#define LIBSBX_UTILITY_ASSERT_HPP_
7#include <source_location>
12#include <fmt/format.h>
14#include <libsbx/utility/target.hpp>
16namespace sbx::utility {
18template<std::convertible_to<
bool> Expression>
19inline auto assert_that(Expression&& expression, std::string_view message,
const std::source_location& source_location = std::source_location::current()) ->
void {
20 if constexpr (is_build_configuration_debug_v) {
21 if (!
static_cast<bool>(std::forward<Expression>(expression))) {
22 const auto error = fmt::format(
"Assertion '{}' at {}:{} in '{}' failed. Terminating.\n", message, source_location.file_name(), source_location.line(), source_location.function_name());
24 std::cerr.write(error.data(),
static_cast<std::streamsize
>(error.size()));
32template<std::ranges::range Range,
typename Project>
33requires (std::is_invocable_r_v<bool, Project, std::ranges::range_const_reference_t<Range>>)
34inline auto assert_that(Range&& range, Project&& project, std::string_view message,
const std::source_location& source_location = std::source_location::current()) ->
void {
35 if constexpr (is_build_configuration_debug_v) {
36 for (
const auto& [index, value] : std::views::enumerate(range)) {
37 if (!
static_cast<bool>(std::invoke(project, value))) {
38 const auto error = fmt::format(
"Assertion '{}' at {}:{} in '{}' failed at index {}. Terminating.\n", message, source_location.file_name(), source_location.line(), source_location.function_name(), index);
40 std::cerr.write(error.data(),
static_cast<std::streamsize
>(error.size()));
50template<std::convertible_to<
bool> Expression>
51inline auto expect_that(Expression&& expression, std::string_view message,
const std::source_location& source_location = std::source_location::current()) ->
void {
52 if constexpr (is_build_configuration_debug_v) {
53 if (!
static_cast<bool>(expression)) {
54 const auto warning = fmt::format(
"Expectation '{}' at {}:{} in '{}' failed.\n", message, source_location.file_name(), source_location.line(), source_location.function_name());
56 std::cerr.write(warning.data(),
static_cast<std::streamsize
>(warning.size()));
62template<std::ranges::range Range,
typename Project>
63requires (std::is_invocable_r_v<bool, Project, std::ranges::range_const_reference_t<Range>>)
64inline auto expect_that(Range&& range, Project&& project, std::string_view message,
const std::source_location& source_location = std::source_location::current()) ->
void {
65 if constexpr (is_build_configuration_debug_v) {
66 for (
const auto& [index, value] : std::views::enumerate(range)) {
67 if (!
static_cast<bool>(std::invoke(project, value))) {
68 const auto error = fmt::format(
"Expectation '{}' at {}:{} in '{}' failed at index {}.\n", message, source_location.file_name(), source_location.line(), source_location.function_name(), index);
70 std::cerr.write(error.data(),
static_cast<std::streamsize
>(error.size()));