Skip to content

Commit

Permalink
Merge pull request #125 from tcbrindle/pr/safe_numerics
Browse files Browse the repository at this point in the history
Safe numerics
  • Loading branch information
tcbrindle authored Aug 30, 2024
2 parents 2e5ce71 + 5ad5023 commit 7987aa7
Show file tree
Hide file tree
Showing 39 changed files with 3,579 additions and 424 deletions.
31 changes: 30 additions & 1 deletion include/flux/core/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
#define FLUX_DIVIDE_BY_ZERO_POLICY_ERROR 100
#define FLUX_DIVIDE_BY_ZERO_POLICY_IGNORE 101

#define FLUX_INTEGER_CAST_POLICY_CHECKED 1001
#define FLUX_INTEGER_CAST_POLICY_UNCHECKED 1002

// Default error policy is terminate
#define FLUX_DEFAULT_ERROR_POLICY FLUX_ERROR_POLICY_TERMINATE

Expand All @@ -48,6 +51,13 @@
# define FLUX_ERROR_POLICY FLUX_DEFAULT_ERROR_POLICY
#endif // FLUX_TERMINATE_ON_ERROR

// Default integer cast policy is checked in debug builds, unchecked in release builds
#ifdef NDEBUG
# define FLUX_DEFAULT_INTEGER_CAST_POLICY FLUX_INTEGER_CAST_POLICY_UNCHECKED
#else
# define FLUX_DEFAULT_INTEGER_CAST_POLICY FLUX_INTEGER_CAST_POLICY_CHECKED
#endif // NDEBUG

// Should we print an error message before terminating?
#ifndef FLUX_PRINT_ERROR_ON_TERMINATE
# define FLUX_PRINT_ERROR_ON_TERMINATE 1
Expand All @@ -73,7 +83,7 @@
# define FLUX_OVERFLOW_POLICY FLUX_DEFAULT_OVERFLOW_POLICY
#endif // FLUX_ERROR_ON_OVERFLOW

// Select which overflow policy to use
// Select which divide by zero policy to use
#if defined(FLUX_ERROR_ON_DIVIDE_BY_ZERO)
# define FLUX_DIVIDE_BY_ZERO_POLICY FLUX_DIVIDE_BY_ZERO_POLICY_ERROR
#elif defined(FLUX_IGNORE_DIVIDE_BY_ZERO)
Expand All @@ -82,6 +92,15 @@
# define FLUX_DIVIDE_BY_ZERO_POLICY FLUX_DEFAULT_DIVIDE_BY_ZERO_POLICY
#endif // FLUX_ERROR_ON_DIVIDE_BY_ZERO

// Select which integer cast policy to use
#if defined(FLUX_CHECKED_INTEGER_CASTS)
# define FLUX_INTEGER_CAST_POLICY FLUX_INTEGER_CAST_POLICY_CHECKED
#elif defined(FLUX_UNCHECKED_INTEGER_CASTS)
# define FLUX_INTEGER_CAST_POLICY FLUX_INTEGER_CAST_POLICY_UNCHECKED
#else
# define FLUX_INTEGER_CAST_POLICY FLUX_DEFAULT_INTEGER_CAST_POLICY
#endif

// Should we try to use static bounds checking?
#if !defined(FLUX_DISABLE_STATIC_BOUNDS_CHECKING)
# if defined(__has_cpp_attribute) && defined(__has_builtin)
Expand Down Expand Up @@ -114,11 +133,18 @@ enum class overflow_policy {
error = FLUX_OVERFLOW_POLICY_ERROR
};

FLUX_EXPORT
enum class divide_by_zero_policy {
ignore = FLUX_DIVIDE_BY_ZERO_POLICY_IGNORE,
error = FLUX_DIVIDE_BY_ZERO_POLICY_ERROR
};

FLUX_EXPORT
enum class integer_cast_policy {
checked = FLUX_INTEGER_CAST_POLICY_CHECKED,
unchecked = FLUX_INTEGER_CAST_POLICY_UNCHECKED
};

