diff options
| author | Leitwolf11 | 2026-10-31 13:00:24 +0300 |
|---|---|---|
| committer | Leitwolf11 | 2026-10-31 13:00:24 +0300 |
| commit | 8814bd0b796b2e291fa5b4a1033f0313c8a26065 (patch) | |
| tree | e87e5f5150f3712bb05ed53911425600aa871f45 /src/Progmasoft | |
| parent | 6a42cdf6461b2577106ef094d6f98025554b6077 (diff) | |
| download | catch3-8814bd0b796b2e291fa5b4a1033f0313c8a26065.tar.gz | |
Build Catch3 as C++17
C++17 is still the widest common target, and a library built on it stays
usable from C++17 and every later standard, while C++20 would have left
out many users.
Concepts become enable_if on named traits in Detail/TypeTraits.hpp, which
also replaces std::remove_cvref_t and std::identity. std::span becomes
std::vector references, std::bit_cast becomes static_cast and memcpy,
template lambdas become helper templates, and std::erase_if, contains,
starts_with and ends_with have their C++17 forms. Random::Between no
longer uses a lambda over a constexpr local, which MSVC rejects outside
/permissive-, so the headers work under its default mode too.
Tests give up designated initializers, which MSVC refuses in C++17. CI
builds the matrix in C++17 and C++20, since the headers promise both.
Diffstat (limited to 'src/Progmasoft')
| -rw-r--r-- | src/Progmasoft/BUILD.bazel | 15 | ||||
| -rw-r--r-- | src/Progmasoft/Catch3/Detail/TypeTraits.hpp | 47 | ||||
| -rw-r--r-- | src/Progmasoft/Catch3/ForAll.hpp | 38 | ||||
| -rw-r--r-- | src/Progmasoft/Catch3/Generators/Element.hpp | 12 | ||||
| -rw-r--r-- | src/Progmasoft/Catch3/Generators/Integer.hpp | 12 | ||||
| -rw-r--r-- | src/Progmasoft/Catch3/Generators/Tuple.hpp | 3 | ||||
| -rw-r--r-- | src/Progmasoft/Catch3/Property.hpp | 15 | ||||
| -rw-r--r-- | src/Progmasoft/Catch3/Random.hpp | 43 | ||||
| -rw-r--r-- | src/Progmasoft/Catch3/Strategy/ChoiceSource.hpp | 14 | ||||
| -rw-r--r-- | src/Progmasoft/Catch3/Strategy/Containers.hpp | 4 | ||||
| -rw-r--r-- | src/Progmasoft/Catch3/Strategy/Engine.hpp | 7 | ||||
| -rw-r--r-- | src/Progmasoft/Catch3/Strategy/Numeric.hpp | 14 | ||||
| -rw-r--r-- | src/Progmasoft/Catch3/Strategy/Strategy.hpp | 27 | ||||
| -rw-r--r-- | src/Progmasoft/Catch3/meson.build | 2 | ||||
| -rw-r--r-- | src/Progmasoft/ChoiceShrinker.cpp | 8 | ||||
| -rw-r--r-- | src/Progmasoft/PropertyEngine.cpp | 16 | ||||
| -rw-r--r-- | src/Progmasoft/Runner/Process.cpp | 42 | ||||
| -rw-r--r-- | src/Progmasoft/meson.build | 1 |
18 files changed, 194 insertions, 126 deletions
diff --git a/src/Progmasoft/BUILD.bazel b/src/Progmasoft/BUILD.bazel index 5824d1b6..a3b4d68e 100644 --- a/src/Progmasoft/BUILD.bazel +++ b/src/Progmasoft/BUILD.bazel @@ -4,12 +4,11 @@ load("@bazel_skylib//rules:expand_template.bzl", "expand_template") load("@rules_cc//cc:defs.bzl", "cc_library") # Catch3: the Catch2-compatible engine in Catch3/, the runner in Runner/, -# property testing and snapshots. It is built as C++20; code that includes -# only the engine's headers needs C++14. //:catch3 and //:catch3_main are the -# public names. -CPP20 = select({ - "@platforms//os:windows": ["/std:c++20"], - "//conditions:default": ["-std=c++20"], +# property testing and snapshots. It is C++17 and its headers work in C++17 +# and later. //:catch3 and //:catch3_main are the public names. +CPP17 = select({ + "@platforms//os:windows": ["/std:c++17"], + "//conditions:default": ["-std=c++17"], }) # The engine's configuration header, with Bazel support switched on. @@ -89,7 +88,7 @@ cc_library( exclude = ["Catch3/Internal/Main.cpp"], ), hdrs = glob(["**/*.hpp"]) + [":Catch3/UserConfig.hpp"], - copts = CPP20, + copts = CPP17, linkstatic = True, strip_include_prefix = "/src", visibility = ["//:__pkg__"], @@ -102,7 +101,7 @@ cc_library( cc_library( name = "catch3_main", srcs = ["Catch3/Internal/Main.cpp"], - copts = CPP20, + copts = CPP17, linkstatic = True, visibility = ["//:__pkg__"], deps = [":catch3"], diff --git a/src/Progmasoft/Catch3/Detail/TypeTraits.hpp b/src/Progmasoft/Catch3/Detail/TypeTraits.hpp new file mode 100644 index 00000000..56f06665 --- /dev/null +++ b/src/Progmasoft/Catch3/Detail/TypeTraits.hpp @@ -0,0 +1,47 @@ +// Copyright (c) 2026 Progmasoft. +// SPDX-License-Identifier: MPL-2.0 WITH AdditionRef-Progmasoft-Exception-1.1 +#pragma once + +#include <type_traits> +#include <utility> + +namespace Progmasoft::Catch3::Detail +{ + + /// std::remove_cvref_t, which C++17 does not have. + template<typename Type> + using RemoveCvRef = std::remove_cv_t<std::remove_reference_t<Type>>; + + /// std::identity, which C++17 does not have. + struct Identity final + { + template<typename Type> + [[nodiscard]] constexpr Type && + operator()(Type &&value) const noexcept + { + return std::forward<Type>(value); + } + }; + + /// An integral type that holds numbers, so anything but bool. + template<typename Type> + inline constexpr bool kIsInteger + = std::is_integral_v<Type> + && !std::is_same_v<std::remove_cv_t<Type>, bool>; + + /// Limits a function template to the types of kIsInteger. + template<typename Type> + using EnableIfInteger = std::enable_if_t<kIsInteger<Type>, int>; + + template<typename Type, typename = void> + inline constexpr bool kIsEqualityComparable = false; + + template<typename Type> + inline constexpr bool kIsEqualityComparable< + Type, + std::enable_if_t< + std::is_convertible_v<decltype(std::declval<const Type &>() + == std::declval<const Type &>()), + bool>>> = true; + +} // namespace Progmasoft::Catch3::Detail diff --git a/src/Progmasoft/Catch3/ForAll.hpp b/src/Progmasoft/Catch3/ForAll.hpp index e41bfdb6..748b89c6 100644 --- a/src/Progmasoft/Catch3/ForAll.hpp +++ b/src/Progmasoft/Catch3/ForAll.hpp @@ -148,7 +148,27 @@ namespace Progmasoft::Catch3 template<typename Type> inline constexpr bool kIsPropertyOptions - = std::is_same_v<std::remove_cvref_t<Type>, PropertyOptions>; + = std::is_same_v<RemoveCvRef<Type>, PropertyOptions>; + + template<typename Arguments, std::size_t... Index> + [[nodiscard]] PropertyResult + ForAllWithOptions(Arguments &all, std::index_sequence<Index...>) + { + constexpr std::size_t kCount = std::tuple_size_v<Arguments>; + return ForAllWith(std::get<0>(all), + std::get<kCount - 1U>(all), + std::get<Index + 1U>(all)...); + } + + template<typename Arguments, std::size_t... Index> + [[nodiscard]] PropertyResult + ForAllWithDefaults(Arguments &all, std::index_sequence<Index...>) + { + constexpr std::size_t kCount = std::tuple_size_v<Arguments>; + return ForAllWith(PropertyOptions{}, + std::get<kCount - 1U>(all), + std::get<Index>(all)...); + } } // namespace Detail @@ -172,19 +192,15 @@ namespace Progmasoft::Catch3 using First = std::tuple_element_t<0, std::tuple<Arguments...>>; if constexpr (Detail::kIsPropertyOptions<First>) { - return [&]<std::size_t... Index>(std::index_sequence<Index...>) { - return Detail::ForAllWith(std::get<0>(all), - std::get<kCount - 1U>(all), - std::get<Index + 1U>(all)...); - }(std::make_index_sequence<kCount - 2U>{}); + return Detail::ForAllWithOptions( + all, + std::make_index_sequence<kCount - 2U>{}); } else { - return [&]<std::size_t... Index>(std::index_sequence<Index...>) { - return Detail::ForAllWith(PropertyOptions{}, - std::get<kCount - 1U>(all), - std::get<Index>(all)...); - }(std::make_index_sequence<kCount - 1U>{}); + return Detail::ForAllWithDefaults( + all, + std::make_index_sequence<kCount - 1U>{}); } } diff --git a/src/Progmasoft/Catch3/Generators/Element.hpp b/src/Progmasoft/Catch3/Generators/Element.hpp index 087b6355..2c270d18 100644 --- a/src/Progmasoft/Catch3/Generators/Element.hpp +++ b/src/Progmasoft/Catch3/Generators/Element.hpp @@ -2,9 +2,9 @@ // SPDX-License-Identifier: MPL-2.0 WITH AdditionRef-Progmasoft-Exception-1.1 #pragma once +#include <Progmasoft/Catch3/Detail/TypeTraits.hpp> #include <Progmasoft/Catch3/Generator.hpp> #include <algorithm> -#include <concepts> #include <cstddef> #include <initializer_list> #include <iterator> @@ -20,8 +20,9 @@ namespace Progmasoft::Catch3 /// The list order is the simplicity order: a value shrinks to the values /// listed before it, earliest first, so place the simplest case first. /// A value that is not in the list has no candidates. - template<typename ValueType> - requires std::equality_comparable<ValueType> + template<typename ValueType, + std::enable_if_t<Detail::kIsEqualityComparable<ValueType>, int> + = 0> [[nodiscard]] Generator<ValueType> Element(std::vector<ValueType> values) { @@ -52,8 +53,9 @@ namespace Progmasoft::Catch3 } /// Convenience overload for a literal list of values. - template<typename ValueType> - requires std::equality_comparable<ValueType> + template<typename ValueType, + std::enable_if_t<Detail::kIsEqualityComparable<ValueType>, int> + = 0> [[nodiscard]] Generator<ValueType> Element(std::initializer_list<ValueType> values) { diff --git a/src/Progmasoft/Catch3/Generators/Integer.hpp b/src/Progmasoft/Catch3/Generators/Integer.hpp index 45192b3d..3659aa4f 100644 --- a/src/Progmasoft/Catch3/Generators/Integer.hpp +++ b/src/Progmasoft/Catch3/Generators/Integer.hpp @@ -2,9 +2,9 @@ // SPDX-License-Identifier: MPL-2.0 WITH AdditionRef-Progmasoft-Exception-1.1 #pragma once +#include <Progmasoft/Catch3/Detail/TypeTraits.hpp> #include <Progmasoft/Catch3/Generator.hpp> #include <algorithm> -#include <concepts> #include <limits> #include <type_traits> @@ -13,8 +13,7 @@ namespace Progmasoft::Catch3 namespace Detail { - template<std::integral IntegerType> - requires(!std::same_as<IntegerType, bool>) + template<typename IntegerType, Detail::EnableIfInteger<IntegerType> = 0> [[nodiscard]] std::vector<IntegerType> ShrinkInteger(IntegerType value, IntegerType minimum, @@ -24,7 +23,9 @@ namespace Progmasoft::Catch3 const auto addCandidate = [&](IntegerType candidate) { if (candidate < minimum || candidate > maximum || candidate == value - || std::ranges::find(candidates, candidate) + || std::find(candidates.begin(), + candidates.end(), + candidate) != candidates.end()) { return; @@ -86,8 +87,7 @@ namespace Progmasoft::Catch3 /// Generates integers over the inclusive range and shrinks toward simple /// values. - template<std::integral IntegerType> - requires(!std::same_as<IntegerType, bool>) + template<typename IntegerType, Detail::EnableIfInteger<IntegerType> = 0> [[nodiscard]] Generator<IntegerType> Integer(IntegerType minimum = std::numeric_limits<IntegerType>::lowest(), IntegerType maximum = std::numeric_limits<IntegerType>::max()) diff --git a/src/Progmasoft/Catch3/Generators/Tuple.hpp b/src/Progmasoft/Catch3/Generators/Tuple.hpp index df58da05..3e889307 100644 --- a/src/Progmasoft/Catch3/Generators/Tuple.hpp +++ b/src/Progmasoft/Catch3/Generators/Tuple.hpp @@ -54,10 +54,11 @@ namespace Progmasoft::Catch3 /// runner's greedy restart this minimizes every component without /// trying the cross product of candidates. template<typename... ValueTypes> - requires(sizeof...(ValueTypes) > 0) [[nodiscard]] Generator<std::tuple<ValueTypes...>> Tuple(Generator<ValueTypes>... generators) { + static_assert(sizeof...(ValueTypes) > 0, + "Tuple requires at least one generator"); using Value = std::tuple<ValueTypes...>; const std::tuple<Generator<ValueTypes>...> components{ std::move( generators)... }; diff --git a/src/Progmasoft/Catch3/Property.hpp b/src/Progmasoft/Catch3/Property.hpp index 1ce97adb..5109fd37 100644 --- a/src/Progmasoft/Catch3/Property.hpp +++ b/src/Progmasoft/Catch3/Property.hpp @@ -2,9 +2,9 @@ // SPDX-License-Identifier: MPL-2.0 WITH AdditionRef-Progmasoft-Exception-1.1 #pragma once +#include <Progmasoft/Catch3/Detail/TypeTraits.hpp> #include <Progmasoft/Catch3/Generator.hpp> #include <Progmasoft/Catch3/ToString.hpp> -#include <concepts> #include <cstddef> #include <cstdint> #include <exception> @@ -304,8 +304,7 @@ namespace Progmasoft::Catch3 [[nodiscard]] std::string StringifyPropertyValue(const ValueType &value) { - return PropertyValuePrinter<std::remove_cvref_t<ValueType>>::Print( - value); + return PropertyValuePrinter<RemoveCvRef<ValueType>>::Print(value); } template<typename Predicate, typename ValueType> @@ -362,11 +361,11 @@ namespace Progmasoft::Catch3 /// Runs independently seeded trials and greedily accepts failing shrink /// candidates. - template<typename ValueType, typename Predicate> - requires std::invocable<Predicate &, const ValueType &> - && std::convertible_to< - std::invoke_result_t<Predicate &, const ValueType &>, - bool> + template<typename ValueType, + typename Predicate, + std::enable_if_t< + std::is_invocable_r_v<bool, Predicate &, const ValueType &>, + int> = 0> [[nodiscard]] PropertyResult CheckProperty(const Generator<ValueType> &generator, Predicate predicate, diff --git a/src/Progmasoft/Catch3/Random.hpp b/src/Progmasoft/Catch3/Random.hpp index a1f1ac94..31e9dd1d 100644 --- a/src/Progmasoft/Catch3/Random.hpp +++ b/src/Progmasoft/Catch3/Random.hpp @@ -3,8 +3,7 @@ #pragma once #include <Progmasoft/Catch3/Detail/InvalidArgument.hpp> -#include <bit> -#include <concepts> +#include <Progmasoft/Catch3/Detail/TypeTraits.hpp> #include <cstdint> #include <limits> #include <stdexcept> @@ -63,8 +62,7 @@ namespace Progmasoft::Catch3 /// Returns an inclusive integral value without overflowing at type /// limits. - template<std::integral IntegerType> - requires(!std::same_as<IntegerType, bool>) + template<typename IntegerType, Detail::EnableIfInteger<IntegerType> = 0> [[nodiscard]] IntegerType Between(IntegerType minimum, IntegerType maximum) { @@ -82,31 +80,15 @@ namespace Progmasoft::Catch3 constexpr UnsignedType kSignBit = UnsignedType{ 1 } << (kBitCount - 1U); - const auto encode - = [](IntegerType value) constexpr -> UnsignedType { - if constexpr (std::is_signed_v<IntegerType>) - { - return std::bit_cast<UnsignedType>(value) ^ kSignBit; - } - else - { - return value; - } - }; - const auto decode - = [](UnsignedType value) constexpr -> IntegerType { - if constexpr (std::is_signed_v<IntegerType>) - { - return std::bit_cast<IntegerType>(value ^ kSignBit); - } - else - { - return value; - } - }; - - const UnsignedType lower = encode(minimum); - const UnsignedType upper = encode(maximum); + // Flipping the sign bit orders signed values as unsigned ones. + const UnsignedType flip + = std::is_signed_v<IntegerType> ? kSignBit : UnsignedType{}; + const auto lower + = static_cast<UnsignedType>(static_cast<UnsignedType>(minimum) + ^ flip); + const auto upper + = static_cast<UnsignedType>(static_cast<UnsignedType>(maximum) + ^ flip); // Unsigned wrap to zero represents the complete value domain. const UnsignedType width = static_cast<UnsignedType>(upper - lower + UnsignedType{ 1 }); @@ -114,7 +96,8 @@ namespace Progmasoft::Catch3 = width == 0 ? static_cast<UnsignedType>(Next()) : static_cast<UnsignedType>( Below(static_cast<std::uint64_t>(width))); - return decode(static_cast<UnsignedType>(lower + offset)); + return static_cast<IntegerType>( + static_cast<UnsignedType>(lower + offset) ^ flip); } /// Derives an independent, reproducible seed for one trial. diff --git a/src/Progmasoft/Catch3/Strategy/ChoiceSource.hpp b/src/Progmasoft/Catch3/Strategy/ChoiceSource.hpp index aaa6c509..126d4420 100644 --- a/src/Progmasoft/Catch3/Strategy/ChoiceSource.hpp +++ b/src/Progmasoft/Catch3/Strategy/ChoiceSource.hpp @@ -6,7 +6,6 @@ #include <cstddef> #include <cstdint> #include <optional> -#include <span> #include <vector> namespace Progmasoft::Catch3 @@ -36,11 +35,12 @@ namespace Progmasoft::Catch3 , size_(size) {} - /// Replay: choices are read from a recorded sequence. - ChoiceSource(std::span<const std::uint64_t> replay, + /// Replay: choices are read from a recorded sequence, which has to + /// outlive this object. + ChoiceSource(const std::vector<std::uint64_t> &replay, std::size_t size) noexcept : random_(0) - , replay_(replay) + , replay_(&replay) , replaying_(true) , size_(size) {} @@ -148,12 +148,12 @@ namespace Progmasoft::Catch3 [[nodiscard]] std::uint64_t ReadReplay(std::uint64_t maximum) noexcept { - if (position_ >= replay_.size()) + if (position_ >= replay_->size()) { overran_ = true; return 0; } - const std::uint64_t value = replay_[position_++]; + const std::uint64_t value = (*replay_)[position_++]; // A shrink may lower a choice that an earlier, changed choice // now bounds more tightly; clamping keeps the replay valid. return value > maximum ? maximum : value; @@ -180,7 +180,7 @@ namespace Progmasoft::Catch3 } Random random_; - std::span<const std::uint64_t> replay_; + const std::vector<std::uint64_t> *replay_ = nullptr; std::size_t position_ = 0; bool replaying_ = false; bool overran_ = false; diff --git a/src/Progmasoft/Catch3/Strategy/Containers.hpp b/src/Progmasoft/Catch3/Strategy/Containers.hpp index ad4daf39..e0b95cd0 100644 --- a/src/Progmasoft/Catch3/Strategy/Containers.hpp +++ b/src/Progmasoft/Catch3/Strategy/Containers.hpp @@ -132,7 +132,7 @@ namespace Progmasoft::Catch3 /// Vectors whose elements are distinct under key. A duplicate is /// drawn again up to maximumRetries times before the trial gives /// up. - template<typename ElementType, typename Key = std::identity> + template<typename ElementType, typename Key = Detail::Identity> [[nodiscard]] Strategy<std::vector<ElementType>> UniqueVectors(Strategy<ElementType> element, SizeRange range = {}, @@ -210,7 +210,7 @@ namespace Progmasoft::Catch3 { return false; } - if (result.contains(*drawnKey)) + if (result.find(*drawnKey) != result.end()) { continue; } diff --git a/src/Progmasoft/Catch3/Strategy/Engine.hpp b/src/Progmasoft/Catch3/Strategy/Engine.hpp index fbe8d340..79690963 100644 --- a/src/Progmasoft/Catch3/Strategy/Engine.hpp +++ b/src/Progmasoft/Catch3/Strategy/Engine.hpp @@ -9,7 +9,6 @@ #include <cstdint> #include <functional> #include <optional> -#include <span> #include <string> #include <string_view> #include <vector> @@ -52,7 +51,7 @@ namespace Progmasoft::Catch3::Detail /// A replay token: the size of the trial and its choices. [[nodiscard]] std::string - EncodeChoices(std::size_t size, std::span<const std::uint64_t> choices); + EncodeChoices(std::size_t size, const std::vector<std::uint64_t> &choices); struct DecodedChoices final { @@ -79,7 +78,7 @@ namespace Progmasoft::Catch3::Detail /// Shortlex order: shorter first, then lexicographically smaller. [[nodiscard]] bool - IsSimpler(std::span<const std::uint64_t> candidate, - std::span<const std::uint64_t> current) noexcept; + IsSimpler(const std::vector<std::uint64_t> &candidate, + const std::vector<std::uint64_t> ¤t) noexcept; } // namespace Progmasoft::Catch3::Detail diff --git a/src/Progmasoft/Catch3/Strategy/Numeric.hpp b/src/Progmasoft/Catch3/Strategy/Numeric.hpp index 8f58b06d..80c4174e 100644 --- a/src/Progmasoft/Catch3/Strategy/Numeric.hpp +++ b/src/Progmasoft/Catch3/Strategy/Numeric.hpp @@ -4,10 +4,9 @@ #include <Progmasoft/Catch3/Strategy/Strategy.hpp> #include <array> -#include <bit> #include <cmath> -#include <concepts> #include <cstdint> +#include <cstring> #include <limits> #include <optional> #include <type_traits> @@ -34,8 +33,8 @@ namespace Progmasoft::Catch3::Gen /// Integers in [minimum, maximum]. They shrink towards the value of the /// range closest to zero; generation favours small magnitudes, zero and /// the bounds, scaled by the trial size. - template<std::integral IntegerType> - requires(!std::same_as<IntegerType, bool>) + template<typename IntegerType, + Catch3::Detail::EnableIfInteger<IntegerType> = 0> [[nodiscard]] Strategy<IntegerType> Integers(IntegerType minimum = std::numeric_limits<IntegerType>::lowest(), IntegerType maximum = std::numeric_limits<IntegerType>::max()) @@ -105,7 +104,8 @@ namespace Progmasoft::Catch3::Gen /// Generation mixes integral values, short binary fractions, uniform /// values of the range, arbitrary bit patterns, and edge values such as /// the smallest subnormal and the largest finite value. - template<std::floating_point FloatType> + template<typename FloatType, + std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0> [[nodiscard]] Strategy<FloatType> Floats(FloatOptions options = {}) { @@ -204,7 +204,9 @@ namespace Progmasoft::Catch3::Gen { // Any bit pattern; non-finite patterns fall back. const auto bits = source.Draw(UINT64_MAX); - const double value = std::bit_cast<double>(bits); + static_assert(sizeof(double) == sizeof(bits)); + double value{}; + std::memcpy(&value, &bits, sizeof(value)); return finish(std::isfinite(value) ? value : anchor); } default: diff --git a/src/Progmasoft/Catch3/Strategy/Strategy.hpp b/src/Progmasoft/Catch3/Strategy/Strategy.hpp index 5eb06d6f..77f24b82 100644 --- a/src/Progmasoft/Catch3/Strategy/Strategy.hpp +++ b/src/Progmasoft/Catch3/Strategy/Strategy.hpp @@ -3,9 +3,9 @@ #pragma once #include <Progmasoft/Catch3/Detail/InvalidArgument.hpp> +#include <Progmasoft/Catch3/Detail/TypeTraits.hpp> #include <Progmasoft/Catch3/Strategy/ChoiceSource.hpp> #include <algorithm> -#include <concepts> #include <cstddef> #include <cstdint> #include <functional> @@ -58,7 +58,7 @@ namespace Progmasoft::Catch3 [[nodiscard]] auto Map(Transform transform) const { - using Result = std::remove_cvref_t< + using Result = Catch3::Detail::RemoveCvRef< std::invoke_result_t<Transform &, ValueType>>; Strategy self = *this; return Strategy<Result>( @@ -114,8 +114,8 @@ namespace Progmasoft::Catch3 [[nodiscard]] auto FlatMap(Bind bind) const { - using Next - = std::remove_cvref_t<std::invoke_result_t<Bind &, ValueType>>; + using Next = Catch3::Detail::RemoveCvRef< + std::invoke_result_t<Bind &, ValueType>>; using Result = typename Next::Value; Strategy self = *this; return Strategy<Result>( @@ -136,17 +136,18 @@ namespace Progmasoft::Catch3 /// The value type of a strategy. template<typename StrategyType> - using StrategyValue = typename std::remove_cvref_t<StrategyType>::Value; + using StrategyValue = + typename Catch3::Detail::RemoveCvRef<StrategyType>::Value; namespace Gen { /// Always the same value; draws no choice. template<typename ValueType> - [[nodiscard]] Strategy<std::remove_cvref_t<ValueType>> + [[nodiscard]] Strategy<Catch3::Detail::RemoveCvRef<ValueType>> Just(ValueType value) { - using Result = std::remove_cvref_t<ValueType>; + using Result = Catch3::Detail::RemoveCvRef<ValueType>; return Strategy<Result>( [value = Result(std::move(value))](ChoiceSource &) -> std::optional<Result> { return value; }); @@ -172,9 +173,12 @@ namespace Progmasoft::Catch3 }); } - template<typename First, typename... Rest> - requires(std::same_as<StrategyValue<First>, StrategyValue<Rest>> - && ...) + template<typename First, + typename... Rest, + std::enable_if_t< + (std::is_same_v<StrategyValue<First>, StrategyValue<Rest>> + && ...), + int> = 0> [[nodiscard]] Strategy<StrategyValue<First>> OneOf(First first, Rest... rest) { @@ -249,7 +253,8 @@ namespace Progmasoft::Catch3 [[nodiscard]] auto Lazy(Factory factory) { - using Result = std::remove_cvref_t<std::invoke_result_t<Factory &>>; + using Result + = Catch3::Detail::RemoveCvRef<std::invoke_result_t<Factory &>>; using ValueType = typename Result::Value; return Strategy<ValueType>( [factory]( diff --git a/src/Progmasoft/Catch3/meson.build b/src/Progmasoft/Catch3/meson.build index 70bf336d..b8d38908 100644 --- a/src/Progmasoft/Catch3/meson.build +++ b/src/Progmasoft/Catch3/meson.build @@ -354,7 +354,7 @@ catch3 = static_library( sources, dependencies: catch3_dependencies, include_directories: '../..', - override_options: ['cpp_std=c++20'], + override_options: ['cpp_std=c++17'], install: get_option('install'), ) diff --git a/src/Progmasoft/ChoiceShrinker.cpp b/src/Progmasoft/ChoiceShrinker.cpp index c1aac19c..b9b5a47d 100644 --- a/src/Progmasoft/ChoiceShrinker.cpp +++ b/src/Progmasoft/ChoiceShrinker.cpp @@ -14,8 +14,8 @@ namespace Progmasoft::Catch3::Detail { bool - IsSimpler(std::span<const std::uint64_t> candidate, - std::span<const std::uint64_t> current) noexcept + IsSimpler(const std::vector<std::uint64_t> &candidate, + const std::vector<std::uint64_t> ¤t) noexcept { if (candidate.size() != current.size()) { @@ -299,7 +299,7 @@ namespace Progmasoft::Catch3::Detail } std::string - EncodeChoices(std::size_t size, std::span<const std::uint64_t> choices) + EncodeChoices(std::size_t size, const std::vector<std::uint64_t> &choices) { // c3.<size>.<choice>-<choice>-... with each number in base 36: short // enough to paste from a CI log, and only characters that survive @@ -329,7 +329,7 @@ namespace Progmasoft::Catch3::Detail std::optional<DecodedChoices> DecodeChoices(std::string_view token) { - if (!token.starts_with(kTokenPrefix)) + if (token.substr(0, kTokenPrefix.size()) != kTokenPrefix) { return std::nullopt; } diff --git a/src/Progmasoft/PropertyEngine.cpp b/src/Progmasoft/PropertyEngine.cpp index 571a5ac3..7151dd1a 100644 --- a/src/Progmasoft/PropertyEngine.cpp +++ b/src/Progmasoft/PropertyEngine.cpp @@ -231,7 +231,7 @@ namespace Progmasoft::Catch3::Detail std::size_t size, bool describe) { - return Execute(ChoiceSource(std::span(choices), size), describe); + return Execute(ChoiceSource(choices, size), describe); } static PropertyResult @@ -302,10 +302,16 @@ namespace Progmasoft::Catch3::Detail // Only the examples checked here are dropped; another // process may have stored new ones meanwhile. database_.Update([&](std::vector<std::string> &stored) { - std::erase_if(stored, [&](const std::string &token) { - return std::find(tokens.begin(), tokens.end(), token) - != tokens.end(); - }); + const auto removed = std::remove_if( + stored.begin(), + stored.end(), + [&](const std::string &token) { + return std::find(tokens.begin(), + tokens.end(), + token) + != tokens.end(); + }); + stored.erase(removed, stored.end()); |