basedOpinionated utility library |
git clone git://git.dimitrijedobrota.com/based.git |
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |
commit | cbb280b1215db7a68f492e9930191a594c40f905 |
parent | c521dbe99b9c3fe2f43691c3d2fac4ea01d3883a |
author | Dimitrije Dobrota < mail@dimitrijedobrota.com > |
date | Mon, 5 May 2025 22:31:34 +0200 |
Restructure
Restructure the project to have one function per header, to ease
compilation times and provide for better cross referencing
M | .clang-format | | | +++++ |
M | .clang-tidy | | | ++++ |
M | example/algorithm.cpp | | | +++++ --- |
M | example/instrumentation.cpp | | | +++ - |
M | example/list.cpp | | | + - |
M | example/template.cpp | | | ++ - |
M | example/type_traits.cpp | | | ++ - |
D | include/based/algorithm.hpp | | | --------------------------------------------------------------------------------- |
A | include/based/algorithms/batch/for_each.hpp | | | +++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/bsearch/lower_bound.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/bsearch/upper_bound.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/minmax/max.hpp | | | +++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/minmax/max_element.hpp | | | ++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/minmax/min.hpp | | | ++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/minmax/min_element.hpp | | | ++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/minmax/minmax_element.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/numeric/accumulate.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/search/all.hpp | | | ++++++++++++++++++++++++ |
A | include/based/algorithms/search/count.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/search/count_if.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/search/count_if_not.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/search/count_not.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/search/find.hpp | | | ++++++++++++++++++++++++++++++ |
A | include/based/algorithms/search/find_adjacent_mismatch.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/search/find_if.hpp | | | +++++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/search/find_if_not.hpp | | | +++++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/search/find_mismatch.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/search/find_not.hpp | | | ++++++++++++++++++++++++++++++ |
A | include/based/algorithms/search/none.hpp | | | ++++++++++++++++++++++++ |
A | include/based/algorithms/search/not_all.hpp | | | ++++++++++++++++++++++++ |
A | include/based/algorithms/search/some.hpp | | | ++++++++++++++++++++++++ |
A | include/based/algorithms/sort/increasing_range.hpp | | | +++++++++++++++++++++++++++++++ |
A | include/based/algorithms/sort/partition_point.hpp | | | ++++++++++++++++++++++++++++++++++++++++ |
A | include/based/algorithms/sort/partitioned.hpp | | | ++++++++++++++++++++++++++ |
A | include/based/algorithms/sort/relation_preserving_range.hpp | | | ++++++++++++++++++++++++++ |
A | include/based/algorithms/sort/strictly_increasing_range.hpp | | | +++++++++++++++++++++++++ |
A | include/based/concepts/callable.hpp | | | ++++++++++++++++++++++++++++++++++++++++ |
A | include/based/concepts/comparable/equal.hpp | | | +++++++++++++++++++++ |
A | include/based/concepts/comparable/equality.hpp | | | +++++++++++++++++++ |
A | include/based/concepts/comparable/greater.hpp | | | +++++++++++++++++++++ |
A | include/based/concepts/comparable/greater_equal.hpp | | | +++++++++++++++++++++ |
A | include/based/concepts/comparable/less.hpp | | | +++++++++++++++++++++ |
A | include/based/concepts/comparable/less_equal.hpp | | | +++++++++++++++++++++ |
A | include/based/concepts/comparable/not_equal.hpp | | | +++++++++++++++++++++ |
A | include/based/concepts/is/convertable.hpp | | | +++++++++++++++ |
A | include/based/concepts/is/invocable.hpp | | | +++++++++++ |
A | include/based/concepts/is/regular.hpp | | | ++++++++++++++++ |
A | include/based/concepts/is/same.hpp | | | +++++++++++++++ |
A | include/based/concepts/is/semiregular.hpp | | | ++++++++++++++++ |
A | include/based/concepts/iterator.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/concepts/ordered/totally.hpp | | | +++++++++++++++++++++++++ |
A | include/based/concepts/procedure/domain.hpp | | | ++++++++++++++++++++++++++++++++++++++++ |
A | include/based/concepts/procedure/function.hpp | | | ++++++++++++++++++++++++++++ |
A | include/based/concepts/procedure/function_iter.hpp | | | +++++++++++++++++++++++++++ |
A | include/based/concepts/procedure/operation.hpp | | | +++++++++++++++++++++++ |
A | include/based/concepts/procedure/operation_iter.hpp | | | +++++++++++++++++++++ |
A | include/based/concepts/procedure/predicate.hpp | | | ++++++++++++++++++++++++++ |
A | include/based/concepts/procedure/predicate_iter.hpp | | | +++++++++++++++++++++++++++++++++ |
A | include/based/concepts/procedure/procedure.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/concepts/procedure/procedure_iter.hpp | | | +++++++++++++++++++++++++++ |
A | include/based/count.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | include/based/enum.hpp | | | --------------------------------------------------------------------------------- |
A | include/based/enum/enum.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | include/based/functional.hpp | | | --------------------------------------------------------------------------------- |
A | include/based/functional/curry.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/functional/function.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/functional/overload.hpp | | | +++++++++++++++++ |
A | include/based/functional/predicate.hpp | | | +++++++++++++++++++++++++++++++++++ |
D | include/based/instrumentation.hpp | | | --------------------------------------------------------------------------------- |
A | include/based/instrumentation/instrumented.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/instrumentation/registry.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/instrumentation/table.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/instrumentation/timer.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | include/based/integer.hpp | | | ------------------------------------------------------------------------ |
D | include/based/iterator.hpp | | | ------------------------------------------- |
M | include/based/string.hpp | | | ++ -- |
D | include/based/template.hpp | | | --------------------------------------------------------------------------------- |
D | include/based/type_traits.hpp | | | --------------------------------------------------------------------------------- |
A | include/based/type_traits/add/lvalue_reference.hpp | | | +++++++++++++++++++++++++++ |
A | include/based/type_traits/add/rvalue_reference.hpp | | | +++++++++++++++++++++++++++ |
A | include/based/type_traits/integral_constant.hpp | | | ++++++++++++++++++++++ |
A | include/based/type_traits/invoke/result.hpp | | | ++++++++++++++ |
A | include/based/type_traits/is/const.hpp | | | +++++++++++++++++ |
A | include/based/type_traits/is/convertable.hpp | | | ++++++++++++++ |
A | include/based/type_traits/is/invocable.hpp | | | ++++++++++++++ |
A | include/based/type_traits/is/same.hpp | | | +++++++++++++++++ |
A | include/based/type_traits/iterator.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/type_traits/remove/const.hpp | | | +++++++++++++++ |
A | include/based/type_traits/remove/cv.hpp | | | +++++++++++++++++ |
A | include/based/type_traits/remove/cvref.hpp | | | +++++++++++++++++++ |
A | include/based/type_traits/remove/pointer.hpp | | | ++++++++++++++++++ |
A | include/based/type_traits/remove/reference.hpp | | | ++++++++++++++++ |
A | include/based/type_traits/remove/volatile.hpp | | | +++++++++++++++ |
A | include/based/type_traits/signature.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/type_traits/type_identity.hpp | | | ++++++++++++++ |
A | include/based/types/types.hpp | | | ++++++++++++++++++++++ |
M | include/based/utility.hpp | | | ------------------------ |
A | include/based/utility/buffer.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/utility/declvar.hpp | | | ++++++++++++++ |
A | include/based/utility/scopeguard.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | include/based/utility/uncaught_exception.hpp | | | ++++++++++++++++++++++++ |
M | test/CMakeLists.txt | | | ++++++++++++++++++++++++++++++++++++++++++ ---------------------------------------- |
A | test/source/algorithms/all_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/count_if_not_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/count_if_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/count_not_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/count_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/find_adjacent_mismatch_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/find_if_not_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/find_if_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/find_mismatch_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/find_not_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/find_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/foreach_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/lower_bound_test.cpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/max_element_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/max_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/min_element_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/min_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/minmax_element_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/none_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/not_all_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/partition_point_test.cpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/partitioned_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/reduce_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/some_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/algorithms/upper_bound_test.cpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++ |
D | test/source/buffer_test.cpp | | | ------------------------------------------------------------------ |
D | test/source/callable_test.cpp | | | ---------------------------------------------------------- |
A | test/source/concepts/callable_test.cpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | test/source/count_if_n_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/count_if_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/count_n_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/count_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/curry_test.cpp | | | ----------------------------------------------------------------------------- |
M | test/source/enum_test.cpp | | | +++++++++++++++ --------- |
D | test/source/find_if_n_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/find_if_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/find_if_unguarded_test.cpp | | | ---------------------------------------------------------------------------- |
D | test/source/find_mismatch_n_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/find_mismatch_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/find_n_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/find_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/for_each_n_test.cpp | | | ---------------------------------------------------- |
D | test/source/for_each_test.cpp | | | -------------------------------------------- |
D | test/source/function_test.cpp | | | ---------------------------------------------- |
A | test/source/functional/curry_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/functional/function_test.cpp | | | ++++++++++++++++++++++++++++++++++++++++++++++ |
M | test/source/list_test.cpp | | | ++++++++++++++++++ ---------------- |
D | test/source/max_element_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/max_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/min_element_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/min_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/minmax_element_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/partition_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/reduce_test.cpp | | | ------------------------------------------------------------------ |
D | test/source/scopeguard_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/signature_test.cpp | | | --------------------------------------------------------------------------------- |
D | test/source/standard_traits_test.cpp | | | --------------------------------------------------------------------------------- |
A | test/source/type_traits/remove_const.cpp | | | +++++++++++++++++++++++++++++++++++++ |
A | test/source/type_traits/remove_cv.cpp | | | +++++++++++++++++++++++++++++++++++++ |
A | test/source/type_traits/remove_cvref.cpp | | | +++++++++++++++++++++++++++++++++++++ |
A | test/source/type_traits/remove_pointer.cpp | | | ++++++++++++++++++++++ |
A | test/source/type_traits/remove_reference.cpp | | | +++++++++++++++++++++++++++++++++++++ |
A | test/source/type_traits/remove_volatile.cpp | | | +++++++++++++++++++++++++++++++++++++ |
A | test/source/type_traits/signature_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/utility/buffer_test.cpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/utility/scopeguard_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
168 files changed, 8143 insertions(+), 7081 deletions(-)
diff --git a/ .clang-format b/ .clang-format
@@ -20,6 +20,7 @@
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
@@ -50,6 +51,7 @@
BreakBeforeBraces: Custom
# BreakBeforeInheritanceComma: true
BreakInheritanceList: BeforeComma
BreakBeforeTernaryOperators: true
BreakBeforeConceptDeclarations: Always
BreakConstructorInitializersBeforeComma: true
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: true
@@ -91,6 +93,8 @@
IndentPPDirectives: AfterHash
IndentExternBlock: NoIndent
IndentWidth: 2
IndentWrappedFunctionNames: false
IndentRequiresClause: true
RequiresClausePosition: OwnLine
InsertTrailingCommas: Wrapped
JavaScriptQuotes: Double
JavaScriptWrapImports: true
@@ -99,6 +103,7 @@
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
RequiresExpressionIndentation: OuterScope
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
diff --git a/ .clang-tidy b/ .clang-tidy
@@ -165,4 +165,8 @@
CheckOptions:
value: "^[abcdxyznm]$"
- key: 'readability-identifier-length.IgnoredParameterNames'
value: "^[abcdxyznm]$"
- key: 'google-runtime-int.UnsignedTypePrefix'
value: "u"
- key: 'google-runtime-int.SignedTypePrefix'
value: "i"
...
diff --git a/ example/algorithm.cpp b/ example/algorithm.cpp
@@ -1,6 +1,8 @@
#include "based/algorithm.hpp"
#include "based/instrumentation.hpp"
#include "based/algorithms/minmax/max_element.hpp"
#include "based/algorithms/minmax/min_element.hpp"
#include "based/algorithms/minmax/minmax_element.hpp"
#include "based/instrumentation/instrumented.hpp"
#include "based/instrumentation/timer.hpp"
based::instrumented_base::op::type::array<double>
based::instrumented_base::counts;
diff --git a/ example/instrumentation.cpp b/ example/instrumentation.cpp
@@ -1,7 +1,9 @@
#include <algorithm>
#include <iostream>
#include "based/instrumentation.hpp"
#include "based/instrumentation/instrumented.hpp"
#include "based/instrumentation/registry.hpp"
#include "based/instrumentation/timer.hpp"
based::instrumented_base::op::type::array<double>
based::instrumented_base::counts;
diff --git a/ example/list.cpp b/ example/list.cpp
@@ -2,7 +2,7 @@
#include "based/list.hpp"
#include "based/instrumentation.hpp"
#include "based/instrumentation/instrumented.hpp"
based::instrumented_base::op::type::array<double>
based::instrumented_base::counts;
diff --git a/ example/template.cpp b/ example/template.cpp
@@ -1,7 +1,8 @@
#include <functional>
#include <iostream>
#include "based/template.hpp"
#include "based/functional/function.hpp"
#include "based/functional/overload.hpp"
int main()
{
diff --git a/ example/type_traits.cpp b/ example/type_traits.cpp
@@ -1,4 +1,5 @@
#include "based/type_traits.hpp"
#include "based/concepts/procedure/function.hpp"
#include "based/concepts/procedure/procedure.hpp"
namespace
{
diff --git a/ include/based/algorithm.hpp b/ include/based/algorithm.hpp
@@ -1,837 +0,0 @@
#pragma once
#include <functional>
#include <utility>
#include "based/functional.hpp"
#include "based/iterator.hpp"
#include "based/type_traits.hpp"
namespace based
{
namespace detail
{
/* ----- Min and Max ----- */
template<typename P, typename Arg>
concept NoninputRelation = RegularProcedure<P, bool, Arg, Arg>;
} // namespace detail
// returns min element, first if equal
template<BareRegular T, BareRegular U, detail::NoninputRelation<T> Rel>
requires BareSameAs<T, U>
decltype(auto) min(T&& lhs, U&& rhs, Rel rel)
{
return rel(rhs, lhs) ? std::forward<U>(rhs) : std::forward<T>(lhs);
}
// returns min element, first if equal
template<BareRegular T, BareRegular U>
requires BareSameAs<T, U>
decltype(auto) min(T&& lhs, U&& rhs)
{
return based::min(
std::forward<T>(lhs), std::forward<U>(rhs), std::less<bare_t<T>>()
);
}
// returns max element, second if equal
template<BareRegular T, BareRegular U, detail::NoninputRelation<T> Rel>
requires BareSameAs<T, U>
decltype(auto) max(T&& lhs, U&& rhs, Rel rel)
{
return rel(rhs, lhs) ? std::forward<T>(lhs) : std::forward<U>(rhs);
}
// returns max element, second if equal
template<BareRegular T, BareRegular U>
requires BareSameAs<T, U>
decltype(auto) max(T&& lhs, U&& rhs)
{
return based::max(
std::forward<T>(lhs), std::forward<U>(rhs), std::less<bare_t<T>>()
);
}
/* ----- Bounded Range Algorithms ----- */
// return first min element
template<Iterator I, IterRelation<I> Rel>
I min_element(I first, I last, Rel rel)
{
if (first == last) {
return last;
}
I mini = first++;
while (first != last) {
if (rel(*first, *mini)) {
mini = first;
}
first++;
}
return mini;
}
template<Iterator I>
I min_element(I first, I last)
{
return based::min_element(first, last, std::less<iter_value_t<I>>());
}
// return last max element
template<Iterator I, IterRelation<I> Rel>
I max_element(I first, I last, Rel rel)
{
if (first == last) {
return last;
}
I maxi = first++;
while (first != last) {
if (!rel(*first, *maxi)) {
maxi = first;
}
first++;
}
return maxi;
}
template<Iterator I>
I max_element(I first, I last)
{
return based::max_element(first, last, std::less<iter_value_t<I>>());
}
// return first min and last max element
template<Iterator I, IterRelation<I> Rel>
std::pair<I, I> minmax_element(I first, I last, Rel rel)
{
if (first == last) {
return {last, last};
}
I mini = first++;
if (first == last) {
return {mini, mini};
}
I maxi = first++;
if (rel(*maxi, *mini)) {
std::swap(mini, maxi);
}
I next = successor(first);
while (first != last && next != last) {
I pmini = first;
I pmaxi = next;
if (rel(*pmaxi, *pmini)) {
std::swap(pmini, pmaxi);
}
if (rel(*pmini, *mini)) {
mini = pmini;
}
if (!rel(*pmaxi, *maxi)) {
maxi = pmaxi;
}
next++;
first = next;
next++;
}
if (first != last) {
if (rel(*first, *mini)) {
mini = first;
} else if (!rel(*first, *maxi)) {
maxi = first;
}
}
return {mini, maxi};
}
template<Iterator I>
std::pair<I, I> minmax_element(I first, I last)
{
return based::minmax_element(first, last, std::less<iter_value_t<I>>());
}
template<ReadableIterator I, IterUnaryProcedure<void, I> Proc>
Proc for_each(I first, I last, Proc proc)
{
// Precondition: readable_bounded_range(first, last);
while (first != last) {
proc(*first);
first = successor(first);
}
return proc;
}
template<ReadableIterator I>
I find(I first, I lst, const iter_value_t<I>& val)
{
// Precondition: readable_bounded_range(first, last);
while (first != lst && *first != val) {
first = successor(first);
}
return first;
}
template<ReadableIterator I>
I find_not(I first, I last, const iter_value_t<I>& val)
{
// Precondition: readable_bounded_range(first, last);
while (first != last && *first == val) {
first = successor(first);
}
return first;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
I find_if(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
while (first != last && !pred(*first)) {
first = successor(first);
}
return first;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
I find_if_not(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
while (first != last && pred(*first)) {
first = successor(first);
}
return first;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool all(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
return find_if_not(first, last, pred) == last;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool none(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
return find_if(first, last, pred) == last;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool not_all(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
return first == last || find_if_not(first, last, pred) != last;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool some(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
return find_if(first, last, pred) != last;
}
template<ReadableIterator I, Iterator J>
J count(I first, I last, const iter_value_t<I>& val, J cnt)
{
// Precondition: readable_bounded_range(first, last);
while (first != last) {
if (*first == val) {
cnt++;
}
first = successor(first);
}
return cnt;
}
template<ReadableIterator I>
iter_dist_t<I> count(I first, I last, const iter_value_t<I>& val)
{
// Precondition: readable_bounded_range(first, last);
return count(first, last, val, iter_dist_t<I> {0});
}
template<ReadableIterator I, Iterator J>
J count_not(I first, I last, const iter_value_t<I>& val, J cnt)
{
// Precondition: readable_bounded_range(first, last);
while (first != last) {
if (*first != val) {
cnt++;
}
first = successor(first);
}
return cnt;
}
template<ReadableIterator I>
iter_dist_t<I> count_not(I first, I last, const iter_value_t<I>& val)
{
// Precondition: readable_bounded_range(first, last);
return count_not(first, last, val, iter_dist_t<I> {0});
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred, Iterator J>
J count_if(I first, I last, Pred pred, J cnt)
{
// Precondition: readable_bounded_range(first, last);
while (first != last) {
if (pred(*first)) {
cnt++;
}
first = successor(first);
}
return cnt;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
iter_dist_t<I> count_if(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
return count_if(first, last, pred, iter_dist_t<I> {0});
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred, Iterator J>
J count_if_not(I first, I last, Pred pred, J cnt)
{
// Precondition: readable_bounded_range(first, last);
while (first != last) {
if (!pred(*first)) {
cnt++;
}
first = successor(first);
}
return cnt;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
iter_dist_t<I> count_if_not(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
return count_if_not(first, last, pred, iter_dist_t<I> {0});
}
template<Iterator I, UnaryFunction<void, I> F, BinaryOperation<ret_t<F, I>> Op>
auto reduce_nonempty(I first, I last, Op opr, F fun)
{
assert(first != last);
// Precondition: bounded_range(first, last)
// Precondition: partially_associative(opr)
auto res = fun(first);
first = successor(first);
while (first != last) {
res = opr(res, fun(first));
first = successor(first);
}
return res;
}
template<Iterator I, UnaryFunction<void, I> F, BinaryOperation<ret_t<F, I>> Op>
auto reduce(
I first,
I last,
Op opr,
F fun,
const decltype(reduce_nonempty(first, last, opr, fun))& zero
)
{
// Precondition: bounded_range(first, last)
// Precondition: partially_associative(opr)
if (first == last) {
return zero;
}
return reduce_nonempty(first, last, opr, fun);
}
template<Iterator I, UnaryFunction<void, I> F, BinaryOperation<ret_t<F, I>> Op>
auto reduce_nonzero(
I first,
I last,
Op opr,
F fun,
const decltype(reduce_nonempty(first, last, opr, fun))& zero
)
{
// Precondition: bounded_range(first, last)
// Precondition: partially_associative(opr)
ret_t<F, I> res;
do {
if (first == last) {
return zero;
}
res = fun(first);
first = successor(first);
} while (res == zero);
while (first != last) {
auto crnt = fun(first);
if (crnt != zero) {
res = opr(res, crnt);
}
first = successor(first);
}
return res;
}
template<ReadableIterator I0, ReadableIterator I1, IterRelation<I0> Rel>
requires BareSameAs<iter_value_t<I0>, iter_value_t<I1>>
auto find_mismatch(I0 first0, I0 last0, I1 first1, I1 last1, Rel rel)
{
// Precondition: readable_bounded_range(first0, last0)
// Precondition: readable_bounded_range(first1, last1)
while (first0 != last0 && first1 != last1 && rel(*first0, *first1)) {
first0 = successor(first0);
first1 = successor(first1);
}
return std::make_pair(first0, first1);
}
template<ReadableIterator I, IterRelation<I> Rel>
I find_adjacent_mismatch(I first, I last, Rel rel)
{
// Precondition: readable_bounded_range(first, last)
if (first == last) {
return last;
}
auto crnt = *first;
first = successor(first);
while (first != last && rel(crnt, *first)) {
crnt = *first;
first = successor(first);
}
return first;
}
template<ReadableIterator I, IterRelation<I> Rel>
bool relation_preserving(I first, I last, Rel rel)
{
// Precondition: readable_bounded_range(first, last)
// Precondition: weak_ordering(rel);
return find_adjacent_mismatch(first, last, rel) == last;
}
template<ReadableIterator I, IterRelation<I> Rel>
bool strictly_increasing_range(I first, I last, Rel rel)
{
// Precondition: readable_bounded_range(first, last)
// Precondition: weak_ordering(rel);
return relation_preserving(first, last, rel);
}
template<ReadableIterator I, IterRelation<I> Rel>
bool increasing_range(I first, I last, Rel rel)
{
// Precondition: readable_bounded_range(first, last)
// Precondition: weak_ordering(rel);
return relation_preserving(
first, last, complement_of_converse<iter_value_t<I>>(rel)
);
}
/* ----- Counted Range Algorithms ----- */
template<ReadableIterator I, IterUnaryProcedure<void, I> Proc>
auto for_each_n(I first, iter_dist_t<I> size, Proc proc)
{
// Precondition: readable_weak_range(first, size);
while (!zero(size)) {
size = predecessor(size);
proc(*first);
first = successor(first);
}
return std::make_pair(proc, first);
}
template<ReadableIterator I>
auto find_n(I first, iter_dist_t<I> size, const iter_value_t<I>& val)
{
// Precondition: readable_weak_range(first, size);
while (!zero(size) && *first != val) {
size = predecessor(size);
first = successor(first);
}
return std::make_pair(first, size);
}
template<ReadableIterator I>
auto find_not_n(I first, iter_dist_t<I> size, const iter_value_t<I>& val)
{
// Precondition: readable_weak_range(first, size);
while (!zero(size) && *first == val) {
size = predecessor(size);
first = successor(first);
}
return std::make_pair(first, size);
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
auto find_if_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
while (!zero(size) && !pred(*first)) {
size = predecessor(size);
first = successor(first);
}
return std::make_pair(first, size);
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
auto find_if_not_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
while (!zero(size) && pred(*first)) {
size = predecessor(size);
first = successor(first);
}
return std::make_pair(first, size);
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool all_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, last);
return find_if_not_n(first, size, pred).second == 0;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool none_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
return find_if_n(first, size, pred).second == 0;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool not_all_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
return size == 0 || find_if_not_n(first, size, pred).second != 0;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool some_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
return find_if_n(first, size, pred).second != 0;
}
template<ReadableIterator I, Iterator J>
auto count_n(I first, iter_dist_t<I> size, const iter_value_t<I>& val, J cnt)
{
// Precondition: readable_weak_range(first, size);
while (!zero(size)) {
if (*first == val) {
cnt++;
}
size = predecessor(size);
first = successor(first);
}
return std::make_pair(first, cnt);
}
template<ReadableIterator I>
auto count_n(I first, iter_dist_t<I> size, const iter_value_t<I>& val)
{
// Precondition: readable_weak_range(first, size);
return count_n(first, size, val, iter_dist_t<I> {0});
}
template<ReadableIterator I, Iterator J>
auto count_not_n(
I first, iter_dist_t<I> size, const iter_value_t<I>& val, J cnt
)
{
// Precondition: readable_weak_range(first, size);
while (!zero(size)) {
if (*first != val) {
cnt++;
}
size = predecessor(size);
first = successor(first);
}
return std::make_pair(first, cnt);
}
template<ReadableIterator I>
auto count_not_n(I first, iter_dist_t<I> size, const iter_value_t<I>& val)
{
// Precondition: readable_weak_range(first, size);
return count_not_n(first, size, val, iter_dist_t<I> {0});
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred, Iterator J>
auto count_if_n(I first, iter_dist_t<I> size, Pred pred, J cnt)
{
// Precondition: readable_weak_range(first, size);
while (!zero(size)) {
if (pred(*first)) {
cnt++;
}
size = predecessor(size);
first = successor(first);
}
return std::make_pair(first, cnt);
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
auto count_if_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
return count_if_n(first, size, pred, iter_dist_t<I> {0});
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred, Iterator J>
auto count_if_not_n(I first, iter_dist_t<I> size, Pred pred, J cnt)
{
// Precondition: readable_weak_range(first, size);
while (!zero(size)) {
if (!pred(*first)) {
cnt++;
}
size = predecessor(size);
first = successor(first);
}
return std::make_pair(first, cnt);
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
auto count_if_not_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
return count_if_not_n(first, size, pred, iter_dist_t<I> {0});
}
template<ReadableIterator I0, ReadableIterator I1, IterRelation<I0> Rel>
requires BareSameAs<iter_value_t<I0>, iter_value_t<I1>>
auto find_mismatch_n(
I0 first0, iter_dist_t<I0> size0, I1 first1, I1 last1, Rel rel
)
{
// Precondition: readable_weak_range(first0, size0)
// Precondition: readable_bounded_range(first1,last1)
while (!zero(size0) && first1 != last1 && rel(*first0, *first1)) {
size0 = predecessor(size0);
first0 = successor(first0);
first1 = successor(first1);
}
return std::make_tuple(first0, size0, first1);
}
template<ReadableIterator I0, ReadableIterator I1, IterRelation<I0> Rel>
requires BareSameAs<iter_value_t<I0>, iter_value_t<I1>>
auto find_mismatch_m(
I0 first0, I0 last0, I1 first1, iter_dist_t<I1> size1, Rel rel
)
{
// Precondition: readable_bounded_range(first0,last0)
// Precondition: readable_weak_range(first1, size1)
while (first0 != last0 && !zero(size1) && rel(*first0, *first1)) {
size1 = predecessor(size1);
first0 = successor(first0);
first1 = successor(first1);
}
return std::make_tuple(first0, first1, size1);
}
template<ReadableIterator I0, ReadableIterator I1, IterRelation<I0> Rel>
requires BareSameAs<iter_value_t<I0>, iter_value_t<I1>>
auto find_mismatch_n_m(
I0 first0, iter_dist_t<I0> size0, I1 first1, iter_dist_t<I1> size1, Rel rel
)
{
// Precondition: readable_weak_range(first0, size0)
// Precondition: readable_weak_range(first1, size1)
while (!zero(size0) && !zero(size1) && rel(*first0, *first1)) {
size0 = predecessor(size0);
size1 = predecessor(size1);
first0 = successor(first0);
first1 = successor(first1);
}
return std::make_tuple(first0, size0, first1, size1);
}
template<ReadableIterator I, IterRelation<I> Rel>
auto find_adjacent_mismatch_n(I first, iter_dist_t<I> size, Rel rel)
{
// Precondition: readable_bounded_range(first, last)
if (zero(size)) {
return std::make_pair(first, size);
}
auto crnt = *first;
first = successor(first);
size = predecessor(size);
while (!zero(size) && rel(crnt, *first)) {
crnt = *first;
size = predecessor(size);
first = successor(first);
}
return std::make_pair(first, size);
}
template<ReadableIterator I, IterRelation<I> Rel>
bool relation_preserving_n(I first, iter_dist_t<I> size, Rel rel)
{
// Precondition: readable_bounded_range(first, size)
// Precondition: weak_ordering(rel);
return find_adjacent_mismatch_n(first, size, rel).second == 0;
}
template<ReadableIterator I, IterRelation<I> Rel>
bool strictly_increasing_range_n(I first, iter_dist_t<I> size, Rel rel)
{
// Precondition: readable_bounded_range(first, size)
// Precondition: weak_ordering(rel);
return relation_preserving_n(first, size, rel);
}
template<ReadableIterator I, IterRelation<I> Rel>
bool increasing_range_n(I first, iter_dist_t<I> size, Rel rel)
{
// Precondition: readable_bounded_range(first, size)
// Precondition: weak_ordering(rel);
return relation_preserving_n(
first, size, complement_of_converse<iter_value_t<I>>(rel)
);
}
/* ----- Sentinel Ranges ----- */
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
I find_if_unguarded(I first, Pred pred)
{
// Precondition: readable_bounded_range(first, last) && some(f, d, p);
while (!pred(*first)) {
first = successor(first);
}
return first;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
I find_if_not_unguarded(I first, Pred pred)
{
// Precondition: readable_bounded_range(first, last) && not_all(f, d, p);
while (pred(*first)) {
first = successor(first);
}
return first;
}
template<ReadableForwardIterator I, IterRelation<I> Rel>
I find_adjacent_mismatch_forward(I first, I last, Rel rel)
{
// Precondition: readable_bounded_range(first, last)
if (first == last) {
return last;
}
I tmp;
do {
tmp = first;
first = successor(first);
} while (first != last && rel(*tmp, *first));
return first;
}
template<ReadableForwardIterator I, IterUnaryPredicate<I> Pred>
bool partitioned_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_bounded_range(first, size)
std::tie(first, size) = find_if_n(first, size, pred);
return find_if_not_n(first, size, pred).second == 0;
}
template<ReadableForwardIterator I, IterUnaryPredicate<I> Pred>
I partition_point_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_bounded_range(first, size)
assert(partitioned_n(first, size, pred));
while (!zero(size)) {
const auto hlf = half(size);
I mid = first + hlf;
if (pred(*mid)) {
size = hlf;
} else {
size -= successor(hlf);
first = successor(mid);
}
}
return first;
}
template<ReadableForwardIterator I, IterRelation<I> Rel>
I lower_bound_n(
I first, iter_dist_t<I> size, const iter_value_t<I>& val, Rel rel
)
{
// Precondition: weak_ordering(rel)
assert(increasing_range_n(first, size, rel));
return partition_point_n(first, size, lower_bound_predicate(val, rel));
}
template<ReadableForwardIterator I, IterRelation<I> Rel>
I upper_bound_n(
I first, iter_dist_t<I> size, const iter_value_t<I>& val, Rel rel
)
{
// Precondition: weak_ordering(rel)
assert(increasing_range_n(first, size, rel));
return partition_point_n(first, size, upper_bound_predicate(val, rel));
}
template<ReadableForwardIterator I, IterUnaryPredicate<I> Pred>
bool partitioned(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last)
return find_if_not(find_if(first, last, pred), last, pred) == last;
}
template<ReadableForwardIterator I, IterUnaryPredicate<I> Pred>
I partition_point(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last)
assert(partitioned(first, last, pred));
return partition_point_n(first, last - first, pred);
}
template<ReadableForwardIterator I, IterRelation<I> Rel>
I lower_bound(I first, I last, const iter_value_t<I>& val, Rel rel)
{
// Precondition: weak_ordering(rel)
assert(increasing_range(first, last, rel));
return based::lower_bound_n(first, last - first, val, rel);
}
template<ReadableForwardIterator I, IterRelation<I> Rel>
I upper_bound(I first, I last, const iter_value_t<I>& val, Rel rel)
{
// Precondition: weak_ordering(rel)
assert(increasing_range(first, last, rel));
return based::upper_bound_n(first, last - first, val, rel);
}
} // namespace based
diff --git a/ include/based/algorithms/batch/for_each.hpp b/ include/based/algorithms/batch/for_each.hpp
@@ -0,0 +1,33 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/procedure_iter.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
template<ReadableIterator I, IterUnaryProcedure<void, I> Proc>
Proc for_each(I first, I last, Proc proc)
{
// Precondition: readable_bounded_range(first, last);
while (first != last) {
proc(*first);
first++;
}
return proc;
}
template<ReadableIterator I, IterUnaryProcedure<void, I> Proc>
auto for_each_n(I first, iter_dist_t<I> size, Proc proc)
{
// Precondition: readable_weak_range(first, size);
while (size != 0) {
size--;
proc(*first);
first++;
}
return std::make_pair(proc, first);
}
} // namespace based
diff --git a/ include/based/algorithms/bsearch/lower_bound.hpp b/ include/based/algorithms/bsearch/lower_bound.hpp
@@ -0,0 +1,50 @@
#pragma once
#include <cassert>
#include "based/algorithms/sort/increasing_range.hpp"
#include "based/algorithms/sort/partition_point.hpp"
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
namespace based
{
namespace detail
{
template<typename T, Relation<T> Rel>
auto lower_bound_predicate(const T& goal, Rel rel)
{
return [=](const T& val)
{
return !rel(val, goal);
};
}
} // namespace detail
template<ReadableForwardIterator I, IterRelation<I> Rel>
I lower_bound_n(
I first, iter_dist_t<I> size, const iter_value_t<I>& val, Rel rel
)
{
// Precondition: weak_ordering(rel)
assert(increasing_range_n(first, size, rel));
return partition_point_n(
first, size, detail::lower_bound_predicate(val, rel)
);
}
template<ReadableForwardIterator I, IterRelation<I> Rel>
I lower_bound(I first, I last, const iter_value_t<I>& val, Rel rel)
{
// Precondition: weak_ordering(rel)
assert(increasing_range(first, last, rel));
return based::lower_bound_n(first, last - first, val, rel);
}
} // namespace based
diff --git a/ include/based/algorithms/bsearch/upper_bound.hpp b/ include/based/algorithms/bsearch/upper_bound.hpp
@@ -0,0 +1,50 @@
#pragma once
#include <cassert>
#include "based/algorithms/sort/increasing_range.hpp"
#include "based/algorithms/sort/partition_point.hpp"
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
namespace based
{
namespace detail
{
template<typename T, Relation<T> Rel>
auto upper_bound_predicate(const T& goal, Rel rel)
{
return [=](const T& val)
{
return rel(goal, val);
};
}
} // namespace detail
template<ReadableForwardIterator I, IterRelation<I> Rel>
I upper_bound_n(
I first, iter_dist_t<I> size, const iter_value_t<I>& val, Rel rel
)
{
// Precondition: weak_ordering(rel)
assert(increasing_range_n(first, size, rel));
return partition_point_n(
first, size, detail::upper_bound_predicate(val, rel)
);
}
template<ReadableForwardIterator I, IterRelation<I> Rel>
I upper_bound(I first, I last, const iter_value_t<I>& val, Rel rel)
{
// Precondition: weak_ordering(rel)
assert(increasing_range(first, last, rel));
return based::upper_bound_n(first, last - first, val, rel);
}
} // namespace based
diff --git a/ include/based/algorithms/minmax/max.hpp b/ include/based/algorithms/minmax/max.hpp
@@ -0,0 +1,39 @@
#pragma once
#include <functional>
#include "based/concepts/is/regular.hpp"
#include "based/concepts/is/same.hpp"
#include "based/concepts/procedure/procedure.hpp"
#include "based/type_traits/remove/cvref.hpp"
namespace based
{
namespace detail
{
template<typename P, typename Arg>
concept NoninputRelation = RegularProcedure<P, bool, Arg, Arg>;
} // namespace detail
// returns max element, second if equal
template<BareRegular T, BareRegular U, detail::NoninputRelation<T> Rel>
requires BareSameAs<T, U>
decltype(auto) max(T&& lhs, U&& rhs, Rel rel)
{
return rel(rhs, lhs) ? std::forward<T>(lhs) : std::forward<U>(rhs);
}
// returns max element, second if equal
template<BareRegular T, BareRegular U>
requires BareSameAs<T, U>
decltype(auto) max(T&& lhs, U&& rhs)
{
return based::max(
std::forward<T>(lhs), std::forward<U>(rhs), std::less<remove_cvref_t<T>>()
);
}
} // namespace based
diff --git a/ include/based/algorithms/minmax/max_element.hpp b/ include/based/algorithms/minmax/max_element.hpp
@@ -0,0 +1,38 @@
#pragma once
#include <functional>
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
// return last max element
template<Iterator I, IterRelation<I> Rel>
I max_element(I first, I last, Rel rel)
{
if (first == last) {
return last;
}
I maxi = first;
first++;
while (first != last) {
if (!rel(*first, *maxi)) {
maxi = first;
}
first++;
}
return maxi;
}
// return last max element
template<Iterator I>
I max_element(I first, I last)
{
return based::max_element(first, last, std::less<iter_value_t<I>>());
}
} // namespace based
diff --git a/ include/based/algorithms/minmax/min.hpp b/ include/based/algorithms/minmax/min.hpp
@@ -0,0 +1,38 @@
#pragma once
#include <functional>
#include "based/concepts/is/regular.hpp"
#include "based/concepts/is/same.hpp"
#include "based/concepts/procedure/procedure.hpp"
#include "based/type_traits/remove/cvref.hpp"
namespace based
{
namespace detail
{
template<typename P, typename Arg>
concept NoninputRelation = RegularProcedure<P, bool, Arg, Arg>;
} // namespace detail
template<BareRegular T, BareRegular U, detail::NoninputRelation<T> Rel>
requires BareSameAs<T, U>
decltype(auto) min(T&& lhs, U&& rhs, Rel rel)
{
return rel(rhs, lhs) ? std::forward<U>(rhs) : std::forward<T>(lhs);
}
// returns min element, first if equal
template<BareRegular T, BareRegular U>
requires BareSameAs<T, U>
decltype(auto) min(T&& lhs, U&& rhs)
{
return based::min(
std::forward<T>(lhs), std::forward<U>(rhs), std::less<remove_cvref_t<T>>()
);
}
} // namespace based
diff --git a/ include/based/algorithms/minmax/min_element.hpp b/ include/based/algorithms/minmax/min_element.hpp
@@ -0,0 +1,38 @@
#pragma once
#include <functional>
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
// return first min element
template<Iterator I, IterRelation<I> Rel>
I min_element(I first, I last, Rel rel)
{
if (first == last) {
return last;
}
I mini = first;
first++;
while (first != last) {
if (rel(*first, *mini)) {
mini = first;
}
first++;
}
return mini;
}
// return first min element
template<Iterator I>
I min_element(I first, I last)
{
return based::min_element(first, last, std::less<iter_value_t<I>>());
}
} // namespace based
diff --git a/ include/based/algorithms/minmax/minmax_element.hpp b/ include/based/algorithms/minmax/minmax_element.hpp
@@ -0,0 +1,70 @@
#pragma once
#include <functional>
#include <iterator>
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
// return first min and last max element
template<Iterator I, IterRelation<I> Rel>
std::pair<I, I> minmax_element(I first, I last, Rel rel)
{
if (first == last) {
return {last, last};
}
I mini = first++;
if (first == last) {
return {mini, mini};
}
I maxi = first++;
if (rel(*maxi, *mini)) {
std::swap(mini, maxi);
}
I next = std::next(first);
while (first != last && next != last) {
I pmini = first;
I pmaxi = next;
if (rel(*pmaxi, *pmini)) {
std::swap(pmini, pmaxi);
}
if (rel(*pmini, *mini)) {
mini = pmini;
}
if (!rel(*pmaxi, *maxi)) {
maxi = pmaxi;
}
next++;
first = next;
next++;
}
if (first != last) {
if (rel(*first, *mini)) {
mini = first;
} else if (!rel(*first, *maxi)) {
maxi = first;
}
}
return {mini, maxi};
}
template<Iterator I>
std::pair<I, I> minmax_element(I first, I last)
{
return based::minmax_element(first, last, std::less<iter_value_t<I>>());
}
} // namespace based
diff --git a/ include/based/algorithms/numeric/accumulate.hpp b/ include/based/algorithms/numeric/accumulate.hpp
@@ -0,0 +1,74 @@
#pragma once
#include <cassert>
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/operation.hpp"
namespace based
{
template<Iterator I, UnaryFunction<void, I> F, BinaryOperation<ret_t<F, I>> Op>
auto accumulate_nonempty(I first, I last, Op opr, F fun)
{
assert(first != last);
// Precondition: bounded_range(first, last)
// Precondition: partially_associative(opr)
auto res = fun(first);
first++;
while (first != last) {
res = opr(res, fun(first));
first++;
}
return res;
}
template<Iterator I, UnaryFunction<void, I> F, BinaryOperation<ret_t<F, I>> Op>
auto accumulate(
I first,
I last,
Op opr,
F fun,
const decltype(accumulate_nonempty(first, last, opr, fun))& zero
)
{
// Precondition: bounded_range(first, last)
// Precondition: partially_associative(opr)
if (first == last) {
return zero;
}
return accumulate_nonempty(first, last, opr, fun);
}
template<Iterator I, UnaryFunction<void, I> F, BinaryOperation<ret_t<F, I>> Op>
auto accumulate_nonzero(
I first,
I last,
Op opr,
F fun,
const decltype(accumulate_nonempty(first, last, opr, fun))& zero
)
{
// Precondition: bounded_range(first, last)
// Precondition: partially_associative(opr)
ret_t<F, I> res;
do {
if (first == last) {
return zero;
}
res = fun(first);
first++;
} while (res == zero);
while (first != last) {
auto crnt = fun(first);
if (crnt != zero) {
res = opr(res, crnt);
}
first++;
}
return res;
}
} // namespace based
diff --git a/ include/based/algorithms/search/all.hpp b/ include/based/algorithms/search/all.hpp
@@ -0,0 +1,24 @@
#pragma once
#include "based/algorithms/search/find_if_not.hpp"
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
namespace based
{
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool all(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
return find_if_not(first, last, pred) == last;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool all_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, last);
return find_if_not_n(first, size, pred).second == 0;
}
} // namespace based
diff --git a/ include/based/algorithms/search/count.hpp b/ include/based/algorithms/search/count.hpp
@@ -0,0 +1,50 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
template<ReadableIterator I, Iterator J>
J count(I first, I last, const iter_value_t<I>& val, J cnt)
{
// Precondition: readable_bounded_range(first, last);
while (first != last) {
if (*first == val) {
cnt++;
}
first++;
}
return cnt;
}
template<ReadableIterator I>
iter_dist_t<I> count(I first, I last, const iter_value_t<I>& val)
{
// Precondition: readable_bounded_range(first, last);
return count(first, last, val, iter_dist_t<I> {0});
}
template<ReadableIterator I, Iterator J>
auto count_n(I first, iter_dist_t<I> size, const iter_value_t<I>& val, J cnt)
{
// Precondition: readable_weak_range(first, size);
while (size != 0) {
if (*first == val) {
cnt++;
}
size--;
first++;
}
return std::make_pair(first, cnt);
}
template<ReadableIterator I>
auto count_n(I first, iter_dist_t<I> size, const iter_value_t<I>& val)
{
// Precondition: readable_weak_range(first, size);
return count_n(first, size, val, iter_dist_t<I> {0});
}
} // namespace based
diff --git a/ include/based/algorithms/search/count_if.hpp b/ include/based/algorithms/search/count_if.hpp
@@ -0,0 +1,51 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
template<ReadableIterator I, IterUnaryPredicate<I> Pred, Iterator J>
J count_if(I first, I last, Pred pred, J cnt)
{
// Precondition: readable_bounded_range(first, last);
while (first != last) {
if (pred(*first)) {
cnt++;
}
first++;
}
return cnt;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
iter_dist_t<I> count_if(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
return count_if(first, last, pred, iter_dist_t<I> {0});
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred, Iterator J>
auto count_if_n(I first, iter_dist_t<I> size, Pred pred, J cnt)
{
// Precondition: readable_weak_range(first, size);
while (size != 0) {
if (pred(*first)) {
cnt++;
}
size--;
first++;
}
return std::make_pair(first, cnt);
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
auto count_if_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
return count_if_n(first, size, pred, iter_dist_t<I> {0});
}
} // namespace based
diff --git a/ include/based/algorithms/search/count_if_not.hpp b/ include/based/algorithms/search/count_if_not.hpp
@@ -0,0 +1,51 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
template<ReadableIterator I, IterUnaryPredicate<I> Pred, Iterator J>
J count_if_not(I first, I last, Pred pred, J cnt)
{
// Precondition: readable_bounded_range(first, last);
while (first != last) {
if (!pred(*first)) {
cnt++;
}
first++;
}
return cnt;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
iter_dist_t<I> count_if_not(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
return count_if_not(first, last, pred, iter_dist_t<I> {0});
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred, Iterator J>
auto count_if_not_n(I first, iter_dist_t<I> size, Pred pred, J cnt)
{
// Precondition: readable_weak_range(first, size);
while (size != 0) {
if (!pred(*first)) {
cnt++;
}
size--;
first++;
}
return std::make_pair(first, cnt);
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
auto count_if_not_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
return count_if_not_n(first, size, pred, iter_dist_t<I> {0});
}
} // namespace based
diff --git a/ include/based/algorithms/search/count_not.hpp b/ include/based/algorithms/search/count_not.hpp
@@ -0,0 +1,53 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
template<ReadableIterator I, Iterator J>
J count_not(I first, I last, const iter_value_t<I>& val, J cnt)
{
// Precondition: readable_bounded_range(first, last);
while (first != last) {
if (*first != val) {
cnt++;
}
first++;
}
return cnt;
}
template<ReadableIterator I>
iter_dist_t<I> count_not(I first, I last, const iter_value_t<I>& val)
{
// Precondition: readable_bounded_range(first, last);
return count_not(first, last, val, iter_dist_t<I> {0});
}
template<ReadableIterator I, Iterator J>
auto count_not_n(
I first, iter_dist_t<I> size, const iter_value_t<I>& val, J cnt
)
{
// Precondition: readable_weak_range(first, size);
while (size != 0) {
if (*first != val) {
cnt++;
}
size--;
first++;
}
return std::make_pair(first, cnt);
}
template<ReadableIterator I>
auto count_not_n(I first, iter_dist_t<I> size, const iter_value_t<I>& val)
{
// Precondition: readable_weak_range(first, size);
return count_not_n(first, size, val, iter_dist_t<I> {0});
}
} // namespace based
diff --git a/ include/based/algorithms/search/find.hpp b/ include/based/algorithms/search/find.hpp
@@ -0,0 +1,30 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
template<ReadableIterator I>
I find(I first, I lst, const iter_value_t<I>& val)
{
// Precondition: readable_bounded_range(first, last);
while (first != lst && *first != val) {
first++;
}
return first;
}
template<ReadableIterator I>
auto find_n(I first, iter_dist_t<I> size, const iter_value_t<I>& val)
{
// Precondition: readable_weak_range(first, size);
while (size != 0 && *first != val) {
size--;
first++;
}
return std::make_pair(first, size);
}
} // namespace based
diff --git a/ include/based/algorithms/search/find_adjacent_mismatch.hpp b/ include/based/algorithms/search/find_adjacent_mismatch.hpp
@@ -0,0 +1,68 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
template<ReadableIterator I, IterRelation<I> Rel>
I find_adjacent_mismatch(I first, I last, Rel rel)
{
// Precondition: readable_bounded_range(first, last)
if (first == last) {
return last;
}
auto crnt = *first;
first++;
while (first != last && rel(crnt, *first)) {
crnt = *first;
first++;
}
return first;
}
template<ReadableIterator I, IterRelation<I> Rel>
auto find_adjacent_mismatch_n(I first, iter_dist_t<I> size, Rel rel)
{
// Precondition: readable_bounded_range(first, last)
if (size == 0) {
return std::make_pair(first, size);
}
auto crnt = *first;
first++;
size--;
while (size != 0 && rel(crnt, *first)) {
crnt = *first;
size--;
first++;
}
return std::make_pair(first, size);
}
template<ReadableForwardIterator I, IterRelation<I> Rel>
I find_adjacent_mismatch_forward(I first, I last, Rel rel)
{
// Precondition: readable_bounded_range(first, last)
if (first == last) {
return last;
}
I tmp;
do {
tmp = first;
first++;
} while (first != last && rel(*tmp, *first));
return first;
}
} // namespace based
diff --git a/ include/based/algorithms/search/find_if.hpp b/ include/based/algorithms/search/find_if.hpp
@@ -0,0 +1,41 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
I find_if(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
while (first != last && !pred(*first)) {
first++;
}
return first;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
auto find_if_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
while (size != 0 && !pred(*first)) {
size--;
first++;
}
return std::make_pair(first, size);
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
I find_if_unguarded(I first, Pred pred)
{
// Precondition: readable_bounded_range(first, last) && some(f, d, p);
while (!pred(*first)) {
first++;
}
return first;
}
} // namespace based
diff --git a/ include/based/algorithms/search/find_if_not.hpp b/ include/based/algorithms/search/find_if_not.hpp
@@ -0,0 +1,41 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
I find_if_not(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
while (first != last && pred(*first)) {
first++;
}
return first;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
auto find_if_not_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
while (size != 0 && pred(*first)) {
size--;
first++;
}
return std::make_pair(first, size);
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
I find_if_not_unguarded(I first, Pred pred)
{
// Precondition: readable_bounded_range(first, last) && not_all(f, d, p);
while (pred(*first)) {
first++;
}
return first;
}
} // namespace based
diff --git a/ include/based/algorithms/search/find_mismatch.hpp b/ include/based/algorithms/search/find_mismatch.hpp
@@ -0,0 +1,75 @@
#pragma once
#include <tuple>
#include <utility>
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
template<ReadableIterator I0, ReadableIterator I1, IterRelation<I0> Rel>
requires BareSameAs<iter_value_t<I0>, iter_value_t<I1>>
auto find_mismatch(I0 first0, I0 last0, I1 first1, I1 last1, Rel rel)
{
// Precondition: readable_bounded_range(first0, last0)
// Precondition: readable_bounded_range(first1, last1)
while (first0 != last0 && first1 != last1 && rel(*first0, *first1)) {
first0++;
first1++;
}
return std::make_pair(first0, first1);
}
template<ReadableIterator I0, ReadableIterator I1, IterRelation<I0> Rel>
requires BareSameAs<iter_value_t<I0>, iter_value_t<I1>>
auto find_mismatch_n(
I0 first0, iter_dist_t<I0> size0, I1 first1, I1 last1, Rel rel
)
{
// Precondition: readable_weak_range(first0, size0)
// Precondition: readable_bounded_range(first1,last1)
while (size0 != 0 && first1 != last1 && rel(*first0, *first1)) {
first0++;
first1++;
size0--;
}
return std::make_tuple(first0, size0, first1);
}
template<ReadableIterator I0, ReadableIterator I1, IterRelation<I0> Rel>
requires BareSameAs<iter_value_t<I0>, iter_value_t<I1>>
auto find_mismatch_m(
I0 first0, I0 last0, I1 first1, iter_dist_t<I1> size1, Rel rel
)
{
// Precondition: readable_bounded_range(first0,last0)
// Precondition: readable_weak_range(first1, size1)
while (first0 != last0 && size1 != 0 && rel(*first0, *first1)) {
first0++;
first1++;
size1--;
}
return std::make_tuple(first0, first1, size1);
}
template<ReadableIterator I0, ReadableIterator I1, IterRelation<I0> Rel>
requires BareSameAs<iter_value_t<I0>, iter_value_t<I1>>
auto find_mismatch_n_m(
I0 first0, iter_dist_t<I0> size0, I1 first1, iter_dist_t<I1> size1, Rel rel
)
{
// Precondition: readable_weak_range(first0, size0)
// Precondition: readable_weak_range(first1, size1)
while (size0 != 0 && size1 != 0 && rel(*first0, *first1)) {
first0++;
first1++;
size0--;
size1--;
}
return std::make_tuple(first0, size0, first1, size1);
}
} // namespace based
diff --git a/ include/based/algorithms/search/find_not.hpp b/ include/based/algorithms/search/find_not.hpp
@@ -0,0 +1,30 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
template<ReadableIterator I>
I find_not(I first, I last, const iter_value_t<I>& val)
{
// Precondition: readable_bounded_range(first, last);
while (first != last && *first == val) {
first++;
}
return first;
}
template<ReadableIterator I>
auto find_not_n(I first, iter_dist_t<I> size, const iter_value_t<I>& val)
{
// Precondition: readable_weak_range(first, size);
while (size != 0 && *first == val) {
size--;
first++;
}
return std::make_pair(first, size);
}
} // namespace based
diff --git a/ include/based/algorithms/search/none.hpp b/ include/based/algorithms/search/none.hpp
@@ -0,0 +1,24 @@
#pragma once
#include "based/algorithms/search/find_if.hpp"
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
namespace based
{
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool none(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
return find_if(first, last, pred) == last;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool none_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
return find_if_n(first, size, pred).second == 0;
}
} // namespace based
diff --git a/ include/based/algorithms/search/not_all.hpp b/ include/based/algorithms/search/not_all.hpp
@@ -0,0 +1,24 @@
#pragma once
#include "based/algorithms/search/find_if_not.hpp"
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
namespace based
{
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool not_all(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
return first == last || find_if_not(first, last, pred) != last;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool not_all_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
return size == 0 || find_if_not_n(first, size, pred).second != 0;
}
} // namespace based
diff --git a/ include/based/algorithms/search/some.hpp b/ include/based/algorithms/search/some.hpp
@@ -0,0 +1,24 @@
#pragma once
#include "based/algorithms/search/find_if.hpp"
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
namespace based
{
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool some(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last);
return find_if(first, last, pred) != last;
}
template<ReadableIterator I, IterUnaryPredicate<I> Pred>
bool some_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_weak_range(first, size);
return find_if_n(first, size, pred).second != 0;
}
} // namespace based
diff --git a/ include/based/algorithms/sort/increasing_range.hpp b/ include/based/algorithms/sort/increasing_range.hpp
@@ -0,0 +1,31 @@
#pragma once
#include "based/algorithms/sort/relation_preserving_range.hpp"
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
#include "based/functional/predicate.hpp"
namespace based
{
template<ReadableIterator I, IterRelation<I> Rel>
bool increasing_range(I first, I last, Rel rel)
{
// Precondition: readable_bounded_range(first, last)
// Precondition: weak_ordering(rel);
return relation_preserving_range(
first, last, complement_of_converse<iter_value_t<I>>(rel)
);
}
template<ReadableIterator I, IterRelation<I> Rel>
bool increasing_range_n(I first, iter_dist_t<I> size, Rel rel)
{
// Precondition: readable_bounded_range(first, size)
// Precondition: weak_ordering(rel);
return relation_preserving_range_n(
first, size, complement_of_converse<iter_value_t<I>>(rel)
);
}
} // namespace based
diff --git a/ include/based/algorithms/sort/partition_point.hpp b/ include/based/algorithms/sort/partition_point.hpp
@@ -0,0 +1,40 @@
#pragma once
#include <cassert>
#include "based/algorithms/sort/partitioned.hpp"
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
namespace based
{
template<ReadableForwardIterator I, IterUnaryPredicate<I> Pred>
I partition_point_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_bounded_range(first, size)
assert(partitioned_n(first, size, pred));
while (size != 0) {
const auto hlf = size / 2;
I mid = first + hlf;
if (pred(*mid)) {
size = hlf;
} else {
size -= hlf + 1;
first = mid + 1;
}
}
return first;
}
template<ReadableForwardIterator I, IterUnaryPredicate<I> Pred>
I partition_point(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last)
assert(partitioned(first, last, pred));
return partition_point_n(first, last - first, pred);
}
} // namespace based
diff --git a/ include/based/algorithms/sort/partitioned.hpp b/ include/based/algorithms/sort/partitioned.hpp
@@ -0,0 +1,26 @@
#pragma once
#include "based/algorithms/search/find_if.hpp"
#include "based/algorithms/search/find_if_not.hpp"
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
namespace based
{
template<ReadableForwardIterator I, IterUnaryPredicate<I> Pred>
bool partitioned_n(I first, iter_dist_t<I> size, Pred pred)
{
// Precondition: readable_bounded_range(first, size)
std::tie(first, size) = find_if_n(first, size, pred);
return find_if_not_n(first, size, pred).second == 0;
}
template<ReadableForwardIterator I, IterUnaryPredicate<I> Pred>
bool partitioned(I first, I last, Pred pred)
{
// Precondition: readable_bounded_range(first, last)
return find_if_not(find_if(first, last, pred), last, pred) == last;
}
} // namespace based
diff --git a/ include/based/algorithms/sort/relation_preserving_range.hpp b/ include/based/algorithms/sort/relation_preserving_range.hpp
@@ -0,0 +1,26 @@
#pragma once
#include "based/algorithms/search/find_adjacent_mismatch.hpp"
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
namespace based
{
template<ReadableIterator I, IterRelation<I> Rel>
bool relation_preserving_range(I first, I last, Rel rel)
{
// Precondition: readable_bounded_range(first, last)
// Precondition: weak_ordering(rel);
return find_adjacent_mismatch(first, last, rel) == last;
}
template<ReadableIterator I, IterRelation<I> Rel>
bool relation_preserving_range_n(I first, iter_dist_t<I> size, Rel rel)
{
// Precondition: readable_bounded_range(first, size)
// Precondition: weak_ordering(rel);
return find_adjacent_mismatch_n(first, size, rel).second == 0;
}
} // namespace based
diff --git a/ include/based/algorithms/sort/strictly_increasing_range.hpp b/ include/based/algorithms/sort/strictly_increasing_range.hpp
@@ -0,0 +1,25 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate_iter.hpp"
namespace based
{
template<ReadableIterator I, IterRelation<I> Rel>
bool strictly_increasing_range(I first, I last, Rel rel)
{
// Precondition: readable_bounded_range(first, last)
// Precondition: weak_ordering(rel);
return relation_preserving_range(first, last, rel);
}
template<ReadableIterator I, IterRelation<I> Rel>
bool strictly_increasing_range_n(I first, iter_dist_t<I> size, Rel rel)
{
// Precondition: readable_bounded_range(first, size)
// Precondition: weak_ordering(rel);
return relation_preserving_range_n(first, size, rel);
}
} // namespace based
diff --git a/ include/based/concepts/callable.hpp b/ include/based/concepts/callable.hpp
@@ -0,0 +1,40 @@
#pragma once
#include "based/type_traits/remove/pointer.hpp"
#include "based/type_traits/signature.hpp"
namespace based
{
template<typename T>
struct callable;
template<typename T>
requires(std::is_function_v<T>)
struct callable<T> : public signature<std::decay_t<T>>
{
};
template<typename T>
requires(requires { &std::decay_t<T>::operator(); })
struct callable<T> : public signature<decltype(&T::operator())>
{
};
template<typename T>
requires(std::is_member_function_pointer_v<std::decay_t<T>>)
struct callable<T> : public signature<remove_pointer_t<T>>
{
};
template<typename T>
// concept Callable = is_instantiable_v<callable, T>;
concept Callable = true;
template<Callable T>
using callable_sig_t = typename callable<T>::signature::sig_type;
template<Callable T>
using callable_ret_t = typename callable<T>::signature::ret_type;
} // namespace based
diff --git a/ include/based/concepts/comparable/equal.hpp b/ include/based/concepts/comparable/equal.hpp
@@ -0,0 +1,21 @@
#pragma once
#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"
namespace based
{
// clang-format off
template<typename T>
concept EqualComparable = requires(
const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs
) {
{ lhs == rhs } -> SameAs<bool>;
{ rhs == lhs } -> SameAs<bool>;
};
// clang-format on
} // namespace based
diff --git a/ include/based/concepts/comparable/equality.hpp b/ include/based/concepts/comparable/equality.hpp
@@ -0,0 +1,19 @@
#pragma once
#include "based/concepts/comparable/equal.hpp"
#include "based/concepts/comparable/not_equal.hpp"
namespace based
{
// clang-format off
template<typename T>
concept EqualityComparable = requires {
requires(EqualComparable<T>);
requires(NotEqualComparable<T>);
};
// clang-format on
} // namespace based
diff --git a/ include/based/concepts/comparable/greater.hpp b/ include/based/concepts/comparable/greater.hpp
@@ -0,0 +1,21 @@
#pragma once
#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"
namespace based
{
// clang-format off
template<typename T>
concept GreaterComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs > rhs} -> SameAs<bool>;
{rhs > lhs} -> SameAs<bool>;
};
// clang-format on
} // namespace based
diff --git a/ include/based/concepts/comparable/greater_equal.hpp b/ include/based/concepts/comparable/greater_equal.hpp
@@ -0,0 +1,21 @@
#pragma once
#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"
namespace based
{
// clang-format off
template<typename T>
concept LessEqualComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs <= rhs} -> SameAs<bool>;
{rhs <= lhs} -> SameAs<bool>;
};
// clang-format on
} // namespace based
diff --git a/ include/based/concepts/comparable/less.hpp b/ include/based/concepts/comparable/less.hpp
@@ -0,0 +1,21 @@
#pragma once
#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"
namespace based
{
// clang-format off
template<typename T>
concept LessComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs < rhs} -> SameAs<bool>;
{rhs < lhs} -> SameAs<bool>;
};
// clang-format on
} // namespace based
diff --git a/ include/based/concepts/comparable/less_equal.hpp b/ include/based/concepts/comparable/less_equal.hpp
@@ -0,0 +1,21 @@
#pragma once
#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"
namespace based
{
// clang-format off
template<typename T>
concept GreaterEqualComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs >= rhs} -> SameAs<bool>;
{rhs >= lhs} -> SameAs<bool>;
};
// clang-format on
} // namespace based
diff --git a/ include/based/concepts/comparable/not_equal.hpp b/ include/based/concepts/comparable/not_equal.hpp
@@ -0,0 +1,21 @@
#pragma once
#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"
namespace based
{
// clang-format off
template<typename T>
concept NotEqualComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs != rhs} -> SameAs<bool>;
{rhs != lhs} -> SameAs<bool>;
};
// clang-format on
} // namespace based
diff --git a/ include/based/concepts/is/convertable.hpp b/ include/based/concepts/is/convertable.hpp
@@ -0,0 +1,15 @@
#pragma once
#include "based/type_traits/is/convertable.hpp"
#include "based/utility/declvar.hpp"
namespace based
{
template<class From, class To>
concept ConvertibleTo = requires {
requires(is_convertible_v<From, To>);
static_cast<To>(declval<From>());
};
} // namespace based
diff --git a/ include/based/concepts/is/invocable.hpp b/ include/based/concepts/is/invocable.hpp
@@ -0,0 +1,11 @@
#pragma once
#include <concepts>
namespace based
{
template<typename P, typename... Args>
concept Invocable = std::invocable<P, Args...>;
} // namespace based
diff --git a/ include/based/concepts/is/regular.hpp b/ include/based/concepts/is/regular.hpp
@@ -0,0 +1,16 @@
#pragma once
#include <concepts>
#include "based/type_traits/remove/cvref.hpp"
namespace based
{
template<typename T>
concept Regular = std::regular<T>;
template<typename T>
concept BareRegular = Regular<remove_cvref_t<T>>;
} // namespace based
diff --git a/ include/based/concepts/is/same.hpp b/ include/based/concepts/is/same.hpp
@@ -0,0 +1,15 @@
#pragma once
#include "based/type_traits/is/same.hpp"
#include "based/type_traits/remove/cvref.hpp"
namespace based
{
template<class T, class U>
concept SameAs = is_same_v<T, U> && is_same_v<U, T>;
template<class T, class U>
concept BareSameAs = SameAs<remove_cvref_t<T>, remove_cvref_t<U>>;
} // namespace based
diff --git a/ include/based/concepts/is/semiregular.hpp b/ include/based/concepts/is/semiregular.hpp
@@ -0,0 +1,16 @@
#pragma once
#include <concepts>
#include "based/type_traits/remove/cvref.hpp"
namespace based
{
template<typename T>
concept Semiregular = std::semiregular<T>;
template<typename T>
concept BareSemiregular = Semiregular<remove_cvref_t<T>>;
} // namespace based
diff --git a/ include/based/concepts/iterator.hpp b/ include/based/concepts/iterator.hpp
@@ -0,0 +1,51 @@
#pragma once
#include "based/concepts/is/regular.hpp"
#include "based/concepts/is/same.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
// clang-format off
template<typename T>
concept Readable = requires(T val) {
requires(Regular<T>);
typename iter_value_t<T>;
{
*val
} -> BareSameAs<iter_value_t<T>>;
};
template<typename T>
concept Iterator = requires(T val) {
requires(Regular<T>);
typename iter_dist_t<T>;
{
++val
} -> BareSameAs<T>;
// successor is not necessarily regular
};
template<typename T>
concept ForwardIterator = requires {
requires(Iterator<T>);
// successor is regular
};
template<typename T>
concept ReadableIterator = requires {
requires(Iterator<T>);
requires(Readable<T>);
};
template<typename T>
concept ReadableForwardIterator = requires {
requires(ForwardIterator<T>);
requires(Readable<T>);
};
// clang-format on
} // namespace based
diff --git a/ include/based/concepts/ordered/totally.hpp b/ include/based/concepts/ordered/totally.hpp
@@ -0,0 +1,25 @@
#pragma once
#include "based/concepts/comparable/equality.hpp"
#include "based/concepts/comparable/greater.hpp"
#include "based/concepts/comparable/greater_equal.hpp"
#include "based/concepts/comparable/less.hpp"
#include "based/concepts/comparable/less_equal.hpp"
namespace based
{
// clang-format off
template<typename T>
concept totally_ordered = requires {
requires(EqualityComparable<T>);
requires(LessComparable<T>);
requires(GreaterComparable<T>);
requires(LessEqualComparable<T>);
requires(GreaterEqualComparable<T>);
};
// clang-format on
} // namespace based
diff --git a/ include/based/concepts/procedure/domain.hpp b/ include/based/concepts/procedure/domain.hpp
@@ -0,0 +1,40 @@
#pragma once
#include <tuple>
#include "based/concepts/is/regular.hpp"
#include "based/concepts/is/same.hpp"
#include "based/concepts/is/semiregular.hpp"
#include "based/type_traits/is/const.hpp"
#include "based/type_traits/remove/cvref.hpp"
#include "based/type_traits/remove/pointer.hpp"
#include "based/type_traits/remove/reference.hpp"
#include "based/types/types.hpp"
namespace based
{
template<typename T>
concept Input = SameAs<T, remove_cvref_t<remove_pointer_t<T>>>
|| is_const_v<remove_reference_t<T>> || is_const_v<remove_pointer_t<T>>;
template<size_t idx, typename... Args>
requires(idx < sizeof...(Args))
using elem_t = std::tuple_element_t<idx, std::tuple<Args...>>;
template<typename... Args>
concept SemiregularDomain = (Semiregular<remove_cvref_t<Args>> && ...);
template<typename... Args>
concept RegularDomain = (Regular<remove_cvref_t<Args>> && ...);
template<typename... Args>
concept InputDomain = (Input<Args> && ...);
template<typename... Args>
concept HomogeneousDomain = (SameAs<elem_t<0, Args...>, Args> && ...);
template<typename P, typename... Args>
using ret_t = std::invoke_result_t<P, Args...>;
} // namespace based
diff --git a/ include/based/concepts/procedure/function.hpp b/ include/based/concepts/procedure/function.hpp
@@ -0,0 +1,28 @@
#pragma once
#include "based/concepts/procedure/domain.hpp"
#include "based/concepts/procedure/procedure.hpp"
namespace based
{
template<typename P, typename Ret, typename... Args>
concept FunctionalProcedure = requires {
requires(RegularProcedure<P, Ret, Args...>);
requires(InputDomain<Args...>);
};
template<typename P, typename Ret, typename Arg>
concept UnaryFunction = requires {
requires(FunctionalProcedure<P, Ret, Arg>);
requires(UnaryProcedure<P, Ret, Arg>);
};
template<typename P, typename Ret, typename... Args>
concept HomogeneousFunction = requires {
requires(FunctionalProcedure<P, Ret, Args...>);
requires(sizeof...(Args) > 0);
requires(HomogeneousDomain<Args...>);
};
} // namespace based
diff --git a/ include/based/concepts/procedure/function_iter.hpp b/ include/based/concepts/procedure/function_iter.hpp
@@ -0,0 +1,27 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/function.hpp"
namespace based
{
template<typename P, typename Ret, typename I>
concept IterFunctionalProcedure = requires {
requires(Iterator<I>);
requires(FunctionalProcedure<P, Ret, iter_value_t<I>>);
};
template<typename P, typename Ret, typename I>
concept IterUnaryFunction = requires {
requires(Iterator<I>);
requires(UnaryFunction<P, Ret, iter_value_t<I>>);
};
template<typename P, typename Ret, typename I>
concept IterHomogeneousFunction = requires {
requires(Iterator<I>);
requires(HomogeneousFunction<P, Ret, iter_value_t<I>>);
};
} // namespace based
diff --git a/ include/based/concepts/procedure/operation.hpp b/ include/based/concepts/procedure/operation.hpp
@@ -0,0 +1,23 @@
#pragma once
#include "based/concepts/procedure/function.hpp"
namespace based
{
template<typename P, typename... Args>
concept Operation = HomogeneousFunction<P, elem_t<0, Args...>, Args...>;
template<typename P, typename Ret, typename Arg>
concept Transformation = requires {
requires(Operation<P, Ret, Arg>);
requires(UnaryFunction<P, Ret, Arg>);
};
template<typename P, typename Arg>
concept BinaryOperation = Operation<P, Arg, Arg>;
template<typename P, typename Arg>
concept AssociativeBinaryOperation = Operation<P, Arg, Arg>;
} // namespace based
diff --git a/ include/based/concepts/procedure/operation_iter.hpp b/ include/based/concepts/procedure/operation_iter.hpp
@@ -0,0 +1,21 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/operation.hpp"
namespace based
{
template<typename P, typename Ret, typename... I>
concept IterOperation = requires {
requires(Iterator<I> && ...);
requires(Operation<P, iter_value_t<I>...>);
};
template<typename P, typename Ret, typename I>
concept IterBinaryOperation = requires {
requires(Iterator<I>);
requires(BinaryOperation<P, iter_value_t<I>>);
};
} // namespace based
diff --git a/ include/based/concepts/procedure/predicate.hpp b/ include/based/concepts/procedure/predicate.hpp
@@ -0,0 +1,26 @@
#pragma once
#include "based/concepts/procedure/function.hpp"
namespace based
{
template<typename P, typename... Args>
concept Predicate = FunctionalProcedure<P, bool, Args...>;
template<typename P, typename... Args>
concept HomogeneousPredicate = requires {
requires(Predicate<P, Args...>);
requires(HomogeneousFunction<P, bool, Args...>);
};
template<typename P, typename Arg>
concept UnaryPredicate = requires {
requires(Predicate<P, Arg>);
requires(UnaryFunction<P, bool, Arg>);
};
template<typename P, typename Arg>
concept Relation = HomogeneousPredicate<P, Arg, Arg>;
} // namespace based
diff --git a/ include/based/concepts/procedure/predicate_iter.hpp b/ include/based/concepts/procedure/predicate_iter.hpp
@@ -0,0 +1,33 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate.hpp"
namespace based
{
template<typename P, typename... I>
concept IterPredicate = requires {
requires(Iterator<I> && ...);
requires(Predicate<P, iter_value_t<I>...>);
};
template<typename P, typename... I>
concept IterHomogeneousPredicate = requires {
requires(Iterator<I> && ...);
requires(HomogeneousPredicate<P, iter_value_t<I>...>);
};
template<typename P, typename I>
concept IterUnaryPredicate = requires {
requires(Iterator<I>);
requires(UnaryPredicate<P, iter_value_t<I>>);
};
template<typename P, typename I>
concept IterRelation = requires {
requires(Iterator<I>);
requires(Relation<P, iter_value_t<I>>);
};
} // namespace based
diff --git a/ include/based/concepts/procedure/procedure.hpp b/ include/based/concepts/procedure/procedure.hpp
@@ -0,0 +1,48 @@
#pragma once
#include "based/concepts/is/convertable.hpp"
#include "based/concepts/is/invocable.hpp"
#include "based/concepts/is/regular.hpp"
#include "based/concepts/procedure/domain.hpp"
#include "based/type_traits/integral_constant.hpp"
#include "based/type_traits/invoke/result.hpp"
namespace based
{
namespace detail
{
// clang-format off
template<typename P, typename Sig> struct procedure : public false_type {};
template<typename P, typename Ret, typename... Args>
requires (Invocable<P, Args...> && ConvertibleTo<invoke_result_t<P, Args...>, Ret>)
struct procedure<P, Ret(Args...)> : public true_type {};
template<typename P, typename... Args>
requires (Invocable<P, Args...>)
struct procedure<P, void(Args...)> : public true_type {};
template<typename P, typename Ret, typename... Args>
static constexpr bool procedure_v = procedure<P, Ret(Args...)>::value;
// clang-format on
} // namespace detail
template<typename P, typename Ret, typename... Args>
concept Procedure = detail::procedure_v<P, Ret, Args...>;
template<typename P, typename Ret, typename Arg>
concept UnaryProcedure = Procedure<P, Ret, Arg>;
template<typename P, typename Ret, typename... Args>
concept RegularProcedure = requires {
requires(Procedure<P, Ret, Args...>);
requires(RegularDomain<Args...>);
requires(Regular<ret_t<P, Args...>>);
};
} // namespace based
diff --git a/ include/based/concepts/procedure/procedure_iter.hpp b/ include/based/concepts/procedure/procedure_iter.hpp
@@ -0,0 +1,27 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/procedure.hpp"
namespace based
{
template<typename P, typename Ret, typename I>
concept IterProcedure = requires {
requires(Iterator<I>);
requires(Procedure<P, Ret, iter_value_t<I>>);
};
template<typename P, typename Ret, typename I>
concept IterUnaryProcedure = requires {
requires(Iterator<I>);
requires(UnaryProcedure<P, Ret, iter_value_t<I>>);
};
template<typename P, typename Ret, typename I>
concept IterRegularProcedure = requires {
requires(Iterator<I>);
requires(RegularProcedure<P, Ret, iter_value_t<I>>);
};
} // namespace based
diff --git a/ include/based/count.hpp b/ include/based/count.hpp
@@ -0,0 +1,50 @@
#pragma once
#include "based/concepts/iterator.hpp"
#include "based/type_traits/iterator.hpp"
namespace based
{
template<ReadableIterator I, Iterator J>
J count(I first, I last, const iter_value_t<I>& val, J cnt)
{
// Precondition: readable_bounded_range(first, last);
while (first != last) {
if (*first == val) {
cnt++;
}
first++;
}
return cnt;
}
template<ReadableIterator I>
iter_dist_t<I> count(I first, I last, const iter_value_t<I>& val)
{
// Precondition: readable_bounded_range(first, last);
return count(first, last, val, iter_dist_t<I> {0});
}
template<ReadableIterator I, Iterator J>
auto count_n(I first, iter_dist_t<I> size, const iter_value_t<I>& val, J cnt)
{
// Precondition: readable_weak_range(first, size);
while (size != 0) {
if (*first == val) {
cnt++;
}
size--;
first++;
}
return std::make_pair(first, cnt);
}
template<ReadableIterator I>
auto count_n(I first, iter_dist_t<I> size, const iter_value_t<I>& val)
{
// Precondition: readable_weak_range(first, size);
return count_n(first, size, val, iter_dist_t<I> {0});
}
} // namespace based
diff --git a/ include/based/enum.hpp b/ include/based/enum.hpp
@@ -1,124 +0,0 @@
#pragma once
#include <array>
#include <cassert>
#include "based/macros.hpp"
// NOLINTBEGIN(*macro-usage*)
#define BASED_LIST_ELEM_STR(Name, Index) #Name,
#define BASED_LIST_STR(...) BASED_FOREACH(BASED_LIST_ELEM_STR, __VA_ARGS__)
// NOLINTNEXTLINE(*macro-parentheses*)
#define BASED_SET(var, val) decltype(var) var = decltype(var) {val};
#define BASED_DETAIL_ENUM_DECLARE_VAL(Name, Index) static const type Name;
#define BASED_DETAIL_ENUM_DECLARE_CASE(Qualifier, Name, Index) \
case Qualifier::Name.value: \
return Name;
#define BASED_DETAIL_ENUM_DEFINE_VAL(Qualifier, Name, Index) \
inline constexpr BASED_SET( \
Qualifier::Name, Qualifier::type::size - (Index) - 1 \
)
#define BASED_DETAIL_ENUM_DEFINE_VALS(Qualifier, ...) \
BASED_FOREACH_1(Qualifier, BASED_DETAIL_ENUM_DEFINE_VAL, __VA_ARGS__)
#define BASED_DETAIL_ENUM_DEFINE_NAMES(Qualifier, ...) \
inline constexpr BASED_SET( \
Qualifier::type::names, BASED_LIST_STR(__VA_ARGS__) \
)
#define BASED_DETAIL_ENUM_DEFINE_GET(Qualifier, Type, ...) \
inline const Qualifier::type& Qualifier::type::get(Type idx) \
{ \
/* NOLINTNEXTLINE(*paths-covered*) */ \
switch (idx) { \
BASED_FOREACH_1(Qualifier, BASED_DETAIL_ENUM_DECLARE_CASE, __VA_ARGS__) \
default: \
break; \
} \
assert(0); /* NOLINT(*assert*,cert-dcl03-c) */ \
}
#define BASED_DETAIL_ENUM_DEFINE(Qualifier, Type, ...) \
BASED_DETAIL_ENUM_DEFINE_VALS(Qualifier, __VA_ARGS__) \
BASED_DETAIL_ENUM_DEFINE_NAMES(Qualifier, __VA_ARGS__) \
BASED_DETAIL_ENUM_DEFINE_GET(Qualifier, Type, __VA_ARGS__)
#define BASED_ENUM_DECLARE_ARRAY(Name) \
template<typename T> \
class array : public std::array<T, Name::type::size> \
{ \
using base = std::array<T, Name::type::size>; \
using base::operator[]; \
\
public: \
constexpr array() noexcept \
: base() \
{ \
} \
\
template<class... Args> \
requires(sizeof...(Args) == Name::type::size) \
constexpr explicit array(Args&&... args \
) noexcept /* NOLINTNEXTLINE(*decay*) */ \
: base({std::forward<Args>(args)...}) \
{ \
} \
\
const T& operator[](Name::type val) const \
{ \
return base::operator[](val.value); \
} \
\
T& operator[](Name::type val) \
{ \
return base::operator[](val.value); \
} \
};
#define BASED_ENUM_DECLARE(Name, Type, ...) \
struct Name \
{ \
class type \
{ \
friend Name; \
\
constexpr explicit type(Type enum_value) \
: value(enum_value) \
{ \
} \
\
public: \
using size_t = Type; \
static constexpr size_t size = \
BASED_NUMARGS(BASED_LIST_STR(__VA_ARGS__)); \
\
BASED_ENUM_DECLARE_ARRAY(Name) \
static const array<const char*> names; \
\
static const type& get(Type idx); \
\
friend bool operator==(type lhs, type rhs) \
{ \
return lhs.value == rhs.value; \
} \
\
Type value; \
}; \
\
BASED_FOREACH(BASED_DETAIL_ENUM_DECLARE_VAL, __VA_ARGS__) \
};
#define BASED_ENUM_DEFINE(Name, Type, ...) \
BASED_DETAIL_ENUM_DEFINE(Name, Type, __VA_ARGS__)
#define BASED_DEFINE_CLASS_ENUM(Class, Name, Type, ...) \
BASED_DETAIL_ENUM_DEFINE(Class::Name, Type, __VA_ARGS__)
// NOLINTEND(*macro-usage*)
diff --git a/ include/based/enum/enum.hpp b/ include/based/enum/enum.hpp
@@ -0,0 +1,124 @@
#pragma once
#include <array>
#include <cassert>
#include "based/macros.hpp"
// NOLINTBEGIN(*macro-usage*)
#define BASED_LIST_ELEM_STR(Name, Index) #Name,
#define BASED_LIST_STR(...) BASED_FOREACH(BASED_LIST_ELEM_STR, __VA_ARGS__)
// NOLINTNEXTLINE(*macro-parentheses*)
#define BASED_SET(var, val) decltype(var) var = decltype(var) {val};
#define BASED_DETAIL_ENUM_DECLARE_VAL(Name, Index) static const type Name;
#define BASED_DETAIL_ENUM_DECLARE_CASE(Qualifier, Name, Index) \
case Qualifier::Name.value: \
return Name;
#define BASED_DETAIL_ENUM_DEFINE_VAL(Qualifier, Name, Index) \
inline constexpr BASED_SET( \
Qualifier::Name, Qualifier::type::size - (Index) - 1 \
)
#define BASED_DETAIL_ENUM_DEFINE_VALS(Qualifier, ...) \
BASED_FOREACH_1(Qualifier, BASED_DETAIL_ENUM_DEFINE_VAL, __VA_ARGS__)
#define BASED_DETAIL_ENUM_DEFINE_NAMES(Qualifier, ...) \
inline constexpr BASED_SET( \
Qualifier::type::names, BASED_LIST_STR(__VA_ARGS__) \
)
#define BASED_DETAIL_ENUM_DEFINE_GET(Qualifier, Type, ...) \
inline const Qualifier::type& Qualifier::type::get(Type idx) \
{ \
/* NOLINTNEXTLINE(*paths-covered*) */ \
switch (idx) { \
BASED_FOREACH_1(Qualifier, BASED_DETAIL_ENUM_DECLARE_CASE, __VA_ARGS__) \
default: \
break; \
} \
assert(0); /* NOLINT(*assert*,cert-dcl03-c) */ \
}
#define BASED_DETAIL_ENUM_DEFINE(Qualifier, Type, ...) \
BASED_DETAIL_ENUM_DEFINE_VALS(Qualifier, __VA_ARGS__) \
BASED_DETAIL_ENUM_DEFINE_NAMES(Qualifier, __VA_ARGS__) \
BASED_DETAIL_ENUM_DEFINE_GET(Qualifier, Type, __VA_ARGS__)
#define BASED_ENUM_DECLARE_ARRAY(Name) \
template<typename T> \
class array : public std::array<T, Name::type::size> \
{ \
using base = std::array<T, Name::type::size>; \
using base::operator[]; \
\
public: \
constexpr array() noexcept \
: base() \
{ \
} \
\
template<class... Args> \
requires(sizeof...(Args) == Name::type::size) \
constexpr explicit array(Args&&... args \
) noexcept /* NOLINTNEXTLINE(*decay*) */ \
: base({std::forward<Args>(args)...}) \
{ \
} \
\
const T& operator[](Name::type val) const \
{ \
return base::operator[](val.value); \
} \
\
T& operator[](Name::type val) \
{ \
return base::operator[](val.value); \
} \
};
#define BASED_ENUM_DECLARE(Name, Type, ...) \
struct Name \
{ \
class type \
{ \
friend Name; \
\
constexpr explicit type(Type enum_value) \
: value(enum_value) \
{ \
} \
\
public: \
using size_t = Type; \
static constexpr size_t size = \
BASED_NUMARGS(BASED_LIST_STR(__VA_ARGS__)); \
\
BASED_ENUM_DECLARE_ARRAY(Name) \
static const array<const char*> names; \
\
static const type& get(Type idx); \
\
friend bool operator==(type lhs, type rhs) \
{ \
return lhs.value == rhs.value; \
} \
\
Type value; \
}; \
\
BASED_FOREACH(BASED_DETAIL_ENUM_DECLARE_VAL, __VA_ARGS__) \
};
#define BASED_ENUM_DEFINE(Name, Type, ...) \
BASED_DETAIL_ENUM_DEFINE(Name, Type, __VA_ARGS__)
#define BASED_DEFINE_CLASS_ENUM(Class, Name, Type, ...) \
BASED_DETAIL_ENUM_DEFINE(Class::Name, Type, __VA_ARGS__)
// NOLINTEND(*macro-usage*)
diff --git a/ include/based/functional.hpp b/ include/based/functional.hpp
@@ -1,96 +0,0 @@
#pragma once
#include <cassert>
#include "based/type_traits.hpp"
namespace based
{
template<typename Function, typename... CapturedArgs>
class curried
{
template<typename FFunction, typename... FCapturedArgs>
friend class curried;
Function m_function;
std::tuple<CapturedArgs...> m_captured;
curried(Function function, std::tuple<CapturedArgs...> args)
: m_function(function)
, m_captured(std::move(args))
{
}
public:
curried(Function function, CapturedArgs&&... args) // NOLINT(*explicit*)
: m_function(function)
, m_captured(std::forward<CapturedArgs>(args)...)
{
}
template<typename... NewArgs>
auto operator()(NewArgs&&... args) const
{
auto all_args = std::tuple_cat(
m_captured, std::make_tuple(std::forward<NewArgs>(args)...)
);
if constexpr (std::is_invocable_v<Function, CapturedArgs..., NewArgs...>) {
return std::apply(m_function, std::move(all_args));
} else {
return curried<Function, CapturedArgs..., NewArgs...> {
m_function, std::move(all_args)
};
}
}
};
/* ----- Relation modifiers ----- */
template<typename T, Relation<T> Rel>
auto complement(Rel rel)
{
return [=](const T& lhs, const T& rhs)
{
return !rel(lhs, rhs);
};
}
template<typename T, Relation<T> Rel>
auto converse(Rel rel)
{
return [=](const T& lhs, const T& rhs)
{
return rel(rhs, lhs);
};
}
template<typename T, Relation<T> Rel>
auto complement_of_converse(Rel rel)
{
return [=](const T& lhs, const T& rhs)
{
return !rel(rhs, lhs);
};
}
template<typename T, Relation<T> Rel>
auto lower_bound_predicate(const T& goal, Rel rel)
{
return [=](const T& val)
{
return !rel(val, goal);
};
}
template<typename T, Relation<T> Rel>
auto upper_bound_predicate(const T& goal, Rel rel)
{
return [=](const T& val)
{
return rel(goal, val);
};
}
} // namespace based
diff --git a/ include/based/functional/curry.hpp b/ include/based/functional/curry.hpp
@@ -0,0 +1,47 @@
#pragma once
#include <tuple>
namespace based
{
template<typename Function, typename... CapturedArgs>
class curried
{
template<typename FFunction, typename... FCapturedArgs>
friend class curried;
Function m_function;
std::tuple<CapturedArgs...> m_captured;
curried(Function function, std::tuple<CapturedArgs...> args)
: m_function(function)
, m_captured(std::move(args))
{
}
public:
curried(Function function, CapturedArgs&&... args) // NOLINT(*explicit*)
: m_function(function)
, m_captured(std::forward<CapturedArgs>(args)...)
{
}
template<typename... NewArgs>
auto operator()(NewArgs&&... args) const
{
auto all_args = std::tuple_cat(
m_captured, std::make_tuple(std::forward<NewArgs>(args)...)
);
if constexpr (std::is_invocable_v<Function, CapturedArgs..., NewArgs...>) {
return std::apply(m_function, std::move(all_args));
} else {
return curried<Function, CapturedArgs..., NewArgs...> {
m_function, std::move(all_args)
};
}
}
};
} // namespace based
diff --git a/ include/based/functional/function.hpp b/ include/based/functional/function.hpp
@@ -0,0 +1,81 @@
#pragma once
#include <functional>
#include "based/concepts/is/same.hpp"
#include "based/type_traits/signature.hpp"
#include "based/types/types.hpp"
#include "based/utility/buffer.hpp"
namespace based
{
/* ----- Function Wrapper with type erasure ----- */
template<
typename Signature,
size_t size = sizeof(void*),
size_t alignment = alignof(void*)>
class function;
template<size_t size, size_t alignment, typename Ret, typename... Args>
class function<Ret(Args...), size, alignment>
{
buffer<size, alignment> m_space;
using executor_t = Ret (*)(Args..., void*);
static constexpr Ret default_executor(Args... /* args */, void* /* func */)
{
throw std::bad_function_call();
}
constexpr static executor_t m_default_executor = default_executor;
executor_t m_executor = m_default_executor;
template<typename Callable>
static Ret executor(Args... args, void* func)
{
return std::invoke(
*static_cast<function*>(func)->m_space.template as<Callable>(),
std::forward<Args>(args)...
);
}
public:
function() = default;
template<typename CallableArg, typename Callable = std::decay_t<CallableArg>>
requires(requires {
!SameAs<function, Callable>;
sizeof(Callable) <= size;
alignof(Callable) <= alignment;
std::is_trivially_destructible_v<Callable>;
std::is_trivially_copyable_v<Callable>;
})
function(CallableArg&& callable) // NOLINT(*explicit*)
: m_space(
std::in_place_type<Callable>, std::forward<CallableArg>(callable)
)
, m_executor(executor<Callable>)
{
}
template<typename... CallArgs>
Ret operator()(CallArgs&&... callargs) const
{
return this->m_executor(
std::forward<CallArgs>(callargs)...,
const_cast<function*>(this) // NOLINT(*const-cast*)
);
}
};
template<typename Ret, typename... Args>
function(Ret (*)(Args...)) -> function<Ret(Args...)>;
template<typename F, typename Sig = signature_t<F, decltype(&F::operator())>>
function(F) -> function<Sig>;
} // namespace based
diff --git a/ include/based/functional/overload.hpp b/ include/based/functional/overload.hpp
@@ -0,0 +1,17 @@
#pragma once
namespace based
{
/* ----- Overload Lambdas ----- */
template<typename... F>
struct overload : public F...
{
using F::operator()...;
};
template<typename... F>
overload(F&&...) -> overload<F...>;
} // namespace based
diff --git a/ include/based/functional/predicate.hpp b/ include/based/functional/predicate.hpp
@@ -0,0 +1,35 @@
#pragma once
#include "based/concepts/procedure/predicate.hpp"
namespace based
{
template<typename T, Relation<T> Rel>
auto complement(Rel rel)
{
return [=](const T& lhs, const T& rhs)
{
return !rel(lhs, rhs);
};
}
template<typename T, Relation<T> Rel>
auto converse(Rel rel)
{
return [=](const T& lhs, const T& rhs)
{
return rel(rhs, lhs);
};
}
template<typename T, Relation<T> Rel>
auto complement_of_converse(Rel rel)
{
return [=](const T& lhs, const T& rhs)
{
return !rel(rhs, lhs);
};
}
} // namespace based
diff --git a/ include/based/instrumentation.hpp b/ include/based/instrumentation.hpp
@@ -1,375 +0,0 @@
#pragma once
#include <algorithm>
#include <array>
#include <chrono>
#include <cmath>
#include <concepts>
#include <cstddef>
#include <cstdint>
#include <format>
#include <iostream>
#include <numbers>
#include <numeric>
#include <random>
#include <vector>
#include "based/enum.hpp"
namespace based
{
class table
{
public:
explicit table(std::size_t min_wth)
: m_min_wth(min_wth)
{
}
template<typename I>
void print_header(I first, I last)
{
while (first != last) {
std::cout << std::format("{:^{}} | ", *first, m_min_wth);
first++;
}
std::cout << '\n';
}
template<typename I>
void print_row(I first, I last, std::size_t precision)
{
std::cout << std::format("{:{}} | ", *first++, m_min_wth);
while (first != last) {
std::cout << std::format("{:{}.{}f} | ", *first, m_min_wth, precision);
first++;
}
std::cout << '\n';
}
private:
std::size_t m_min_wth;
};
inline auto dont_normalize(double x, double /* n */)
{
return x;
}
inline auto normalize_n(double x, double n)
{
return x / n;
}
inline auto normalize_nlogn(double x, double n)
{
return x / (n * (std::log(n) / std::numbers::ln2));
}
inline auto normalize_nlogn1(double x, double n)
{
return x / (n * std::log(n) - n);
}
struct instrumented_base
{
BASED_ENUM_DECLARE(
op,
std::uint8_t,
n,
ctor_default,
ctor_value,
ctor_copy,
ctor_move,
asgn_copy,
asgn_move,
destructor,
equality,
comparison
)
static op::type::array<double> counts;
static void initialize(std::size_t size)
{
std::fill(std::begin(counts), std::end(counts), 0.0);
counts[op::n] = static_cast<double>(size);
}
};
BASED_DEFINE_CLASS_ENUM(
instrumented_base,
op,
std::uint8_t,
n,
ctor_default,
ctor_value,
ctor_copy,
ctor_move,
asgn_copy,
asgn_move,
destructor,
equality,
comparison
)
template<typename T>
requires std::semiregular<T>
struct instrumented : instrumented_base
{
using value_type = T;
value_type value;
instrumented(const value_type& val) // NOLINT(*explicit*)
: value(std::move(val))
{
++counts[op::ctor_value];
;
}
instrumented(value_type&& val) // NOLINT(*explicit*)
: value(std::move(val))
{
++counts[op::ctor_value];
;
}
// Semiregular:
instrumented()
{
++counts[op::ctor_default];
;
}
instrumented(const instrumented& val)
: value(val.value)
{
++counts[op::ctor_copy];
;
}
instrumented(instrumented&& val) noexcept
: value(std::move(val.value))
{
++counts[op::ctor_move];
;
}
// self assign should be handled by the value_type
instrumented& operator=(const instrumented& val) // NOLINT(*cert-oop54-cpp*)
{
++counts[op::asgn_copy];
;
value = val.value;
return *this;
}
// self assign should be handled by the value_type
instrumented& operator=(instrumented&& val
) noexcept // NOLINT(*cert-oop54-cpp*)
{
++counts[op::asgn_move];
;
value = std::move(val.value);
return *this;
}
~instrumented()
{
++counts[op::destructor];
;
}
// Regular
friend bool operator==(const instrumented& lhs, const instrumented& rhs)
{
++counts[op::equality];
;
return lhs.value == rhs.value;
}
friend bool operator!=(const instrumented& lhs, const instrumented& rhs)
{
return !(lhs == rhs);
}
// TotallyOrdered
friend bool operator<(const instrumented& lhs, const instrumented& rhs)
{
++counts[op::comparison];
;
return lhs.value < rhs.value;
}
friend bool operator>(const instrumented& lhs, const instrumented& rhs)
{
return rhs < lhs;
}
friend bool operator<=(const instrumented& lhs, const instrumented& rhs)
{
return !(rhs < lhs);
}
friend bool operator>=(const instrumented& lhs, const instrumented& rhs)
{
return !(lhs < rhs);
}
friend std::ostream& operator<<(std::ostream& ost, const instrumented& rhs)
{
return ost << rhs.value;
}
};
template<typename D>
class registry
{
public:
static size_t count;
static D* head;
D* prev;
D* next;
registry(registry&&) = delete;
registry& operator=(const registry&) = delete;
registry& operator=(registry&&) = delete;
private:
registry()
: prev(nullptr)
, next(head)
{
head = static_cast<D*>(this);
++count;
if (next) {
next->prev = head;
}
}
registry(const registry& /* reg */)
: registry()
{
}
~registry()
{
--count;
if (prev != nullptr) {
prev->next = next;
}
if (next != nullptr) {
next->prev = prev;
}
if (head == this) {
head = next;
}
}
friend D;
};
template<typename D>
size_t registry<D>::count(0);
template<typename D>
D* registry<D>::head(nullptr);
template<typename Function>
void count_operations(
size_t first,
size_t last,
Function fun,
double (*norm)(double, double) = dont_normalize
)
{
using instrumented = based::instrumented<double>;
using size_t = instrumented::op::type::size_t;
constexpr size_t cols = instrumented::op::type::size;
const size_t decimals((norm == dont_normalize) ? 0 : 2);
std::array<double, cols> values = {0};
static constexpr int width = 12;
table tbl(width);
tbl.print_header(
std::begin(instrumented::op::type::names),
std::end(instrumented::op::type::names)
);
std::mt19937 rng(0); // NOLINT(*cert-msc32-c*, *cert-msc51-cpp*)
while (first <= last) {
std::vector<instrumented> vec(first);
std::iota(std::begin(vec), std::end(vec), 0.0);
std::shuffle(std::begin(vec), std::end(vec), rng);
instrumented::initialize(first);
fun(std::begin(vec), std::end(vec));
const auto dbl = static_cast<double>(first);
values[0] = dbl;
for (size_t k = 1; k < cols; ++k) {
const auto& val = instrumented::op::type::get(k);
values[k] = norm(instrumented::counts[val], dbl);
}
tbl.print_row(std::begin(values), std::end(values), decimals);
first <<= 1U;
}
}
class timer
{
public:
using clock_t = std::chrono::high_resolution_clock;
using duration_t = std::chrono::microseconds;
timer()
: m_startp(clock_t::now())
{
}
timer(const timer&) = delete;
timer(timer&&) = delete;
timer& operator=(const timer&) = delete;
timer& operator=(timer&&) = delete;
~timer()
{
stop();
std::cout << std::flush;
}
void stop()
{
static const auto count = [](const auto& time)
{
return std::chrono::time_point_cast<duration_t>(time)
.time_since_epoch()
.count();
};
const auto endp = clock_t::now();
const auto start = count(m_startp);
const auto end = count(endp);
const auto duration = end - start;
const auto msec = static_cast<double>(duration) * 0.001;
std::cout << std::format("{}us ({}ms)\n", duration, msec);
}
private:
std::chrono::time_point<clock_t> m_startp;
};
} // namespace based
diff --git a/ include/based/instrumentation/instrumented.hpp b/ include/based/instrumentation/instrumented.hpp
@@ -0,0 +1,237 @@
#pragma once
#include <algorithm>
#include <cmath>
#include <iostream>
#include <numeric>
#include <random>
#include <vector>
#include "based/enum/enum.hpp"
#include "based/instrumentation/table.hpp"
#include "based/types/types.hpp"
namespace based
{
struct instrumented_base
{
BASED_ENUM_DECLARE(
op,
u8,
n,
ctor_default,
ctor_value,
ctor_copy,
ctor_move,
asgn_copy,
asgn_move,
destructor,
equality,
comparison
)
static op::type::array<double> counts;
static void initialize(size_t size)
{
std::fill(std::begin(counts), std::end(counts), 0.0);
counts[op::n] = static_cast<double>(size);
}
};
BASED_DEFINE_CLASS_ENUM(
instrumented_base,
op,
u8,
n,
ctor_default,
ctor_value,
ctor_copy,
ctor_move,
asgn_copy,
asgn_move,
destructor,
equality,
comparison
)
template<typename T>
requires std::semiregular<T>
struct instrumented : instrumented_base
{
using value_type = T;
value_type value;
instrumented(const value_type& val) // NOLINT(*explicit*)
: value(std::move(val))
{
++counts[op::ctor_value];
;
}
instrumented(value_type&& val) // NOLINT(*explicit*)
: value(std::move(val))
{
++counts[op::ctor_value];
;
}
// Semiregular:
instrumented()
{
++counts[op::ctor_default];
;
}
instrumented(const instrumented& val)
: value(val.value)
{
++counts[op::ctor_copy];
;
}
instrumented(instrumented&& val) noexcept
: value(std::move(val.value))
{
++counts[op::ctor_move];
;
}
// self assign should be handled by the value_type
instrumented& operator=(const instrumented& val) // NOLINT(*cert-oop54-cpp*)
{
++counts[op::asgn_copy];
;
value = val.value;
return *this;
}
// self assign should be handled by the value_type
instrumented& operator=(instrumented&& val
) noexcept // NOLINT(*cert-oop54-cpp*)
{
++counts[op::asgn_move];
;
value = std::move(val.value);
return *this;
}
~instrumented()
{
++counts[op::destructor];
;
}
// Regular
friend bool operator==(const instrumented& lhs, const instrumented& rhs)
{
++counts[op::equality];
;
return lhs.value == rhs.value;
}
friend bool operator!=(const instrumented& lhs, const instrumented& rhs)
{
return !(lhs == rhs);
}
// TotallyOrdered
friend bool operator<(const instrumented& lhs, const instrumented& rhs)
{
++counts[op::comparison];
;
return lhs.value < rhs.value;
}
friend bool operator>(const instrumented& lhs, const instrumented& rhs)
{
return rhs < lhs;
}
friend bool operator<=(const instrumented& lhs, const instrumented& rhs)
{
return !(rhs < lhs);
}
friend bool operator>=(const instrumented& lhs, const instrumented& rhs)
{
return !(lhs < rhs);
}
friend std::ostream& operator<<(std::ostream& ost, const instrumented& rhs)
{
return ost << rhs.value;
}
};
inline auto dont_normalize(double x, double /* n */)
{
return x;
}
inline auto normalize_n(double x, double n)
{
return x / n;
}
inline auto normalize_nlogn(double x, double n)
{
return x / (n * (std::log(n) / std::numbers::ln2));
}
inline auto normalize_nlogn1(double x, double n)
{
return x / (n * std::log(n) - n);
}
template<typename Function>
void count_operations(
size_t first,
size_t last,
Function fun,
double (*norm)(double, double) = dont_normalize
)
{
using instrumented = instrumented<double>;
using esize_t = instrumented::op::type::size_t;
constexpr esize_t cols = instrumented::op::type::size;
const esize_t decimals((norm == dont_normalize) ? 0 : 2);
instrumented_base::op::type::array<double> values;
static constexpr int width = 12;
table tbl(width);
tbl.print_header(
std::begin(instrumented::op::type::names),
std::end(instrumented::op::type::names)
);
std::mt19937 rng(0); // NOLINT(*cert-msc32-c*, *cert-msc51-cpp*)
while (first <= last) {
std::vector<instrumented> vec(first);
std::iota(std::begin(vec), std::end(vec), 0.0);
std::shuffle(std::begin(vec), std::end(vec), rng);
instrumented::initialize(first);
fun(std::begin(vec), std::end(vec));
const auto dbl = static_cast<double>(first);
values[instrumented_base::op::n] = dbl;
for (esize_t k = 1; k < cols; ++k) {
const auto& val = instrumented::op::type::get(k);
values[val] = norm(instrumented::counts[val], dbl);
}
tbl.print_row(std::begin(values), std::end(values), decimals);
first <<= 1U;
}
}
} // namespace based
diff --git a/ include/based/instrumentation/registry.hpp b/ include/based/instrumentation/registry.hpp
@@ -0,0 +1,62 @@
#pragma once
#include "based/types/types.hpp"
namespace based
{
template<typename D>
class registry
{
public:
static size_t count;
static D* head;
D* prev;
D* next;
registry(registry&&) = delete;
registry& operator=(const registry&) = delete;
registry& operator=(registry&&) = delete;
private:
registry()
: prev(nullptr)
, next(head)
{
head = static_cast<D*>(this);
++count;
if (next) {
next->prev = head;
}
}
registry(const registry& /* reg */)
: registry()
{
}
~registry()
{
--count;
if (prev != nullptr) {
prev->next = next;
}
if (next != nullptr) {
next->prev = prev;
}
if (head == this) {
head = next;
}
}
friend D;
};
template<typename D>
size_t registry<D>::count(0);
template<typename D>
D* registry<D>::head(nullptr);
} // namespace based
diff --git a/ include/based/instrumentation/table.hpp b/ include/based/instrumentation/table.hpp
@@ -0,0 +1,44 @@
#pragma once
#include <format>
#include <iostream>
#include "based/types/types.hpp"
namespace based
{
class table
{
public:
explicit table(size_t min_wth)
: m_min_wth(min_wth)
{
}
template<typename I>
void print_header(I first, I last)
{
while (first != last) {
std::cout << std::format("{:^{}} | ", *first, m_min_wth);
first++;
}
std::cout << '\n';
}
template<typename I>
void print_row(I first, I last, size_t precision)
{
std::cout << std::format("{:{}} | ", *first++, m_min_wth);
while (first != last) {
std::cout << std::format("{:{}.{}f} | ", *first, m_min_wth, precision);
first++;
}
std::cout << '\n';
}
private:
size_t m_min_wth;
};
} // namespace based
diff --git a/ include/based/instrumentation/timer.hpp b/ include/based/instrumentation/timer.hpp
@@ -0,0 +1,56 @@
#pragma once
#include <chrono>
#include <format>
#include <iostream>
namespace based
{
class timer
{
public:
using clock_t = std::chrono::high_resolution_clock;
using duration_t = std::chrono::microseconds;
timer()
: m_startp(clock_t::now())
{
}
timer(const timer&) = delete;
timer(timer&&) = delete;
timer& operator=(const timer&) = delete;
timer& operator=(timer&&) = delete;
~timer()
{
stop();
std::cout << std::flush;
}
void stop()
{
static const auto count = [](const auto& time)
{
return std::chrono::time_point_cast<duration_t>(time)
.time_since_epoch()
.count();
};
const auto endp = clock_t::now();
const auto start = count(m_startp);
const auto end = count(endp);
const auto duration = end - start;
const auto msec = static_cast<double>(duration) * 0.001;
std::cout << std::format("{}us ({}ms)\n", duration, msec);
}
private:
std::chrono::time_point<clock_t> m_startp;
};
} // namespace based
diff --git a/ include/based/integer.hpp b/ include/based/integer.hpp
@@ -1,72 +0,0 @@
#pragma once
namespace based
{
template<typename T>
T successor(T n)
{
return n + T {1};
}
template<typename T>
T predecessor(T n)
{
return n - T {1};
}
template<typename T>
T twice(T n)
{
return n * T {2};
}
template<typename T>
T half(T n)
{
return n / T {2};
}
template<typename T>
bool positive(T n)
{
return n > T {0};
}
template<typename T>
bool negative(T n)
{
return n < T {0};
}
template<typename T>
bool zero(T n)
{
return n == T {0};
}
template<typename T>
bool one(T n)
{
return n == T {1};
}
template<typename T>
bool two(T n)
{
return n == T {2};
}
template<typename T>
bool even(T n)
{
return n % T {2} == T {0};
}
template<typename T>
bool odd(T n)
{
return n % T {2} != T {0};
}
} // namespace based
diff --git a/ include/based/iterator.hpp b/ include/based/iterator.hpp
@@ -1,43 +0,0 @@
#include "based/integer.hpp"
#include "based/type_traits.hpp"
namespace based
{
template<Iterator I>
I successor(I itr)
{
return ++itr;
}
template<Iterator I>
void increment(I& itr)
{
// Precondition: next(itr) is defined
itr = next(itr);
}
template<Iterator I>
I operator+(I first, iter_dist_t<I> size)
{
// Precondition: size >= 0 & weak_range(first, size)
while (!zero(size)) {
size = predecessor(size);
first = successor(first);
}
return first;
}
template<Iterator I>
iter_dist_t<I> operator-(I last, I first)
{
// Precondition: bounded_range(first, last)
iter_dist_t<I> cnt {0};
while (first != last) {
cnt = successor(cnt);
first = successor(first);
}
return cnt;
}
} // namespace based
diff --git a/ include/based/string.hpp b/ include/based/string.hpp
@@ -6,7 +6,7 @@
namespace based
{
template<std::size_t n>
template<size_t n>
struct string_literal
{
// NOLINTNEXTLINE(*explicit*, *array*)
@@ -15,7 +15,7 @@
struct string_literal
{
}
[[nodiscard]] constexpr std::size_t size() const { return n; }
[[nodiscard]] constexpr size_t size() const { return n; }
[[nodiscard]] constexpr const char* data() const { return m_value.data(); }
std::array<char, n> m_value;
diff --git a/ include/based/template.hpp b/ include/based/template.hpp
@@ -1,241 +0,0 @@
#pragma once
#include <concepts>
#include <cstddef>
#include <cstring>
#include <functional>
#include <type_traits>
#include <utility>
#include "based/type_traits.hpp"
#include "based/utility.hpp"
namespace based
{
template<typename T>
class error_template;
/* ----- Buffer used for Local Buffer Optimization ----- */
template<size_t size, size_t alignment = alignof(void*)>
struct buffer
{
template<typename T>
static constexpr bool valid_type()
{
return sizeof(T) <= size && (alignment % sizeof(T)) == 0;
}
alignas(alignment) char m_space[size] = {0}; // NOLINT(*array*)
buffer() = default;
template<typename T, typename... Args>
requires(valid_type<T>() && std::constructible_from<T, Args...>)
explicit buffer(
std::in_place_type_t<T> /* t */, Args&&... args
) noexcept(std::is_nothrow_constructible_v<T, Args...>)
{
static_assert(std::is_trivially_destructible_v<T>);
static_assert(std::is_trivially_copyable_v<T>);
::new (static_cast<void*>(as<T>())) T(std::forward<Args>(args)...);
}
template<typename T, typename... Args>
requires(valid_type<T>() && std::constructible_from<T, Args...>)
T* emplace(Args&&... args
) noexcept(std::is_nothrow_constructible_v<T, Args...>)
{
static_assert(std::is_trivially_destructible_v<T>);
static_assert(std::is_trivially_copyable_v<T>);
// NOLINTNEXTLINE(*owning-memory*)
return ::new (static_cast<void*>(as<T>())) T(std::forward<Args>(args)...);
}
template<typename T>
requires(valid_type<T>())
[[nodiscard]] T* as() noexcept
{
return reinterpret_cast<T*>(&m_space); // NOLINT(*reinterpret-cast*)
}
template<typename T>
requires(valid_type<T>())
[[nodiscard]] const T* as() const noexcept
{
return const_cast<buffer*>(this)->as<T>(); // NOLINT(*const-cast*)
}
void swap(buffer& that) noexcept
{
// NOLINTBEGIN(*array*)
alignas(alignment) char tmp[size];
::memcpy(tmp, this->m_space, size);
::memcpy(this->m_space, that.m_space, size);
::memcpy(that.m_space, tmp, size);
// NOLINTEND(*array*)
}
};
/* ----- Overload Lambdas ----- */
template<typename... F>
struct overload : public F...
{
using F::operator()...;
};
template<typename... F>
overload(F&&...) -> overload<F...>;
/* ----- Function Wrapper with type erasure ----- */
template<
typename Signature,
std::size_t size = sizeof(void*),
std::size_t alignment = alignof(void*)>
class function;
template<
std::size_t size,
std::size_t alignment,
typename Ret,
typename... Args>
class function<Ret(Args...), size, alignment>
{
buffer<size, alignment> m_space;
using executor_t = Ret (*)(Args..., void*);
static constexpr Ret default_executor(Args... /* args */, void* /* func */)
{
throw std::bad_function_call();
}
constexpr static executor_t m_default_executor = default_executor;
executor_t m_executor = m_default_executor;
template<typename Callable>
static Ret executor(Args... args, void* func)
{
return std::invoke(
*static_cast<function*>(func)->m_space.template as<Callable>(),
std::forward<Args>(args)...
);
}
public:
function() = default;
template<typename CallableArg, typename Callable = std::decay_t<CallableArg>>
requires(requires {
!SameAs<function, Callable>;
sizeof(Callable) <= size;
alignof(Callable) <= alignment;
std::is_trivially_destructible_v<Callable>;
std::is_trivially_copyable_v<Callable>;
})
function(CallableArg&& callable) // NOLINT(*explicit*)
: m_space(
std::in_place_type<Callable>, std::forward<CallableArg>(callable)
)
, m_executor(executor<Callable>)
{
}
template<typename... CallArgs>
Ret operator()(CallArgs&&... callargs) const
{
return this->m_executor(
std::forward<CallArgs>(callargs)...,
const_cast<function*>(this) // NOLINT(*const-cast*)
);
}
};
template<typename Ret, typename... Args>
function(Ret (*)(Args...)) -> function<Ret(Args...)>;
template<typename F, typename Sig = signature_t<F, decltype(&F::operator())>>
function(F) -> function<Sig>;
template<typename Func, bool on_success = false, bool on_failure = false>
class scopeguard
{
uncaught_exception_detector m_detector;
Func m_func;
public:
scopeguard(Func&& func) // NOLINT(*explicit*)
: m_func(std::move(func))
{
}
/*
scopeguard(const Func& func) // NOLINT(*explicit*)
: m_func(func)
{
}
*/
scopeguard(const scopeguard&) = delete;
scopeguard& operator=(const scopeguard&) = delete;
scopeguard(scopeguard&&) = delete;
scopeguard& operator=(scopeguard&&) = delete;
~scopeguard()
{
if ((on_success && !m_detector) || (on_failure && m_detector)) {
m_func();
}
}
};
template<typename Func>
class scopeguard<Func, false, false>
{
bool m_commit = false;
Func m_func;
public:
scopeguard(Func&& func) // NOLINT(*explicit*)
: m_func(std::move(func))
{
}
/*
scopeguard(const Func& func) // NOLINT(*explicit*)
: m_func(func)
{
}
*/
scopeguard(const scopeguard&) = delete;
scopeguard& operator=(const scopeguard&) = delete;
scopeguard(scopeguard&&) = delete;
scopeguard& operator=(scopeguard&&) = delete;
~scopeguard()
{
if (m_commit) {
m_func();
}
}
void commit() { m_commit = true; }
};
template<typename Func>
using scopeguard_exit = scopeguard<Func, true, true>;
template<typename Func>
using scopeguard_success = scopeguard<Func, true, false>;
template<typename Func>
using scopeguard_failure = scopeguard<Func, false, true>;
} // namespace based
diff --git a/ include/based/type_traits.hpp b/ include/based/type_traits.hpp
@@ -1,696 +0,0 @@
#pragma once
#include <cstdint>
#include <iterator>
#include <tuple>
#include <type_traits>
#include "based/integer.hpp"
namespace based
{
/* ----- Standard Traits ----- */
template<typename...>
using void_t = void;
template<class T, T v>
struct integral_constant
{
static constexpr T value = v;
using value_type = T;
using type = integral_constant;
// NOLINTNEXTLINE(*explicit*)
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};
using true_type = integral_constant<bool, true>;
using false_type = integral_constant<bool, false>;
// clang-format off
template<class T, class U> struct is_same : false_type { };
template<class T> struct is_same<T, T> : true_type { };
template<class T, class U> constexpr bool is_same_v = is_same<T, U>::value;
template<typename T, typename U>
concept SameAs = is_same_v<T, U> && is_same_v<U, T>;
template<class T> struct remove_reference { using type = T; };
template<class T> struct remove_reference<T&> { using type = T; };
template<class T> struct remove_reference<T&&> { using type = T; };
template<class T> using remove_reference_t = typename remove_reference<T>::type;
template<class T> struct remove_cv { using type = T; };
template<class T> struct remove_cv<const T> { using type = T; };
template<class T> struct remove_cv<volatile T> { using type = T; };
template<class T> struct remove_cv<const volatile T> { using type = T; };
template<class T> using remove_cv_t = typename remove_cv<T>::type;
template<class T> struct remove_const { using type = T; };
template<class T> struct remove_const<const T> { using type = T; };
template<class T> using remove_const_t = typename remove_const<T>::type;
template<class T> struct remove_volatile { using type = T; };
template<class T> struct remove_volatile<volatile T> { using type = T; };
template<class T> using remove_volatile_t = typename remove_volatile<T>::type;
template<class T> struct remove_cvref { using type = remove_cv_t<remove_reference_t<T>>; };
template<class T> using remove_cvref_t = typename remove_cvref<T>::type;
template<class T> struct remove_pointer { using type = T; };
template<class T> struct remove_pointer<T*> { using type = T; };
template<class T> struct remove_pointer<T* const> { using type = T; };
template<class T> struct remove_pointer<T* volatile> { using type = T; };
template<class T> struct remove_pointer<T* const volatile> { using type = T; };
template<class T> using remove_pointer_t = typename remove_pointer<T>::type;
template<template<class...> class T, class Void, class... Ts>
struct is_instantiable : false_type {};
template<template<class...> class T, class... Ts>
struct is_instantiable<T, void_t<T<Ts...>>, Ts...> : true_type {};
template<template<class...> class T, class... Ts>
inline constexpr auto is_instantiable_v = is_instantiable<T, void, Ts...>::value;
template<typename T>
concept equal_comparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs == rhs} -> SameAs<bool>;
{rhs == lhs} -> SameAs<bool>;
};
template<typename T>
concept not_equal_comparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs != rhs} -> SameAs<bool>;
{rhs != lhs} -> SameAs<bool>;
};
template<typename T>
concept less_comparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs < rhs} -> SameAs<bool>;
{rhs < lhs} -> SameAs<bool>;
};
template<typename T>
concept greater_comparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs > rhs} -> SameAs<bool>;
{rhs > lhs} -> SameAs<bool>;
};
template<typename T>
concept less_equal_comparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs <= rhs} -> SameAs<bool>;
{rhs <= lhs} -> SameAs<bool>;
};
template<typename T>
concept greater_equal_comparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs >= rhs} -> SameAs<bool>;
{rhs >= lhs} -> SameAs<bool>;
};
template<typename T>
concept equality_comparable = requires {
requires(equal_comparable<T>);
requires(not_equal_comparable<T>);
};
template<typename T>
concept totally_ordered = requires {
requires(equality_comparable<T>);
requires(less_comparable<T>);
requires(greater_comparable<T>);
requires(less_equal_comparable<T>);
requires(greater_equal_comparable<T>);
};
// clang-format on
/* ----- Integer ----- */
template<typename T>
concept Integer = requires(T n) {
successor(n);
predecessor(n);
twice(n);
half(n);
positive(n);
negative(n);
zero(n);
one(n);
even(n);
odd(n);
};
/* ----- Regular ----- */
template<typename T>
using bare_t = remove_cvref_t<T>;
template<typename T>
concept Semiregular = std::semiregular<T>;
template<typename T>
concept Regular = std::regular<T>;
template<typename T>
concept BareRegular = std::regular<bare_t<T>>;
template<typename T, typename U>
concept BareSameAs = SameAs<bare_t<T>, bare_t<U>>;
/* ----- Iterator ----- */
namespace detail
{
template<typename I>
struct iterator_traits
{
using value_type = I;
using distance_type = std::uint64_t;
using pointer_type = I&;
using reference_type = I*;
};
template<typename I>
requires std::input_or_output_iterator<I>
struct iterator_traits<I>
{
using value_type = std::iterator_traits<I>::value_type;
using distance_type = std::iterator_traits<I>::difference_type;
using pointer_type = std::iterator_traits<I>::pointer;
using reference_type = std::iterator_traits<I>::reference;
};
} // namespace detail
template<typename T>
using iter_value_t = detail::iterator_traits<T>::value_type;
template<typename T>
using iter_dist_t = detail::iterator_traits<T>::distance_type;
template<typename T>
using iter_ptr_t = detail::iterator_traits<T>::pointer;
template<typename T>
using iter_ref_t = detail::iterator_traits<T>::reference;
template<typename T>
concept Readable = requires(T val) {
requires(Regular<T>);
typename iter_value_t<T>;
{
*val
} -> BareSameAs<iter_value_t<T>>;
};
template<typename T>
concept Iterator = requires(T val) {
requires(Regular<T>);
typename iter_dist_t<T>;
// requires(Integer<iter_dist_t<T>>);
{
++val
} -> BareSameAs<T>;
// successor is not necessarily regular
};
template<typename T>
concept ForwardIterator = requires {
requires(Iterator<T>);
// successor is regular
};
template<typename T>
concept ReadableIterator = requires {
requires(Iterator<T>);
requires(Readable<T>);
};
template<typename T>
concept ReadableForwardIterator = requires {
requires(ForwardIterator<T>);
requires(Readable<T>);
};
/* ----- Function Signature ----- */
template<typename>
struct signature;
template<typename Ret, bool ne, typename... Args>
struct signature<Ret(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, bool ne, typename... Args>
struct signature<Ret (*)(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = false_type;
using volatile_val = false_type;
using lvalref_val = false_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = false_type;
using volatile_val = false_type;
using lvalref_val = true_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = false_type;
using volatile_val = false_type;
using lvalref_val = false_type;
using rvalref_val = true_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = true_type;
using volatile_val = false_type;
using lvalref_val = false_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = true_type;
using volatile_val = false_type;
using lvalref_val = true_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = true_type;
using volatile_val = false_type;
using lvalref_val = false_type;
using rvalref_val = true_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) volatile noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = false_type;
using volatile_val = true_type;
using lvalref_val = false_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) volatile & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = false_type;
using volatile_val = true_type;
using lvalref_val = true_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) volatile && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = false_type;
using volatile_val = true_type;
using lvalref_val = false_type;
using rvalref_val = true_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const volatile noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = true_type;
using volatile_val = true_type;
using lvalref_val = false_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const volatile & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = true_type;
using volatile_val = true_type;
using lvalref_val = true_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const volatile && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = true_type;
using volatile_val = true_type;
using lvalref_val = false_type;
using rvalref_val = true_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename StaticCallOp>
struct signature_static
{
};
template<typename Ret, bool ne, typename... Args>
struct signature_static<Ret (*)(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
};
template<typename F, typename Op>
using signature_t = typename std::conditional_t<requires(F& func) {
(void)func.operator();
}, signature_static<Op>, signature<Op>>::sig_type;
/*
template<typename Sig>
class function;
template<typename Ret, typename... Args>
class function<Ret(Args...)>
{
};
template<typename Ret, typename... Args>
function(Ret (*)(Args...)) -> function<Ret(Args...)>;
template<typename F, typename Sig = signature_t<F, decltype(&F::operator())>>
function(F) -> function<Sig>;
*/
/* ----- Callable Interface ----- */
template<typename P, typename... Args>
concept Invocable = std::invocable<P, Args...>;
template<typename T>
struct callable;
template<typename T>
requires(std::is_function_v<T>)
struct callable<T> : public signature<std::decay_t<T>>
{
};
template<typename T>
requires(requires { &std::decay_t<T>::operator(); })
struct callable<T> : public signature<decltype(&T::operator())>
{
};
template<typename T>
requires(std::is_member_function_pointer_v<std::decay_t<T>>)
struct callable<T> : public signature<remove_pointer_t<T>>
{
};
template<typename T>
concept Callable = is_instantiable_v<callable, T>;
template<Callable T>
using callable_sig_t = typename callable<T>::signature::sig_type;
template<Callable T>
using callable_ret_t = typename callable<T>::signature::ret_type;
/* ----- Function Concepts ----- */
template<typename T>
concept Input = std::is_same_v<T, remove_cvref_t<remove_pointer_t<T>>>
|| std::is_const_v<remove_reference_t<T>>
|| std::is_const_v<remove_pointer_t<T>>;
template<std::size_t idx, typename... Args>
requires(idx < sizeof...(Args))
using elem_t = std::tuple_element_t<idx, std::tuple<Args...>>;
template<typename... Args>
concept SemiregularDomain = (Semiregular<remove_cvref_t<Args>> && ...);
template<typename... Args>
concept RegularDomain = (Regular<remove_cvref_t<Args>> && ...);
template<typename... Args>
concept InputDomain = (Input<Args> && ...);
template<typename... Args>
concept HomogeneousDomain = (SameAs<elem_t<0, Args...>, Args> && ...);
template<typename P, typename... Args>
using ret_t = std::invoke_result_t<P, Args...>;
namespace detail
{
// clang-format off
template<typename P, typename Sig> struct procedure : public false_type {};
template<typename P, typename Ret, typename... Args>
requires (Invocable<P, Args...> && std::convertible_to<std::invoke_result_t<P, Args...>, Ret>)
struct procedure<P, Ret(Args...)> : public true_type {};
template<typename P, typename... Args>
requires (Invocable<P, Args...>)
struct procedure<P, void(Args...)> : public true_type {};
template<typename P, typename Ret, typename... Args>
static constexpr bool procedure_v = procedure<P, Ret(Args...)>::value;
// clang-format on
} // namespace detail
template<typename P, typename Ret, typename... Args>
concept Procedure = detail::procedure_v<P, Ret, Args...>;
template<typename P, typename Ret, typename Arg>
concept UnaryProcedure = Procedure<P, Ret, Arg>;
template<typename P, typename Ret, typename... Args>
concept RegularProcedure = requires {
requires(Procedure<P, Ret, Args...>);
requires(RegularDomain<Args...>);
requires(Regular<ret_t<P, Args...>>);
};
template<typename P, typename Ret, typename... Args>
concept FunctionalProcedure = requires {
requires(RegularProcedure<P, Ret, Args...>);
requires(InputDomain<Args...>);
};
template<typename P, typename Ret, typename Arg>
concept UnaryFunction = requires {
requires(FunctionalProcedure<P, Ret, Arg>);
requires(UnaryProcedure<P, Ret, Arg>);
};
template<typename P, typename Ret, typename... Args>
concept HomogeneousFunction = requires {
requires(FunctionalProcedure<P, Ret, Args...>);
requires(sizeof...(Args) > 0);
requires(HomogeneousDomain<Args...>);
};
template<typename P, typename... Args>
concept Predicate = FunctionalProcedure<P, bool, Args...>;
template<typename P, typename... Args>
concept HomogeneousPredicate = requires {
requires(Predicate<P, Args...>);
requires(HomogeneousFunction<P, bool, Args...>);
};
template<typename P, typename Arg>
concept UnaryPredicate = requires {
requires(Predicate<P, Arg>);
requires(UnaryFunction<P, bool, Arg>);
};
template<typename P, typename... Args>
concept Operation = HomogeneousFunction<P, elem_t<0, Args...>, Args...>;
template<typename P, typename Ret, typename Arg>
concept Transformation = requires {
requires(Operation<P, Ret, Arg>);
requires(UnaryFunction<P, Ret, Arg>);
};
template<typename P, typename Arg>
concept BinaryOperation = Operation<P, Arg, Arg>;
template<typename P, typename Arg>
concept AssociativeBinaryOperation = Operation<P, Arg, Arg>;
template<typename P, typename Arg>
concept Relation = HomogeneousPredicate<P, Arg, Arg>;
/* ----- Iterator variants ----- */
template<typename P, typename Ret, typename I>
concept IterUnaryProcedure = requires {
requires(Iterator<I>);
requires(UnaryProcedure<P, Ret, iter_value_t<I>>);
};
template<typename P, typename Ret, typename I>
concept IterUnaryFunction = requires {
requires(Iterator<I>);
requires(UnaryFunction<P, Ret, iter_value_t<I>>);
};
template<typename P, typename... I>
concept IterHomogeneousPredicate = requires {
requires(Iterator<I> && ...);
requires(HomogeneousPredicate<P, iter_value_t<I>...>);
};
template<typename P, typename I>
concept IterUnaryPredicate = requires {
requires(Iterator<I>);
requires(UnaryPredicate<P, iter_value_t<I>>);
};
template<typename P, typename Ret, typename... I>
concept IterOperation = requires {
requires(Iterator<I> && ...);
requires(Operation<P, iter_value_t<I>...>);
};
template<typename P, typename Ret, typename I>
concept IterBinaryOperation = requires {
requires(Iterator<I>);
requires(BinaryOperation<P, iter_value_t<I>>);
};
template<typename P, typename I>
concept IterRelation = requires {
requires(Iterator<I>);
requires(Relation<P, iter_value_t<I>>);
};
} // namespace based
diff --git a/ include/based/type_traits/add/lvalue_reference.hpp b/ include/based/type_traits/add/lvalue_reference.hpp
@@ -0,0 +1,27 @@
#pragma once
#include "based/type_traits/type_identity.hpp"
namespace based
{
// clang-format off
namespace detail
{
// Note that “cv void&” is a substitution failure
template<class T> auto try_add(int) -> type_identity<T&>;
// Handle T = cv void case
template<class T> auto try_add(...) -> type_identity<T>;
} // namespace detail
template<class T> struct add_lvalue_reference : decltype(detail::try_add<T>(0)) {};
template<class T> using add_lvalue_reference_t = add_lvalue_reference<T>::type;
// clang-format on
} // namespace based
diff --git a/ include/based/type_traits/add/rvalue_reference.hpp b/ include/based/type_traits/add/rvalue_reference.hpp
@@ -0,0 +1,27 @@
#pragma once
#include "based/type_traits/type_identity.hpp"
namespace based
{
// clang-format off
namespace detail
{
// Note that “cv void&&” is a substitution failure
template<class T> auto try_add(int) -> type_identity<T&&>;
// Handle T = cv void case
template<class T> auto try_add(...) -> type_identity<T>;
} // namespace detail
template<class T> struct add_rvalue_reference : decltype(detail::try_add<T>(0)) {};
template<class T> using add_rvalue_reference_t = add_rvalue_reference<T>::type;
// clang-format on
} // namespace based
diff --git a/ include/based/type_traits/integral_constant.hpp b/ include/based/type_traits/integral_constant.hpp
@@ -0,0 +1,22 @@
#pragma once
namespace based
{
template<class T, T v>
struct integral_constant
{
static constexpr T value = v;
using value_type = T;
using type = integral_constant;
// NOLINTNEXTLINE(*explicit*)
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};
using true_type = integral_constant<bool, true>;
using false_type = integral_constant<bool, false>;
} // namespace based
diff --git a/ include/based/type_traits/invoke/result.hpp b/ include/based/type_traits/invoke/result.hpp
@@ -0,0 +1,14 @@
#pragma once
#include <type_traits>
namespace based
{
template<class F, class... Args>
using invoke_result = std::invoke_result<F, Args...>;
template<class F, class... Args>
using invoke_result_t = invoke_result<F, Args...>::type;
} // namespace based
diff --git a/ include/based/type_traits/is/const.hpp b/ include/based/type_traits/is/const.hpp
@@ -0,0 +1,17 @@
#pragma once
#include "based/type_traits/integral_constant.hpp"
namespace based
{
// clang-format off
template<class T> struct is_const : false_type {};
template<class T> struct is_const<const T> : true_type {};
template<class T> constexpr bool is_const_v = is_const<T>::value;
// clang-format on
} // namespace based
diff --git a/ include/based/type_traits/is/convertable.hpp b/ include/based/type_traits/is/convertable.hpp
@@ -0,0 +1,14 @@
#pragma once
#include <type_traits>
namespace based
{
template<class From, class To>
using is_convertible = std::is_convertible<From, To>;
template<class From, class To>
static constexpr bool is_convertible_v = std::is_convertible_v<From, To>;
} // namespace based
diff --git a/ include/based/type_traits/is/invocable.hpp b/ include/based/type_traits/is/invocable.hpp
@@ -0,0 +1,14 @@
#pragma once
#include <type_traits>
namespace based
{
template<class F, class... Args>
using is_invocable = std::is_invocable<F, Args...>;
template<class F, class... Args>
static constexpr bool is_invocable_v = is_invocable<F, Args...>::value;
} // namespace based
diff --git a/ include/based/type_traits/is/same.hpp b/ include/based/type_traits/is/same.hpp
@@ -0,0 +1,17 @@
#pragma once
#include "based/type_traits/integral_constant.hpp"
namespace based
{
// clang-format off
template<class T, class U> struct is_same : false_type {};
template<class T> struct is_same<T, T> : true_type {};
template<class T, class U> constexpr bool is_same_v = is_same<T, U>::value;
// clang-format on
} // namespace based
diff --git a/ include/based/type_traits/iterator.hpp b/ include/based/type_traits/iterator.hpp
@@ -0,0 +1,45 @@
#pragma once
#include <iterator>
#include "based/types/types.hpp"
namespace based
{
namespace detail
{
template<typename I>
struct iterator_traits
{
using value_type = I;
using distance_type = u64;
using pointer_type = I&;
using reference_type = I*;
};
template<typename I>
requires std::input_or_output_iterator<I>
struct iterator_traits<I>
{
using value_type = std::iterator_traits<I>::value_type;
using distance_type = std::iterator_traits<I>::difference_type;
using pointer_type = std::iterator_traits<I>::pointer;
using reference_type = std::iterator_traits<I>::reference;
};
} // namespace detail
template<typename T>
using iter_value_t = detail::iterator_traits<T>::value_type;
template<typename T>
using iter_dist_t = detail::iterator_traits<T>::distance_type;
template<typename T>
using iter_ptr_t = detail::iterator_traits<T>::pointer;
template<typename T>
using iter_ref_t = detail::iterator_traits<T>::reference;
} // namespace based
diff --git a/ include/based/type_traits/remove/const.hpp b/ include/based/type_traits/remove/const.hpp
@@ -0,0 +1,15 @@
#pragma once
namespace based
{
// clang-format off
template<class T> struct remove_const { using type = T; };
template<class T> struct remove_const<const T> { using type = T; };
template<class T> using remove_const_t = typename remove_const<T>::type;
// clang-format on
} // namespace based
diff --git a/ include/based/type_traits/remove/cv.hpp b/ include/based/type_traits/remove/cv.hpp
@@ -0,0 +1,17 @@
#pragma once
namespace based
{
// clang-format off
template<class T> struct remove_cv { using type = T; };
template<class T> struct remove_cv<const T> { using type = T; };
template<class T> struct remove_cv<volatile T> { using type = T; };
template<class T> struct remove_cv<const volatile T> { using type = T; };
template<class T> using remove_cv_t = typename remove_cv<T>::type;
// clang-format on
} // namespace based
diff --git a/ include/based/type_traits/remove/cvref.hpp b/ include/based/type_traits/remove/cvref.hpp
@@ -0,0 +1,19 @@
#pragma once
#include "based/type_traits/remove/cv.hpp"
#include "based/type_traits/remove/reference.hpp"
namespace based
{
// clang-format off
template<class T> struct remove_cvref {
using type = remove_cv_t<remove_reference_t<T>>;
};
template<class T> using remove_cvref_t = typename remove_cvref<T>::type;
// clang-format on
} // namespace based
diff --git a/ include/based/type_traits/remove/pointer.hpp b/ include/based/type_traits/remove/pointer.hpp
@@ -0,0 +1,18 @@
#pragma once
namespace based
{
// clang-format off
template<class T> struct remove_pointer { using type = T; };
template<class T> struct remove_pointer<T*> { using type = T; };
template<class T> struct remove_pointer<T* const> { using type = T; };
template<class T> struct remove_pointer<T* volatile> { using type = T; };
template<class T> struct remove_pointer<T* const volatile> { using type = T; };
template<class T> using remove_pointer_t = typename remove_pointer<T>::type;
// clang-format on
} // namespace based
diff --git a/ include/based/type_traits/remove/reference.hpp b/ include/based/type_traits/remove/reference.hpp
@@ -0,0 +1,16 @@
#pragma once
namespace based
{
// clang-format off
template<class T> struct remove_reference { using type = T; };
template<class T> struct remove_reference<T&> { using type = T; };
template<class T> struct remove_reference<T&&> { using type = T; };
template<class T> using remove_reference_t = typename remove_reference<T>::type;
// clang-format on
} // namespace based
diff --git a/ include/based/type_traits/remove/volatile.hpp b/ include/based/type_traits/remove/volatile.hpp
@@ -0,0 +1,15 @@
#pragma once
namespace based
{
// clang-format off
template<class T> struct remove_volatile { using type = T; };
template<class T> struct remove_volatile<volatile T> { using type = T; };
template<class T> using remove_volatile_t = typename remove_volatile<T>::type;
// clang-format on
} // namespace based
diff --git a/ include/based/type_traits/signature.hpp b/ include/based/type_traits/signature.hpp
@@ -0,0 +1,257 @@
#pragma once
#include <tuple>
#include "based/type_traits/integral_constant.hpp"
namespace based
{
template<typename>
struct signature;
template<typename Ret, bool ne, typename... Args>
struct signature<Ret(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, bool ne, typename... Args>
struct signature<Ret (*)(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = false_type;
using volatile_val = false_type;
using lvalref_val = false_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = false_type;
using volatile_val = false_type;
using lvalref_val = true_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = false_type;
using volatile_val = false_type;
using lvalref_val = false_type;
using rvalref_val = true_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = true_type;
using volatile_val = false_type;
using lvalref_val = false_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = true_type;
using volatile_val = false_type;
using lvalref_val = true_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = true_type;
using volatile_val = false_type;
using lvalref_val = false_type;
using rvalref_val = true_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) volatile noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = false_type;
using volatile_val = true_type;
using lvalref_val = false_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) volatile & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = false_type;
using volatile_val = true_type;
using lvalref_val = true_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) volatile && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = false_type;
using volatile_val = true_type;
using lvalref_val = false_type;
using rvalref_val = true_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const volatile noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = true_type;
using volatile_val = true_type;
using lvalref_val = false_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const volatile & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = true_type;
using volatile_val = true_type;
using lvalref_val = true_type;
using rvalref_val = false_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const volatile && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
using const_val = true_type;
using volatile_val = true_type;
using lvalref_val = false_type;
using rvalref_val = true_type;
using noexcept_val = integral_constant<bool, ne>;
};
template<typename StaticCallOp>
struct signature_static
{
};
template<typename Ret, bool ne, typename... Args>
struct signature_static<Ret (*)(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
};
template<typename F, typename Op>
using signature_t = typename std::conditional_t<requires(F& func) {
(void)func.operator();
}, signature_static<Op>, signature<Op>>::sig_type;
/*
template<typename Sig>
class function;
template<typename Ret, typename... Args>
class function<Ret(Args...)>
{
};
template<typename Ret, typename... Args>
function(Ret (*)(Args...)) -> function<Ret(Args...)>;
template<typename F, typename Sig = signature_t<F, decltype(&F::operator())>>
function(F) -> function<Sig>;
*/
} // namespace based
diff --git a/ include/based/type_traits/type_identity.hpp b/ include/based/type_traits/type_identity.hpp
@@ -0,0 +1,14 @@
#pragma once
namespace based
{
// clang-format off
template<class T> struct type_identity { using type = T; };
template<class T> using type_dentity_t = type_identity<T>::type;
// clang-format on
} // namespace based
diff --git a/ include/based/types/types.hpp b/ include/based/types/types.hpp
@@ -0,0 +1,22 @@
#pragma once
namespace based
{
// NOLINTBEGIN(google-runtime-int)
using i8 = signed char;
using i16 = signed short int;
using i32 = signed int;
using i64 = signed long int;
using u8 = unsigned char;
using u16 = unsigned short int;
using u32 = unsigned int;
using u64 = unsigned long int;
using size_t = u64;
// NOLINTEND(google-runtime-int)
} // namespace based
diff --git a/ include/based/utility.hpp b/ include/based/utility.hpp
@@ -1,24 +0,0 @@
#pragma once
#include <exception>
namespace based
{
class uncaught_exception_detector
{
int m_count;
public:
uncaught_exception_detector()
: m_count(std::uncaught_exceptions())
{
}
operator bool() const noexcept // NOLINT(*explicit*)
{
return std::uncaught_exceptions() > m_count;
}
};
} // namespace based
diff --git a/ include/based/utility/buffer.hpp b/ include/based/utility/buffer.hpp
@@ -0,0 +1,75 @@
#pragma once
#include <concepts>
#include <cstring>
#include <utility>
#include "based/types/types.hpp"
namespace based
{
/* ----- Buffer used for Local Buffer Optimization ----- */
template<size_t size, size_t alignment = alignof(void*)>
struct buffer
{
template<typename T>
static constexpr bool valid_type()
{
return sizeof(T) <= size && (alignment % sizeof(T)) == 0;
}
alignas(alignment) char m_space[size] = {0}; // NOLINT(*array*)
buffer() = default;
template<typename T, typename... Args>
requires(valid_type<T>() && std::constructible_from<T, Args...>)
explicit buffer(
std::in_place_type_t<T> /* t */, Args&&... args
) noexcept(std::is_nothrow_constructible_v<T, Args...>)
{
static_assert(std::is_trivially_destructible_v<T>);
static_assert(std::is_trivially_copyable_v<T>);
::new (static_cast<void*>(as<T>())) T(std::forward<Args>(args)...);
}
template<typename T, typename... Args>
requires(valid_type<T>() && std::constructible_from<T, Args...>)
T* emplace(Args&&... args
) noexcept(std::is_nothrow_constructible_v<T, Args...>)
{
static_assert(std::is_trivially_destructible_v<T>);
static_assert(std::is_trivially_copyable_v<T>);
// NOLINTNEXTLINE(*owning-memory*)
return ::new (static_cast<void*>(as<T>())) T(std::forward<Args>(args)...);
}
template<typename T>
requires(valid_type<T>())
[[nodiscard]] T* as() noexcept
{
return reinterpret_cast<T*>(&m_space); // NOLINT(*reinterpret-cast*)
}
template<typename T>
requires(valid_type<T>())
[[nodiscard]] const T* as() const noexcept
{
return const_cast<buffer*>(this)->as<T>(); // NOLINT(*const-cast*)
}
void swap(buffer& that) noexcept
{
// NOLINTBEGIN(*array*)
alignas(alignment) char tmp[size];
::memcpy(tmp, this->m_space, size);
::memcpy(this->m_space, that.m_space, size);
::memcpy(that.m_space, tmp, size);
// NOLINTEND(*array*)
}
};
} // namespace based
diff --git a/ include/based/utility/declvar.hpp b/ include/based/utility/declvar.hpp
@@ -0,0 +1,14 @@
#pragma once
#include "based/type_traits/add/rvalue_reference.hpp"
namespace based
{
template<typename T>
add_rvalue_reference_t<T> declval() noexcept
{
static_assert(false, "declval not allowed in an evaluated context");
}
} // namespace based
diff --git a/ include/based/utility/scopeguard.hpp b/ include/based/utility/scopeguard.hpp
@@ -0,0 +1,84 @@
#pragma once
#include "based/utility/uncaught_exception.hpp"
namespace based
{
template<typename Func, bool on_success = false, bool on_failure = false>
class scopeguard
{
uncaught_exception_detector m_detector;
Func m_func;
public:
scopeguard(Func&& func) // NOLINT(*explicit*)
: m_func(std::move(func))
{
}
/*
scopeguard(const Func& func) // NOLINT(*explicit*)
: m_func(func)
{
}
*/
scopeguard(const scopeguard&) = delete;
scopeguard& operator=(const scopeguard&) = delete;
scopeguard(scopeguard&&) = delete;
scopeguard& operator=(scopeguard&&) = delete;
~scopeguard()
{
if ((on_success && !m_detector) || (on_failure && m_detector)) {
m_func();
}
}
};
template<typename Func>
class scopeguard<Func, false, false>
{
bool m_commit = false;
Func m_func;
public:
scopeguard(Func&& func) // NOLINT(*explicit*)
: m_func(std::move(func))
{
}
/*
scopeguard(const Func& func) // NOLINT(*explicit*)
: m_func(func)
{
}
*/
scopeguard(const scopeguard&) = delete;
scopeguard& operator=(const scopeguard&) = delete;
scopeguard(scopeguard&&) = delete;
scopeguard& operator=(scopeguard&&) = delete;
~scopeguard()
{
if (m_commit) {
m_func();
}
}
void commit() { m_commit = true; }
};
template<typename Func>
using scopeguard_exit = scopeguard<Func, true, true>;
template<typename Func>
using scopeguard_success = scopeguard<Func, true, false>;
template<typename Func>
using scopeguard_failure = scopeguard<Func, false, true>;
} // namespace based
diff --git a/ include/based/utility/uncaught_exception.hpp b/ include/based/utility/uncaught_exception.hpp
@@ -0,0 +1,24 @@
#pragma once
#include <exception>
namespace based
{
class uncaught_exception_detector
{
int m_count;
public:
uncaught_exception_detector()
: m_count(std::uncaught_exceptions())
{
}
operator bool() const noexcept // NOLINT(*explicit*)
{
return std::uncaught_exceptions() > m_count;
}
};
} // namespace based
diff --git a/ test/CMakeLists.txt b/ test/CMakeLists.txt
@@ -17,76 +17,78 @@
include(Catch)
# ---- Tests ----
function(add_test NAME)
add_executable("${NAME}" "source/${NAME}.cpp")
function(add_test DIR NAME)
add_executable("${NAME}" "source/${DIR}/${NAME}.cpp")
target_link_libraries("${NAME}" PRIVATE based::based)
target_link_libraries("${NAME}" PRIVATE Catch2::Catch2WithMain)
target_compile_features("${NAME}" PRIVATE cxx_std_20)
catch_discover_tests("${NAME}")
endfunction()
# ----- Algorithm -----
# ----- Type Traits -----
## ----- Type Traits -----
add_test(standard_traits_test)
add_test(signature_test)
add_test(callable_test)
add_test(type_traits remove_const)
add_test(type_traits remove_cv)
add_test(type_traits remove_cvref)
add_test(type_traits remove_pointer)
add_test(type_traits remove_reference)
add_test(type_traits remove_volatile)
add_test(type_traits signature_test)
## ----- Min and Max -----
## ----- Concepts -----
add_test(min_test)
add_test(max_test)
add_test(concepts callable_test)
## ----- Bounded Range -----
## ----- Algorithm -----
add_test(min_element_test)
add_test(max_element_test)
add_test(minmax_element_test)
add_test(algorithms all_test)
add_test(algorithms count_if_not_test)
add_test(algorithms count_if_test)
add_test(algorithms count_not_test)
add_test(algorithms count_test)
add_test(algorithms find_adjacent_mismatch_test)
add_test(algorithms find_if_not_test)
add_test(algorithms find_if_test)
add_test(algorithms find_mismatch_test)
add_test(algorithms find_not_test)
add_test(algorithms find_test)
add_test(algorithms foreach_test)
add_test(algorithms lower_bound_test)
add_test(algorithms max_element_test)
add_test(algorithms max_test)
add_test(algorithms min_element_test)
add_test(algorithms minmax_element_test)
add_test(algorithms min_test)
add_test(algorithms none_test)
add_test(algorithms not_all_test)
add_test(algorithms partitioned_test)
add_test(algorithms partition_point_test)
add_test(algorithms reduce_test)
add_test(algorithms some_test)
add_test(algorithms upper_bound_test)
add_test(for_each_test)
add_test(find_test)
add_test(find_if_test)
add_test(count_test)
add_test(count_if_test)
add_test(reduce_test)
add_test(find_mismatch_test)
add_test(partition_test)
## ----- Utility -----
## ----- Counted Range -----
add_test(utility buffer_test)
add_test(utility scopeguard_test)
add_test(for_each_n_test)
add_test(find_n_test)
add_test(find_if_n_test)
add_test(count_n_test)
add_test(count_if_n_test)
add_test(find_mismatch_n_test)
## ----- Functional -----
## ----- Unguarded Range -----
add_test(functional curry_test)
add_test(functional function_test)
add_test(find_if_unguarded_test)
## ------ Enum -----
# ---- List ----
add_test(. enum_test)
add_test(list_test)
## ----- List -----
# ---- String ----
add_test(. list_test)
add_test(string_literal_test)
## ----- String -----
# ---- Template ----
add_test(buffer_test)
add_test(function_test)
add_test(scopeguard_test)
# ----- Functional -----
add_test(curry_test)
# ------ Enum -----
add_test(enum_test)
add_test(. string_literal_test)
# ---- End-of-file commands ----
diff --git a/ test/source/algorithms/all_test.cpp b/ test/source/algorithms/all_test.cpp
@@ -0,0 +1,63 @@
#include <array>
#include "based/algorithms/search/all.hpp"
#include <catch2/catch_test_macros.hpp>
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("all(empty)", "[algorithm/all]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::all(std::begin(arr), std::end(arr), predicate {0}));
}
TEST_CASE("all(homogeneous)", "[algorithm/all]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::all(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(!based::all(std::begin(arr), std::end(arr), predicate {2}));
}
TEST_CASE("all(non homogenous)", "[algorithm/all]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(!based::all(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(!based::all(std::begin(arr), std::end(arr), predicate {2}));
}
TEST_CASE("all_n(empty)", "[algorithm/all_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::all_n(std::begin(arr), std::size(arr), predicate {0}));
}
TEST_CASE("all_n(homogeneous)", "[algorithm/all_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::all_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(!based::all_n(std::begin(arr), std::size(arr), predicate {2}));
}
TEST_CASE("all_n(non homogenous)", "[algorithm/all_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(!based::all_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(!based::all_n(std::begin(arr), std::size(arr), predicate {2}));
}
diff --git a/ test/source/algorithms/count_if_not_test.cpp b/ test/source/algorithms/count_if_not_test.cpp
@@ -0,0 +1,161 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <array>
#include "based/algorithms/search/count_if_not.hpp"
#include <catch2/catch_test_macros.hpp>
#include "based/concepts/is/same.hpp"
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("count_if_not return type", "[algorithm/count_if_not]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t = decltype(based::count_if_not(
std::begin(arr), std::end(arr), predicate {0}
));
STATIC_REQUIRE(based::SameAs<
based::iter_dist_t<decltype(arr)::iterator>,
res_t>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count_if_not(
std::begin(arr), std::end(arr), predicate {0}, based::u8 {0}
));
STATIC_REQUIRE(based::SameAs<based::u8, res_t>);
}
}
TEST_CASE("count_if_not(empty)", "[algorithm/count_if_not]")
{
const std::array<int, 0> arr = {};
const auto count =
based::count_if_not(std::begin(arr), std::end(arr), predicate {0});
REQUIRE(count == 0);
}
TEST_CASE("count_if_not(homogeneous)", "[algorithm/count_if_not]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto count0 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto count1 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {1});
REQUIRE(count0 == 6);
REQUIRE(count1 == 0);
}
TEST_CASE("count_if_not(non homogeneous)", "[algorithm/count_if_not]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto count0 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto count1 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {1});
const auto count2 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {2});
REQUIRE(count0 == 6);
REQUIRE(count1 == 2);
REQUIRE(count2 == 4);
}
TEST_CASE("count_if_not_n return type", "[algorithm/count_if_not_n]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t = decltype(based::count_if_not_n(
std::begin(arr), std::size(arr), predicate {0}
));
STATIC_REQUIRE(based::SameAs<
based::iter_dist_t<decltype(arr)::iterator>,
res_t::second_type>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count_if_not_n(
std::begin(arr), std::size(arr), predicate {0}, based::u8 {0}
));
STATIC_REQUIRE(based::SameAs<based::u8, res_t::second_type>);
}
}
TEST_CASE("count_if_not_n(empty)", "[algorithm/count_if_not_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, count] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {0});
REQUIRE(count == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("count_if_not_n(homogeneous)", "[algorithm/count_if_not_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto [itr0, count0] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto [itr1, count1] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {1});
REQUIRE(count0 == 6);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 0);
REQUIRE(itr1 == std::end(arr));
}
TEST_CASE("count_if_not_n(non homogeneous)", "[algorithm/count_if_not_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto [itr0, count0] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto [itr1, count1] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {1});
const auto [itr2, count2] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {2});
REQUIRE(count0 == 6);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 2);
REQUIRE(itr1 == std::end(arr));
REQUIRE(count2 == 4);
REQUIRE(itr2 == std::end(arr));
}
diff --git a/ test/source/algorithms/count_if_test.cpp b/ test/source/algorithms/count_if_test.cpp
@@ -0,0 +1,164 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <array>
#include "based/algorithms/search/count_if.hpp"
#include <catch2/catch_test_macros.hpp>
#include "based/concepts/is/same.hpp"
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("count_if return type", "[algorithm/count_if]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t =
decltype(based::count_if(std::begin(arr), std::end(arr), predicate {0})
);
STATIC_REQUIRE(based::SameAs<
based::iter_dist_t<decltype(arr)::iterator>,
res_t>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count_if(
std::begin(arr), std::end(arr), predicate {0}, based::u8 {0}
));
STATIC_REQUIRE(based::SameAs<based::u8, res_t>);
}
}
TEST_CASE("count_if(empty)", "[algorithm/count_if]")
{
const std::array<int, 0> arr = {};
const auto count =
based::count_if(std::begin(arr), std::end(arr), predicate {0});
REQUIRE(count == 0);
}
TEST_CASE("count_if(homogeneous)", "[algorithm/count_if]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto count0 =
based::count_if(std::begin(arr), std::end(arr), predicate {0});
const auto count1 =
based::count_if(std::begin(arr), std::end(arr), predicate {1});
REQUIRE(count0 == 0);
REQUIRE(count1 == 6);
}
TEST_CASE("count_if(non homogeneous)", "[algorithm/count_if]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto count0 =
based::count_if(std::begin(arr), std::end(arr), predicate {0});
const auto count1 =
based::count_if(std::begin(arr), std::end(arr), predicate {1});
const auto count2 =
based::count_if(std::begin(arr), std::end(arr), predicate {2});
REQUIRE(count0 == 0);
REQUIRE(count1 == 4);
REQUIRE(count2 == 2);
}
TEST_CASE("count_if_n return type", "[algorithm/count_if_n]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t = decltype(based::count_if_n(
std::begin(arr), std::size(arr), predicate {0}
)
.second);
STATIC_REQUIRE(based::SameAs<
based::iter_dist_t<decltype(arr)::iterator>,
res_t>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count_if_n(
std::begin(arr),
std::size(arr),
predicate {0},
based::u8 {0}
)
.second);
STATIC_REQUIRE(based::SameAs<based::u8, res_t>);
}
}
TEST_CASE("count_if_n(empty)", "[algorithm/count_if_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, count] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {0});
REQUIRE(count == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("count_if_n(homogeneous)", "[algorithm/count_if_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto [itr0, count0] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto [itr1, count1] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {1});
REQUIRE(count0 == 0);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 6);
REQUIRE(itr1 == std::end(arr));
}
TEST_CASE("count_if_n(non homogeneous)", "[algorithm/count_if_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto [itr0, count0] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto [itr1, count1] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {1});
const auto [itr2, count2] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {2});
REQUIRE(count0 == 0);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 4);
REQUIRE(itr1 == std::end(arr));
REQUIRE(count2 == 2);
REQUIRE(itr2 == std::end(arr));
}
diff --git a/ test/source/algorithms/count_not_test.cpp b/ test/source/algorithms/count_not_test.cpp
@@ -0,0 +1,138 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <array>
#include "based/algorithms/search/count_not.hpp"
#include <catch2/catch_test_macros.hpp>
TEST_CASE("count_not return type", "[algorithm/count_not]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t = decltype(based::count_not(std::begin(arr), std::end(arr), 0));
STATIC_REQUIRE(based::SameAs<
based::iter_dist_t<decltype(arr)::iterator>,
res_t>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count_not(
std::begin(arr), std::end(arr), 0, based::u8 {0}
));
STATIC_REQUIRE(based::SameAs<based::u8, res_t>);
}
}
TEST_CASE("count_not(empty)", "[algorithm/count_not]")
{
const std::array<int, 0> arr = {};
const auto count_not = based::count_not(std::begin(arr), std::end(arr), 0);
REQUIRE(count_not == 0);
}
TEST_CASE("count_not(homogeneous)", "[algorithm/count_not]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto count0 = based::count_not(std::begin(arr), std::end(arr), 0);
const auto count1 = based::count_not(std::begin(arr), std::end(arr), 1);
REQUIRE(count0 == 6);
REQUIRE(count1 == 0);
}
TEST_CASE("count_not(non homogeneous)", "[algorithm/count_not]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto count0 = based::count_not(std::begin(arr), std::end(arr), 0);
const auto count1 = based::count_not(std::begin(arr), std::end(arr), 1);
const auto count2 = based::count_not(std::begin(arr), std::end(arr), 2);
REQUIRE(count0 == 6);
REQUIRE(count1 == 2);
REQUIRE(count2 == 4);
}
TEST_CASE("count_not_n return type", "[algorithm/count_not_n]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t =
decltype(based::count_not_n(std::begin(arr), std::size(arr), 0));
STATIC_REQUIRE(based::SameAs<
based::iter_dist_t<decltype(arr)::iterator>,
res_t::second_type>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count_not_n(
std::begin(arr), std::size(arr), 0, based::u8 {0}
));
STATIC_REQUIRE(based::SameAs<based::u8, res_t::second_type>);
}
}
TEST_CASE("count_not_n(empty)", "[algorithm/count_not_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, count] =
based::count_not_n(std::begin(arr), std::size(arr), 0);
REQUIRE(count == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("count_not_n(homogeneous)", "[algorithm/count_not_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto [itr0, count0] =
based::count_not_n(std::begin(arr), std::size(arr), 0);
const auto [itr1, count1] =
based::count_not_n(std::begin(arr), std::size(arr), 1);
REQUIRE(count0 == 6);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 0);
REQUIRE(itr1 == std::end(arr));
}
TEST_CASE("count_not_n(non homogeneous)", "[algorithm/count_not_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto [itr0, count0] =
based::count_not_n(std::begin(arr), std::size(arr), 0);
const auto [itr1, count1] =
based::count_not_n(std::begin(arr), std::size(arr), 1);
const auto [itr2, count2] =
based::count_not_n(std::begin(arr), std::size(arr), 2);
REQUIRE(count0 == 6);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 2);
REQUIRE(itr1 == std::end(arr));
REQUIRE(count2 == 4);
REQUIRE(itr2 == std::end(arr));
}
diff --git a/ test/source/algorithms/count_test.cpp b/ test/source/algorithms/count_test.cpp
@@ -0,0 +1,137 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <array>
#include "based/algorithms/search/count.hpp"
#include <catch2/catch_test_macros.hpp>
TEST_CASE("count return type", "[algorithm/count]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t = decltype(based::count(std::begin(arr), std::end(arr), 0));
STATIC_REQUIRE(based::SameAs<
based::iter_dist_t<decltype(arr)::iterator>,
res_t>);
}
SECTION("explicit counter")
{
using res_t =
decltype(based::count(std::begin(arr), std::end(arr), 0, based::u8 {0})
);
STATIC_REQUIRE(based::SameAs<based::u8, res_t>);
}
}
TEST_CASE("count(empty)", "[algorithm/count]")
{
const std::array<int, 0> arr = {};
const auto count = based::count(std::begin(arr), std::end(arr), 0);
REQUIRE(count == 0);
}
TEST_CASE("count(homogeneous)", "[algorithm/count]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto count0 = based::count(std::begin(arr), std::end(arr), 0);
const auto count1 = based::count(std::begin(arr), std::end(arr), 1);
REQUIRE(count0 == 0);
REQUIRE(count1 == 6);
}
TEST_CASE("count(non homogeneous)", "[algorithm/count]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto count0 = based::count(std::begin(arr), std::end(arr), 0);
const auto count1 = based::count(std::begin(arr), std::end(arr), 1);
const auto count2 = based::count(std::begin(arr), std::end(arr), 2);
REQUIRE(count0 == 0);
REQUIRE(count1 == 4);
REQUIRE(count2 == 2);
}
TEST_CASE("count_n return type", "[algorithm/count_n]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t =
decltype(based::count_n(std::begin(arr), std::size(arr), 0).second);
STATIC_REQUIRE(based::SameAs<
based::iter_dist_t<decltype(arr)::iterator>,
res_t>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count_n(
std::begin(arr), std::size(arr), 0, based::u8 {0}
)
.second);
STATIC_REQUIRE(based::SameAs<based::u8, res_t>);
}
}
TEST_CASE("count_n(empty)", "[algorithm/count_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, count] = based::count_n(std::begin(arr), std::size(arr), 0);
REQUIRE(count == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("count_n(homogeneous)", "[algorithm/count_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto [itr0, count0] =
based::count_n(std::begin(arr), std::size(arr), 0);
const auto [itr1, count1] =
based::count_n(std::begin(arr), std::size(arr), 1);
REQUIRE(count0 == 0);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 6);
REQUIRE(itr1 == std::end(arr));
}
TEST_CASE("count_n(non homogeneous)", "[algorithm/count_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto [itr0, count0] =
based::count_n(std::begin(arr), std::size(arr), 0);
const auto [itr1, count1] =
based::count_n(std::begin(arr), std::size(arr), 1);
const auto [itr2, count2] =
based::count_n(std::begin(arr), std::size(arr), 2);
REQUIRE(count0 == 0);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 4);
REQUIRE(itr1 == std::end(arr));
REQUIRE(count2 == 2);
REQUIRE(itr2 == std::end(arr));
}
diff --git a/ test/source/algorithms/find_adjacent_mismatch_test.cpp b/ test/source/algorithms/find_adjacent_mismatch_test.cpp
@@ -0,0 +1,160 @@
#include <array>
#include "based/algorithms/search/find_adjacent_mismatch.hpp"
#include <catch2/catch_test_macros.hpp>
struct equal
{
auto operator()(int a, int b) const { return a == b; }
};
TEST_CASE("find_adjacent_mismatch(empty)", "[algorithm/find_adjacent_mismatch]")
{
std::array<int, 0> arr = {};
const auto* itr =
based::find_adjacent_mismatch(std::begin(arr), std::end(arr), equal {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_adjacent_mismatch(one)", "[algorithm/find_adjacent_mismatch]")
{
std::array arr = {0};
const auto* itr =
based::find_adjacent_mismatch(std::begin(arr), std::end(arr), equal {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch(two equal)", "[algorithm/find_adjacent_mismatch]"
)
{
std::array arr = {0, 0};
const auto* itr =
based::find_adjacent_mismatch(std::begin(arr), std::end(arr), equal {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch(two nonequal)", "[algorithm/find_adjacent_mismatch]"
)
{
std::array arr = {0, 1};
const auto* itr =
based::find_adjacent_mismatch(std::begin(arr), std::end(arr), equal {});
REQUIRE(itr == std::next(std::begin(arr), 1));
}
TEST_CASE("find_adjacent_mismatch(equal)", "[algorithm/find_adjacent_mismatch]")
{
std::array arr = {0, 0, 0, 0, 0, 0};
const auto* itr =
based::find_adjacent_mismatch(std::begin(arr), std::end(arr), equal {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch(nonequal)", "[algorithm/find_adjacent_mismatch]"
)
{
std::array arr = {0, 0, 0, 0, 1, 1, 1, 1};
const auto* itr =
based::find_adjacent_mismatch(std::begin(arr), std::end(arr), equal {});
REQUIRE(itr == std::next(std::begin(arr), 4));
}
TEST_CASE(
"find_adjacent_mismatch_forward(empty)",
"[algorithm/find_adjacent_mismatch_forward]"
)
{
std::array<int, 0> arr = {};
const auto* itr = based::find_adjacent_mismatch_forward(
std::begin(arr), std::end(arr), equal {}
);
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch_forward(one)",
"[algorithm/find_adjacent_mismatch_forward]"
)
{
std::array arr = {0};
const auto* itr = based::find_adjacent_mismatch_forward(
std::begin(arr), std::end(arr), equal {}
);
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch_forward(two equal)",
"[algorithm/find_adjacent_mismatch_forward]"
)
{
std::array arr = {0, 0};
const auto* itr = based::find_adjacent_mismatch_forward(
std::begin(arr), std::end(arr), equal {}
);
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch_forward(two nonequal)",
"[algorithm/find_adjacent_mismatch_forward]"
)
{
std::array arr = {0, 1};
const auto* itr = based::find_adjacent_mismatch_forward(
std::begin(arr), std::end(arr), equal {}
);
REQUIRE(itr == std::next(std::begin(arr), 1));
}
TEST_CASE(
"find_adjacent_mismatch_forward(equal)",
"[algorithm/find_adjacent_mismatch_forward]"
)
{
std::array arr = {0, 0, 0, 0, 0, 0};
const auto* itr = based::find_adjacent_mismatch_forward(
std::begin(arr), std::end(arr), equal {}
);
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch_forward(nonequal)",
"[algorithm/find_adjacent_mismatch_forward]"
)
{
std::array arr = {0, 0, 0, 0, 1, 1, 1, 1};
const auto* itr = based::find_adjacent_mismatch_forward(
std::begin(arr), std::end(arr), equal {}
);
REQUIRE(itr == std::next(std::begin(arr), 4));
}
diff --git a/ test/source/algorithms/find_if_not_test.cpp b/ test/source/algorithms/find_if_not_test.cpp
@@ -0,0 +1,206 @@
#include <array>
#include "based/algorithms/search/find_if_not.hpp"
#include <catch2/catch_test_macros.hpp>
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("find_if_not_n(empty)", "[algorithm/find_if_not_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {0});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_if_not_n(one)", "[algorithm/find_if_not_n]")
{
const std::array arr = {0};
SECTION("found")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_not_n(two)", "[algorithm/find_if_not_n]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("found 2")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_not_n(multiple)", "[algorithm/find_if_not_n]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_not(empty)", "[algorithm/find_if_not]")
{
const std::array<int, 0> arr = {};
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {0});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_if_not(one)", "[algorithm/find_if_not]")
{
const std::array arr = {0};
SECTION("found")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}
TEST_CASE("find_if_not(two)", "[algorithm/find_if_not]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("found 2")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}
TEST_CASE("find_if_not(multiple)", "[algorithm/find_if_not]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
}
}
TEST_CASE("find_if_not_unguarded(one)", "[algorithm/find_if_not_unguarded]")
{
const std::array arr = {0};
const auto* itr =
based::find_if_not_unguarded(std::begin(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("find_if_not_unguarded(two)", "[algorithm/find_if_not_unguarded]")
{
const std::array arr = {0, 1};
const auto* itr =
based::find_if_not_unguarded(std::begin(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE(
"find_if_not_unguarded(multiple)", "[algorithm/find_if_not_unguarded]"
)
{
const std::array arr = {1, 1, 0, 1};
const auto* itr =
based::find_if_not_unguarded(std::begin(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
diff --git a/ test/source/algorithms/find_if_test.cpp b/ test/source/algorithms/find_if_test.cpp
@@ -0,0 +1,218 @@
#include <array>
#include "based/algorithms/search/find_if.hpp"
#include <catch2/catch_test_macros.hpp>
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("find_if(empty)", "[algorithm/find_if]")
{
const std::array<int, 0> arr = {};
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {0});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_if(one)", "[algorithm/find_if]")
{
const std::array arr = {0};
SECTION("found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}
TEST_CASE("find_if(two)", "[algorithm/find_if]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("found 2")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
SECTION("not found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {2});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
}
TEST_CASE("find_if(multiple)", "[algorithm/find_if]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
}
}
TEST_CASE("find_if_n(empty)", "[algorithm/find_if_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {0});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_if_n(one)", "[algorithm/find_if_n]")
{
const std::array arr = {0};
SECTION("found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_n(two)", "[algorithm/find_if_n]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("found 2")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {2});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_n(multiple)", "[algorithm/find_if_n]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_unguarded(one)", "[algorithm/find_if_unguarded]")
{
const std::array arr = {0};
const auto* itr = based::find_if_unguarded(std::begin(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("find_if_unguarded(two)", "[algorithm/find_if_unguarded]")
{
const std::array arr = {0, 1};
const auto* itr = based::find_if_unguarded(std::begin(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("find_if_unguarded(multiple)", "[algorithm/find_if_unguarded]")
{
const std::array arr = {0, 0, 0, 0};
const auto* itr = based::find_if_unguarded(std::begin(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
diff --git a/ test/source/algorithms/find_mismatch_test.cpp b/ test/source/algorithms/find_mismatch_test.cpp
@@ -0,0 +1,535 @@
#include <array>
#include "based/algorithms/search/find_mismatch.hpp"
#include <catch2/catch_test_macros.hpp>
struct equal
{
auto operator()(int lhs, int rhs) const { return lhs == rhs; }
};
TEST_CASE("find_mismatch(empty)", "[algorithm/find_mismatch]")
{
std::array<int, 0> arr0 = {};
std::array<int, 0> arr1 = {};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch(empty, nonempty)", "[algorithm/find_mismatch]")
{
std::array<int, 0> arr0 = {};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::begin(arr1));
}
TEST_CASE("find_mismatch(nonempty, empty)", "[algorithm/find_mismatch]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array<int, 0> arr1 = {};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::begin(arr0));
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch(equal)", "[algorithm/find_mismatch]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch(equal, longer)", "[algorithm/find_mismatch]")
{
std::array arr0 = {0, 1, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::next(std::begin(arr1), std::size(arr0)));
}
TEST_CASE("find_mismatch(longer, equal)", "[algorithm/find_mismatch]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), std::size(arr1)));
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch(mismatch)", "[algorithm/find_mismatch]")
{
std::array arr0 = {0, 1, 4, 3, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), 2));
REQUIRE(itr1 == std::next(std::begin(arr1), 2));
}
TEST_CASE("find_mismatch_n(empty)", "[algorithm/find_mismatch_n]")
{
std::array<int, 0> arr0 = {};
std::array<int, 0> arr1 = {};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch_n(empty, nonempty)", "[algorithm/find_mismatch_n]")
{
std::array<int, 0> arr0 = {};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::begin(arr1));
}
TEST_CASE("find_mismatch_n(nonempty, empty)", "[algorithm/find_mismatch_n]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array<int, 0> arr1 = {};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::begin(arr0));
REQUIRE(n0 == std::size(arr0));
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch_n(equal)", "[algorithm/find_mismatch_n]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch_n(equal, longer)", "[algorithm/find_mismatch_n]")
{
std::array arr0 = {0, 1, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::next(std::begin(arr1), std::size(arr0)));
}
TEST_CASE("find_mismatch_n(longer, equal)", "[algorithm/find_mismatch_n]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), std::size(arr1)));
REQUIRE(n0 == 2);
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch_n(mismatch)", "[algorithm/find_mismatch_n]")
{
std::array arr0 = {0, 1, 4, 3, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), 2));
REQUIRE(n0 == 3);
REQUIRE(itr1 == std::next(std::begin(arr1), 2));
}
TEST_CASE("find_mismatch_m(empty)", "[algorithm/find_mismatch_m]")
{
std::array<int, 0> arr0 = {};
std::array<int, 0> arr1 = {};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_m(empty, nonempty)", "[algorithm/find_mismatch_m]")
{
std::array<int, 0> arr0 = {};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::begin(arr1));
REQUIRE(n1 == std::size(arr1));
}
TEST_CASE("find_mismatch_m(nonempty, empty)", "[algorithm/find_mismatch_m]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array<int, 0> arr1 = {};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::begin(arr0));
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_m(equal)", "[algorithm/find_mismatch_m]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_m(equal, longer)", "[algorithm/find_mismatch_m]")
{
std::array arr0 = {0, 1, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::next(std::begin(arr1), std::size(arr0)));
REQUIRE(n1 == 2);
}
TEST_CASE("find_mismatch_m(longer, equal)", "[algorithm/find_mismatch_m]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), std::size(arr1)));
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_m(mismatch)", "[algorithm/find_mismatch_m]")
{
std::array arr0 = {0, 1, 4, 3, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), 2));
REQUIRE(itr1 == std::next(std::begin(arr1), 2));
REQUIRE(n1 == 3);
}
TEST_CASE("find_mismatch_n_m(empty)", "[algorithm/find_mismatch_n_m]")
{
std::array<int, 0> arr0 = {};
std::array<int, 0> arr1 = {};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_n_m(empty, nonempty)", "[algorithm/find_mismatch_n_m]")
{
std::array<int, 0> arr0 = {};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::begin(arr1));
REQUIRE(n1 == std::size(arr1));
}
TEST_CASE("find_mismatch_n_m(nonempty, empty)", "[algorithm/find_mismatch_n_m]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array<int, 0> arr1 = {};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::begin(arr0));
REQUIRE(n0 == std::size(arr0));
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_n_m(equal)", "[algorithm/find_mismatch_n_m]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_n_m(equal, longer)", "[algorithm/find_mismatch_n_m]")
{
std::array arr0 = {0, 1, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::next(std::begin(arr1), std::size(arr0)));
REQUIRE(n1 == 2);
}
TEST_CASE("find_mismatch_n_m(longer, equal)", "[algorithm/find_mismatch_n_m]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), std::size(arr1)));
REQUIRE(n0 == 2);
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_n_m(mismatch)", "[algorithm/find_mismatch_n_m]")
{
std::array arr0 = {0, 1, 4, 3, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), 2));
REQUIRE(n0 == 3);
REQUIRE(itr1 == std::next(std::begin(arr1), 2));
REQUIRE(n1 == 3);
}
diff --git a/ test/source/algorithms/find_not_test.cpp b/ test/source/algorithms/find_not_test.cpp
@@ -0,0 +1,157 @@
#include <array>
#include "based/algorithms/search/find_not.hpp"
#include <catch2/catch_test_macros.hpp>
TEST_CASE("find_not(empty)", "[algorithm/find_not]")
{
const std::array<int, 0> arr = {};
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_not(one) = found", "[algorithm/find_not]")
{
const std::array arr = {0};
SECTION("found")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}
TEST_CASE("find_not(two) = found", "[algorithm/find_not]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("found 2")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}
TEST_CASE("find_not(multiple) = found", "[algorithm/find_not]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
}
}
TEST_CASE("find_not_n(empty)", "[algorithm/find_not_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
TEST_CASE("find_not_n(one)", "[algorithm/find_not_n]")
{
const std::array arr = {0};
SECTION("found")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_not_n(two)", "[algorithm/find_not_n]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("found 2")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_not_n(multiple)", "[algorithm/find_not_n]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
REQUIRE(idx + left == std::size(arr));
}
}
diff --git a/ test/source/algorithms/find_test.cpp b/ test/source/algorithms/find_test.cpp
@@ -0,0 +1,164 @@
#include <array>
#include "based/algorithms/search/find.hpp"
#include <catch2/catch_test_macros.hpp>
TEST_CASE("find(empty)", "[algorithm/find]")
{
const std::array<int, 0> arr = {};
const auto* itr = based::find(std::begin(arr), std::end(arr), 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find(one) = found", "[algorithm/find]")
{
const std::array arr = {0};
SECTION("found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}
TEST_CASE("find(two) = found", "[algorithm/find]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("found 2")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
SECTION("not found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 2);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
}
TEST_CASE("find(multiple) = found", "[algorithm/find]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
}
}
TEST_CASE("find_n(empty)", "[algorithm/find_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
TEST_CASE("find_n(one)", "[algorithm/find_n]")
{
const std::array arr = {0};
SECTION("found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_n(two)", "[algorithm/find_n]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("found 2")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 2);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_n(multiple)", "[algorithm/find_n]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
REQUIRE(idx + left == std::size(arr));
}
}
diff --git a/ test/source/algorithms/foreach_test.cpp b/ test/source/algorithms/foreach_test.cpp
@@ -0,0 +1,84 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithms/batch/for_each.hpp"
struct functor
{
int operator()(int n) { return sum += n; }
int sum = 0;
};
TEST_CASE("for_each(empty)", "[algorithm/for_each]")
{
const std::array<int, 0> arr = {};
const auto func = based::for_each(std::begin(arr), std::end(arr), functor {});
REQUIRE(func.sum == 0);
}
TEST_CASE("for_each(one)", "[algorithm/for_each]")
{
const std::array arr = {1};
const auto func = based::for_each(std::begin(arr), std::end(arr), functor {});
REQUIRE(func.sum == 1);
}
TEST_CASE("for_each(two)", "[algorithm/for_each]")
{
const std::array arr = {1, 2};
const auto func = based::for_each(std::begin(arr), std::end(arr), functor {});
REQUIRE(func.sum == 3);
}
TEST_CASE("for_each(three)", "[algorithm/for_each]")
{
const std::array arr = {1, 2, 3};
const auto func = based::for_each(std::begin(arr), std::end(arr), functor {});
REQUIRE(func.sum == 6);
}
TEST_CASE("for_each_n(empty)", "[algorithm/for_each_n]")
{
const std::array<int, 0> arr = {};
const auto [f, itr] =
based::for_each_n(std::begin(arr), std::size(arr), functor {});
REQUIRE(f.sum == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("for_each_n(one)", "[algorithm/for_each_n]")
{
const std::array arr = {1};
const auto [f, itr] =
based::for_each_n(std::begin(arr), std::size(arr), functor {});
REQUIRE(f.sum == 1);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("for_each_n(two)", "[algorithm/for_each_n]")
{
const std::array arr = {1, 2};
const auto [f, itr] =
based::for_each_n(std::begin(arr), std::size(arr), functor {});
REQUIRE(f.sum == 3);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("for_each_n(three)", "[algorithm/for_each_n]")
{
const std::array arr = {1, 2, 3};
const auto [f, itr] =
based::for_each_n(std::begin(arr), std::size(arr), functor {});
REQUIRE(f.sum == 6);
REQUIRE(itr == std::end(arr));
}
diff --git a/ test/source/algorithms/lower_bound_test.cpp b/ test/source/algorithms/lower_bound_test.cpp
@@ -0,0 +1,48 @@
#include <array>
#include "based/algorithms/bsearch/lower_bound.hpp"
#include <catch2/catch_test_macros.hpp>
struct equal
{
auto operator()(int a) const { return a == goal; }
int goal;
};
TEST_CASE("lower_bound(empty)", "[algorithm/lower_bound]")
{
std::array<int, 0> arr = {};
const auto* itr =
based::lower_bound(std::begin(arr), std::end(arr), 4, std::less<int> {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("lower_bound(one equal)", "[algorithm/lower_bound]")
{
std::array arr = {4};
const auto* itr =
based::lower_bound(std::begin(arr), std::end(arr), 4, std::less<int> {});
REQUIRE(itr == std::begin(arr));
}
TEST_CASE("lower_bound(one nonequal)", "[algorithm/lower_bound]")
{
std::array arr = {1};
const auto* itr =
based::lower_bound(std::begin(arr), std::end(arr), 4, std::less<int> {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("lower_bound(sequence)", "[algorithm/lower_bound]")
{
std::array arr = {0, 1, 2, 3, 3, 4};
const auto* itr =
based::lower_bound(std::begin(arr), std::end(arr), 3, std::less<int> {});
REQUIRE(itr == std::next(std::begin(arr), 3));
}
diff --git a/ test/source/algorithms/max_element_test.cpp b/ test/source/algorithms/max_element_test.cpp
@@ -0,0 +1,92 @@
#include <array>
#include "based/algorithms/minmax/max_element.hpp"
#include <catch2/catch_test_macros.hpp>
TEST_CASE("max_element(empty)", "[algorithm/max_element]")
{
const std::array<int, 0> arr = {};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
REQUIRE(itr == std::end(arr));
}
TEST_CASE("max_element(1)", "[algorithm/max_element]")
{
const std::array arr = {0};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("max_element(2) = first", "[algorithm/max_element]")
{
const std::array arr = {1, 0};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("max_element(2) = second", "[algorithm/max_element]")
{
const std::array arr = {0, 1};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("max_element(2) = stable", "[algorithm/max_element]")
{
const std::array arr = {0, 0};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("max_element(3) = first", "[algorithm/max_element]")
{
const std::array arr = {2, 1, 0};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("max_element(3) = second", "[algorithm/max_element]")
{
const std::array arr = {1, 2, 0};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("max_element(3) = third", "[algorithm/max_element]")
{
const std::array arr = {0, 1, 2};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
TEST_CASE("max_element(3) = stable(1, 2)", "[algorithm/max_element]")
{
const std::array arr = {1, 1, 0};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("max_element(3) = stable(1, 3)", "[algorithm/max_element]")
{
const std::array arr = {1, 0, 1};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
TEST_CASE("max_element(3) = stable(2, 3)", "[algorithm/max_element]")
{
const std::array arr = {0, 1, 1};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
diff --git a/ test/source/algorithms/max_test.cpp b/ test/source/algorithms/max_test.cpp
@@ -0,0 +1,361 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include "based/algorithms/minmax/max.hpp"
#include <catch2/catch_test_macros.hpp>
#include "based/concepts/is/same.hpp"
// NOLINTBEGIN(*const-arg*,*const-correctness*,*after-move, *access-moved)
TEST_CASE("max(literal, literal) = right", "[algorithm/max]")
{
using res_t = decltype(based::max(3, 4));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(3, 4) == 4);
}
TEST_CASE("max(literal, literal) = left", "[algorithm/max]")
{
using res_t = decltype(based::max(4, 3));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(4, 3) == 4);
}
TEST_CASE("max(value, literal) = right", "[algorithm/max]")
{
int a = 3;
using res_t = decltype(based::max(a, 4));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 4) == 4);
}
TEST_CASE("max(value, literal) = left", "[algorithm/max]")
{
int a = 4;
using res_t = decltype(based::max(a, 3));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 3) == 4);
}
TEST_CASE("max(literal, value) = right", "[algorithm/max]")
{
int b = 4;
using res_t = decltype(based::max(3, b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(3, b) == 4);
}
TEST_CASE("max(literal, value) = left", "[algorithm/max]")
{
int b = 3;
using res_t = decltype(based::max(4, b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(4, b) == 4);
}
TEST_CASE("max(value, value) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::max(a, b));
STATIC_REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(value, value) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::max(a, b));
STATIC_REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(const value, literal) = right", "[algorithm/max]")
{
const int a = 3;
using res_t = decltype(based::max(a, 4));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 4) == 4);
}
TEST_CASE("max(const value, literal) = left", "[algorithm/max]")
{
const int a = 4;
using res_t = decltype(based::max(a, 3));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 3) == 4);
}
TEST_CASE("max(literal, const value) = right", "[algorithm/max]")
{
const int b = 4;
using res_t = decltype(based::max(3, b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(3, b) == 4);
}
TEST_CASE("max(literal, const value) = left", "[algorithm/max]")
{
const int b = 3;
using res_t = decltype(based::max(4, b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(4, b) == 4);
}
TEST_CASE("max(const value, const value) = right", "[algorithm/max]")
{
const int a = 3;
const int b = 4;
using res_t = decltype(based::max(a, b));
STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(const value, const value) = left", "[algorithm/max]")
{
const int a = 4;
const int b = 3;
using res_t = decltype(based::max(a, b));
STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(value, const value) = right", "[algorithm/max]")
{
int a = 3;
const int b = 4;
using res_t = decltype(based::max(a, b));
STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(value, const value) = left", "[algorithm/max]")
{
int a = 4;
const int b = 3;
using res_t = decltype(based::max(a, b));
STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(const value, value) = right", "[algorithm/max]")
{
const int a = 3;
int b = 4;
using res_t = decltype(based::max(a, b));
STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(const value, value) = left", "[algorithm/max]")
{
const int a = 4;
int b = 3;
using res_t = decltype(based::max(a, b));
STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(move, literal) = right", "[algorithm/max]")
{
int a = 3;
using res_t = decltype(based::max(std::move(a), 4));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(std::move(a), 4) == 4);
}
TEST_CASE("max(move, literal) = left", "[algorithm/max]")
{
int a = 4;
using res_t = decltype(based::max(std::move(a), 3));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(std::move(a), 3) == 4);
}
TEST_CASE("max(move, value) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::max(std::move(a), b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(std::move(a), b) == 4);
}
TEST_CASE("max(move, value) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::max(std::move(a), b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(std::move(a), b) == 4);
}
TEST_CASE("max(move, const value) = right", "[algorithm/max]")
{
int a = 3;
const int b = 4;
using res_t = decltype(based::max(std::move(a), b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(std::move(a), b) == 4);
}
TEST_CASE("max(move, const value) = left", "[algorithm/max]")
{
int a = 4;
const int b = 3;
using res_t = decltype(based::max(std::move(a), b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(std::move(a), b) == 4);
}
TEST_CASE("max(literal, move) = right", "[algorithm/max]")
{
int b = 4;
using res_t = decltype(based::max(3, std::move(b)));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(3, std::move(b)) == 4);
}
TEST_CASE("max(literal, move) = left", "[algorithm/max]")
{
int b = 3;
using res_t = decltype(based::max(4, std::move(b)));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(4, std::move(b)) == 4);
}
TEST_CASE("max(value, move) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::max(a, std::move(b)));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, std::move(b)) == 4);
}
TEST_CASE("max(value, move) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::max(a, std::move(b)));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, std::move(b)) == 4);
}
TEST_CASE("max(const value, move) = right", "[algorithm/max]")
{
const int a = 3;
int b = 4;
using res_t = decltype(based::max(a, std::move(b)));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, std::move(b)) == 4);
}
TEST_CASE("max(const value, move) = left", "[algorithm/max]")
{
const int a = 4;
int b = 3;
using res_t = decltype(based::max(a, std::move(b)));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, std::move(b)) == 4);
}
TEST_CASE("max(move, move) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::max(std::move(a), std::move(b)));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(std::move(a), std::move(b)) == 4);
}
TEST_CASE("max(move, move) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::max(std::move(a), std::move(b)));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(std::move(a), std::move(b)) == 4);
}
// NOLINTEND(*const-arg*,*const-correctness*,*after-move, *access-moved)
TEST_CASE("max-stability", "[algorithm/max]")
{
using type_t = std::pair<int, int>;
static const auto cmp = [](const type_t& x, const type_t& y)
{
return x.first < y.first;
};
const type_t a = {3, 4};
const type_t b = {3, 5};
REQUIRE(based::max(a, b, cmp).second == 5);
REQUIRE(based::max(b, a, cmp).second == 4);
}
diff --git a/ test/source/algorithms/min_element_test.cpp b/ test/source/algorithms/min_element_test.cpp
@@ -0,0 +1,92 @@
#include <array>
#include "based/algorithms/minmax/min_element.hpp"
#include <catch2/catch_test_macros.hpp>
TEST_CASE("min_element(empty)", "[algorithm/min_element]")
{
const std::array<int, 0> arr = {};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
REQUIRE(itr == std::end(arr));
}
TEST_CASE("min_element(1)", "[algorithm/min_element]")
{
const std::array arr = {0};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("min_element(2) = first", "[algorithm/min_element]")
{
const std::array arr = {0, 1};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("min_element(2) = second", "[algorithm/min_element]")
{
const std::array arr = {1, 0};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("min_element(2) = stable", "[algorithm/min_element]")
{
const std::array arr = {0, 0};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("min_element(3) = first", "[algorithm/min_element]")
{
const std::array arr = {0, 1, 2};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("min_element(3) = second", "[algorithm/min_element]")
{
const std::array arr = {1, 0, 2};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("min_element(3) = third", "[algorithm/min_element]")
{
const std::array arr = {2, 1, 0};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
TEST_CASE("min_element(3) = stable(1, 2)", "[algorithm/min_element]")
{
const std::array arr = {0, 0, 1};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("min_element(3) = stable(1, 3)", "[algorithm/min_element]")
{
const std::array arr = {0, 1, 0};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("min_element(3) = stable(2, 3)", "[algorithm/min_element]")
{
const std::array arr = {1, 0, 0};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
diff --git a/ test/source/algorithms/min_test.cpp b/ test/source/algorithms/min_test.cpp
@@ -0,0 +1,359 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include "based/algorithms/minmax/min.hpp"
#include <catch2/catch_test_macros.hpp>
// NOLINTBEGIN(*const-arg*,*const-correctness*,*after-move, *access-moved)
TEST_CASE("min(literal, literal) = left", "[algorithm/min]")
{
using res_t = decltype(based::min(3, 4));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(3, 4) == 3);
}
TEST_CASE("min(literal, literal) = right", "[algorithm/min]")
{
using res_t = decltype(based::min(4, 3));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(4, 3) == 3);
}
TEST_CASE("min(value, literal) = left", "[algorithm/min]")
{
int a = 3;
using res_t = decltype(based::min(a, 4));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 4) == 3);
}
TEST_CASE("min(value, literal) = right", "[algorithm/min]")
{
int a = 4;
using res_t = decltype(based::min(a, 3));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 3) == 3);
}
TEST_CASE("min(literal, value) = left", "[algorithm/min]")
{
int b = 4;
using res_t = decltype(based::min(3, b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(3, b) == 3);
}
TEST_CASE("min(literal, value) = right", "[algorithm/min]")
{
int b = 3;
using res_t = decltype(based::min(4, b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(4, b) == 3);
}
TEST_CASE("min(value, value) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::min(a, b));
STATIC_REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(value, value) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::min(a, b));
STATIC_REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(const value, literal) = left", "[algorithm/min]")
{
const int a = 3;
using res_t = decltype(based::min(a, 4));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 4) == 3);
}
TEST_CASE("min(const value, literal) = right", "[algorithm/min]")
{
const int a = 4;
using res_t = decltype(based::min(a, 3));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 3) == 3);
}
TEST_CASE("min(literal, const value) = left", "[algorithm/min]")
{
const int b = 4;
using res_t = decltype(based::min(3, b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(3, b) == 3);
}
TEST_CASE("min(literal, const value) = right", "[algorithm/min]")
{
const int b = 3;
using res_t = decltype(based::min(4, b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(4, b) == 3);
}
TEST_CASE("min(const value, const value) = left", "[algorithm/min]")
{
const int a = 3;
const int b = 4;
using res_t = decltype(based::min(a, b));
STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(const value, const value) = right", "[algorithm/min]")
{
const int a = 4;
const int b = 3;
using res_t = decltype(based::min(a, b));
STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(value, const value) = left", "[algorithm/min]")
{
int a = 3;
const int b = 4;
using res_t = decltype(based::min(a, b));
STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(value, const value) = right", "[algorithm/min]")
{
int a = 4;
const int b = 3;
using res_t = decltype(based::min(a, b));
STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(const value, value) = left", "[algorithm/min]")
{
const int a = 3;
int b = 4;
using res_t = decltype(based::min(a, b));
STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(const value, value) = right", "[algorithm/min]")
{
const int a = 4;
int b = 3;
using res_t = decltype(based::min(a, b));
STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(move, literal) = left", "[algorithm/min]")
{
int a = 3;
using res_t = decltype(based::min(std::move(a), 4));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(std::move(a), 4) == 3);
}
TEST_CASE("min(move, literal) = right", "[algorithm/min]")
{
int a = 4;
using res_t = decltype(based::min(std::move(a), 3));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(std::move(a), 3) == 3);
}
TEST_CASE("min(move, value) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::min(std::move(a), b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(std::move(a), b) == 3);
}
TEST_CASE("min(move, value) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::min(std::move(a), b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(std::move(a), b) == 3);
}
TEST_CASE("min(move, const value) = left", "[algorithm/min]")
{
int a = 3;
const int b = 4;
using res_t = decltype(based::min(std::move(a), b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(std::move(a), b) == 3);
}
TEST_CASE("min(move, const value) = right", "[algorithm/min]")
{
int a = 4;
const int b = 3;
using res_t = decltype(based::min(std::move(a), b));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(std::move(a), b) == 3);
}
TEST_CASE("min(literal, move) = left", "[algorithm/min]")
{
int b = 4;
using res_t = decltype(based::min(3, std::move(b)));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(3, std::move(b)) == 3);
}
TEST_CASE("min(literal, move) = right", "[algorithm/min]")
{
int b = 3;
using res_t = decltype(based::min(4, std::move(b)));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(4, std::move(b)) == 3);
}
TEST_CASE("min(value, move) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::min(a, std::move(b)));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, std::move(b)) == 3);
}
TEST_CASE("min(value, move) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::min(a, std::move(b)));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, std::move(b)) == 3);
}
TEST_CASE("min(const value, move) = left", "[algorithm/min]")
{
const int a = 3;
int b = 4;
using res_t = decltype(based::min(a, std::move(b)));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, std::move(b)) == 3);
}
TEST_CASE("min(const value, move) = right", "[algorithm/min]")
{
const int a = 4;
int b = 3;
using res_t = decltype(based::min(a, std::move(b)));
STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, std::move(b)) == 3);
}
TEST_CASE("min(move, move) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::min(std::move(a), std::move(b)));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(std::move(a), std::move(b)) == 3);
}
TEST_CASE("min(move, move) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::min(std::move(a), std::move(b)));
STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(std::move(a), std::move(b)) == 3);
}
// NOLINTEND(*const-arg*,*const-correctness*,*after-move, *access-moved)
TEST_CASE("min-stability", "[algorithm/min]")
{
using type_t = std::pair<int, int>;
static const auto cmp = [](const type_t& x, const type_t& y)
{
return x.first < y.first;
};
const type_t a = {3, 4};
const type_t b = {3, 5};
REQUIRE(based::min(a, b, cmp).second == 4);
REQUIRE(based::min(b, a, cmp).second == 5);
}
diff --git a/ test/source/algorithms/minmax_element_test.cpp b/ test/source/algorithms/minmax_element_test.cpp
@@ -0,0 +1,101 @@
#include "based/algorithms/minmax/minmax_element.hpp"
#include <catch2/catch_test_macros.hpp>
TEST_CASE("minmax_element(empty)", "[algorithm/minmax_element]")
{
const std::array<int, 0> arr = {};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
REQUIRE(min == std::end(arr));
REQUIRE(max == std::end(arr));
}
TEST_CASE("minmax_element(1)", "[algorithm/minmax_element]")
{
const std::array arr = {0};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == 0);
REQUIRE(maxi == 0);
}
TEST_CASE("minmax_element(increasing even)", "[algorithm/minmax_element]")
{
const std::array arr = {0, 1, 2, 3};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == 0);
REQUIRE(maxi == std::size(arr) - 1);
}
TEST_CASE("minmax_element(increasing odd)", "[algorithm/minmax_element]")
{
const std::array arr = {0, 1, 2, 3, 4};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == 0);
REQUIRE(maxi == std::size(arr) - 1);
}
TEST_CASE("minmax_element(decreasing even)", "[algorithm/minmax_element]")
{
const std::array arr = {3, 2, 1, 0};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == std::size(arr) - 1);
REQUIRE(maxi == 0);
}
TEST_CASE("minmax_element(decreasing odd)", "[algorithm/minmax_element]")
{
const std::array arr = {4, 3, 2, 1, 0};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == std::size(arr) - 1);
REQUIRE(maxi == 0);
}
TEST_CASE("minmax_element(stable even)", "[algorithm/minmax_element]")
{
const std::array arr = {3, 0, 0, 3};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == 1);
REQUIRE(maxi == std::size(arr) - 1);
}
TEST_CASE("minmax_element(stable odd)", "[algorithm/minmax_element]")
{
const std::array arr = {3, 0, 3, 3, 0};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == 1);
REQUIRE(maxi == std::size(arr) - 2);
}
TEST_CASE("minmax_element(stable increasing)", "[algorithm/minmax_element]")
{
const std::array arr = {0, 0, 1, 2, 3, 4, 4};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == 0);
REQUIRE(maxi == std::size(arr) - 1);
}
TEST_CASE("minmax_element(stable decreasing)", "[algorithm/minmax_element]")
{
const std::array arr = {4, 4, 3, 2, 1, 0, 0};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == std::size(arr) - 2);
REQUIRE(maxi == 1);
}
diff --git a/ test/source/algorithms/none_test.cpp b/ test/source/algorithms/none_test.cpp
@@ -0,0 +1,65 @@
#include <array>
#include "based/algorithms/search/none.hpp"
#include <catch2/catch_test_macros.hpp>
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("none(empty)", "[algorithm/none]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::none(std::begin(arr), std::end(arr), predicate {0}));
}
TEST_CASE("none(homogeneous)", "[algorithm/none]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::none(std::begin(arr), std::end(arr), predicate {2}));
REQUIRE(!based::none(std::begin(arr), std::end(arr), predicate {1}));
}
TEST_CASE("none(non homogeneous)", "[algorithm/none]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::none(std::begin(arr), std::end(arr), predicate {0}));
REQUIRE(!based::none(std::begin(arr), std::end(arr), predicate {2}));
REQUIRE(!based::none(std::begin(arr), std::end(arr), predicate {1}));
}
TEST_CASE("none_n(empty)", "[algorithm/none_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::none_n(std::begin(arr), std::size(arr), predicate {0}));
}
TEST_CASE("none_n(homogeneous)", "[algorithm/none_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::none_n(std::begin(arr), std::size(arr), predicate {2}));
REQUIRE(!based::none_n(std::begin(arr), std::size(arr), predicate {1}));
}
TEST_CASE("none_n(non homogeneous)", "[algorithm/none_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::none_n(std::begin(arr), std::size(arr), predicate {0}));
REQUIRE(!based::none_n(std::begin(arr), std::size(arr), predicate {2}));
REQUIRE(!based::none_n(std::begin(arr), std::size(arr), predicate {1}));
}
diff --git a/ test/source/algorithms/not_all_test.cpp b/ test/source/algorithms/not_all_test.cpp
@@ -0,0 +1,65 @@
#include <array>
#include "based/algorithms/search/not_all.hpp"
#include <catch2/catch_test_macros.hpp>
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("not_all(empty)", "[algorithm/not_all]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {0}));
}
TEST_CASE("not_all(homogeneous)", "[algorithm/not_all]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {2}));
REQUIRE(!based::not_all(std::begin(arr), std::end(arr), predicate {1}));
}
TEST_CASE("not_all(non homogeneous)", "[algorithm/not_all]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {0}));
REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {2}));
}
TEST_CASE("not_all_n(empty)", "[algorithm/not_all_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {0}));
}
TEST_CASE("not_all_n(homogeneous)", "[algorithm/not_all_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {2}));
REQUIRE(!based::not_all_n(std::begin(arr), std::size(arr), predicate {1}));
}
TEST_CASE("not_all_n(non homogeneous)", "[algorithm/not_all_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {0}));
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {2}));
}
diff --git a/ test/source/algorithms/partition_point_test.cpp b/ test/source/algorithms/partition_point_test.cpp
@@ -0,0 +1,48 @@
#include <array>
#include "based/algorithms/sort/partition_point.hpp"
#include <catch2/catch_test_macros.hpp>
struct equal
{
auto operator()(int a) const { return a == goal; }
int goal;
};
TEST_CASE("partition_point(empty)", "[algorithm/partition_point]")
{
std::array<int, 0> arr = {};
const auto* itr =
based::partition_point(std::begin(arr), std::end(arr), equal {4});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("partition_point(one equal)", "[algorithm/partition_point]")
{
std::array arr = {4};
const auto* itr =
based::partition_point(std::begin(arr), std::end(arr), equal {4});
REQUIRE(itr == std::begin(arr));
}
TEST_CASE("partition_point(one nonequal)", "[algorithm/partition_point]")
{
std::array arr = {1};
const auto* itr =
based::partition_point(std::begin(arr), std::end(arr), equal {4});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("partition_point(sequence)", "[algorithm/partition_point]")
{
std::array arr = {0, 1, 2, 3, 4, 4, 4, 4};
const auto* itr =
based::partition_point(std::begin(arr), std::end(arr), equal {4});
REQUIRE(itr == std::next(std::begin(arr), 4));
}
diff --git a/ test/source/algorithms/partitioned_test.cpp b/ test/source/algorithms/partitioned_test.cpp
@@ -0,0 +1,53 @@
#include <array>
#include "based/algorithms/sort/partitioned.hpp"
#include <catch2/catch_test_macros.hpp>
struct equal
{
auto operator()(int a) const { return a == goal; }
int goal;
};
TEST_CASE("partitioned(empty)", "[algorithm/partitioned]")
{
std::array<int, 0> arr = {};
REQUIRE(based::partitioned(std::begin(arr), std::end(arr), equal {4}));
}
TEST_CASE("partitioned(one equal)", "[algorithm/partitioned]")
{
std::array arr = {4};
REQUIRE(based::partitioned(std::begin(arr), std::end(arr), equal {4}));
}
TEST_CASE("partitioned(one nonequal)", "[algorithm/partitioned]")
{
std::array arr = {1};
REQUIRE(based::partitioned(std::begin(arr), std::end(arr), equal {4}));
}
TEST_CASE("partitioned(partitioned)", "[algorithm/partitioned]")
{
std::array arr = {0, 1, 2, 3, 4, 4, 4, 4};
REQUIRE(based::partitioned(std::begin(arr), std::end(arr), equal {4}));
}
TEST_CASE("partitioned(nonpartitioned equal)", "[algorithm/partitioned]")
{
std::array arr = {4, 0, 1, 2, 3, 4, 4, 4};
REQUIRE(!based::partitioned(std::begin(arr), std::end(arr), equal {4}));
}
TEST_CASE("partitioned(nonpartitioned nonequal)", "[algorithm/partitioned]")
{
std::array arr = {4, 0, 1, 2, 3, 4, 4, 4, 0};
REQUIRE(!based::partitioned(std::begin(arr), std::end(arr), equal {4}));
}
diff --git a/ test/source/algorithms/reduce_test.cpp b/ test/source/algorithms/reduce_test.cpp
@@ -0,0 +1,69 @@
#include <array>
#include <vector>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithms/numeric/accumulate.hpp"
struct op
{
auto operator()(const auto& lhs, const auto& rhs) { return lhs + rhs; }
};
struct fun
{
auto operator()(based::Iterator auto itr) { return *itr; }
};
TEST_CASE("accumulate_nonempty(sequence)", "[algorithm/accumulate_nonempty]")
{
const std::array arr = {0, 1, 2, 3, 4, 5};
const auto count = based::accumulate_nonempty(
std::cbegin(arr), std::cend(arr), op {}, fun {}
);
REQUIRE(count == 15);
}
TEST_CASE("accumulate(empty)", "[algorithm/accumulate]")
{
const std::array<int, 0> arr = {};
const auto count =
based::accumulate(std::cbegin(arr), std::cend(arr), op {}, fun {}, 0);
REQUIRE(count == 0);
}
TEST_CASE("accumulate(sequence)", "[algorithm/accumulate]")
{
const std::array arr = {0, 1, 2, 3, 4, 5};
const auto count =
based::accumulate(std::cbegin(arr), std::cend(arr), op {}, fun {}, 0);
REQUIRE(count == 15);
}
TEST_CASE("accumulate_nonzero(empty)", "[algorithm/accumulate_nonzero]")
{
const std::array<int, 0> arr = {};
const auto count = based::accumulate_nonzero(
std::cbegin(arr), std::cend(arr), op {}, fun {}, 0
);
REQUIRE(count == 0);
}
TEST_CASE("accumulate_nonzero(sequence)", "[algorithm/accumulate_nonzero]")
{
const std::array arr = {0, 1, 2, 3, 4, 5};
const auto count = based::accumulate_nonzero(
std::cbegin(arr), std::cend(arr), op {}, fun {}, 0
);
REQUIRE(count == 15);
}
diff --git a/ test/source/algorithms/some_test.cpp b/ test/source/algorithms/some_test.cpp
@@ -0,0 +1,65 @@
#include <array>
#include "based/algorithms/search/some.hpp"
#include <catch2/catch_test_macros.hpp>
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("some(empty)", "[algorithm/some]")
{
const std::array<int, 0> arr = {};
REQUIRE(!based::some(std::begin(arr), std::end(arr), predicate {0}));
}
TEST_CASE("some(homogeneous)", "[algorithm/some]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::some(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(!based::some(std::begin(arr), std::end(arr), predicate {2}));
}
TEST_CASE("some(non homogeneous)", "[algorithm/some]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::some(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(based::some(std::begin(arr), std::end(arr), predicate {2}));
REQUIRE(!based::some(std::begin(arr), std::end(arr), predicate {0}));
}
TEST_CASE("some_n(empty)", "[algorithm/some_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(!based::some_n(std::begin(arr), std::size(arr), predicate {0}));
}
TEST_CASE("some_n(homogeneous)", "[algorithm/some_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::some_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(!based::some_n(std::begin(arr), std::size(arr), predicate {2}));
}
TEST_CASE("some_n(non homogeneous)", "[algorithm/some_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::some_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(based::some_n(std::begin(arr), std::size(arr), predicate {2}));
REQUIRE(!based::some_n(std::begin(arr), std::size(arr), predicate {0}));
}
diff --git a/ test/source/algorithms/upper_bound_test.cpp b/ test/source/algorithms/upper_bound_test.cpp
@@ -0,0 +1,48 @@
#include <array>
#include "based/algorithms/bsearch/upper_bound.hpp"
#include <catch2/catch_test_macros.hpp>
struct equal
{
auto operator()(int a) const { return a == goal; }
int goal;
};
TEST_CASE("upper_bound(empty)", "[algorithm/lower_bound]")
{
std::array<int, 0> arr = {};
const auto* itr =
based::upper_bound(std::begin(arr), std::end(arr), 4, std::less<int> {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("upper_bound(one equal)", "[algorithm/lower_bound]")
{
std::array arr = {4};
const auto* itr =
based::upper_bound(std::begin(arr), std::end(arr), 4, std::less<int> {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("upper_bound(one nonequal)", "[algorithm/lower_bound]")
{
std::array arr = {1};
const auto* itr =
based::upper_bound(std::begin(arr), std::end(arr), 4, std::less<int> {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("upper_bound(sequence)", "[algorithm/lower_bound]")
{
std::array arr = {0, 1, 2, 3, 3, 4};
const auto* itr =
based::upper_bound(std::begin(arr), std::end(arr), 3, std::less<int> {});
REQUIRE(itr == std::next(std::begin(arr), 5));
}
diff --git a/ test/source/buffer_test.cpp b/ test/source/buffer_test.cpp
@@ -1,66 +0,0 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <catch2/catch_test_macros.hpp>
#include "based/template.hpp"
template struct based::buffer<sizeof(void*)>;
TEST_CASE("valid type", "[template/buffer]")
{
SECTION("small buffer")
{
using buffer = based::buffer<sizeof(std::uint8_t)>;
STATIC_REQUIRE(buffer::valid_type<std::uint8_t>());
STATIC_REQUIRE_FALSE(buffer::valid_type<std::size_t>());
STATIC_REQUIRE_FALSE(buffer::valid_type<char[5]>()); // NOLINT(*array*)
}
SECTION("big buffer")
{
using buffer = based::buffer<sizeof(std::size_t), alignof(std::size_t)>;
STATIC_REQUIRE(buffer::valid_type<std::uint8_t>());
STATIC_REQUIRE(buffer::valid_type<std::size_t>());
STATIC_REQUIRE_FALSE(buffer::valid_type<char[5]>()); // NOLINT(*array*)
}
}
TEST_CASE("buffer", "[template/buffer]")
{
using buffer = based::buffer<sizeof(std::size_t)>;
static constexpr std::uint8_t value = 8;
buffer buf(std::in_place_type<std::uint8_t>, value);
REQUIRE(*buf.as<std::uint8_t>() == value);
SECTION("emplace")
{
static constexpr std::uint16_t new_value = 10;
buf.emplace<std::uint16_t>(new_value);
REQUIRE(*buf.as<std::uint16_t>() == new_value);
}
SECTION("swap")
{
static constexpr std::uint16_t new_value = 10;
buffer new_buf(std::in_place_type<std::uint16_t>, new_value);
buf.swap(new_buf);
REQUIRE(*buf.as<std::uint16_t>() == new_value);
REQUIRE(*new_buf.as<std::uint8_t>() == value);
}
}
TEST_CASE("const buffer", "[template/buffer]")
{
using buffer = based::buffer<sizeof(std::size_t)>;
static constexpr std::uint8_t value = 8;
const buffer buf(std::in_place_type<std::uint8_t>, value);
REQUIRE(*buf.as<std::uint8_t>() == value);
}
diff --git a/ test/source/callable_test.cpp b/ test/source/callable_test.cpp
@@ -1,58 +0,0 @@
// #define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <catch2/catch_test_macros.hpp>
#include "based/type_traits.hpp"
namespace
{
// NOLINTNEXTLINE(*need*)
int free_func(int a, double b)
{
return static_cast<int>(a + b);
}
} // namespace
using based::SameAs;
TEST_CASE("free function", "[type_traits/callable]")
{
using type_t = decltype(free_func);
STATIC_REQUIRE(based::Callable<type_t>);
STATIC_REQUIRE(SameAs<based::callable_sig_t<type_t>, int(int, double)>);
STATIC_REQUIRE(SameAs<based::callable_ret_t<type_t>, int>);
}
TEST_CASE("lambda", "[type_traits/callable]")
{
const auto func = [](int a, double b)
{
return static_cast<int>(a + b);
};
using type_t = decltype(func);
STATIC_REQUIRE(based::Callable<type_t>);
STATIC_REQUIRE(SameAs<based::callable_sig_t<type_t>, int(int, double)>);
STATIC_REQUIRE(SameAs<based::callable_ret_t<type_t>, int>);
}
/*
struct func
{
auto operator()(auto a, auto b) { return static_cast<int>(a + b); }
};
TEST_CASE("member function", "[type_traits/callable]")
{
// [&](auto&&... args) -> decltype(auto) { return
// f(std::forward<decltype(args)>(args)...); }
// based::error_template<decltype(&func::template operator()<int, double>)>();
STATIC_REQUIRE(based::Callable<func>);
STATIC_REQUIRE(SameAs<based::callable_sig_t<func>, int(int, double)>);
STATIC_REQUIRE(SameAs<based::callable_ret_t<func>, int>);
}
*/
diff --git a/ test/source/concepts/callable_test.cpp b/ test/source/concepts/callable_test.cpp
@@ -0,0 +1,60 @@
// #define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include "based/concepts/callable.hpp"
#include <catch2/catch_test_macros.hpp>
#include "based/concepts/is/same.hpp"
namespace
{
// NOLINTNEXTLINE(*need*)
int free_func(int a, double b)
{
return static_cast<int>(a + b);
}
} // namespace
using based::SameAs;
TEST_CASE("free function", "[type_traits/callable]")
{
using type_t = decltype(free_func);
STATIC_REQUIRE(based::Callable<type_t>);
STATIC_REQUIRE(SameAs<based::callable_sig_t<type_t>, int(int, double)>);
STATIC_REQUIRE(SameAs<based::callable_ret_t<type_t>, int>);
}
TEST_CASE("lambda", "[type_traits/callable]")
{
const auto func = [](int a, double b)
{
return static_cast<int>(a + b);
};
using type_t = decltype(func);
STATIC_REQUIRE(based::Callable<type_t>);
STATIC_REQUIRE(SameAs<based::callable_sig_t<type_t>, int(int, double)>);
STATIC_REQUIRE(SameAs<based::callable_ret_t<type_t>, int>);
}
/*
struct func
{
auto operator()(auto a, auto b) { return static_cast<int>(a + b); }
};
TEST_CASE("member function", "[type_traits/callable]")
{
// [&](auto&&... args) -> decltype(auto) { return
// f(std::forward<decltype(args)>(args)...); }
// based::error_template<decltype(&func::template operator()<int, double>)>();
STATIC_REQUIRE(based::Callable<func>);
STATIC_REQUIRE(SameAs<based::callable_sig_t<func>, int(int, double)>);
STATIC_REQUIRE(SameAs<based::callable_ret_t<func>, int>);
}
*/
diff --git a/ test/source/count_if_n_test.cpp b/ test/source/count_if_n_test.cpp
@@ -1,169 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
#include "based/type_traits.hpp"
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("count_if_n return type", "[algorithm/count_if_n]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t = decltype(based::count_if_n(
std::begin(arr), std::size(arr), predicate {0}
)
.second);
REQUIRE(based::SameAs<based::iter_dist_t<decltype(arr)::iterator>, res_t>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count_if_n(
std::begin(arr),
std::size(arr),
predicate {0},
std::uint8_t {0}
)
.second);
REQUIRE(based::SameAs<std::uint8_t, res_t>);
}
}
TEST_CASE("count_if_n(empty)", "[algorithm/count_if_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, count] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {0});
REQUIRE(count == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("count_if_n(homogeneous)", "[algorithm/count_if_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto [itr0, count0] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto [itr1, count1] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {1});
REQUIRE(count0 == 0);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 6);
REQUIRE(itr1 == std::end(arr));
}
TEST_CASE("count_if_n(non homogeneous)", "[algorithm/count_if_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto [itr0, count0] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto [itr1, count1] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {1});
const auto [itr2, count2] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {2});
REQUIRE(count0 == 0);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 4);
REQUIRE(itr1 == std::end(arr));
REQUIRE(count2 == 2);
REQUIRE(itr2 == std::end(arr));
}
TEST_CASE("count_if_not_n return type", "[algorithm/count_if_not_n]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t = decltype(based::count_if_not_n(
std::begin(arr), std::size(arr), predicate {0}
));
REQUIRE(based::SameAs<
based::iter_dist_t<decltype(arr)::iterator>,
res_t::second_type>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count_if_not_n(
std::begin(arr), std::size(arr), predicate {0}, std::uint8_t {0}
));
REQUIRE(based::SameAs<std::uint8_t, res_t::second_type>);
}
}
TEST_CASE("count_if_not_n(empty)", "[algorithm/count_if_not_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, count] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {0});
REQUIRE(count == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("count_if_not_n(homogeneous)", "[algorithm/count_if_not_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto [itr0, count0] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto [itr1, count1] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {1});
REQUIRE(count0 == 6);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 0);
REQUIRE(itr1 == std::end(arr));
}
TEST_CASE("count_if_not_n(non homogeneous)", "[algorithm/count_if_not_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto [itr0, count0] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto [itr1, count1] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {1});
const auto [itr2, count2] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {2});
REQUIRE(count0 == 6);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 2);
REQUIRE(itr1 == std::end(arr));
REQUIRE(count2 == 4);
REQUIRE(itr2 == std::end(arr));
}
diff --git a/ test/source/count_if_test.cpp b/ test/source/count_if_test.cpp
@@ -1,138 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
#include "based/type_traits.hpp"
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("count_if return type", "[algorithm/count_if]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t =
decltype(based::count_if(std::begin(arr), std::end(arr), predicate {0})
);
REQUIRE(based::SameAs<based::iter_dist_t<decltype(arr)::iterator>, res_t>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count_if(
std::begin(arr), std::end(arr), predicate {0}, std::uint8_t {0}
));
REQUIRE(based::SameAs<std::uint8_t, res_t>);
}
}
TEST_CASE("count_if(empty)", "[algorithm/count_if]")
{
const std::array<int, 0> arr = {};
const auto count =
based::count_if(std::begin(arr), std::end(arr), predicate {0});
REQUIRE(count == 0);
}
TEST_CASE("count_if(homogeneous)", "[algorithm/count_if]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto count0 =
based::count_if(std::begin(arr), std::end(arr), predicate {0});
const auto count1 =
based::count_if(std::begin(arr), std::end(arr), predicate {1});
REQUIRE(count0 == 0);
REQUIRE(count1 == 6);
}
TEST_CASE("count_if(non homogeneous)", "[algorithm/count_if]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto count0 =
based::count_if(std::begin(arr), std::end(arr), predicate {0});
const auto count1 =
based::count_if(std::begin(arr), std::end(arr), predicate {1});
const auto count2 =
based::count_if(std::begin(arr), std::end(arr), predicate {2});
REQUIRE(count0 == 0);
REQUIRE(count1 == 4);
REQUIRE(count2 == 2);
}
TEST_CASE("count_if_not return type", "[algorithm/count_if_not]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t = decltype(based::count_if_not(
std::begin(arr), std::end(arr), predicate {0}
));
REQUIRE(based::SameAs<based::iter_dist_t<decltype(arr)::iterator>, res_t>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count_if_not(
std::begin(arr), std::end(arr), predicate {0}, std::uint8_t {0}
));
REQUIRE(based::SameAs<std::uint8_t, res_t>);
}
}
TEST_CASE("count_if_not(empty)", "[algorithm/count_if_not]")
{
const std::array<int, 0> arr = {};
const auto count =
based::count_if_not(std::begin(arr), std::end(arr), predicate {0});
REQUIRE(count == 0);
}
TEST_CASE("count_if_not(homogeneous)", "[algorithm/count_if_not]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto count0 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto count1 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {1});
REQUIRE(count0 == 6);
REQUIRE(count1 == 0);
}
TEST_CASE("count_if_not(non homogeneous)", "[algorithm/count_if_not]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto count0 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto count1 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {1});
const auto count2 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {2});
REQUIRE(count0 == 6);
REQUIRE(count1 == 2);
REQUIRE(count2 == 4);
}
diff --git a/ test/source/count_n_test.cpp b/ test/source/count_n_test.cpp
@@ -1,151 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
#include "based/type_traits.hpp"
TEST_CASE("count_n return type", "[algorithm/count_n]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t =
decltype(based::count_n(std::begin(arr), std::size(arr), 0).second);
REQUIRE(based::SameAs<based::iter_dist_t<decltype(arr)::iterator>, res_t>);
}
SECTION("explicit counter")
{
using res_t =
decltype(based::count_n(
std::begin(arr), std::size(arr), 0, std::uint8_t {0}
)
.second);
REQUIRE(based::SameAs<std::uint8_t, res_t>);
}
}
TEST_CASE("count_n(empty)", "[algorithm/count_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, count] = based::count_n(std::begin(arr), std::size(arr), 0);
REQUIRE(count == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("count_n(homogeneous)", "[algorithm/count_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto [itr0, count0] =
based::count_n(std::begin(arr), std::size(arr), 0);
const auto [itr1, count1] =
based::count_n(std::begin(arr), std::size(arr), 1);
REQUIRE(count0 == 0);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 6);
REQUIRE(itr1 == std::end(arr));
}
TEST_CASE("count_n(non homogeneous)", "[algorithm/count_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto [itr0, count0] =
based::count_n(std::begin(arr), std::size(arr), 0);
const auto [itr1, count1] =
based::count_n(std::begin(arr), std::size(arr), 1);
const auto [itr2, count2] =
based::count_n(std::begin(arr), std::size(arr), 2);
REQUIRE(count0 == 0);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 4);
REQUIRE(itr1 == std::end(arr));
REQUIRE(count2 == 2);
REQUIRE(itr2 == std::end(arr));
}
TEST_CASE("count_not_n return type", "[algorithm/count_not_n]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t =
decltype(based::count_not_n(std::begin(arr), std::size(arr), 0));
REQUIRE(based::SameAs<
based::iter_dist_t<decltype(arr)::iterator>,
res_t::second_type>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count_not_n(
std::begin(arr), std::size(arr), 0, std::uint8_t {0}
));
REQUIRE(based::SameAs<std::uint8_t, res_t::second_type>);
}
}
TEST_CASE("count_not_n(empty)", "[algorithm/count_not_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, count] =
based::count_not_n(std::begin(arr), std::size(arr), 0);
REQUIRE(count == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("count_not_n(homogeneous)", "[algorithm/count_not_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto [itr0, count0] =
based::count_not_n(std::begin(arr), std::size(arr), 0);
const auto [itr1, count1] =
based::count_not_n(std::begin(arr), std::size(arr), 1);
REQUIRE(count0 == 6);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 0);
REQUIRE(itr1 == std::end(arr));
}
TEST_CASE("count_not_n(non homogeneous)", "[algorithm/count_not_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto [itr0, count0] =
based::count_not_n(std::begin(arr), std::size(arr), 0);
const auto [itr1, count1] =
based::count_not_n(std::begin(arr), std::size(arr), 1);
const auto [itr2, count2] =
based::count_not_n(std::begin(arr), std::size(arr), 2);
REQUIRE(count0 == 6);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 2);
REQUIRE(itr1 == std::end(arr));
REQUIRE(count2 == 4);
REQUIRE(itr2 == std::end(arr));
}
diff --git a/ test/source/count_test.cpp b/ test/source/count_test.cpp
@@ -1,109 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
#include "based/type_traits.hpp"
TEST_CASE("count return type", "[algorithm/count]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t = decltype(based::count(std::begin(arr), std::end(arr), 0));
REQUIRE(based::SameAs<based::iter_dist_t<decltype(arr)::iterator>, res_t>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count(
std::begin(arr), std::end(arr), 0, std::uint8_t {0}
));
REQUIRE(based::SameAs<std::uint8_t, res_t>);
}
}
TEST_CASE("count(empty)", "[algorithm/count]")
{
const std::array<int, 0> arr = {};
const auto count = based::count(std::begin(arr), std::end(arr), 0);
REQUIRE(count == 0);
}
TEST_CASE("count(homogeneous)", "[algorithm/count]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto count0 = based::count(std::begin(arr), std::end(arr), 0);
const auto count1 = based::count(std::begin(arr), std::end(arr), 1);
REQUIRE(count0 == 0);
REQUIRE(count1 == 6);
}
TEST_CASE("count(non homogeneous)", "[algorithm/count]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto count0 = based::count(std::begin(arr), std::end(arr), 0);
const auto count1 = based::count(std::begin(arr), std::end(arr), 1);
const auto count2 = based::count(std::begin(arr), std::end(arr), 2);
REQUIRE(count0 == 0);
REQUIRE(count1 == 4);
REQUIRE(count2 == 2);
}
TEST_CASE("count_not return type", "[algorithm/count_not]")
{
const std::array<int, 0> arr = {};
SECTION("auto counter")
{
using res_t = decltype(based::count_not(std::begin(arr), std::end(arr), 0));
REQUIRE(based::SameAs<based::iter_dist_t<decltype(arr)::iterator>, res_t>);
}
SECTION("explicit counter")
{
using res_t = decltype(based::count_not(
std::begin(arr), std::end(arr), 0, std::uint8_t {0}
));
REQUIRE(based::SameAs<std::uint8_t, res_t>);
}
}
TEST_CASE("count_not(empty)", "[algorithm/count_not]")
{
const std::array<int, 0> arr = {};
const auto count_not = based::count_not(std::begin(arr), std::end(arr), 0);
REQUIRE(count_not == 0);
}
TEST_CASE("count_not(homogeneous)", "[algorithm/count_not]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto count0 = based::count_not(std::begin(arr), std::end(arr), 0);
const auto count1 = based::count_not(std::begin(arr), std::end(arr), 1);
REQUIRE(count0 == 6);
REQUIRE(count1 == 0);
}
TEST_CASE("count_not(non homogeneous)", "[algorithm/count_not]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto count0 = based::count_not(std::begin(arr), std::end(arr), 0);
const auto count1 = based::count_not(std::begin(arr), std::end(arr), 1);
const auto count2 = based::count_not(std::begin(arr), std::end(arr), 2);
REQUIRE(count0 == 6);
REQUIRE(count1 == 2);
REQUIRE(count2 == 4);
}
diff --git a/ test/source/curry_test.cpp b/ test/source/curry_test.cpp
@@ -1,77 +0,0 @@
#include <catch2/catch_test_macros.hpp>
#include "based/functional.hpp"
// NOLINTBEGIN(*cognitive-complexity*, *magic*)
namespace
{
auto free_func(int a, double b, int c, double d)
{
return static_cast<int>(a + b + c + d);
}
} // namespace
TEST_CASE("free function", "[functional/curry]")
{
const based::curried curried = free_func;
REQUIRE(curried(1)(2.0)(3)(4.0) == 10);
REQUIRE(curried(1)(2.0, 3)(4.0) == 10);
REQUIRE(curried(1)(2.0, 3, 4.0) == 10);
REQUIRE(curried(1, 2.0)(3, 4.0) == 10);
REQUIRE(curried(1, 2.0, 3)(4.0) == 10);
REQUIRE(curried(1, 2.0, 3, 4.0) == 10);
}
TEST_CASE("lambda", "[functional/curry]")
{
const based::curried curried = [](int a, double b, int c, double d)
{
return static_cast<int>(a + b + c + d);
};
REQUIRE(curried(1)(2.0)(3)(4.0) == 10);
REQUIRE(curried(1)(2.0)(3, 4.0) == 10);
REQUIRE(curried(1)(2.0, 3)(4.0) == 10);
REQUIRE(curried(1)(2.0, 3, 4.0) == 10);
REQUIRE(curried(1, 2.0)(3)(4.0) == 10);
REQUIRE(curried(1, 2.0)(3, 4.0) == 10);
REQUIRE(curried(1, 2.0, 3)(4.0) == 10);
REQUIRE(curried(1, 2.0, 3, 4.0) == 10);
}
TEST_CASE("member function", "[functional/curry]")
{
struct test
{
[[nodiscard]] auto func(int a, double b, int c, double d) const
{
return static_cast<int>(m_x + a + b + c + d);
}
int m_x = 0;
};
const based::curried curried = &test::func;
test tmp;
REQUIRE(curried(std::ref(tmp))(1)(2.0)(3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1)(2.0)(3, 4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1)(2.0, 3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1)(2.0, 3, 4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1, 2.0)(3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1, 2.0)(3, 4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1, 2.0, 3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1, 2.0, 3, 4.0) == 10);
REQUIRE(curried(std::ref(tmp), 1)(2.0)(3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp), 1)(2.0, 3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp), 1, 2.0)(3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp), 1, 2.0, 3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp), 1, 2.0, 3, 4.0) == 10);
REQUIRE(curried(std::ref(tmp), 1, 2.0, 3, 4.0) == 10);
}
// NOLINTEND(*cognitive-complexity*, *magic*)
diff --git a/ test/source/enum_test.cpp b/ test/source/enum_test.cpp
@@ -1,14 +1,20 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include "based/enum.hpp"
#include "based/enum/enum.hpp"
#include <catch2/catch_test_macros.hpp>
#include "based/type_traits.hpp"
#include "based/concepts/comparable/equality.hpp"
#include "based/concepts/comparable/greater.hpp"
#include "based/concepts/comparable/greater_equal.hpp"
#include "based/concepts/comparable/less.hpp"
#include "based/concepts/comparable/less_equal.hpp"
#include "based/concepts/is/same.hpp"
#include "based/types/types.hpp"
struct test
{
BASED_ENUM_DECLARE(var, std::uint8_t, a, b, c)
BASED_ENUM_DECLARE(var, based::u8, a, b, c)
[[nodiscard]] int get_var(var::type req) const;
@@ -18,7 +24,7 @@
private:
int m_c = 3;
};
BASED_DEFINE_CLASS_ENUM(test, var, std::uint8_t, a, b, c)
BASED_DEFINE_CLASS_ENUM(test, var, based::u8, a, b, c)
inline int test::get_var(var::type req) const
{
@@ -62,9 +68,9 @@
TEST_CASE("operations", "[enum/enum]")
{
using based::SameAs;
STATIC_REQUIRE(based::equality_comparable<test::var::type>);
STATIC_REQUIRE(!based::less_comparable<test::var::type>);
STATIC_REQUIRE(!based::greater_comparable<test::var::type>);
STATIC_REQUIRE(!based::less_equal_comparable<test::var::type>);
STATIC_REQUIRE(!based::greater_equal_comparable<test::var::type>);
STATIC_REQUIRE(based::EqualityComparable<test::var::type>);
STATIC_REQUIRE(!based::LessComparable<test::var::type>);
STATIC_REQUIRE(!based::GreaterComparable<test::var::type>);
STATIC_REQUIRE(!based::LessEqualComparable<test::var::type>);
STATIC_REQUIRE(!based::GreaterEqualComparable<test::var::type>);
}
diff --git a/ test/source/find_if_n_test.cpp b/ test/source/find_if_n_test.cpp
@@ -1,290 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("find_if_n(empty)", "[algorithm/find_if_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {0});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_if_n(one)", "[algorithm/find_if_n]")
{
const std::array arr = {0};
SECTION("found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_n(two)", "[algorithm/find_if_n]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("found 2")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {2});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_n(multiple)", "[algorithm/find_if_n]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_not_n(empty)", "[algorithm/find_if_not_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {0});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_if_not_n(one)", "[algorithm/find_if_not_n]")
{
const std::array arr = {0};
SECTION("found")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_not_n(two)", "[algorithm/find_if_not_n]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("found 2")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_not_n(multiple)", "[algorithm/find_if_not_n]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("all_n(empty)", "[algorithm/all_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::all_n(std::begin(arr), std::size(arr), predicate {0}));
}
TEST_CASE("all_n(homogeneous)", "[algorithm/all_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::all_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(!based::all_n(std::begin(arr), std::size(arr), predicate {2}));
}
TEST_CASE("all_n(non homogenous)", "[algorithm/all_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(!based::all_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(!based::all_n(std::begin(arr), std::size(arr), predicate {2}));
}
TEST_CASE("none_n(empty)", "[algorithm/none_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::none_n(std::begin(arr), std::size(arr), predicate {0}));
}
TEST_CASE("none_n(homogeneous)", "[algorithm/none_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::none_n(std::begin(arr), std::size(arr), predicate {2}));
REQUIRE(!based::none_n(std::begin(arr), std::size(arr), predicate {1}));
}
TEST_CASE("none_n(non homogeneous)", "[algorithm/none_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::none_n(std::begin(arr), std::size(arr), predicate {0}));
REQUIRE(!based::none_n(std::begin(arr), std::size(arr), predicate {2}));
REQUIRE(!based::none_n(std::begin(arr), std::size(arr), predicate {1}));
}
TEST_CASE("not_all_n(empty)", "[algorithm/not_all_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {0}));
}
TEST_CASE("not_all_n(homogeneous)", "[algorithm/not_all_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {2}));
REQUIRE(!based::not_all_n(std::begin(arr), std::size(arr), predicate {1}));
}
TEST_CASE("not_all_n(non homogeneous)", "[algorithm/not_all_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {0}));
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {2}));
}
TEST_CASE("some_n(empty)", "[algorithm/some_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(!based::some_n(std::begin(arr), std::size(arr), predicate {0}));
}
TEST_CASE("some_n(homogeneous)", "[algorithm/some_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::some_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(!based::some_n(std::begin(arr), std::size(arr), predicate {2}));
}
TEST_CASE("some_n(non homogeneous)", "[algorithm/some_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::some_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(based::some_n(std::begin(arr), std::size(arr), predicate {2}));
REQUIRE(!based::some_n(std::begin(arr), std::size(arr), predicate {0}));
}
diff --git a/ test/source/find_if_test.cpp b/ test/source/find_if_test.cpp
@@ -1,265 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("find_if(empty)", "[algorithm/find_if]")
{
const std::array<int, 0> arr = {};
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {0});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_if(one)", "[algorithm/find_if]")
{
const std::array arr = {0};
SECTION("found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}
TEST_CASE("find_if(two)", "[algorithm/find_if]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("found 2")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
SECTION("not found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {2});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
}
TEST_CASE("find_if(multiple)", "[algorithm/find_if]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
}
}
TEST_CASE("find_if_not(empty)", "[algorithm/find_if_not]")
{
const std::array<int, 0> arr = {};
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {0});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_if_not(one)", "[algorithm/find_if_not]")
{
const std::array arr = {0};
SECTION("found")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}
TEST_CASE("find_if_not(two)", "[algorithm/find_if_not]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("found 2")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}
TEST_CASE("find_if_not(multiple)", "[algorithm/find_if_not]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
}
}
TEST_CASE("all(empty)", "[algorithm/all]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::all(std::begin(arr), std::end(arr), predicate {0}));
}
TEST_CASE("all(homogeneous)", "[algorithm/all]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::all(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(!based::all(std::begin(arr), std::end(arr), predicate {2}));
}
TEST_CASE("all(non homogenous)", "[algorithm/all]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(!based::all(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(!based::all(std::begin(arr), std::end(arr), predicate {2}));
}
TEST_CASE("none(empty)", "[algorithm/none]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::none(std::begin(arr), std::end(arr), predicate {0}));
}
TEST_CASE("none(homogeneous)", "[algorithm/none]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::none(std::begin(arr), std::end(arr), predicate {2}));
REQUIRE(!based::none(std::begin(arr), std::end(arr), predicate {1}));
}
TEST_CASE("none(non homogeneous)", "[algorithm/none]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::none(std::begin(arr), std::end(arr), predicate {0}));
REQUIRE(!based::none(std::begin(arr), std::end(arr), predicate {2}));
REQUIRE(!based::none(std::begin(arr), std::end(arr), predicate {1}));
}
TEST_CASE("not_all(empty)", "[algorithm/not_all]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {0}));
}
TEST_CASE("not_all(homogeneous)", "[algorithm/not_all]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {2}));
REQUIRE(!based::not_all(std::begin(arr), std::end(arr), predicate {1}));
}
TEST_CASE("not_all(non homogeneous)", "[algorithm/not_all]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {0}));
REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {2}));
}
TEST_CASE("some(empty)", "[algorithm/some]")
{
const std::array<int, 0> arr = {};
REQUIRE(!based::some(std::begin(arr), std::end(arr), predicate {0}));
}
TEST_CASE("some(homogeneous)", "[algorithm/some]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::some(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(!based::some(std::begin(arr), std::end(arr), predicate {2}));
}
TEST_CASE("some(non homogeneous)", "[algorithm/some]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::some(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(based::some(std::begin(arr), std::end(arr), predicate {2}));
REQUIRE(!based::some(std::begin(arr), std::end(arr), predicate {0}));
}
diff --git a/ test/source/find_if_unguarded_test.cpp b/ test/source/find_if_unguarded_test.cpp
@@ -1,76 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("find_if_unguarded(one)", "[algorithm/find_if_unguarded]")
{
const std::array arr = {0};
const auto* itr = based::find_if_unguarded(std::begin(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("find_if_unguarded(two)", "[algorithm/find_if_unguarded]")
{
const std::array arr = {0, 1};
const auto* itr = based::find_if_unguarded(std::begin(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("find_if_unguarded(multiple)", "[algorithm/find_if_unguarded]")
{
const std::array arr = {0, 0, 0, 0};
const auto* itr = based::find_if_unguarded(std::begin(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("find_if_not_unguarded(one)", "[algorithm/find_if_not_unguarded]")
{
const std::array arr = {0};
const auto* itr =
based::find_if_not_unguarded(std::begin(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("find_if_not_unguarded(two)", "[algorithm/find_if_not_unguarded]")
{
const std::array arr = {0, 1};
const auto* itr =
based::find_if_not_unguarded(std::begin(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE(
"find_if_not_unguarded(multiple)", "[algorithm/find_if_not_unguarded]"
)
{
const std::array arr = {1, 1, 0, 1};
const auto* itr =
based::find_if_not_unguarded(std::begin(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
diff --git a/ test/source/find_mismatch_n_test.cpp b/ test/source/find_mismatch_n_test.cpp
@@ -1,416 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
struct equal
{
auto operator()(int a, int b) const { return a == b; }
};
TEST_CASE("find_mismatch_n(empty)", "[algorithm/find_mismatch_n]")
{
std::array<int, 0> arr0 = {};
std::array<int, 0> arr1 = {};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch_n(empty, nonempty)", "[algorithm/find_mismatch_n]")
{
std::array<int, 0> arr0 = {};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::begin(arr1));
}
TEST_CASE("find_mismatch_n(nonempty, empty)", "[algorithm/find_mismatch_n]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array<int, 0> arr1 = {};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::begin(arr0));
REQUIRE(n0 == std::size(arr0));
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch_n(equal)", "[algorithm/find_mismatch_n]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch_n(equal, longer)", "[algorithm/find_mismatch_n]")
{
std::array arr0 = {0, 1, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::next(std::begin(arr1), std::size(arr0)));
}
TEST_CASE("find_mismatch_n(longer, equal)", "[algorithm/find_mismatch_n]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), std::size(arr1)));
REQUIRE(n0 == 2);
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch_n(mismatch)", "[algorithm/find_mismatch_n]")
{
std::array arr0 = {0, 1, 4, 3, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1] = based::find_mismatch_n(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), 2));
REQUIRE(n0 == 3);
REQUIRE(itr1 == std::next(std::begin(arr1), 2));
}
TEST_CASE("find_mismatch_m(empty)", "[algorithm/find_mismatch_m]")
{
std::array<int, 0> arr0 = {};
std::array<int, 0> arr1 = {};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_m(empty, nonempty)", "[algorithm/find_mismatch_m]")
{
std::array<int, 0> arr0 = {};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::begin(arr1));
REQUIRE(n1 == std::size(arr1));
}
TEST_CASE("find_mismatch_m(nonempty, empty)", "[algorithm/find_mismatch_m]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array<int, 0> arr1 = {};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::begin(arr0));
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_m(equal)", "[algorithm/find_mismatch_m]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_m(equal, longer)", "[algorithm/find_mismatch_m]")
{
std::array arr0 = {0, 1, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::next(std::begin(arr1), std::size(arr0)));
REQUIRE(n1 == 2);
}
TEST_CASE("find_mismatch_m(longer, equal)", "[algorithm/find_mismatch_m]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), std::size(arr1)));
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_m(mismatch)", "[algorithm/find_mismatch_m]")
{
std::array arr0 = {0, 1, 4, 3, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1, n1] = based::find_mismatch_m(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), 2));
REQUIRE(itr1 == std::next(std::begin(arr1), 2));
REQUIRE(n1 == 3);
}
TEST_CASE("find_mismatch_n_m(empty)", "[algorithm/find_mismatch_n_m]")
{
std::array<int, 0> arr0 = {};
std::array<int, 0> arr1 = {};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_n_m(empty, nonempty)", "[algorithm/find_mismatch_n_m]")
{
std::array<int, 0> arr0 = {};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::begin(arr1));
REQUIRE(n1 == std::size(arr1));
}
TEST_CASE("find_mismatch_n_m(nonempty, empty)", "[algorithm/find_mismatch_n_m]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array<int, 0> arr1 = {};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::begin(arr0));
REQUIRE(n0 == std::size(arr0));
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_n_m(equal)", "[algorithm/find_mismatch_n_m]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_n_m(equal, longer)", "[algorithm/find_mismatch_n_m]")
{
std::array arr0 = {0, 1, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(n0 == 0);
REQUIRE(itr1 == std::next(std::begin(arr1), std::size(arr0)));
REQUIRE(n1 == 2);
}
TEST_CASE("find_mismatch_n_m(longer, equal)", "[algorithm/find_mismatch_n_m]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), std::size(arr1)));
REQUIRE(n0 == 2);
REQUIRE(itr1 == std::end(arr1));
REQUIRE(n1 == 0);
}
TEST_CASE("find_mismatch_n_m(mismatch)", "[algorithm/find_mismatch_n_m]")
{
std::array arr0 = {0, 1, 4, 3, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, n0, itr1, n1] = based::find_mismatch_n_m(
std::begin(arr0),
std::size(arr0),
std::begin(arr1),
std::size(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), 2));
REQUIRE(n0 == 3);
REQUIRE(itr1 == std::next(std::begin(arr1), 2));
REQUIRE(n1 == 3);
}
diff --git a/ test/source/find_mismatch_test.cpp b/ test/source/find_mismatch_test.cpp
@@ -1,279 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
struct equal
{
auto operator()(int lhs, int rhs) const { return lhs == rhs; }
};
TEST_CASE("find_mismatch(empty)", "[algorithm/find_mismatch]")
{
std::array<int, 0> arr0 = {};
std::array<int, 0> arr1 = {};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch(empty, nonempty)", "[algorithm/find_mismatch]")
{
std::array<int, 0> arr0 = {};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::begin(arr1));
}
TEST_CASE("find_mismatch(nonempty, empty)", "[algorithm/find_mismatch]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array<int, 0> arr1 = {};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::begin(arr0));
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch(equal)", "[algorithm/find_mismatch]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch(equal, longer)", "[algorithm/find_mismatch]")
{
std::array arr0 = {0, 1, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::end(arr0));
REQUIRE(itr1 == std::next(std::begin(arr1), std::size(arr0)));
}
TEST_CASE("find_mismatch(longer, equal)", "[algorithm/find_mismatch]")
{
std::array arr0 = {0, 1, 2, 3, 4};
std::array arr1 = {0, 1, 2};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), std::size(arr1)));
REQUIRE(itr1 == std::end(arr1));
}
TEST_CASE("find_mismatch(mismatch)", "[algorithm/find_mismatch]")
{
std::array arr0 = {0, 1, 4, 3, 2};
std::array arr1 = {0, 1, 2, 3, 4};
const auto [itr0, itr1] = based::find_mismatch(
std::begin(arr0),
std::end(arr0),
std::begin(arr1),
std::end(arr1),
equal {}
);
REQUIRE(itr0 == std::next(std::begin(arr0), 2));
REQUIRE(itr1 == std::next(std::begin(arr1), 2));
}
TEST_CASE("find_adjacent_mismatch(empty)", "[algorithm/find_adjacent_mismatch]")
{
std::array<int, 0> arr = {};
const auto* itr =
based::find_adjacent_mismatch(std::begin(arr), std::end(arr), equal {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_adjacent_mismatch(one)", "[algorithm/find_adjacent_mismatch]")
{
std::array arr = {0};
const auto* itr =
based::find_adjacent_mismatch(std::begin(arr), std::end(arr), equal {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch(two equal)", "[algorithm/find_adjacent_mismatch]"
)
{
std::array arr = {0, 0};
const auto* itr =
based::find_adjacent_mismatch(std::begin(arr), std::end(arr), equal {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch(two nonequal)", "[algorithm/find_adjacent_mismatch]"
)
{
std::array arr = {0, 1};
const auto* itr =
based::find_adjacent_mismatch(std::begin(arr), std::end(arr), equal {});
REQUIRE(itr == std::next(std::begin(arr), 1));
}
TEST_CASE("find_adjacent_mismatch(equal)", "[algorithm/find_adjacent_mismatch]")
{
std::array arr = {0, 0, 0, 0, 0, 0};
const auto* itr =
based::find_adjacent_mismatch(std::begin(arr), std::end(arr), equal {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch(nonequal)", "[algorithm/find_adjacent_mismatch]"
)
{
std::array arr = {0, 0, 0, 0, 1, 1, 1, 1};
const auto* itr =
based::find_adjacent_mismatch(std::begin(arr), std::end(arr), equal {});
REQUIRE(itr == std::next(std::begin(arr), 4));
}
TEST_CASE(
"find_adjacent_mismatch_forward(empty)",
"[algorithm/find_adjacent_mismatch_forward]"
)
{
std::array<int, 0> arr = {};
const auto* itr = based::find_adjacent_mismatch_forward(
std::begin(arr), std::end(arr), equal {}
);
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch_forward(one)",
"[algorithm/find_adjacent_mismatch_forward]"
)
{
std::array arr = {0};
const auto* itr = based::find_adjacent_mismatch_forward(
std::begin(arr), std::end(arr), equal {}
);
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch_forward(two equal)",
"[algorithm/find_adjacent_mismatch_forward]"
)
{
std::array arr = {0, 0};
const auto* itr = based::find_adjacent_mismatch_forward(
std::begin(arr), std::end(arr), equal {}
);
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch_forward(two nonequal)",
"[algorithm/find_adjacent_mismatch_forward]"
)
{
std::array arr = {0, 1};
const auto* itr = based::find_adjacent_mismatch_forward(
std::begin(arr), std::end(arr), equal {}
);
REQUIRE(itr == std::next(std::begin(arr), 1));
}
TEST_CASE(
"find_adjacent_mismatch_forward(equal)",
"[algorithm/find_adjacent_mismatch_forward]"
)
{
std::array arr = {0, 0, 0, 0, 0, 0};
const auto* itr = based::find_adjacent_mismatch_forward(
std::begin(arr), std::end(arr), equal {}
);
REQUIRE(itr == std::end(arr));
}
TEST_CASE(
"find_adjacent_mismatch_forward(nonequal)",
"[algorithm/find_adjacent_mismatch_forward]"
)
{
std::array arr = {0, 0, 0, 0, 1, 1, 1, 1};
const auto* itr = based::find_adjacent_mismatch_forward(
std::begin(arr), std::end(arr), equal {}
);
REQUIRE(itr == std::next(std::begin(arr), 4));
}
diff --git a/ test/source/find_n_test.cpp b/ test/source/find_n_test.cpp
@@ -1,179 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
TEST_CASE("find_n(empty)", "[algorithm/find_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
TEST_CASE("find_n(one)", "[algorithm/find_n]")
{
const std::array arr = {0};
SECTION("found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_n(two)", "[algorithm/find_n]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("found 2")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 2);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_n(multiple)", "[algorithm/find_n]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_not_n(empty)", "[algorithm/find_not_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
TEST_CASE("find_not_n(one)", "[algorithm/find_not_n]")
{
const std::array arr = {0};
SECTION("found")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_not_n(two)", "[algorithm/find_not_n]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("found 2")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_not_n(multiple)", "[algorithm/find_not_n]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
REQUIRE(idx + left == std::size(arr));
}
}
diff --git a/ test/source/find_test.cpp b/ test/source/find_test.cpp
@@ -1,142 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
TEST_CASE("find(empty)", "[algorithm/find]")
{
const std::array<int, 0> arr = {};
const auto* itr = based::find(std::begin(arr), std::end(arr), 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find(one) = found", "[algorithm/find]")
{
const std::array arr = {0};
SECTION("found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}
TEST_CASE("find(two) = found", "[algorithm/find]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("found 2")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
SECTION("not found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 2);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
}
TEST_CASE("find(multiple) = found", "[algorithm/find]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
}
}
TEST_CASE("find_not(empty)", "[algorithm/find_not]")
{
const std::array<int, 0> arr = {};
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_not(one) = found", "[algorithm/find_not]")
{
const std::array arr = {0};
SECTION("found")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}
TEST_CASE("find_not(two) = found", "[algorithm/find_not]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("found 2")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}
TEST_CASE("find_not(multiple) = found", "[algorithm/find_not]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
SECTION("not found")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
}
}
diff --git a/ test/source/for_each_n_test.cpp b/ test/source/for_each_n_test.cpp
@@ -1,52 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
struct functor
{
int operator()(int n) { return sum += n; }
int sum = 0;
};
TEST_CASE("for_each_n(empty)", "[algorithm/for_each_n]")
{
const std::array<int, 0> arr = {};
const auto [f, itr] =
based::for_each_n(std::begin(arr), std::size(arr), functor {});
REQUIRE(f.sum == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("for_each_n(one)", "[algorithm/for_each_n]")
{
const std::array arr = {1};
const auto [f, itr] =
based::for_each_n(std::begin(arr), std::size(arr), functor {});
REQUIRE(f.sum == 1);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("for_each_n(two)", "[algorithm/for_each_n]")
{
const std::array arr = {1, 2};
const auto [f, itr] =
based::for_each_n(std::begin(arr), std::size(arr), functor {});
REQUIRE(f.sum == 3);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("for_each_n(three)", "[algorithm/for_each_n]")
{
const std::array arr = {1, 2, 3};
const auto [f, itr] =
based::for_each_n(std::begin(arr), std::size(arr), functor {});
REQUIRE(f.sum == 6);
REQUIRE(itr == std::end(arr));
}
diff --git a/ test/source/for_each_test.cpp b/ test/source/for_each_test.cpp
@@ -1,44 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
struct functor
{
int operator()(int n) { return sum += n; }
int sum = 0;
};
TEST_CASE("for_each(empty)", "[algorithm/for_each]")
{
const std::array<int, 0> arr = {};
const auto func = based::for_each(std::begin(arr), std::end(arr), functor {});
REQUIRE(func.sum == 0);
}
TEST_CASE("for_each(one)", "[algorithm/for_each]")
{
const std::array arr = {1};
const auto func = based::for_each(std::begin(arr), std::end(arr), functor {});
REQUIRE(func.sum == 1);
}
TEST_CASE("for_each(two)", "[algorithm/for_each]")
{
const std::array arr = {1, 2};
const auto func = based::for_each(std::begin(arr), std::end(arr), functor {});
REQUIRE(func.sum == 3);
}
TEST_CASE("for_each(three)", "[algorithm/for_each]")
{
const std::array arr = {1, 2, 3};
const auto func = based::for_each(std::begin(arr), std::end(arr), functor {});
REQUIRE(func.sum == 6);
}
diff --git a/ test/source/function_test.cpp b/ test/source/function_test.cpp
@@ -1,46 +0,0 @@
#include <catch2/catch_test_macros.hpp>
#include "based/template.hpp"
namespace
{
int identity(int a)
{
return a;
}
} // namespace
template class based::function<decltype(identity)>;
TEST_CASE("empty", "[template/function]")
{
const based::function<void()> func;
try {
func();
REQUIRE(false);
} catch (const std::bad_function_call& err) {
REQUIRE(true);
} catch (...) {
REQUIRE(false);
}
}
TEST_CASE("free function", "[template/function]")
{
const based::function func = identity;
REQUIRE(func(3) == 3);
}
TEST_CASE("lambda function", "[template/function]")
{
const based::function func = [](int a)
{
return a;
};
REQUIRE(func(3) == 3);
}
diff --git a/ test/source/functional/curry_test.cpp b/ test/source/functional/curry_test.cpp
@@ -0,0 +1,77 @@
#include "based/functional/curry.hpp"
#include <catch2/catch_test_macros.hpp>
// NOLINTBEGIN(*cognitive-complexity*, *magic*)
namespace
{
auto free_func(int a, double b, int c, double d)
{
return static_cast<int>(a + b + c + d);
}
} // namespace
TEST_CASE("free function", "[functional/curry]")
{
const based::curried curried = free_func;
REQUIRE(curried(1)(2.0)(3)(4.0) == 10);
REQUIRE(curried(1)(2.0, 3)(4.0) == 10);
REQUIRE(curried(1)(2.0, 3, 4.0) == 10);
REQUIRE(curried(1, 2.0)(3, 4.0) == 10);
REQUIRE(curried(1, 2.0, 3)(4.0) == 10);
REQUIRE(curried(1, 2.0, 3, 4.0) == 10);
}
TEST_CASE("lambda", "[functional/curry]")
{
const based::curried curried = [](int a, double b, int c, double d)
{
return static_cast<int>(a + b + c + d);
};
REQUIRE(curried(1)(2.0)(3)(4.0) == 10);
REQUIRE(curried(1)(2.0)(3, 4.0) == 10);
REQUIRE(curried(1)(2.0, 3)(4.0) == 10);
REQUIRE(curried(1)(2.0, 3, 4.0) == 10);
REQUIRE(curried(1, 2.0)(3)(4.0) == 10);
REQUIRE(curried(1, 2.0)(3, 4.0) == 10);
REQUIRE(curried(1, 2.0, 3)(4.0) == 10);
REQUIRE(curried(1, 2.0, 3, 4.0) == 10);
}
TEST_CASE("member function", "[functional/curry]")
{
struct test
{
[[nodiscard]] auto func(int a, double b, int c, double d) const
{
return static_cast<int>(m_x + a + b + c + d);
}
int m_x = 0;
};
const based::curried curried = &test::func;
test tmp;
REQUIRE(curried(std::ref(tmp))(1)(2.0)(3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1)(2.0)(3, 4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1)(2.0, 3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1)(2.0, 3, 4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1, 2.0)(3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1, 2.0)(3, 4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1, 2.0, 3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp))(1, 2.0, 3, 4.0) == 10);
REQUIRE(curried(std::ref(tmp), 1)(2.0)(3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp), 1)(2.0, 3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp), 1, 2.0)(3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp), 1, 2.0, 3)(4.0) == 10);
REQUIRE(curried(std::ref(tmp), 1, 2.0, 3, 4.0) == 10);
REQUIRE(curried(std::ref(tmp), 1, 2.0, 3, 4.0) == 10);
}
// NOLINTEND(*cognitive-complexity*, *magic*)
diff --git a/ test/source/functional/function_test.cpp b/ test/source/functional/function_test.cpp
@@ -0,0 +1,46 @@
#include "based/functional/function.hpp"
#include <catch2/catch_test_macros.hpp>
namespace
{
int identity(int a)
{
return a;
}
} // namespace
template class based::function<decltype(identity)>;
TEST_CASE("empty", "[template/function]")
{
const based::function<void()> func;
try {
func();
REQUIRE(false);
} catch (const std::bad_function_call& err) {
REQUIRE(true);
} catch (...) {
REQUIRE(false);
}
}
TEST_CASE("free function", "[template/function]")
{
const based::function func = identity;
REQUIRE(func(3) == 3);
}
TEST_CASE("lambda function", "[template/function]")
{
const based::function func = [](int a)
{
return a;
};
REQUIRE(func(3) == 3);
}
diff --git a/ test/source/list_test.cpp b/ test/source/list_test.cpp
@@ -4,11 +4,13 @@
#include <catch2/catch_test_macros.hpp>
template class based::list_pool<std::uint8_t, std::uint8_t>;
#include "based/types/types.hpp"
template class based::list_pool<based::u8, based::u8>;
TEST_CASE("list_pool", "[list/list_pool]")
{
using list_pool = based::list_pool<std::uint8_t, std::uint8_t>;
using list_pool = based::list_pool<based::u8, based::u8>;
auto pool = list_pool();
auto head = pool.node_empty();
@@ -62,13 +64,13 @@
TEST_CASE("list_pool", "[list/list_pool]")
TEST_CASE("list_pool iterator", "[list/list_pool]")
{
using list_pool = based::list_pool<std::uint8_t, std::uint8_t>;
using list_pool = based::list_pool<based::u8, based::u8>;
auto pool = list_pool();
auto head = pool.node_empty();
static constexpr std::size_t iter_count = 0xFF;
for (std::uint8_t i = 0; i < iter_count; i++) {
static constexpr based::size_t iter_count = 0xFF;
for (based::u8 i = 0; i < iter_count; i++) {
head = pool.allocate(i, head);
}
@@ -76,7 +78,7 @@
TEST_CASE("list_pool iterator", "[list/list_pool]")
{
using iter = list_pool::iterator;
std::uint32_t sum = 0;
based::u32 sum = 0;
for (auto it = iter(pool, head); it != iter(pool); it++) {
sum += *it.operator->();
sum += *it;
@@ -92,7 +94,7 @@
TEST_CASE("list_pool iterator", "[list/list_pool]")
const auto sum = std::accumulate(
iter(pool, head),
iter(pool),
std::uint32_t {0},
based::u32 {0},
[](auto a, auto b)
{
return a + b;
@@ -107,13 +109,13 @@
TEST_CASE("list_pool iterator", "[list/list_pool]")
TEST_CASE("list_pool const iterator", "[list/list_pool]")
{
using list_pool = based::list_pool<std::uint8_t, std::uint8_t>;
using list_pool = based::list_pool<based::u8, based::u8>;
auto pool = list_pool();
auto head = pool.node_empty();
static constexpr std::size_t iter_count = 0xFF;
for (std::uint8_t i = 0; i < iter_count; i++) {
static constexpr based::size_t iter_count = 0xFF;
for (based::u8 i = 0; i < iter_count; i++) {
head = pool.allocate(i, head);
}
@@ -121,7 +123,7 @@
TEST_CASE("list_pool const iterator", "[list/list_pool]")
{
using iter = list_pool::const_iterator;
std::uint32_t sum = 0;
based::u32 sum = 0;
for (auto it = iter(pool, head); it != iter(pool); it++) {
sum += *it.operator->();
sum += *it;
@@ -140,7 +142,7 @@
TEST_CASE("list_pool const iterator", "[list/list_pool]")
return std::accumulate(
iter(lpool, lhead),
iter(lpool),
std::uint32_t {0},
based::u32 {0},
[](auto a, auto b)
{
return a + b;
@@ -156,7 +158,7 @@
TEST_CASE("list_pool const iterator", "[list/list_pool]")
TEST_CASE("list_pool queue", "[list/list_pool/queue]")
{
using list_pool = based::list_pool<std::uint8_t, std::uint8_t>;
using list_pool = based::list_pool<based::u8, based::u8>;
using iter = list_pool::iterator;
auto pool = list_pool();
@@ -172,8 +174,8 @@
TEST_CASE("list_pool queue", "[list/list_pool/queue]")
REQUIRE(pool.pop_front(queue) == queue);
}
static constexpr std::size_t iter_count = 0xFF;
for (std::uint8_t i = 0; i < iter_count; i++) {
static constexpr based::size_t iter_count = 0xFF;
for (based::u8 i = 0; i < iter_count; i++) {
if (i % 2 == 0) {
queue = pool.push_front(queue, i);
} else {
@@ -185,7 +187,7 @@
TEST_CASE("list_pool queue", "[list/list_pool/queue]")
}
}
std::uint64_t sum = 0;
based::u64 sum = 0;
for (auto it = iter(pool, queue.first); it != iter(pool); ++it) {
sum += *it;
}
diff --git a/ test/source/max_element_test.cpp b/ test/source/max_element_test.cpp
@@ -1,92 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
TEST_CASE("max_element(empty)", "[algorithm/max_element]")
{
const std::array<int, 0> arr = {};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
REQUIRE(itr == std::end(arr));
}
TEST_CASE("max_element(1)", "[algorithm/max_element]")
{
const std::array arr = {0};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("max_element(2) = first", "[algorithm/max_element]")
{
const std::array arr = {1, 0};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("max_element(2) = second", "[algorithm/max_element]")
{
const std::array arr = {0, 1};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("max_element(2) = stable", "[algorithm/max_element]")
{
const std::array arr = {0, 0};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("max_element(3) = first", "[algorithm/max_element]")
{
const std::array arr = {2, 1, 0};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("max_element(3) = second", "[algorithm/max_element]")
{
const std::array arr = {1, 2, 0};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("max_element(3) = third", "[algorithm/max_element]")
{
const std::array arr = {0, 1, 2};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
TEST_CASE("max_element(3) = stable(1, 2)", "[algorithm/max_element]")
{
const std::array arr = {1, 1, 0};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("max_element(3) = stable(1, 3)", "[algorithm/max_element]")
{
const std::array arr = {1, 0, 1};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
TEST_CASE("max_element(3) = stable(2, 3)", "[algorithm/max_element]")
{
const std::array arr = {0, 1, 1};
const auto* itr = based::max_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
diff --git a/ test/source/max_test.cpp b/ test/source/max_test.cpp
@@ -1,326 +0,0 @@
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
#include "based/type_traits.hpp"
// NOLINTBEGIN(*const-arg*,*const-correctness*,*after-move, *access-moved)
TEST_CASE("max(literal, literal) = right", "[algorithm/max]")
{
using res_t = decltype(based::max(3, 4));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(3, 4) == 4);
}
TEST_CASE("max(literal, literal) = left", "[algorithm/max]")
{
using res_t = decltype(based::max(4, 3));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(4, 3) == 4);
}
TEST_CASE("max(value, literal) = right", "[algorithm/max]")
{
int a = 3;
using res_t = decltype(based::max(a, 4));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 4) == 4);
}
TEST_CASE("max(value, literal) = left", "[algorithm/max]")
{
int a = 4;
using res_t = decltype(based::max(a, 3));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 3) == 4);
}
TEST_CASE("max(literal, value) = right", "[algorithm/max]")
{
int b = 4;
using res_t = decltype(based::max(3, b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(3, b) == 4);
}
TEST_CASE("max(literal, value) = left", "[algorithm/max]")
{
int b = 3;
using res_t = decltype(based::max(4, b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(4, b) == 4);
}
TEST_CASE("max(value, value) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::max(a, b));
REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(value, value) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::max(a, b));
REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(const value, literal) = right", "[algorithm/max]")
{
const int a = 3;
using res_t = decltype(based::max(a, 4));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 4) == 4);
}
TEST_CASE("max(const value, literal) = left", "[algorithm/max]")
{
const int a = 4;
using res_t = decltype(based::max(a, 3));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 3) == 4);
}
TEST_CASE("max(literal, const value) = right", "[algorithm/max]")
{
const int b = 4;
using res_t = decltype(based::max(3, b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(3, b) == 4);
}
TEST_CASE("max(literal, const value) = left", "[algorithm/max]")
{
const int b = 3;
using res_t = decltype(based::max(4, b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(4, b) == 4);
}
TEST_CASE("max(const value, const value) = right", "[algorithm/max]")
{
const int a = 3;
const int b = 4;
using res_t = decltype(based::max(a, b));
REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(const value, const value) = left", "[algorithm/max]")
{
const int a = 4;
const int b = 3;
using res_t = decltype(based::max(a, b));
REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(value, const value) = right", "[algorithm/max]")
{
int a = 3;
const int b = 4;
using res_t = decltype(based::max(a, b));
REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(value, const value) = left", "[algorithm/max]")
{
int a = 4;
const int b = 3;
using res_t = decltype(based::max(a, b));
REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(const value, value) = right", "[algorithm/max]")
{
const int a = 3;
int b = 4;
using res_t = decltype(based::max(a, b));
REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(const value, value) = left", "[algorithm/max]")
{
const int a = 4;
int b = 3;
using res_t = decltype(based::max(a, b));
REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}
TEST_CASE("max(move, literal) = right", "[algorithm/max]")
{
int a = 3;
using res_t = decltype(based::max(std::move(a), 4));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(std::move(a), 4) == 4);
}
TEST_CASE("max(move, literal) = left", "[algorithm/max]")
{
int a = 4;
using res_t = decltype(based::max(std::move(a), 3));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(std::move(a), 3) == 4);
}
TEST_CASE("max(move, value) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::max(std::move(a), b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(std::move(a), b) == 4);
}
TEST_CASE("max(move, value) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::max(std::move(a), b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(std::move(a), b) == 4);
}
TEST_CASE("max(move, const value) = right", "[algorithm/max]")
{
int a = 3;
const int b = 4;
using res_t = decltype(based::max(std::move(a), b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(std::move(a), b) == 4);
}
TEST_CASE("max(move, const value) = left", "[algorithm/max]")
{
int a = 4;
const int b = 3;
using res_t = decltype(based::max(std::move(a), b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(std::move(a), b) == 4);
}
TEST_CASE("max(literal, move) = right", "[algorithm/max]")
{
int b = 4;
using res_t = decltype(based::max(3, std::move(b)));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(3, std::move(b)) == 4);
}
TEST_CASE("max(literal, move) = left", "[algorithm/max]")
{
int b = 3;
using res_t = decltype(based::max(4, std::move(b)));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(4, std::move(b)) == 4);
}
TEST_CASE("max(value, move) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::max(a, std::move(b)));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, std::move(b)) == 4);
}
TEST_CASE("max(value, move) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::max(a, std::move(b)));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, std::move(b)) == 4);
}
TEST_CASE("max(const value, move) = right", "[algorithm/max]")
{
const int a = 3;
int b = 4;
using res_t = decltype(based::max(a, std::move(b)));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, std::move(b)) == 4);
}
TEST_CASE("max(const value, move) = left", "[algorithm/max]")
{
const int a = 4;
int b = 3;
using res_t = decltype(based::max(a, std::move(b)));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, std::move(b)) == 4);
}
TEST_CASE("max(move, move) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::max(std::move(a), std::move(b)));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(std::move(a), std::move(b)) == 4);
}
TEST_CASE("max(move, move) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::max(std::move(a), std::move(b)));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(std::move(a), std::move(b)) == 4);
}
// NOLINTEND(*const-arg*,*const-correctness*,*after-move, *access-moved)
TEST_CASE("max-stability", "[algorithm/max]")
{
using type_t = std::pair<int, int>;
static const auto cmp = [](const type_t& x, const type_t& y)
{
return x.first < y.first;
};
const type_t a = {3, 4};
const type_t b = {3, 5};
REQUIRE(based::max(a, b, cmp).second == 5);
REQUIRE(based::max(b, a, cmp).second == 4);
}
diff --git a/ test/source/min_element_test.cpp b/ test/source/min_element_test.cpp
@@ -1,92 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
TEST_CASE("min_element(empty)", "[algorithm/min_element]")
{
const std::array<int, 0> arr = {};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
REQUIRE(itr == std::end(arr));
}
TEST_CASE("min_element(1)", "[algorithm/min_element]")
{
const std::array arr = {0};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("min_element(2) = first", "[algorithm/min_element]")
{
const std::array arr = {0, 1};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("min_element(2) = second", "[algorithm/min_element]")
{
const std::array arr = {1, 0};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("min_element(2) = stable", "[algorithm/min_element]")
{
const std::array arr = {0, 0};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("min_element(3) = first", "[algorithm/min_element]")
{
const std::array arr = {0, 1, 2};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("min_element(3) = second", "[algorithm/min_element]")
{
const std::array arr = {1, 0, 2};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
TEST_CASE("min_element(3) = third", "[algorithm/min_element]")
{
const std::array arr = {2, 1, 0};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
TEST_CASE("min_element(3) = stable(1, 2)", "[algorithm/min_element]")
{
const std::array arr = {0, 0, 1};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("min_element(3) = stable(1, 3)", "[algorithm/min_element]")
{
const std::array arr = {0, 1, 0};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}
TEST_CASE("min_element(3) = stable(2, 3)", "[algorithm/min_element]")
{
const std::array arr = {1, 0, 0};
const auto* itr = based::min_element(std::begin(arr), std::end(arr));
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
diff --git a/ test/source/min_test.cpp b/ test/source/min_test.cpp
@@ -1,326 +0,0 @@
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
#include "based/type_traits.hpp"
// NOLINTBEGIN(*const-arg*,*const-correctness*,*after-move, *access-moved)
TEST_CASE("min(literal, literal) = left", "[algorithm/min]")
{
using res_t = decltype(based::min(3, 4));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(3, 4) == 3);
}
TEST_CASE("min(literal, literal) = right", "[algorithm/min]")
{
using res_t = decltype(based::min(4, 3));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(4, 3) == 3);
}
TEST_CASE("min(value, literal) = left", "[algorithm/min]")
{
int a = 3;
using res_t = decltype(based::min(a, 4));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 4) == 3);
}
TEST_CASE("min(value, literal) = right", "[algorithm/min]")
{
int a = 4;
using res_t = decltype(based::min(a, 3));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 3) == 3);
}
TEST_CASE("min(literal, value) = left", "[algorithm/min]")
{
int b = 4;
using res_t = decltype(based::min(3, b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(3, b) == 3);
}
TEST_CASE("min(literal, value) = right", "[algorithm/min]")
{
int b = 3;
using res_t = decltype(based::min(4, b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(4, b) == 3);
}
TEST_CASE("min(value, value) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::min(a, b));
REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(value, value) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::min(a, b));
REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(const value, literal) = left", "[algorithm/min]")
{
const int a = 3;
using res_t = decltype(based::min(a, 4));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 4) == 3);
}
TEST_CASE("min(const value, literal) = right", "[algorithm/min]")
{
const int a = 4;
using res_t = decltype(based::min(a, 3));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 3) == 3);
}
TEST_CASE("min(literal, const value) = left", "[algorithm/min]")
{
const int b = 4;
using res_t = decltype(based::min(3, b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(3, b) == 3);
}
TEST_CASE("min(literal, const value) = right", "[algorithm/min]")
{
const int b = 3;
using res_t = decltype(based::min(4, b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(4, b) == 3);
}
TEST_CASE("min(const value, const value) = left", "[algorithm/min]")
{
const int a = 3;
const int b = 4;
using res_t = decltype(based::min(a, b));
REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(const value, const value) = right", "[algorithm/min]")
{
const int a = 4;
const int b = 3;
using res_t = decltype(based::min(a, b));
REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(value, const value) = left", "[algorithm/min]")
{
int a = 3;
const int b = 4;
using res_t = decltype(based::min(a, b));
REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(value, const value) = right", "[algorithm/min]")
{
int a = 4;
const int b = 3;
using res_t = decltype(based::min(a, b));
REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(const value, value) = left", "[algorithm/min]")
{
const int a = 3;
int b = 4;
using res_t = decltype(based::min(a, b));
REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(const value, value) = right", "[algorithm/min]")
{
const int a = 4;
int b = 3;
using res_t = decltype(based::min(a, b));
REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}
TEST_CASE("min(move, literal) = left", "[algorithm/min]")
{
int a = 3;
using res_t = decltype(based::min(std::move(a), 4));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(std::move(a), 4) == 3);
}
TEST_CASE("min(move, literal) = right", "[algorithm/min]")
{
int a = 4;
using res_t = decltype(based::min(std::move(a), 3));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(std::move(a), 3) == 3);
}
TEST_CASE("min(move, value) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::min(std::move(a), b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(std::move(a), b) == 3);
}
TEST_CASE("min(move, value) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::min(std::move(a), b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(std::move(a), b) == 3);
}
TEST_CASE("min(move, const value) = left", "[algorithm/min]")
{
int a = 3;
const int b = 4;
using res_t = decltype(based::min(std::move(a), b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(std::move(a), b) == 3);
}
TEST_CASE("min(move, const value) = right", "[algorithm/min]")
{
int a = 4;
const int b = 3;
using res_t = decltype(based::min(std::move(a), b));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(std::move(a), b) == 3);
}
TEST_CASE("min(literal, move) = left", "[algorithm/min]")
{
int b = 4;
using res_t = decltype(based::min(3, std::move(b)));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(3, std::move(b)) == 3);
}
TEST_CASE("min(literal, move) = right", "[algorithm/min]")
{
int b = 3;
using res_t = decltype(based::min(4, std::move(b)));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(4, std::move(b)) == 3);
}
TEST_CASE("min(value, move) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::min(a, std::move(b)));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, std::move(b)) == 3);
}
TEST_CASE("min(value, move) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::min(a, std::move(b)));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, std::move(b)) == 3);
}
TEST_CASE("min(const value, move) = left", "[algorithm/min]")
{
const int a = 3;
int b = 4;
using res_t = decltype(based::min(a, std::move(b)));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, std::move(b)) == 3);
}
TEST_CASE("min(const value, move) = right", "[algorithm/min]")
{
const int a = 4;
int b = 3;
using res_t = decltype(based::min(a, std::move(b)));
REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, std::move(b)) == 3);
}
TEST_CASE("min(move, move) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;
using res_t = decltype(based::min(std::move(a), std::move(b)));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(std::move(a), std::move(b)) == 3);
}
TEST_CASE("min(move, move) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;
using res_t = decltype(based::min(std::move(a), std::move(b)));
REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(std::move(a), std::move(b)) == 3);
}
// NOLINTEND(*const-arg*,*const-correctness*,*after-move, *access-moved)
TEST_CASE("min-stability", "[algorithm/min]")
{
using type_t = std::pair<int, int>;
static const auto cmp = [](const type_t& x, const type_t& y)
{
return x.first < y.first;
};
const type_t a = {3, 4};
const type_t b = {3, 5};
REQUIRE(based::min(a, b, cmp).second == 4);
REQUIRE(based::min(b, a, cmp).second == 5);
}
diff --git a/ test/source/minmax_element_test.cpp b/ test/source/minmax_element_test.cpp
@@ -1,101 +0,0 @@
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
TEST_CASE("minmax_element(empty)", "[algorithm/minmax_element]")
{
const std::array<int, 0> arr = {};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
REQUIRE(min == std::end(arr));
REQUIRE(max == std::end(arr));
}
TEST_CASE("minmax_element(1)", "[algorithm/minmax_element]")
{
const std::array arr = {0};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == 0);
REQUIRE(maxi == 0);
}
TEST_CASE("minmax_element(increasing even)", "[algorithm/minmax_element]")
{
const std::array arr = {0, 1, 2, 3};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == 0);
REQUIRE(maxi == std::size(arr) - 1);
}
TEST_CASE("minmax_element(increasing odd)", "[algorithm/minmax_element]")
{
const std::array arr = {0, 1, 2, 3, 4};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == 0);
REQUIRE(maxi == std::size(arr) - 1);
}
TEST_CASE("minmax_element(decreasing even)", "[algorithm/minmax_element]")
{
const std::array arr = {3, 2, 1, 0};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == std::size(arr) - 1);
REQUIRE(maxi == 0);
}
TEST_CASE("minmax_element(decreasing odd)", "[algorithm/minmax_element]")
{
const std::array arr = {4, 3, 2, 1, 0};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == std::size(arr) - 1);
REQUIRE(maxi == 0);
}
TEST_CASE("minmax_element(stable even)", "[algorithm/minmax_element]")
{
const std::array arr = {3, 0, 0, 3};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == 1);
REQUIRE(maxi == std::size(arr) - 1);
}
TEST_CASE("minmax_element(stable odd)", "[algorithm/minmax_element]")
{
const std::array arr = {3, 0, 3, 3, 0};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == 1);
REQUIRE(maxi == std::size(arr) - 2);
}
TEST_CASE("minmax_element(stable increasing)", "[algorithm/minmax_element]")
{
const std::array arr = {0, 0, 1, 2, 3, 4, 4};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == 0);
REQUIRE(maxi == std::size(arr) - 1);
}
TEST_CASE("minmax_element(stable decreasing)", "[algorithm/minmax_element]")
{
const std::array arr = {4, 4, 3, 2, 1, 0, 0};
const auto [min, max] = based::minmax_element(std::begin(arr), std::end(arr));
const auto mini = std::distance(std::begin(arr), min);
const auto maxi = std::distance(std::begin(arr), max);
REQUIRE(mini == std::size(arr) - 2);
REQUIRE(maxi == 1);
}
diff --git a/ test/source/partition_test.cpp b/ test/source/partition_test.cpp
@@ -1,161 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
struct equal
{
auto operator()(int a) const { return a == goal; }
int goal;
};
TEST_CASE("partitioned(empty)", "[algorithm/partitioned]")
{
std::array<int, 0> arr = {};
REQUIRE(based::partitioned(std::begin(arr), std::end(arr), equal {4}));
}
TEST_CASE("partitioned(one equal)", "[algorithm/partitioned]")
{
std::array arr = {4};
REQUIRE(based::partitioned(std::begin(arr), std::end(arr), equal {4}));
}
TEST_CASE("partitioned(one nonequal)", "[algorithm/partitioned]")
{
std::array arr = {1};
REQUIRE(based::partitioned(std::begin(arr), std::end(arr), equal {4}));
}
TEST_CASE("partitioned(partitioned)", "[algorithm/partitioned]")
{
std::array arr = {0, 1, 2, 3, 4, 4, 4, 4};
REQUIRE(based::partitioned(std::begin(arr), std::end(arr), equal {4}));
}
TEST_CASE("partitioned(nonpartitioned equal)", "[algorithm/partitioned]")
{
std::array arr = {4, 0, 1, 2, 3, 4, 4, 4};
REQUIRE(!based::partitioned(std::begin(arr), std::end(arr), equal {4}));
}
TEST_CASE("partitioned(nonpartitioned nonequal)", "[algorithm/partitioned]")
{
std::array arr = {4, 0, 1, 2, 3, 4, 4, 4, 0};
REQUIRE(!based::partitioned(std::begin(arr), std::end(arr), equal {4}));
}
TEST_CASE("partition_point(empty)", "[algorithm/partition_point]")
{
std::array<int, 0> arr = {};
const auto* itr =
based::partition_point(std::begin(arr), std::end(arr), equal {4});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("partition_point(one equal)", "[algorithm/partition_point]")
{
std::array arr = {4};
const auto* itr =
based::partition_point(std::begin(arr), std::end(arr), equal {4});
REQUIRE(itr == std::begin(arr));
}
TEST_CASE("partition_point(one nonequal)", "[algorithm/partition_point]")
{
std::array arr = {1};
const auto* itr =
based::partition_point(std::begin(arr), std::end(arr), equal {4});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("partition_point(sequence)", "[algorithm/partition_point]")
{
std::array arr = {0, 1, 2, 3, 4, 4, 4, 4};
const auto* itr =
based::partition_point(std::begin(arr), std::end(arr), equal {4});
REQUIRE(itr == std::next(std::begin(arr), 4));
}
TEST_CASE("lower_bound(empty)", "[algorithm/lower_bound]")
{
std::array<int, 0> arr = {};
const auto* itr =
based::lower_bound(std::begin(arr), std::end(arr), 4, std::less<int> {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("lower_bound(one equal)", "[algorithm/lower_bound]")
{
std::array arr = {4};
const auto* itr =
based::lower_bound(std::begin(arr), std::end(arr), 4, std::less<int> {});
REQUIRE(itr == std::begin(arr));
}
TEST_CASE("lower_bound(one nonequal)", "[algorithm/lower_bound]")
{
std::array arr = {1};
const auto* itr =
based::lower_bound(std::begin(arr), std::end(arr), 4, std::less<int> {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("lower_bound(sequence)", "[algorithm/lower_bound]")
{
std::array arr = {0, 1, 2, 3, 3, 4};
const auto* itr =
based::lower_bound(std::begin(arr), std::end(arr), 3, std::less<int> {});
REQUIRE(itr == std::next(std::begin(arr), 3));
}
TEST_CASE("upper_bound(empty)", "[algorithm/lower_bound]")
{
std::array<int, 0> arr = {};
const auto* itr =
based::upper_bound(std::begin(arr), std::end(arr), 4, std::less<int> {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("upper_bound(one equal)", "[algorithm/lower_bound]")
{
std::array arr = {4};
const auto* itr =
based::upper_bound(std::begin(arr), std::end(arr), 4, std::less<int> {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("upper_bound(one nonequal)", "[algorithm/lower_bound]")
{
std::array arr = {1};
const auto* itr =
based::upper_bound(std::begin(arr), std::end(arr), 4, std::less<int> {});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("upper_bound(sequence)", "[algorithm/lower_bound]")
{
std::array arr = {0, 1, 2, 3, 3, 4};
const auto* itr =
based::upper_bound(std::begin(arr), std::end(arr), 3, std::less<int> {});
REQUIRE(itr == std::next(std::begin(arr), 5));
}
diff --git a/ test/source/reduce_test.cpp b/ test/source/reduce_test.cpp
@@ -1,66 +0,0 @@
#include <array>
#include <vector>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
struct op
{
auto operator()(const auto& lhs, const auto& rhs) { return lhs + rhs; }
};
struct fun
{
auto operator()(based::Iterator auto itr) { return *itr; }
};
TEST_CASE("reduce_nonempty(sequence)", "[algorithm/reduce_nonempty]")
{
const std::array arr = {0, 1, 2, 3, 4, 5};
const auto count =
based::reduce_nonempty(std::cbegin(arr), std::cend(arr), op {}, fun {});
REQUIRE(count == 15);
}
TEST_CASE("reduce(empty)", "[algorithm/reduce]")
{
const std::array<int, 0> arr = {};
const auto count =
based::reduce(std::cbegin(arr), std::cend(arr), op {}, fun {}, 0);
REQUIRE(count == 0);
}
TEST_CASE("reduce(sequence)", "[algorithm/reduce]")
{
const std::array arr = {0, 1, 2, 3, 4, 5};
const auto count =
based::reduce(std::cbegin(arr), std::cend(arr), op {}, fun {}, 0);
REQUIRE(count == 15);
}
TEST_CASE("reduce_nonzero(empty)", "[algorithm/reduce_nonzero]")
{
const std::array<int, 0> arr = {};
const auto count =
based::reduce_nonzero(std::cbegin(arr), std::cend(arr), op {}, fun {}, 0);
REQUIRE(count == 0);
}
TEST_CASE("reduce_nonzero(sequence)", "[algorithm/reduce_nonzero]")
{
const std::array arr = {0, 1, 2, 3, 4, 5};
const auto count =
based::reduce_nonzero(std::cbegin(arr), std::cend(arr), op {}, fun {}, 0);
REQUIRE(count == 15);
}
diff --git a/ test/source/scopeguard_test.cpp b/ test/source/scopeguard_test.cpp
@@ -1,134 +0,0 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <stdexcept>
#include <catch2/catch_test_macros.hpp>
#include "based/template.hpp"
// NOLINTBEGIN(*cognitive-complexity*)
struct set
{
explicit set(int& val)
: m_val(&val)
{
}
void operator()() const { *m_val = 1; }
private:
int* m_val;
};
template class based::scopeguard<set>;
TEST_CASE("manual", "[template/scopeguard]")
{
SECTION("commit")
{
int test = 0;
try {
based::scopeguard guard = set(test);
guard.commit();
} catch (...) {
REQUIRE(false);
}
REQUIRE(test == 1);
}
// breaks coverage for some reason
SECTION("no commit")
{
int test = 0;
try {
based::scopeguard guard = set(test); // NOLINT(*const*)
} catch (...) {
test *= 1;
}
REQUIRE(test == 0);
}
}
TEST_CASE("on success", "[template/scopeguard]")
{
SECTION("success")
{
int test = 0;
try {
const based::scopeguard_success guard = set(test);
} catch (...) {
test *= 1;
}
REQUIRE(test == 1);
}
// breaks coverage for some reason
SECTION("failure")
{
int test = 0;
try {
const based::scopeguard_success guard = set(test);
throw std::runtime_error {"should not leak"};
} catch (...) {
test *= 1;
}
REQUIRE(test == 0);
}
}
TEST_CASE("on failure", "[template/scopeguard]")
{
SECTION("success")
{
int test = 0;
try {
const based::scopeguard_failure guard = set(test);
} catch (...) {
test *= 1;
}
REQUIRE(test == 0);
}
// breaks coverage for some reason
SECTION("failure")
{
int test = 0;
try {
const based::scopeguard_failure guard = set(test);
throw std::runtime_error {"should not leak"};
} catch (...) {
REQUIRE(true);
}
REQUIRE(test == 1);
}
}
TEST_CASE("exit", "[template/scopeguard]")
{
SECTION("success")
{
int test = 0;
try {
const based::scopeguard_exit guard = set(test);
} catch (...) {
REQUIRE(false);
}
REQUIRE(test == 1);
}
// breaks coverage for some reason
SECTION("failure")
{
int test = 0;
try {
const based::scopeguard_exit guard = set(test);
throw std::runtime_error {"should not leak"};
} catch (...) {
test *= 1;
}
REQUIRE(test == 1);
}
}
// NOLINTEND(*cognitive-complexity*)
diff --git a/ test/source/signature_test.cpp b/ test/source/signature_test.cpp
@@ -1,478 +0,0 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <catch2/catch_test_macros.hpp>
#include "based/type_traits.hpp"
// NOLINTBEGIN(*cognitive-complexity*)
namespace
{
// NOLINTNEXTLINE (*needed*)
int free_func(const double& a, int&& b) noexcept(false)
{
return static_cast<int>(a + b);
}
// NOLINTNEXTLINE (*needed*)
int free_func_noexcept(const double& a, int&& b) noexcept(true)
{
return static_cast<int>(a + b);
}
} // namespace
using based::SameAs;
TEST_CASE("free function", "[type_traits/signature]")
{
using sig = based::signature<decltype(free_func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("free function noexcept", "[type_traits/signature]")
{
using sig = based::signature<decltype(free_func_noexcept)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("empty", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("const", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("volatile", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("const volatile", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("noexcept", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("const noexcept", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("volatile noexcept", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("const volatile noexcept", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) & noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("const lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const& noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("volatile lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile& noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("const volatile lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile& noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("noexcept lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) & noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("const noexcept lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const& noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("volatile noexcept lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile& noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("const volatile noexcept lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile& noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) && noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("const rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const&& noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("volatile rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile&& noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("const volatile rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile&& noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("noexcept rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) && noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("const noexcept rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const&& noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("volatile noexcept rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile&& noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("const volatile noexcept rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile&& noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
// NOLINTEND(*cognitive-complexity*)
diff --git a/ test/source/standard_traits_test.cpp b/ test/source/standard_traits_test.cpp
@@ -1,158 +0,0 @@
// #define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <catch2/catch_test_macros.hpp>
#include "based/type_traits.hpp"
// NOLINTBEGIN(*array*)
using based::SameAs;
TEST_CASE("remove_const", "[type_traits/remove_const]")
{
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_const_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int&>, int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int&&>, int&&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int(&)[2]>, int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int(&&)[2]>, int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int>, int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int&>, const int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int(&)[2]>, const int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int&>, volatile int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int&&>, volatile int&&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int(&)[2]>, volatile int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int(&&)[2]>, volatile int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int&>, volatile const int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int(&)[2]>, volatile const int(&)[2]>);
// clang-format on
}
TEST_CASE("remove_volatile", "[type_traits/remove_volatile]")
{
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int&>, int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int&&>, int&&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int(&)[2]>, int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int(&&)[2]>, int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int>, const int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int&>, const int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int(&)[2]>, const int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int&>, volatile int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int&&>, volatile int&&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int(&)[2]>, volatile int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int(&&)[2]>, volatile int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int>, const int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int&>, volatile const int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int(&)[2]>, volatile const int(&)[2]>);
// clang-format on
}
TEST_CASE("remove_cv", "[type_traits/remove_cv]")
{
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_cv_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int&>, int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int&&>, int&&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int(&)[2]>, int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int(&&)[2]>, int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int&>, const int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int(&)[2]>, const int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int&>, volatile int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int&&>, volatile int&&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int(&)[2]>, volatile int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int(&&)[2]>, volatile int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int&>, volatile const int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int(&)[2]>, volatile const int(&)[2]>);
// clang-format on
}
TEST_CASE("remove_reference", "[type_traits/remove_reference]")
{
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_reference_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int&&>, int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int(&&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int>, const int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int&>, const int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int(&)[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int>,volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int&>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int&&>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int(&)[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int(&&)[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int>, const volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int&>, volatile const int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int[2]>, const volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int(&)[2]>, volatile const int[2]>);
// clang-format on
}
TEST_CASE("remove_cvref", "[type_traits/remove_cvref]")
{
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int&&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int(&&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int&&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int(&&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int(&)[2]>, int[2]>);
// clang-format on
}
TEST_CASE("remove_pointer", "[type_traits/remove_pointer]")
{
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int*>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int**>, int*>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int* const>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int* volatile>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int* const volatile>, int>);
// clang-format on
}
// NOLINTEND(*array*)
diff --git a/ test/source/type_traits/remove_const.cpp b/ test/source/type_traits/remove_const.cpp
@@ -0,0 +1,37 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <catch2/catch_test_macros.hpp>
#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/const.hpp"
using based::SameAs;
TEST_CASE("remove_const", "[type_traits/remove/remove_const]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_const_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int&>, int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int&&>, int&&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int(&)[2]>, int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int(&&)[2]>, int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int>, int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int&>, const int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int(&)[2]>, const int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int&>, volatile int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int&&>, volatile int&&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int(&)[2]>, volatile int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int(&&)[2]>, volatile int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int&>, volatile const int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int(&)[2]>, volatile const int(&)[2]>);
// clang-format on
// NOLINTEND(*array*)
}
diff --git a/ test/source/type_traits/remove_cv.cpp b/ test/source/type_traits/remove_cv.cpp
@@ -0,0 +1,37 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <catch2/catch_test_macros.hpp>
#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/cv.hpp"
using based::SameAs;
TEST_CASE("remove_cv", "[type_traits/remove_cv]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_cv_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int&>, int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int&&>, int&&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int(&)[2]>, int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int(&&)[2]>, int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int&>, const int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int(&)[2]>, const int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int&>, volatile int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int&&>, volatile int&&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int(&)[2]>, volatile int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int(&&)[2]>, volatile int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int&>, volatile const int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int(&)[2]>, volatile const int(&)[2]>);
// clang-format on
// NOLINTEND(*array*)
}
diff --git a/ test/source/type_traits/remove_cvref.cpp b/ test/source/type_traits/remove_cvref.cpp
@@ -0,0 +1,37 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <catch2/catch_test_macros.hpp>
#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/cvref.hpp"
using based::SameAs;
TEST_CASE("remove_cvref", "[type_traits/remove_cvref]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int&&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int(&&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int&&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int(&&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int(&)[2]>, int[2]>);
// clang-format on
// NOLINTEND(*array*)
}
diff --git a/ test/source/type_traits/remove_pointer.cpp b/ test/source/type_traits/remove_pointer.cpp
@@ -0,0 +1,22 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <catch2/catch_test_macros.hpp>
#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/pointer.hpp"
using based::SameAs;
TEST_CASE("remove_pointer", "[type_traits/remove_pointer]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int*>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int**>, int*>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int* const>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int* volatile>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int* const volatile>, int>);
// clang-format on
// NOLINTEND(*array*)
}
diff --git a/ test/source/type_traits/remove_reference.cpp b/ test/source/type_traits/remove_reference.cpp
@@ -0,0 +1,37 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <catch2/catch_test_macros.hpp>
#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"
using based::SameAs;
TEST_CASE("remove_reference", "[type_traits/remove_reference]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_reference_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int&&>, int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int(&&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int>, const int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int&>, const int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int(&)[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int>,volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int&>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int&&>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int(&)[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int(&&)[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int>, const volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int&>, volatile const int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int[2]>, const volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int(&)[2]>, volatile const int[2]>);
// clang-format on
// NOLINTEND(*array*)
}
diff --git a/ test/source/type_traits/remove_volatile.cpp b/ test/source/type_traits/remove_volatile.cpp
@@ -0,0 +1,37 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <catch2/catch_test_macros.hpp>
#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/volatile.hpp"
using based::SameAs;
TEST_CASE("remove_volatile", "[type_traits/remove/remove_volatile]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int&>, int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int&&>, int&&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int(&)[2]>, int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int(&&)[2]>, int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int>, const int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int&>, const int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int(&)[2]>, const int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int&>, volatile int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int&&>, volatile int&&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int(&)[2]>, volatile int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int(&&)[2]>, volatile int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int>, const int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int&>, volatile const int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int(&)[2]>, volatile const int(&)[2]>);
// clang-format on
// NOLINTEND(*array*)
}
diff --git a/ test/source/type_traits/signature_test.cpp b/ test/source/type_traits/signature_test.cpp
@@ -0,0 +1,480 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include "based/type_traits/signature.hpp"
#include <catch2/catch_test_macros.hpp>
#include "based/concepts/is/same.hpp"
// NOLINTBEGIN(*cognitive-complexity*)
namespace
{
// NOLINTNEXTLINE (*needed*)
int free_func(const double& a, int&& b) noexcept(false)
{
return static_cast<int>(a + b);
}
// NOLINTNEXTLINE (*needed*)
int free_func_noexcept(const double& a, int&& b) noexcept(true)
{
return static_cast<int>(a + b);
}
} // namespace
using based::SameAs;
TEST_CASE("free function", "[type_traits/signature]")
{
using sig = based::signature<decltype(free_func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("free function noexcept", "[type_traits/signature]")
{
using sig = based::signature<decltype(free_func_noexcept)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("empty", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("const", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("volatile", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("const volatile", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("noexcept", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("const noexcept", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("volatile noexcept", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("const volatile noexcept", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) & noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("const lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const& noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("volatile lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile& noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("const volatile lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile& noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("noexcept lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) & noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("const noexcept lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const& noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("volatile noexcept lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile& noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("const volatile noexcept lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile& noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) && noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("const rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const&& noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("volatile rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile&& noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("const volatile rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile&& noexcept(false);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}
TEST_CASE("noexcept rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) && noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("const noexcept rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const&& noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("volatile noexcept rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile&& noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
TEST_CASE("const volatile noexcept rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile&& noexcept(true);
};
using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}
// NOLINTEND(*cognitive-complexity*)
diff --git a/ test/source/utility/buffer_test.cpp b/ test/source/utility/buffer_test.cpp
@@ -0,0 +1,68 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include "based/utility/buffer.hpp"
#include <catch2/catch_test_macros.hpp>
#include "based/types/types.hpp"
template struct based::buffer<sizeof(void*)>;
TEST_CASE("valid type", "[template/buffer]")
{
SECTION("small buffer")
{
using buffer = based::buffer<sizeof(based::u8)>;
STATIC_REQUIRE(buffer::valid_type<based::u8>());
STATIC_REQUIRE_FALSE(buffer::valid_type<based::size_t>());
STATIC_REQUIRE_FALSE(buffer::valid_type<char[5]>()); // NOLINT(*array*)
}
SECTION("big buffer")
{
using buffer = based::buffer<sizeof(based::size_t), alignof(based::size_t)>;
STATIC_REQUIRE(buffer::valid_type<based::u8>());
STATIC_REQUIRE(buffer::valid_type<based::size_t>());
STATIC_REQUIRE_FALSE(buffer::valid_type<char[5]>()); // NOLINT(*array*)
}
}
TEST_CASE("buffer", "[template/buffer]")
{
using buffer = based::buffer<sizeof(based::size_t)>;
static constexpr based::u8 value = 8;
buffer buf(std::in_place_type<based::u8>, value);
REQUIRE(*buf.as<based::u8>() == value);
SECTION("emplace")
{
static constexpr based::u16 new_value = 10;
buf.emplace<based::u16>(new_value);
REQUIRE(*buf.as<based::u16>() == new_value);
}
SECTION("swap")
{
static constexpr based::u16 new_value = 10;
buffer new_buf(std::in_place_type<based::u16>, new_value);
buf.swap(new_buf);
REQUIRE(*buf.as<based::u16>() == new_value);
REQUIRE(*new_buf.as<based::u8>() == value);
}
}
TEST_CASE("const buffer", "[template/buffer]")
{
using buffer = based::buffer<sizeof(based::size_t)>;
static constexpr based::u8 value = 8;
const buffer buf(std::in_place_type<based::u8>, value);
REQUIRE(*buf.as<based::u8>() == value);
}
diff --git a/ test/source/utility/scopeguard_test.cpp b/ test/source/utility/scopeguard_test.cpp
@@ -0,0 +1,134 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <stdexcept>
#include "based/utility/scopeguard.hpp"
#include <catch2/catch_test_macros.hpp>
// NOLINTBEGIN(*cognitive-complexity*)
struct set
{
explicit set(int& val)
: m_val(&val)
{
}
void operator()() const { *m_val = 1; }
private:
int* m_val;
};
template class based::scopeguard<set>;
TEST_CASE("manual", "[template/scopeguard]")
{
SECTION("commit")
{
int test = 0;
try {
based::scopeguard guard = set(test);
guard.commit();
} catch (...) {
REQUIRE(false);
}
REQUIRE(test == 1);
}
// breaks coverage for some reason
SECTION("no commit")
{
int test = 0;
try {
based::scopeguard guard = set(test); // NOLINT(*const*)
} catch (...) {
test *= 1;
}
REQUIRE(test == 0);
}
}
TEST_CASE("on success", "[template/scopeguard]")
{
SECTION("success")
{
int test = 0;
try {
const based::scopeguard_success guard = set(test);
} catch (...) {
test *= 1;
}
REQUIRE(test == 1);
}
// breaks coverage for some reason
SECTION("failure")
{
int test = 0;
try {
const based::scopeguard_success guard = set(test);
throw std::runtime_error {"should not leak"};
} catch (...) {
test *= 1;
}
REQUIRE(test == 0);
}
}
TEST_CASE("on failure", "[template/scopeguard]")
{
SECTION("success")
{
int test = 0;
try {
const based::scopeguard_failure guard = set(test);
} catch (...) {
test *= 1;
}
REQUIRE(test == 0);
}
// breaks coverage for some reason
SECTION("failure")
{
int test = 0;
try {
const based::scopeguard_failure guard = set(test);
throw std::runtime_error {"should not leak"};
} catch (...) {
REQUIRE(true);
}
REQUIRE(test == 1);
}
}
TEST_CASE("exit", "[template/scopeguard]")
{
SECTION("success")
{
int test = 0;
try {
const based::scopeguard_exit guard = set(test);
} catch (...) {
REQUIRE(false);
}
REQUIRE(test == 1);
}
// breaks coverage for some reason
SECTION("failure")
{
int test = 0;
try {
const based::scopeguard_exit guard = set(test);
throw std::runtime_error {"should not leak"};
} catch (...) {
test *= 1;
}
REQUIRE(test == 1);
}
}
// NOLINTEND(*cognitive-complexity*)