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.

107 lines
2.0KB

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