diff --git a/files.cmake b/files.cmake index c8c92c9b75..51b2bdf95e 100644 --- a/files.cmake +++ b/files.cmake @@ -1581,6 +1581,7 @@ set(DUSK_FILES src/helpers/endian.cpp src/helpers/offset_ptr.cpp src/helpers/string.cpp + src/helpers/cast.cpp ) set(DUSK_HTTP_BACKEND_FILES diff --git a/include/helpers/cast.hpp b/include/helpers/cast.hpp new file mode 100644 index 0000000000..206bc1e3f3 --- /dev/null +++ b/include/helpers/cast.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include + +/** + * Helper functions for performing casts. + */ +namespace dusk::helpers::cast { + /** + * Implementation details of dusk::helpers::cast. + */ + namespace _impl { + [[noreturn]] void overrun_high(); + [[noreturn]] void overrun_low(); + } + + template + concept IntCastable = std::is_integral_v && std::is_trivially_copyable_v; + + /** + * Helper type that allows easily casting between integer types, + * that safely aborts if an overflow were to occur. + * Usage: + * @code + * size_t foobar = 20; + * int real = bounded_cast(foobar); + * @endcode + */ + template + struct bounded_cast { + Source src; + + template + [[nodiscard]] constexpr operator Target() const { + if (std::cmp_greater(src, std::numeric_limits::max())) [[unlikely]] { + _impl::overrun_high(); + } + + if (std::cmp_less(src, std::numeric_limits::min())) [[unlikely]] { + _impl::overrun_low(); + } + + return static_cast(src); + } + }; +} diff --git a/src/helpers/cast.cpp b/src/helpers/cast.cpp new file mode 100644 index 0000000000..71eb3160de --- /dev/null +++ b/src/helpers/cast.cpp @@ -0,0 +1,14 @@ +#include "helpers/cast.hpp" +#include "global.h" + +namespace dusk::helpers::cast::_impl { + +void overrun_high() { + CRASH("bounded cast overran!"); +} + +void overrun_low() { + CRASH("bounded cast overran!"); +} + +} // namespace dusk::helpers::cast::_impl