You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

105 lines
2.0KB

  1. #pragma once
  2. #include <common.hpp>
  3. #include <atomic>
  4. namespace rack {
  5. struct WeakHandle {
  6. void* ptr;
  7. std::atomic<size_t> count{0};
  8. WeakHandle(void* ptr) : ptr(ptr) {}
  9. };
  10. /** Base class for classes that allow WeakPtrs to be used.
  11. */
  12. struct WeakBase {
  13. WeakHandle* weakHandle = nullptr;
  14. ~WeakBase() {
  15. if (weakHandle) {
  16. weakHandle->ptr = nullptr;
  17. }
  18. }
  19. size_t getWeakCount() {
  20. if (!weakHandle)
  21. return 0;
  22. return weakHandle->count;
  23. }
  24. };
  25. /** A weak pointer to a subclass of WeakBase.
  26. Weak pointers behave like raw pointers but can be accessed safely (returning nullptr) after the pointed object is deleted.
  27. Example:
  28. Foo* foo = new Foo;
  29. WeakPtr<Foo> weakFoo = foo;
  30. weakFoo.get(); // returns foo
  31. delete foo;
  32. weakFoo.get(); // returns nullptr
  33. Caveat: In multithreaded environments, the object pointed to by the WeakPtr could be deleted at any time after obtaining its pointer from WeakPtr.
  34. */
  35. template <typename T>
  36. struct WeakPtr {
  37. WeakHandle* weakHandle = NULL;
  38. WeakPtr() {}
  39. WeakPtr(T* ptr) {
  40. set(ptr);
  41. }
  42. WeakPtr& operator=(const WeakPtr& other) {
  43. set(other.get());
  44. return *this;
  45. }
  46. ~WeakPtr() {
  47. set(nullptr);
  48. }
  49. void set(T* ptr) {
  50. // Release handle
  51. if (weakHandle) {
  52. // Decrement and check handle reference count
  53. if (--weakHandle->count == 0) {
  54. // Remove handle from object and delete it
  55. T* oldPtr = reinterpret_cast<T*>(weakHandle->ptr);
  56. if (oldPtr) {
  57. oldPtr->weakHandle = nullptr;
  58. }
  59. delete weakHandle;
  60. }
  61. weakHandle = nullptr;
  62. }
  63. // Obtain handle
  64. if (ptr) {
  65. if (!ptr->weakHandle) {
  66. // Create new handle for object
  67. ptr->weakHandle = new WeakHandle(ptr);
  68. }
  69. weakHandle = ptr->weakHandle;
  70. // Increment handle reference count
  71. weakHandle->count++;
  72. }
  73. }
  74. T* get() const {
  75. if (!weakHandle)
  76. return nullptr;
  77. return reinterpret_cast<T*>(weakHandle->ptr);
  78. }
  79. T& operator*() const {
  80. return *get();
  81. }
  82. T* operator->() const {
  83. return get();
  84. }
  85. explicit operator bool() const {
  86. return get();
  87. }
  88. };
  89. } // namespace rack