Skip to content

Commit 7987aa7

Browse files
authored
Merge pull request #125 from tcbrindle/pr/safe_numerics
Safe numerics
2 parents 2e5ce71 + 5ad5023 commit 7987aa7

39 files changed

+3579
-424
lines changed

include/flux/core/config.hpp

+30-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#define FLUX_DIVIDE_BY_ZERO_POLICY_ERROR 100
2323
#define FLUX_DIVIDE_BY_ZERO_POLICY_IGNORE 101
2424

25+
#define FLUX_INTEGER_CAST_POLICY_CHECKED 1001
26+
#define FLUX_INTEGER_CAST_POLICY_UNCHECKED 1002
27+
2528
// Default error policy is terminate
2629
#define FLUX_DEFAULT_ERROR_POLICY FLUX_ERROR_POLICY_TERMINATE
2730

@@ -48,6 +51,13 @@
4851
# define FLUX_ERROR_POLICY FLUX_DEFAULT_ERROR_POLICY
4952
#endif // FLUX_TERMINATE_ON_ERROR
5053

54+
// Default integer cast policy is checked in debug builds, unchecked in release builds
55+
#ifdef NDEBUG
56+
# define FLUX_DEFAULT_INTEGER_CAST_POLICY FLUX_INTEGER_CAST_POLICY_UNCHECKED
57+
#else
58+
# define FLUX_DEFAULT_INTEGER_CAST_POLICY FLUX_INTEGER_CAST_POLICY_CHECKED
59+
#endif // NDEBUG
60+
5161
// Should we print an error message before terminating?
5262
#ifndef FLUX_PRINT_ERROR_ON_TERMINATE
5363
# define FLUX_PRINT_ERROR_ON_TERMINATE 1
@@ -73,7 +83,7 @@
7383
# define FLUX_OVERFLOW_POLICY FLUX_DEFAULT_OVERFLOW_POLICY
7484
#endif // FLUX_ERROR_ON_OVERFLOW
7585

76-
// Select which overflow policy to use
86+
// Select which divide by zero policy to use
7787
#if defined(FLUX_ERROR_ON_DIVIDE_BY_ZERO)
7888
# define FLUX_DIVIDE_BY_ZERO_POLICY FLUX_DIVIDE_BY_ZERO_POLICY_ERROR
7989
#elif defined(FLUX_IGNORE_DIVIDE_BY_ZERO)
@@ -82,6 +92,15 @@
8292
# define FLUX_DIVIDE_BY_ZERO_POLICY FLUX_DEFAULT_DIVIDE_BY_ZERO_POLICY
8393
#endif // FLUX_ERROR_ON_DIVIDE_BY_ZERO
8494

95+
// Select which integer cast policy to use
96+
#if defined(FLUX_CHECKED_INTEGER_CASTS)
97+
# define FLUX_INTEGER_CAST_POLICY FLUX_INTEGER_CAST_POLICY_CHECKED
98+
#elif defined(FLUX_UNCHECKED_INTEGER_CASTS)
99+
# define FLUX_INTEGER_CAST_POLICY FLUX_INTEGER_CAST_POLICY_UNCHECKED
100+
#else
101+
# define FLUX_INTEGER_CAST_POLICY FLUX_DEFAULT_INTEGER_CAST_POLICY
102+
#endif
103+
85104
// Should we try to use static bounds checking?
86105
#if !defined(FLUX_DISABLE_STATIC_BOUNDS_CHECKING)
87106
# if defined(__has_cpp_attribute) && defined(__has_builtin)
@@ -114,11 +133,18 @@ enum class overflow_policy {
114133
error = FLUX_OVERFLOW_POLICY_ERROR
115134
};
116135

136+
FLUX_EXPORT
117137
enum class divide_by_zero_policy {
118138
ignore = FLUX_DIVIDE_BY_ZERO_POLICY_IGNORE,
119139
error = FLUX_DIVIDE_BY_ZERO_POLICY_ERROR
120140
};
121141

