126 lines
4.6 KiB
C++
126 lines
4.6 KiB
C++
#pragma once
|
|
|
|
#if defined(UTIL_ASSERT_FORMAT)
|
|
#include "print.hpp"
|
|
#endif
|
|
|
|
#ifdef assert
|
|
#pragma push_macro("assert")
|
|
#undef assert
|
|
#define UTIL_ASSERT_UNDEF
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include "move.hpp"
|
|
#include "source_location.hpp"
|
|
#include "type_traits.hpp"
|
|
|
|
namespace util {
|
|
template <class From, class To>
|
|
struct is_convertible
|
|
: std::integral_constant<
|
|
bool,
|
|
(decltype(detail::test_returnable<To>(0))::value &&
|
|
decltype(detail::test_implicitly_convertible<From, To>(0))::value) ||
|
|
(is_void<From>::value && is_void<To>::value)> {};
|
|
|
|
template <typename From, typename To>
|
|
inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
|
|
|
|
template <typename From>
|
|
concept boolean_testable_impl = is_convertible_v<From, bool> && requires {
|
|
static_cast<bool>(declval<From>());
|
|
};
|
|
|
|
template <typename T>
|
|
concept boolean_testable = requires(T &&t) {
|
|
{ !static_cast<T &&>(t) } -> boolean_testable_impl;
|
|
};
|
|
|
|
template <typename A, typename B>
|
|
concept weakly_equality_comparable_with = requires (const remove_reference_t<A>& a, const remove_reference_t<B>& b) {
|
|
{a == b} -> boolean_testable;
|
|
{a != b} -> boolean_testable;
|
|
{b == a} -> boolean_testable;
|
|
{b == a} -> boolean_testable;
|
|
};
|
|
|
|
template <typename T>
|
|
concept equality_comparable = weakly_equality_comparable_with<T, T>;
|
|
|
|
template <typename A, typename B>
|
|
concept equality_comparable_with = weakly_equality_comparable_with<A, B>;
|
|
|
|
template <boolean_testable B>
|
|
inline constexpr auto assert(B&& b, const source_location& source = source_location::current()) ->void {
|
|
if (!b) [[unlikely]] {
|
|
|
|
#if defined (UTIL_ASSERT_FORMAT)
|
|
if constexpr (is_formattable_v<B>) {
|
|
print(std::format("Assertion failed: {}\n", b));
|
|
print(std::format("In function {} at {}:{},{}\n", source.function_name(), source.file_name(), source.line(), source.column()));
|
|
} else {
|
|
print(std::format("Assertion failed in function {} at {}:{},{}\n", source.function_name(), source.file_name(), source.line(), source.column()));
|
|
}
|
|
#else
|
|
printf("Assertion failed in function %s at %s:%d,%d\n",
|
|
source.function_name(), source.file_name(), source.line(),
|
|
source.column());
|
|
#endif
|
|
}
|
|
}
|
|
|
|
template <typename A, typename B>
|
|
requires (equality_comparable_with<A, B>)
|
|
inline constexpr auto assert_eq(A&& rhs, B&& lhs, const source_location& source = source_location::current()) ->void {
|
|
if (rhs != lhs) [[unlikely]] {
|
|
#if defined (UTIL_ASSERT_FORMAT)
|
|
if constexpr (is_formattable_v<A> && is_formattable_v<B>) {
|
|
print(std::format("Assertion failed: {} != {}\n", rhs, lhs));
|
|
print(std::format("In function {} at {}:{},{}\n", source.function_name(), source.file_name(), source.line(), source.column()));
|
|
} else {
|
|
print(std::format("Assertion failed in function {} at {}:{},{}\n", source.function_name(), source.file_name(), source.line(), source.column()));
|
|
}
|
|
#else
|
|
printf("Assertion failed in function %s at %s:%d,%d\n",
|
|
source.function_name(), source.file_name(), source.line(),
|
|
source.column());
|
|
#endif
|
|
}
|
|
}
|
|
|
|
template <equality_comparable T>
|
|
inline constexpr auto assert_eq(T&& rhs, T&& lhs, const source_location& source = source_location::current()) ->void {
|
|
assert_eq<T,T>(FWD(rhs), FWD(lhs),source);
|
|
}
|
|
|
|
|
|
template <typename A, typename B>
|
|
requires (equality_comparable_with<A, B>)
|
|
inline constexpr auto assert_ne(A&& rhs, B&& lhs, const source_location& source = source_location::current()) ->void {
|
|
if (rhs == lhs) [[unlikely]] {
|
|
#if defined (UTIL_ASSERT_FORMAT)
|
|
if constexpr (is_formattable_v<A> && is_formattable_v<B>) {
|
|
print(std::format("Assertion failed: {} == {}\n", rhs, lhs));
|
|
print(std::format("In function {} at {}:{},{}\n", source.function_name(), source.file_name(), source.line(), source.column()));
|
|
} else {
|
|
print(std::format("Assertion failed in function {} at {}:{},{}\n", source.function_name(), source.file_name(), source.line(), source.column()));
|
|
}
|
|
#else
|
|
printf("Assertion failed in function %s at %s:%d,%d\n",
|
|
source.function_name(), source.file_name(), source.line(),
|
|
source.column());
|
|
#endif
|
|
}
|
|
}
|
|
|
|
template <equality_comparable T>
|
|
inline constexpr auto assert_ne(T&& rhs, T&& lhs, const source_location& source = source_location::current()) ->void {
|
|
assert_ne<T, T>(FWD(rhs), FWD(lhs), source);
|
|
}
|
|
} // namespace util
|
|
|
|
#ifdef UTIL_ASSERT_UNDEF
|
|
#pragma pop_macro("assert")
|
|
#undef UTIL_ASSERT_UNDEF
|
|
#endif |