shareddata.h 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #ifndef SHAREDDATA_H
  2. #define SHAREDDATA_H
  3. #include <atomic>
  4. #include <utility>
  5. #include <qmsetup/qmsetup_global.h>
  6. template <class T>
  7. class QMSharedDataPointer;
  8. class QMSharedData {
  9. public:
  10. mutable std::atomic_int ref;
  11. inline QMSharedData() noexcept : ref(0){};
  12. inline QMSharedData(const QMSharedData &) noexcept : ref(0){};
  13. virtual ~QMSharedData() = default;
  14. // using the assignment operator would lead to corruption in the ref-counting
  15. QMSharedData &operator=(const QMSharedData &) = delete;
  16. // NOTICE: must define a function named `clone()` which returns a copy
  17. };
  18. template <class T>
  19. class QMSharedDataPointer {
  20. public:
  21. typedef T Type;
  22. typedef T *pointer;
  23. inline void detach() {
  24. if (d && d->ref.load() != 1)
  25. detach_helper();
  26. }
  27. inline T &operator*() {
  28. detach();
  29. return *d;
  30. }
  31. inline const T &operator*() const {
  32. return *d;
  33. }
  34. inline T *operator->() {
  35. detach();
  36. return d;
  37. }
  38. inline const T *operator->() const {
  39. return d;
  40. }
  41. inline operator T *() {
  42. detach();
  43. return d;
  44. }
  45. inline operator const T *() const {
  46. return d;
  47. }
  48. inline T *data() {
  49. detach();
  50. return d;
  51. }
  52. inline const T *data() const {
  53. return d;
  54. }
  55. inline const T *constData() const {
  56. return d;
  57. }
  58. // Compatible with std::unique_ptr
  59. inline T *get() {
  60. detach();
  61. return d;
  62. }
  63. inline const T *get() const {
  64. return d;
  65. }
  66. inline bool operator==(const QMSharedDataPointer<T> &other) const {
  67. return d == other.d;
  68. }
  69. inline bool operator!=(const QMSharedDataPointer<T> &other) const {
  70. return d != other.d;
  71. }
  72. inline QMSharedDataPointer() {
  73. d = nullptr;
  74. }
  75. inline ~QMSharedDataPointer() {
  76. if (d && d->ref.fetch_sub(1) == 1)
  77. delete d;
  78. }
  79. explicit QMSharedDataPointer(T *data) noexcept;
  80. inline QMSharedDataPointer(const QMSharedDataPointer<T> &o) : d(o.d) {
  81. if (d)
  82. d->ref.fetch_add(1);
  83. }
  84. inline QMSharedDataPointer<T> &operator=(const QMSharedDataPointer<T> &o) {
  85. if (o.d != d) {
  86. if (o.d)
  87. o.d->ref.fetch_add(1);
  88. T *old = d;
  89. d = o.d;
  90. if (old && old->ref.fetch_sub(1) == 1)
  91. delete old;
  92. }
  93. return *this;
  94. }
  95. inline QMSharedDataPointer &operator=(T *o) {
  96. if (o != d) {
  97. if (o)
  98. o->ref.fetch_add(1);
  99. T *old = d;
  100. d = o;
  101. if (old && old->ref.fetch_sub(1) == 1)
  102. delete old;
  103. }
  104. return *this;
  105. }
  106. QMSharedDataPointer(QMSharedDataPointer &&o) noexcept : d(o.d) {
  107. o.d = nullptr;
  108. }
  109. inline QMSharedDataPointer<T> &operator=(QMSharedDataPointer<T> &&other) noexcept {
  110. QMSharedDataPointer moved(std::move(other));
  111. swap(moved);
  112. return *this;
  113. }
  114. inline bool operator!() const {
  115. return !d;
  116. }
  117. inline void swap(QMSharedDataPointer &other) noexcept {
  118. std::swap(d, other.d);
  119. }
  120. protected:
  121. T *clone();
  122. private:
  123. void detach_helper();
  124. T *d;
  125. };
  126. template <class T>
  127. inline bool operator==(std::nullptr_t p1, const QMSharedDataPointer<T> &p2) {
  128. (void) p1;
  129. return !p2;
  130. }
  131. template <class T>
  132. inline bool operator==(const QMSharedDataPointer<T> &p1, std::nullptr_t p2) {
  133. (void) p2;
  134. return !p1;
  135. }
  136. template <class T>
  137. inline QMSharedDataPointer<T>::QMSharedDataPointer(T *adata) noexcept : d(adata) {
  138. if (d)
  139. d->ref.fetch_add(1);
  140. }
  141. template <class T>
  142. inline T *QMSharedDataPointer<T>::clone() {
  143. return d->clone();
  144. }
  145. template <class T>
  146. inline void QMSharedDataPointer<T>::detach_helper() {
  147. T *x = clone();
  148. x->ref.fetch_add(1);
  149. if (d->ref.fetch_sub(1) == 1)
  150. delete d;
  151. d = x;
  152. }
  153. #endif // SHAREDDATA_H