BsAsyncOp.h 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. //__________________________ Banshee Project - A modern game development toolkit _________________________________//
  2. //_____________________________________ www.banshee-project.com __________________________________________________//
  3. //________________________ Copyright (c) 2014 Marko Pintera. All rights reserved. ________________________________//
  4. #pragma once
  5. #include "BsPrerequisitesUtil.h"
  6. #include "BsException.h"
  7. #include "BsAny.h"
  8. namespace BansheeEngine
  9. {
  10. /**
  11. * @brief Object you may use to check on the results of an asynchronous operation.
  12. * Contains uninitialized data until "hasCompleted" returns true.
  13. *
  14. * @note You are allowed (and meant to) to copy this by value.
  15. *
  16. * You'll notice mIsCompleted isn't locked. This is safe on x86 architectures because all stores
  17. * are executed in order. Loads may be executed out of order from stores but worst case scenario is that
  18. * mIsCompleted reports false a few cycles too late, which is not relevant for practical use.
  19. */
  20. class BS_UTILITY_EXPORT AsyncOp
  21. {
  22. private:
  23. struct AsyncOpData
  24. {
  25. AsyncOpData()
  26. :mIsCompleted(false)
  27. { }
  28. Any mReturnValue;
  29. volatile bool mIsCompleted;
  30. };
  31. public:
  32. AsyncOp()
  33. :mData(bs_shared_ptr<AsyncOpData, ScratchAlloc>())
  34. {
  35. #if BS_ARCH_TYPE != BS_ARCHITECTURE_x86_32 && BS_ARCH_TYPE != BS_ARCHITECTURE_x86_64
  36. static_assert(false, "You will likely need to add locks for mIsCompleted on architectures other than x86.");
  37. #endif
  38. }
  39. /**
  40. * @brief True if the async operation has completed.
  41. */
  42. bool hasCompleted() const { return mData->mIsCompleted; }
  43. /**
  44. * @brief Internal method. Mark the async operation as completed.
  45. */
  46. void _completeOperation(Any returnValue);
  47. /**
  48. * @brief Internal method. Mark the async operation as completed, without setting a return value.
  49. */
  50. void _completeOperation();
  51. /**
  52. * @brief Retrieves the value returned by the async operation. Only valid
  53. * if "hasCompleted" returns true.
  54. */
  55. template <typename T>
  56. T getReturnValue() const
  57. {
  58. #if BS_DEBUG_MODE
  59. if(!hasCompleted())
  60. BS_EXCEPT(InternalErrorException, "Trying to get AsyncOp return value but the operation hasn't completed.");
  61. #endif
  62. // Be careful if cast throws an exception. It doesn't support casting of polymorphic types. Provided and returned
  63. // types must be EXACT. (You'll have to cast the data yourself when completing the operation)
  64. return any_cast<T>(mData->mReturnValue);
  65. }
  66. private:
  67. std::shared_ptr<AsyncOpData> mData;
  68. };
  69. }