142+
FLUX_EXPORT
143+
enum class integer_cast_policy {
144+
checked = FLUX_INTEGER_CAST_POLICY_CHECKED,
145+
unchecked = FLUX_INTEGER_CAST_POLICY_UNCHECKED
146+
};
147+
122148
namespace config {
123149

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

164+
FLUX_EXPORT
165+
inline constexpr integer_cast_policy on_integer_cast = static_cast<integer_cast_policy>(FLUX_INTEGER_CAST_POLICY);
166+
138167
FLUX_EXPORT
139168
inline constexpr bool print_error_on_terminate = FLUX_PRINT_ERROR_ON_TERMINATE;
140169

include/flux/core/default_impls.hpp

+14-14
Original file line numberDiff line numberDiff line change
@@ -38,27 +38,27 @@ struct sequence_traits<T[N]> : default_sequence_traits {
3838
static constexpr auto inc(auto const&, index_t& idx)
3939
{
4040
FLUX_DEBUG_ASSERT(idx < N);
41-
idx = num::checked_add(idx, distance_t{1});
41+
idx = num::add(idx, distance_t{1});
4242
}
4343

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

4646
static constexpr auto dec(auto const&, index_t& idx)
4747
{
4848
FLUX_DEBUG_ASSERT(idx > 0);
49-
idx = num::checked_sub(idx, distance_t{1});
49+
idx = num::sub(idx, distance_t{1});
5050
}
5151

5252
static constexpr auto inc(auto const&, index_t& idx, distance_t offset)
5353
{
54-
FLUX_DEBUG_ASSERT(num::checked_add(idx, offset) <= N);
55-
FLUX_DEBUG_ASSERT(num::checked_add(idx, offset) >= 0);
56-
idx = num::checked_add(idx, offset);
54+
FLUX_DEBUG_ASSERT(num::add(idx, offset) <= N);
55+
FLUX_DEBUG_ASSERT(num::add(idx, offset) >= 0);
56+
idx = num::add(idx, offset);
5757
}
5858

5959
static constexpr auto distance(auto const&, index_t from, index_t to) -> distance_t
6060
{
61-
return num::checked_sub(to, from);
61+
return num::sub(to, from);
6262
}
6363

6464
static constexpr auto data(auto& self) -> auto* { return self; }
@@ -186,7 +186,7 @@ struct sequence_traits<R> : default_sequence_traits {
186186
static constexpr auto inc(auto& self, index_t& idx)
187187
{
188188
FLUX_DEBUG_ASSERT(idx < size(self));
189-
idx = num::checked_add(idx, distance_t{1});
189+
idx = num::add(idx, distance_t{1});
190190
}
191191

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

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

211211
static constexpr auto inc(auto& self, index_t& idx, distance_t offset)
212212
{
213-
FLUX_DEBUG_ASSERT(num::checked_add(idx, offset) <= size(self));
214-
FLUX_DEBUG_ASSERT(num::checked_add(idx, offset) >= 0);
215-
idx = num::checked_add(idx, offset);
213+
FLUX_DEBUG_ASSERT(num::add(idx, offset) <= size(self));
214+
FLUX_DEBUG_ASSERT(num::add(idx, offset) >= 0);
215+
idx = num::add(idx, offset);
216216
}
217217

218218
static constexpr auto distance(auto&, index_t from, index_t to) -> distance_t
219219
{
220-
return num::checked_sub(to, from);
220+
return num::sub(to, from);
221221
}
222222

223223
static constexpr auto size(auto& self) -> distance_t
224224
{
225-
return checked_cast<distance_t>(std::ranges::ssize(self));
225+
return num::cast<distance_t>(std::ranges::ssize(self));
226226
}
227227

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

245-
return checked_cast<index_t>(iter - std::ranges::begin(self));
245+
return num::cast<index_t>(iter - std::ranges::begin(self));
246246
}
247247
};
248248

include/flux/core/inline_sequence_base.hpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ struct inline_sequence_base {
235235
(multipass_sequence<Derived> && not infinite_sequence<Derived>);
236236

237237
[[nodiscard]]
238-
constexpr auto chunk(std::integral auto chunk_sz) &&;
238+
constexpr auto chunk(num::integral auto chunk_sz) &&;
239239

240240
template <typename Pred>
241241
requires multipass_sequence<Derived> &&
@@ -251,15 +251,15 @@ struct inline_sequence_base {
251251
requires infinite_sequence<Derived> || multipass_sequence<Derived>;
252252

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

256256
[[nodiscard]]
257257
constexpr auto dedup() &&
258258
requires multipass_sequence<Derived> &&
259259
std::equality_comparable<element_t<Derived>>;
260260

261261
[[nodiscard]]
262-
constexpr auto drop(std::integral auto count) &&;
262+
constexpr auto drop(num::integral auto count) &&;
263263

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

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

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

366366
[[nodiscard]]
367-
constexpr auto stride(std::integral auto by) &&;
367+
constexpr auto stride(num::integral auto by) &&;
368368

369369
[[nodiscard]]
370-
constexpr auto take(std::integral auto count) &&;
370+
constexpr auto take(num::integral auto count) &&;
371371

372372
template <typename Pred>
373373
requires std::predicate<Pred&, element_t<Derived>>

0 commit comments

Comments
 (0)