namespace config {

FLUX_EXPORT
Expand All @@ -135,6 +161,9 @@ inline constexpr overflow_policy on_overflow = static_cast<overflow_policy>(FLUX
FLUX_EXPORT
inline constexpr divide_by_zero_policy on_divide_by_zero = static_cast<divide_by_zero_policy>(FLUX_DIVIDE_BY_ZERO_POLICY);

FLUX_EXPORT
inline constexpr integer_cast_policy on_integer_cast = static_cast<integer_cast_policy>(FLUX_INTEGER_CAST_POLICY);

FLUX_EXPORT
inline constexpr bool print_error_on_terminate = FLUX_PRINT_ERROR_ON_TERMINATE;

Expand Down
28 changes: 14 additions & 14 deletions include/flux/core/default_impls.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,27 @@ struct sequence_traits<T[N]> : default_sequence_traits {
static constexpr auto inc(auto const&, index_t& idx)
{
FLUX_DEBUG_ASSERT(idx < N);
idx = num::checked_add(idx, distance_t{1});
idx = num::add(idx, distance_t{1});
}

static constexpr auto last(auto const&) -> index_t { return N; }

static constexpr auto dec(auto const&, index_t& idx)
{
FLUX_DEBUG_ASSERT(idx > 0);
idx = num::checked_sub(idx, distance_t{1});
idx = num::sub(idx, distance_t{1});
}

static constexpr auto inc(auto const&, index_t& idx, distance_t offset)
{
FLUX_DEBUG_ASSERT(num::checked_add(idx, offset) <= N);
FLUX_DEBUG_ASSERT(num::checked_add(idx, offset) >= 0);
idx = num::checked_add(idx, offset);
FLUX_DEBUG_ASSERT(num::add(idx, offset) <= N);
FLUX_DEBUG_ASSERT(num::add(idx, offset) >= 0);
idx = num::add(idx, offset);
}

static constexpr auto distance(auto const&, index_t from, index_t to) -> distance_t
{
return num::checked_sub(to, from);
return num::sub(to, from);
}

static constexpr auto data(auto& self) -> auto* { return self; }
Expand Down Expand Up @@ -186,7 +186,7 @@ struct sequence_traits<R> : default_sequence_traits {
static constexpr auto inc(auto& self, index_t& idx)
{
FLUX_DEBUG_ASSERT(idx < size(self));
idx = num::checked_add(idx, distance_t{1});
idx = num::add(idx, distance_t{1});
}

static constexpr auto read_at(auto& self, index_t idx) -> decltype(auto)
Expand All @@ -203,26 +203,26 @@ struct sequence_traits<R> : default_sequence_traits {
static constexpr auto dec(auto&, index_t& idx)
{
FLUX_DEBUG_ASSERT(idx > 0);
idx = num::checked_sub(idx, distance_t{1});
idx = num::sub(idx, distance_t{1});
}

static constexpr auto last(auto& self) -> index_t { return size(self); }

static constexpr auto inc(auto& self, index_t& idx, distance_t offset)
{
FLUX_DEBUG_ASSERT(num::checked_add(idx, offset) <= size(self));
FLUX_DEBUG_ASSERT(num::checked_add(idx, offset) >= 0);
idx = num::checked_add(idx, offset);
FLUX_DEBUG_ASSERT(num::add(idx, offset) <= size(self));
FLUX_DEBUG_ASSERT(num::add(idx, offset) >= 0);
idx = num::add(idx, offset);
}

static constexpr auto distance(auto&, index_t from, index_t to) -> distance_t
{
return num::checked_sub(to, from);
return num::sub(to, from);
}

static constexpr auto size(auto& self) -> distance_t
{
return checked_cast<distance_t>(std::ranges::ssize(self));
return num::cast<distance_t>(std::ranges::ssize(self));
}

static constexpr auto data(auto& self) -> auto*
Expand All @@ -242,7 +242,7 @@ struct sequence_traits<R> : default_sequence_traits {
++iter;
}

return checked_cast<index_t>(iter - std::ranges::begin(self));
return num::cast<index_t>(iter - std::ranges::begin(self));
}
};

Expand Down
12 changes: 6 additions & 6 deletions include/flux/core/inline_sequence_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ struct inline_sequence_base {
(multipass_sequence<Derived> && not infinite_sequence<Derived>);

[[nodiscard]]
constexpr auto chunk(std::integral auto chunk_sz) &&;
constexpr auto chunk(num::integral auto chunk_sz) &&;

template <typename Pred>
requires multipass_sequence<Derived> &&
Expand All @@ -251,15 +251,15 @@ struct inline_sequence_base {
requires infinite_sequence<Derived> || multipass_sequence<Derived>;

[[nodiscard]]
constexpr auto cycle(std::integral auto count) && requires multipass_sequence<Derived>;
constexpr auto cycle(num::integral auto count) && requires multipass_sequence<Derived>;

[[nodiscard]]
constexpr auto dedup() &&
requires multipass_sequence<Derived> &&
std::equality_comparable<element_t<Derived>>;

[[nodiscard]]
constexpr auto drop(std::integral auto count) &&;
constexpr auto drop(num::integral auto count) &&;

template <typename Pred>
requires std::predicate<Pred&, element_t<Derived>>
Expand Down Expand Up @@ -338,7 +338,7 @@ struct inline_sequence_base {
constexpr auto scan_first(Func func) &&;

[[nodiscard]]
constexpr auto slide(std::integral auto win_sz) && requires multipass_sequence<Derived>;
constexpr auto slide(num::integral auto win_sz) && requires multipass_sequence<Derived>;

template <typename Pattern>
requires multipass_sequence<Derived> &&
Expand All @@ -364,10 +364,10 @@ struct inline_sequence_base {
constexpr auto split_string(Pattern&& pattern) &&;

[[nodiscard]]
constexpr auto stride(std::integral auto by) &&;
constexpr auto stride(num::integral auto by) &&;

[[nodiscard]]
constexpr auto take(std::integral auto count) &&;
constexpr auto take(num::integral auto count) &&;

template <typename Pred>
requires std::predicate<Pred&, element_t<Derived>>
Expand Down
Loading

0 comments on commit 7987aa7

Please sign in to comment.