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.

111 lines
2.1KB

  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. Not thread safe.
  33. 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(const WeakPtr& other) {
  43. set(other.get());
  44. }
  45. WeakPtr& operator=(const WeakPtr& other) {
  46. set(other.get());
  47. return *this;
  48. }
  49. ~WeakPtr() {
  50. set(nullptr);
  51. }
  52. void set(T* ptr) {
  53. // Release handle
  54. if (weakHandle) {
  55. // Decrement and check handle reference count
  56. if (--weakHandle->count == 0) {
  57. // Remove handle from object and delete it
  58. T* oldPtr = reinterpret_cast<T*>(weakHandle->ptr);
  59. if (oldPtr) {
  60. oldPtr->weakHandle = nullptr;
  61. }
  62. delete weakHandle;
  63. }
  64. weakHandle = nullptr;
  65. }
  66. // Obtain handle
  67. if (ptr) {
  68. if (!ptr->weakHandle) {
  69. // Create new handle for object
  70. ptr->weakHandle = new WeakHandle(ptr);
  71. }
  72. weakHandle = ptr->weakHandle;
  73. // Increment handle reference count
  74. weakHandle->count++;
  75. }
  76. }
  77. T* get() const {
  78. if (!weakHandle)
  79. return nullptr;
  80. return reinterpret_cast<T*>(weakHandle->ptr);
  81. }
  82. T* operator->() const {
  83. return get();
  84. }
  85. T& operator*() const {
  86. return *get();
  87. }
  88. operator T*() const {
  89. return get();
  90. }
  91. explicit operator bool() const {
  92. return get();
  93. }
  94. };
  95. } // namespace rack