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.

110 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 `WeakPtr`s to be used. */
  10. struct WeakBase {
  11. WeakHandle* weakHandle = nullptr;
  12. ~WeakBase() {
  13. if (weakHandle) {
  14. weakHandle->ptr = nullptr;
  15. }
  16. }
  17. size_t getWeakCount() {
  18. if (!weakHandle)
  19. return 0;
  20. return weakHandle->count;
  21. }
  22. };
  23. /** A weak pointer to a subclass of WeakBase.
  24. Weak pointers behave like raw pointers but can be accessed safely (returning nullptr) after the pointed object is deleted.
  25. Example:
  26. Foo* foo = new Foo;
  27. WeakPtr<Foo> weakFoo = foo;
  28. weakFoo.get(); // returns foo
  29. delete foo;
  30. weakFoo.get(); // returns nullptr
  31. Not thread safe.
  32. 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(const WeakPtr& other) {
  42. set(other.get());
  43. }
  44. WeakPtr& operator=(const WeakPtr& other) {
  45. set(other.get());
  46. return *this;
  47. }
  48. ~WeakPtr() {
  49. set(nullptr);
  50. }
  51. void set(T* ptr) {
  52. // Release handle
  53. if (weakHandle) {
  54. // Decrement and check handle reference count
  55. if (--weakHandle->count == 0) {
  56. // Remove handle from object and delete it
  57. T* oldPtr = reinterpret_cast<T*>(weakHandle->ptr);
  58. if (oldPtr) {
  59. oldPtr->weakHandle = nullptr;
  60. }
  61. delete weakHandle;
  62. }
  63. weakHandle = nullptr;
  64. }
  65. // Obtain handle
  66. if (ptr) {
  67. if (!ptr->weakHandle) {
  68. // Create new handle for object
  69. ptr->weakHandle = new WeakHandle(ptr);
  70. }
  71. weakHandle = ptr->weakHandle;
  72. // Increment handle reference count
  73. weakHandle->count++;
  74. }
  75. }
  76. T* get() const {
  77. if (!weakHandle)
  78. return nullptr;
  79. return reinterpret_cast<T*>(weakHandle->ptr);
  80. }
  81. T* operator->() const {
  82. return get();
  83. }
  84. T& operator*() const {
  85. return *get();
  86. }
  87. operator T*() const {
  88. return get();
  89. }
  90. explicit operator bool() const {
  91. return get();
  92. }
  93. };
  94. } // namespace rack