Result.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. JPH_NAMESPACE_BEGIN
  6. // GCC doesn't properly detect that mState is used to ensure that mResult is initialized
  7. JPH_GCC_SUPPRESS_WARNING("-Wmaybe-uninitialized")
  8. /// Helper class that either contains a valid result or an error
  9. template <class Type>
  10. class Result
  11. {
  12. public:
  13. /// Default constructor
  14. Result() { }
  15. /// Copy constructor
  16. Result(const Result<Type> &inRHS) :
  17. mState(inRHS.mState)
  18. {
  19. switch (inRHS.mState)
  20. {
  21. case EState::Valid:
  22. ::new (&mResult) Type (inRHS.mResult);
  23. break;
  24. case EState::Error:
  25. ::new (&mError) String(inRHS.mError);
  26. break;
  27. case EState::Invalid:
  28. break;
  29. }
  30. }
  31. /// Move constructor
  32. Result(Result<Type> &&inRHS) noexcept :
  33. mState(inRHS.mState)
  34. {
  35. switch (inRHS.mState)
  36. {
  37. case EState::Valid:
  38. ::new (&mResult) Type (std::move(inRHS.mResult));
  39. break;
  40. case EState::Error:
  41. ::new (&mError) String(std::move(inRHS.mError));
  42. break;
  43. case EState::Invalid:
  44. break;
  45. }
  46. // Don't reset the state of inRHS, the destructors still need to be called after a move operation
  47. }
  48. /// Destructor
  49. ~Result() { Clear(); }
  50. /// Copy assignment
  51. Result<Type> & operator = (const Result<Type> &inRHS)
  52. {
  53. Clear();
  54. mState = inRHS.mState;
  55. switch (inRHS.mState)
  56. {
  57. case EState::Valid:
  58. ::new (&mResult) Type (inRHS.mResult);
  59. break;
  60. case EState::Error:
  61. ::new (&mError) String(inRHS.mError);
  62. break;
  63. case EState::Invalid:
  64. break;
  65. }
  66. return *this;
  67. }
  68. /// Move assignment
  69. Result<Type> & operator = (Result<Type> &&inRHS) noexcept
  70. {
  71. Clear();
  72. mState = inRHS.mState;
  73. switch (inRHS.mState)
  74. {
  75. case EState::Valid:
  76. ::new (&mResult) Type (std::move(inRHS.mResult));
  77. break;
  78. case EState::Error:
  79. ::new (&mError) String(std::move(inRHS.mError));
  80. break;
  81. case EState::Invalid:
  82. break;
  83. }
  84. // Don't reset the state of inRHS, the destructors still need to be called after a move operation
  85. return *this;
  86. }
  87. /// Clear result or error
  88. void Clear()
  89. {
  90. switch (mState)
  91. {
  92. case EState::Valid:
  93. mResult.~Type();
  94. break;
  95. case EState::Error:
  96. mError.~String();
  97. break;
  98. case EState::Invalid:
  99. break;
  100. }
  101. mState = EState::Invalid;
  102. }
  103. /// Checks if the result is still uninitialized
  104. bool IsEmpty() const { return mState == EState::Invalid; }
  105. /// Checks if the result is valid
  106. bool IsValid() const { return mState == EState::Valid; }
  107. /// Get the result value
  108. const Type & Get() const { JPH_ASSERT(IsValid()); return mResult; }
  109. /// Set the result value
  110. void Set(const Type &inResult) { Clear(); ::new (&mResult) Type(inResult); mState = EState::Valid; }
  111. /// Set the result value (move value)
  112. void Set(Type &&inResult) { Clear(); ::new (&mResult) Type(std::move(inResult)); mState = EState::Valid; }
  113. /// Check if we had an error
  114. bool HasError() const { return mState == EState::Error; }
  115. /// Get the error value
  116. const String & GetError() const { JPH_ASSERT(HasError()); return mError; }
  117. /// Set an error value
  118. void SetError(const char *inError) { Clear(); ::new (&mError) String(inError); mState = EState::Error; }
  119. void SetError(const string_view &inError) { Clear(); ::new (&mError) String(inError); mState = EState::Error; }
  120. void SetError(String &&inError) { Clear(); ::new (&mError) String(std::move(inError)); mState = EState::Error; }
  121. private:
  122. union
  123. {
  124. Type mResult; ///< The actual result object
  125. String mError; ///< The error description if the result failed
  126. };
  127. /// State of the result
  128. enum class EState : uint8
  129. {
  130. Invalid,
  131. Valid,
  132. Error
  133. };
  134. EState mState = EState::Invalid;
  135. };
  136. JPH_NAMESPACE_END