CmAsyncOp.h 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. #pragma once
  2. #include "CmPrerequisitesUtil.h"
  3. #include "CmException.h"
  4. #include "boost/any.hpp"
  5. namespace CamelotFramework
  6. {
  7. /**
  8. * @brief Object you may use to check on the results of an asynchronous operation.
  9. * Contains uninitialized data until "hasCompleted" returns true.
  10. *
  11. * @note You are allowed (and meant to) to copy this by value.
  12. *
  13. * You'll notice mIsCompleted isn't locked. This is safe on x86 architectures because all stores
  14. * are executed in order. Loads may be executed out of order from stores but worst case scenario is that
  15. * mIsCompleted reports false a few cycles too late, which is not relevant for practical use.
  16. */
  17. class CM_UTILITY_EXPORT AsyncOp
  18. {
  19. private:
  20. struct AsyncOpData
  21. {
  22. AsyncOpData()
  23. :mIsCompleted(false)
  24. { }
  25. boost::any mReturnValue;
  26. volatile bool mIsCompleted;
  27. };
  28. public:
  29. AsyncOp()
  30. :mData(cm_shared_ptr<AsyncOpData, ScratchAlloc>())
  31. {
  32. #if CM_ARCH_TYPE != CM_ARCHITECTURE_x86_32 && CM_ARCH_TYPE != CM_ARCHITECTURE_x86_64
  33. static_assert(false, "You will likely need to add locks for mIsCompleted on architectures other than x86.");
  34. #endif
  35. }
  36. /**
  37. * @brief True if the async operation has completed.
  38. */
  39. bool hasCompleted() const { return mData->mIsCompleted; }
  40. /**
  41. * @brief Internal method. Mark the async operation as completed.
  42. */
  43. void _completeOperation(boost::any returnValue);
  44. /**
  45. * @brief Internal method. Mark the async operation as completed, without setting a return value.
  46. */
  47. void _completeOperation();
  48. /**
  49. * @brief Retrieves the value returned by the async operation. Only valid
  50. * if "hasCompleted" returns true.
  51. */
  52. template <typename T>
  53. T getReturnValue() const
  54. {
  55. #if CM_DEBUG_MODE
  56. if(!hasCompleted())
  57. CM_EXCEPT(InternalErrorException, "Trying to get AsyncOp return value but the operation hasn't completed.");
  58. #endif
  59. // Be careful if boost returns bad_any_cast. It doesn't support casting of polymorphic types. Provided and returned
  60. // types must be EXACT. (You'll have to cast the data yourself when completing the operation)
  61. return boost::any_cast<T>(mData->mReturnValue);
  62. }
  63. private:
  64. std::shared_ptr<AsyncOpData> mData;
  65. };
  66. }