Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorLeitwolf112026-10-31 13:00:24 +0300
committerLeitwolf112026-10-31 13:00:24 +0300
commit8814bd0b796b2e291fa5b4a1033f0313c8a26065 (patch)
treee87e5f5150f3712bb05ed53911425600aa871f45 /src
parent6a42cdf6461b2577106ef094d6f98025554b6077 (diff)
downloadcatch3-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')
-rw-r--r--src/CMakeLists.txt5
-rw-r--r--src/Progmasoft/BUILD.bazel15
-rw-r--r--src/Progmasoft/Catch3/Detail/TypeTraits.hpp47
-rw-r--r--src/Progmasoft/Catch3/ForAll.hpp38
-rw-r--r--src/Progmasoft/Catch3/Generators/Element.hpp12
-rw-r--r--src/Progmasoft/Catch3/Generators/Integer.hpp12
-rw-r--r--src/Progmasoft/Catch3/Generators/Tuple.hpp3
-rw-r--r--src/Progmasoft/Catch3/Property.hpp15
-rw-r--r--src/Progmasoft/Catch3/Random.hpp43
-rw-r--r--src/Progmasoft/Catch3/Strategy/ChoiceSource.hpp14
-rw-r--r--src/Progmasoft/Catch3/Strategy/Containers.hpp4
-rw-r--r--src/Progmasoft/Catch3/Strategy/Engine.hpp7
-rw-r--r--src/Progmasoft/Catch3/Strategy/Numeric.hpp14
-rw-r--r--src/Progmasoft/Catch3/Strategy/Strategy.hpp27
-rw-r--r--src/Progmasoft/Catch3/meson.build2
-rw-r--r--src/Progmasoft/ChoiceShrinker.cpp8
-rw-r--r--src/Progmasoft/PropertyEngine.cpp16
-rw-r--r--src/Progmasoft/Runner/Process.cpp42
-rw-r--r--src/Progmasoft/meson.build1
19 files changed, 196 insertions, 129 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f3b7812d..398260fd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -398,8 +398,7 @@ set_target_properties(Catch3 PROPERTIES
# Code that includes the engine's headers needs C++14, and the other
# Progmasoft/ headers C++20; the library itself, with the runner, is built as C++20.
-target_compile_features(Catch3 PUBLIC cxx_std_14)
-set_target_properties(Catch3 PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON)
+target_compile_features(Catch3 PUBLIC cxx_std_17)
configure_file(
"${SOURCES_DIR}/UserConfig.hpp.in"
@@ -491,7 +490,7 @@ if(CATCH3_BUILD_EXAMPLES OR CATCH3_BUILD_EXTRA_TESTS)
)
# These targets compile the library's sources themselves, the runner's
# among them, which need C++20.
- target_compile_features(Catch3_buildall_interface INTERFACE cxx_std_20)
+ target_compile_features(Catch3_buildall_interface INTERFACE cxx_std_17)
endif()
list(APPEND CATCH_IMPL_TARGETS Catch3 Catch3WithMain)
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> &current) 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> &current) 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