TurtleBrains  0.3.5
High quality, portable, C++ framework for rapid 2D game development.
tb_defines.hpp
1 
8 #ifndef TurtleBrains_Defines_hpp
9 #define TurtleBrains_Defines_hpp
10 
11 #include <limits>
12 #include <type_traits>
13 
14 #include <turtle_brains/core/tb_configuration.hpp>
15 #include <turtle_brains/core/tb_error.hpp>
16 
21 
25 #define tb_unused(parameter) ((void)parameter);
26 
30 
31 namespace TurtleBrains::Core
32 {
37  template<typename Type> void SafeDelete(Type*& objectPointer) { if (nullptr != objectPointer) { delete objectPointer; objectPointer = nullptr; } }
38 
43  template<typename Type> void SafeDeleteArray(Type*& arrayPointer) { if (nullptr != arrayPointer) { delete[] arrayPointer; arrayPointer = nullptr; } }
44 
45 
54  template<typename ReturnType, typename InitialType> ReturnType RangedCast(const InitialType& value)
55  {
56 #if defined(tb_visual_cpp)
57  #pragma warning(push)
58  //We are removing 2 warnings here:
59  // 4127: Constant Expression with first part of if, because it is constant ... but we only care about that at
60  // compile time, so it doesn't matter. The C++17 if constexpr (expression) could fix this (and the next).
61  // 4018: Signed/Unsigned Mismatch with the second part (inside the top if statement) because the compiler is
62  // still generating the code for the error checks, and the signs are mismatching. We just don't care since
63  // the code flow would jump to the bottom when those warnings would apply.
64  // Note: Both of these should be fixed in C++17 by using if constexpr () since that would let the compiler
65  // see the actual intent, and remove the error check completely when signs are mismatched.
66  //
67  // 2024-07-31: We might want to try using C++17 constexpr as this is in-progress moving towards C++20. But
68  // MSVC on C++20 threw another warning here and I'm setting that to disable;
69  //
70  // 4244: 'argument': conversion from 'const InitialType' to 'const unsigned short', possible loss of data
71  // which is something we already know is possible and why we've choosen to use RangedCast, as it will
72  // error when the initial value is out of range.
73  //
74  // 4267: warning C4267 : 'argument' : conversion from 'size_t' to 'uint32', possible loss of data and for
75  // some reason the static cast isn't enough?
76  #pragma warning(disable: 4127)
77  #pragma warning(disable: 4018)
78  #pragma warning(disable: 4244)
79  #pragma warning(disable: 4267)
80 #elif defined(__GNUC__)
81  #pragma GCC diagnostic push
82  #pragma GCC diagnostic ignored "-Wsign-compare"
83 #endif
84  // 2025-10-02: I don't remember why this check was initially added. I suspect it was to give a better warning
85  // when casting into a TypedInteger since that required Type::Integer to be used. Today however I was using
86  // this to cast double to float, which perhaps doesn't even require any range checks. I think ensuring it
87  // is trivial is the thing that it wants to be.
88  //
89  //tb_static_error_if(false == std::is_integral<ReturnType>::value, "Expected ReturnType to be an integral type.");
90  tb_static_error_if(false == std::is_trivial<ReturnType>::value, "Expected ReturnType to be a trivial/integral/float type.");
91 
92  if ((std::is_signed<ReturnType>::value == std::is_signed<InitialType>::value))
93  {
94  tb_error_if(value < std::numeric_limits<ReturnType>::min() || value > std::numeric_limits<ReturnType>::max(),
95  "tbCastingError: Value is outside the range of the following cast.");
96  }
97  else if (std::is_signed<InitialType>::value)
98  {
99  tb_error_if(value < 0, "tbCastingError: Signed value is less than 0 going to unsigned-value.");
100  }
101 
102  return static_cast<ReturnType>(value);
103 #if defined(tb_visual_cpp)
104  #pragma warning(pop)
105 #elif defined(__GNUC__)
106  #pragma GCC diagnostic pop
107 #endif
108  }
109 
121  template<typename ReturnType, typename InitialType> ReturnType ClampedCast(const InitialType& value, const ReturnType& minimum, const ReturnType& maximum)
122  {
123  tb_error_if(minimum > maximum, "tbError: Minimum should never be larger than Maximum.");
124  ReturnType unclamped = RangedCast<ReturnType>(value);
125  if (unclamped < minimum)
126  {
127  return minimum;
128  }
129  if (unclamped > maximum)
130  {
131  return maximum;
132  }
133  return unclamped;
134  }
135 
136 }; /* namespace TurtleBrains::Core */
137 
138 namespace tbCore = TurtleBrains::Core;
139 
140 #endif /* TurtleBrains_Defines_hpp */
#define tb_static_error_if(errorTest, message)
Definition: tb_error.hpp:51
#define tb_error_if(errorTest, message,...)
Definition: tb_error.hpp:42
Contains core functionality for each component of the API.
Definition: tb_debug_logger.hpp:125
ReturnType ClampedCast(const InitialType &value, const ReturnType &minimum, const ReturnType &maximum)
Definition: tb_defines.hpp:121
ReturnType RangedCast(const InitialType &value)
Definition: tb_defines.hpp:54
void SafeDelete(Type *&objectPointer)
Definition: tb_defines.hpp:37
void SafeDeleteArray(Type *&arrayPointer)
Definition: tb_defines.hpp:43