From 26dedb603f887d82613eb68d7660609731427d83 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Sun, 25 Jun 2023 17:50:17 -0600 Subject: [PATCH] common: move numeric_cast to dedicated common/numeric_cast.hh --- common/bspfile.cc | 1 + common/bspfile_q1.cc | 1 + common/bspfile_q2.cc | 1 + include/common/bspfile.hh | 42 ----------- include/common/cmdlib.hh | 67 ----------------- include/common/numeric_cast.hh | 132 +++++++++++++++++++++++++++++++++ light/light.cc | 1 + 7 files changed, 136 insertions(+), 109 deletions(-) create mode 100644 include/common/numeric_cast.hh diff --git a/common/bspfile.cc b/common/bspfile.cc index ed79ba97..b710eec9 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/common/bspfile_q1.cc b/common/bspfile_q1.cc index ebf6dbe4..14e40f83 100644 --- a/common/bspfile_q1.cc +++ b/common/bspfile_q1.cc @@ -19,6 +19,7 @@ #include #include +#include // dheader_t diff --git a/common/bspfile_q2.cc b/common/bspfile_q2.cc index 4ab1240a..a49816bd 100644 --- a/common/bspfile_q2.cc +++ b/common/bspfile_q2.cc @@ -19,6 +19,7 @@ #include #include +#include // q2_dheader_t diff --git a/include/common/bspfile.hh b/include/common/bspfile.hh index aaf9c88c..cd72b437 100644 --- a/include/common/bspfile.hh +++ b/include/common/bspfile.hh @@ -47,48 +47,6 @@ struct lump_t void stream_read(std::istream &s); }; -// helper functions to quickly numerically cast mins/maxs -// and floor/ceil them in the case of float -> integral -template -inline qvec aabb_mins_cast(const qvec &f, const char *overflow_message = "mins") -{ - if constexpr (std::is_floating_point_v && !std::is_floating_point_v) - return {numeric_cast(floor(f[0]), overflow_message), numeric_cast(floor(f[1]), overflow_message), - numeric_cast(floor(f[2]), overflow_message)}; - else - return {numeric_cast(f[0], overflow_message), numeric_cast(f[1], overflow_message), - numeric_cast(f[2], overflow_message)}; -} - -template -inline qvec aabb_maxs_cast(const qvec &f, const char *overflow_message = "maxs") -{ - if constexpr (std::is_floating_point_v && !std::is_floating_point_v) - return {numeric_cast(ceil(f[0]), overflow_message), numeric_cast(ceil(f[1]), overflow_message), - numeric_cast(ceil(f[2]), overflow_message)}; - else - return {numeric_cast(f[0], overflow_message), numeric_cast(f[1], overflow_message), - numeric_cast(f[2], overflow_message)}; -} - -// shortcut template to trim (& convert) std::arrays -// between two lengths -template -constexpr ADest array_cast(const ASrc &src, const char *overflow_message = "src") -{ - ADest dest{}; - - for (size_t i = 0; i < std::min(dest.size(), src.size()); i++) { - if constexpr (std::is_arithmetic_v && - std::is_arithmetic_v) - dest[i] = numeric_cast(src[i], overflow_message); - else - dest[i] = static_cast(src[i]); - } - - return dest; -} - struct gamedef_t; struct contentflags_t diff --git a/include/common/cmdlib.hh b/include/common/cmdlib.hh index 1076e343..75569d5d 100644 --- a/include/common/cmdlib.hh +++ b/include/common/cmdlib.hh @@ -490,73 +490,6 @@ inline std::enable_if_t, std::istream &> operator>=(std::istre return s; } -template -constexpr bool numeric_cast_will_overflow(const Src &value) -{ - using DstLim = std::numeric_limits; - using SrcLim = std::numeric_limits; - - constexpr bool positive_overflow_possible = DstLim::max() < SrcLim::max(); - constexpr bool negative_overflow_possible = SrcLim::is_signed || (DstLim::lowest() > SrcLim::lowest()); - - // unsigned <-- unsigned - if constexpr ((!DstLim::is_signed) && (!SrcLim::is_signed)) { - if constexpr (positive_overflow_possible) { - if (value > DstLim::max()) { - return true; - } - } - } - // unsigned <-- signed - else if constexpr ((!DstLim::is_signed) && SrcLim::is_signed) { - if constexpr (positive_overflow_possible) { - if (value > DstLim::max()) { - return true; - } - } - - if constexpr (negative_overflow_possible) { - if (value < 0) { - return true; - } - } - } - // signed <-- unsigned - else if constexpr (DstLim::is_signed && (!SrcLim::is_signed)) { - if constexpr (positive_overflow_possible) { - if (value > DstLim::max()) { - return true; - } - } - } - // signed <-- signed - else if constexpr (DstLim::is_signed && SrcLim::is_signed) { - if constexpr (positive_overflow_possible) { - if (value > DstLim::max()) { - return true; - } - } - - if constexpr (negative_overflow_possible) { - if (value < DstLim::lowest()) { - return true; - } - } - } - - return false; -} - -template -constexpr Dst numeric_cast(const Src &value, const char *overflow_message = "value") -{ - if (numeric_cast_will_overflow(value)) { - throw std::overflow_error(overflow_message); - } - - return static_cast(value); -} - // Memory streams, because C++ doesn't supply these. struct membuf : std::streambuf { diff --git a/include/common/numeric_cast.hh b/include/common/numeric_cast.hh new file mode 100644 index 00000000..0f068208 --- /dev/null +++ b/include/common/numeric_cast.hh @@ -0,0 +1,132 @@ +/* Copyright (C) 1996-1997 Id Software, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + See file, 'COPYING', for details. +*/ + +#pragma once + +#include +#include + +template +constexpr bool numeric_cast_will_overflow(const Src &value) +{ + using DstLim = std::numeric_limits; + using SrcLim = std::numeric_limits; + + constexpr bool positive_overflow_possible = DstLim::max() < SrcLim::max(); + constexpr bool negative_overflow_possible = SrcLim::is_signed || (DstLim::lowest() > SrcLim::lowest()); + + // unsigned <-- unsigned + if constexpr ((!DstLim::is_signed) && (!SrcLim::is_signed)) { + if constexpr (positive_overflow_possible) { + if (value > DstLim::max()) { + return true; + } + } + } + // unsigned <-- signed + else if constexpr ((!DstLim::is_signed) && SrcLim::is_signed) { + if constexpr (positive_overflow_possible) { + if (value > DstLim::max()) { + return true; + } + } + + if constexpr (negative_overflow_possible) { + if (value < 0) { + return true; + } + } + } + // signed <-- unsigned + else if constexpr (DstLim::is_signed && (!SrcLim::is_signed)) { + if constexpr (positive_overflow_possible) { + if (value > DstLim::max()) { + return true; + } + } + } + // signed <-- signed + else if constexpr (DstLim::is_signed && SrcLim::is_signed) { + if constexpr (positive_overflow_possible) { + if (value > DstLim::max()) { + return true; + } + } + + if constexpr (negative_overflow_possible) { + if (value < DstLim::lowest()) { + return true; + } + } + } + + return false; +} + +template +constexpr Dst numeric_cast(const Src &value, const char *overflow_message = "value") +{ + if (numeric_cast_will_overflow(value)) { + throw std::overflow_error(overflow_message); + } + + return static_cast(value); +} + +// helper functions to quickly numerically cast mins/maxs +// and floor/ceil them in the case of float -> integral +template +inline qvec aabb_mins_cast(const qvec &f, const char *overflow_message = "mins") +{ + if constexpr (std::is_floating_point_v && !std::is_floating_point_v) + return {numeric_cast(floor(f[0]), overflow_message), numeric_cast(floor(f[1]), overflow_message), + numeric_cast(floor(f[2]), overflow_message)}; + else + return {numeric_cast(f[0], overflow_message), numeric_cast(f[1], overflow_message), + numeric_cast(f[2], overflow_message)}; +} + +template +inline qvec aabb_maxs_cast(const qvec &f, const char *overflow_message = "maxs") +{ + if constexpr (std::is_floating_point_v && !std::is_floating_point_v) + return {numeric_cast(ceil(f[0]), overflow_message), numeric_cast(ceil(f[1]), overflow_message), + numeric_cast(ceil(f[2]), overflow_message)}; + else + return {numeric_cast(f[0], overflow_message), numeric_cast(f[1], overflow_message), + numeric_cast(f[2], overflow_message)}; +} + +// shortcut template to trim (& convert) std::arrays +// between two lengths +template +constexpr ADest array_cast(const ASrc &src, const char *overflow_message = "src") +{ + ADest dest{}; + + for (size_t i = 0; i < std::min(dest.size(), src.size()); i++) { + if constexpr (std::is_arithmetic_v && + std::is_arithmetic_v) + dest[i] = numeric_cast(src[i], overflow_message); + else + dest[i] = static_cast(src[i]); + } + + return dest; +} diff --git a/light/light.cc b/light/light.cc index ba41d35f..32c578cc 100644 --- a/light/light.cc +++ b/light/light.cc @@ -32,6 +32,7 @@ #include #include +#include #include #include #include