Result.h 3.6 KB

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