Skip to content

Commit 309563a

Browse files
committed
Added tests for enable_observer_from_this and fixed implementation
1 parent 9f24026 commit 309563a

File tree

3 files changed

+211
-69
lines changed

3 files changed

+211
-69
lines changed

include/oup/observable_unique_ptr.hpp

Lines changed: 43 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,11 @@ class observable_unique_ptr_base {
110110
}
111111

112112
/// Fill in the observer pointer for objects inheriting from enable_observer_from_this.
113-
void set_this_observer() noexcept {
113+
void set_this_observer_() noexcept {
114114
if constexpr (std::is_base_of_v<enable_observer_from_this<T>, T>) {
115115
if (ptr_deleter.data) {
116-
ptr_deleter.data->this_observer = *this;
116+
ptr_deleter.data->this_observer.set_data_(block, ptr_deleter.data);
117+
++block->refcount;
117118
}
118119
}
119120
}
@@ -124,9 +125,7 @@ class observable_unique_ptr_base {
124125
* \note This is used by make_observable_unique().
125126
*/
126127
observable_unique_ptr_base(control_block_type* ctrl, T* value) noexcept :
127-
block(ctrl), ptr_deleter{Deleter{}, value} {
128-
set_this_observer();
129-
}
128+
block(ctrl), ptr_deleter{Deleter{}, value} {}
130129

131130
/// Private constructor using pre-allocated control block.
132131
/** \param ctrl The control block pointer
@@ -135,9 +134,7 @@ class observable_unique_ptr_base {
135134
* \note This is used by make_observable_sealed().
136135
*/
137136
observable_unique_ptr_base(control_block_type* ctrl, T* value, Deleter del) noexcept :
138-
block(ctrl), ptr_deleter{std::move(del), value} {
139-
set_this_observer();
140-
}
137+
block(ctrl), ptr_deleter{std::move(del), value} {}
141138

142139
// Friendship is required for conversions.
143140
template<typename U>
@@ -197,7 +194,6 @@ class observable_unique_ptr_base {
197194
observable_unique_ptr_base(value.block, value.ptr_deleter.data, std::move(value.ptr_deleter)) {
198195
value.block = nullptr;
199196
value.ptr_deleter.data = nullptr;
200-
set_this_observer();
201197
}
202198

203199
/// Transfer ownership by implicit casting
@@ -212,7 +208,6 @@ class observable_unique_ptr_base {
212208
observable_unique_ptr_base(value.block, value.ptr_deleter.data, std::move(value.ptr_deleter)) {
213209
value.block = nullptr;
214210
value.ptr_deleter.data = nullptr;
215-
set_this_observer();
216211
}
217212

218213
/// Transfer ownership by explicit casting
@@ -227,7 +222,6 @@ class observable_unique_ptr_base {
227222
observable_unique_ptr_base(manager.block, value) {
228223
manager.block = nullptr;
229224
manager.ptr_deleter.data = nullptr;
230-
set_this_observer();
231225
}
232226

233227
/// Transfer ownership by explicit casting
@@ -242,7 +236,6 @@ class observable_unique_ptr_base {
242236
observable_unique_ptr_base(manager.block, value, std::move(del)) {
243237
manager.block = nullptr;
244238
manager.ptr_deleter.data = nullptr;
245-
set_this_observer();
246239
}
247240

248241
/// Transfer ownership by implicit casting
@@ -260,7 +253,6 @@ class observable_unique_ptr_base {
260253
ptr_deleter.data = value.ptr_deleter.data;
261254
value.ptr_deleter.data = nullptr;
262255
static_cast<Deleter&>(ptr_deleter) = std::move(static_cast<Deleter&>(value.ptr_deleter));
263-
set_this_observer();
264256

265257
return *this;
266258
}
@@ -283,7 +275,6 @@ class observable_unique_ptr_base {
283275
ptr_deleter.data = value.ptr_deleter.data;
284276
value.ptr_deleter.data = nullptr;
285277
static_cast<Deleter&>(ptr_deleter) = std::move(static_cast<Deleter&>(ptr_deleter));
286-
set_this_observer();
287278

288279
return *this;
289280
}
@@ -321,8 +312,6 @@ class observable_unique_ptr_base {
321312
using std::swap;
322313
swap(block, other.block);
323314
swap(ptr_deleter, other.ptr_deleter);
324-
other.set_this_observer();
325-
set_this_observer();
326315
}
327316

328317
/// Replaces the managed object with a null pointer.
@@ -409,21 +398,6 @@ class observable_unique_ptr :
409398
return new control_block_type;
410399
}
411400

412-
static void pop_ref_(control_block_type* block) noexcept {
413-
--block->refcount;
414-
if (block->refcount == 0) {
415-
delete block;
416-
}
417-
}
418-
419-
static void delete_and_pop_ref_(control_block_type* block, T* data, Deleter& deleter) noexcept {
420-
deleter(data);
421-
422-
block->set_expired();
423-
424-
pop_ref_(block);
425-
}
426-
427401
// Friendship is required for conversions.
428402
template<typename U>
429403
friend class observer_ptr;
@@ -461,7 +435,9 @@ class observable_unique_ptr :
461435
* using make_observable_unique() instead of this constructor.
462436
*/
463437
explicit observable_unique_ptr(T* value) :
464-
base(value != nullptr ? allocate_block_() : nullptr, value) {}
438+
base(value != nullptr ? allocate_block_() : nullptr, value) {
439+
base::set_this_observer_();
440+
}
465441

466442
/// Explicit ownership capture of a raw pointer, with customer deleter.
467443
/** \param value The raw pointer to take ownership of
@@ -471,7 +447,9 @@ class observable_unique_ptr :
471447
* using make_observable_unique() instead of this constructor.
472448
*/
473449
explicit observable_unique_ptr(T* value, Deleter del) :
474-
base(value != nullptr ? allocate_block_() : nullptr, value, std::move(del)) {}
450+
base(value != nullptr ? allocate_block_() : nullptr, value, std::move(del)) {
451+
base::set_this_observer_();
452+
}
475453

476454
/// Transfer ownership by implicit casting
477455
/** \param value The pointer to take ownership from
@@ -502,7 +480,9 @@ class observable_unique_ptr :
502480
*/
503481
template<typename U, typename D>
504482
observable_unique_ptr(observable_unique_ptr<U,D>&& manager, T* value) noexcept :
505-
base(std::move(manager), value) {}
483+
base(std::move(manager), value) {
484+
base::set_this_observer_();
485+
}
506486

507487
/// Transfer ownership by explicit casting
508488
/** \param manager The smart pointer to take ownership from
@@ -513,7 +493,9 @@ class observable_unique_ptr :
513493
*/
514494
template<typename U, typename D>
515495
observable_unique_ptr(observable_unique_ptr<U,D>&& manager, T* value, Deleter del) noexcept :
516-
base(std::move(manager), value, del) {}
496+
base(std::move(manager), value, del) {
497+
base::set_this_observer_();
498+
}
517499

518500
/// Transfer ownership by implicit casting
519501
/** \param value The pointer to take ownership from
@@ -572,8 +554,10 @@ class observable_unique_ptr :
572554
// Delete the old pointer
573555
// (this follows std::unique_ptr specs)
574556
if (old_ptr) {
575-
delete_and_pop_ref_(old_block, old_ptr, base::ptr_deleter);
557+
base::delete_and_pop_ref_(old_block, old_ptr, base::ptr_deleter);
576558
}
559+
560+
base::set_this_observer_();
577561
}
578562

579563
/// Releases ownership of the managed object and mark observers as expired.
@@ -636,7 +620,9 @@ class observable_sealed_ptr :
636620
* \note This is used by make_observable_sealed().
637621
*/
638622
observable_sealed_ptr(control_block_type* ctrl, T* value) noexcept :
639-
base(ctrl, value, oup::placement_delete<T>{}) {}
623+
base(ctrl, value, oup::placement_delete<T>{}) {
624+
base::set_this_observer_();
625+
}
640626

641627
// Friendship is required for conversions.
642628
template<typename U>
@@ -863,6 +849,9 @@ class observer_ptr {
863849
// Friendship is required for conversions.
864850
template<typename U>
865851
friend class observer_ptr;
852+
// Friendship is required for enable_observer_from_this.
853+
template<typename U, typename D>
854+
friend class details::observable_unique_ptr_base;
866855

867856
using control_block = details::control_block;
868857

@@ -876,6 +865,15 @@ class observer_ptr {
876865
}
877866
}
878867

868+
void set_data_(control_block* b, T* d) noexcept {
869+
if (data) {
870+
pop_ref_();
871+
}
872+
873+
block = b;
874+
data = d;
875+
}
876+
879877
public:
880878
/// Type of the pointed object
881879
using element_type = T;
@@ -964,12 +962,8 @@ class observer_ptr {
964962
*/
965963
template<typename U, typename D, typename enable = std::enable_if_t<std::is_convertible_v<U*, T*>>>
966964
observer_ptr& operator=(const observable_unique_ptr<U,D>& owner) noexcept {
967-
if (data) {
968-
pop_ref_();
969-
}
965+
set_data_(owner.block, owner.ptr_deleter.data);
970966

971-
block = owner.block;
972-
data = owner.ptr_deleter.data;
973967
if (block) {
974968
++block->refcount;
975969
}
@@ -984,12 +978,8 @@ class observer_ptr {
984978
*/
985979
template<typename U, typename enable = std::enable_if_t<std::is_convertible_v<U*, T*>>>
986980
observer_ptr& operator=(const observable_sealed_ptr<U>& owner) noexcept {
987-
if (data) {
988-
pop_ref_();
989-
}
981+
set_data_(owner.block, owner.ptr_deleter.data);
990982

991-
block = owner.block;
992-
data = owner.ptr_deleter.data;
993983
if (block) {
994984
++block->refcount;
995985
}
@@ -1005,12 +995,8 @@ class observer_ptr {
1005995
return *this;
1006996
}
1007997

1008-
if (data) {
1009-
pop_ref_();
1010-
}
998+
set_data_(value.block, value.data);
1011999

1012-
block = value.block;
1013-
data = value.data;
10141000
if (block) {
10151001
++block->refcount;
10161002
}
@@ -1029,12 +1015,8 @@ class observer_ptr {
10291015
return *this;
10301016
}
10311017

1032-
if (data) {
1033-
pop_ref_();
1034-
}
1018+
set_data_(value.block, value.data);
10351019

1036-
block = value.block;
1037-
data = value.data;
10381020
if (block) {
10391021
++block->refcount;
10401022
}
@@ -1048,13 +1030,9 @@ class observer_ptr {
10481030
* pointer is set to null and looses ownership.
10491031
*/
10501032
observer_ptr& operator=(observer_ptr&& value) noexcept {
1051-
if (data) {
1052-
pop_ref_();
1053-
}
1033+
set_data_(value.block, value.data);
10541034

1055-
block = value.block;
10561035
value.block = nullptr;
1057-
data = value.data;
10581036
value.data = nullptr;
10591037

10601038
return *this;
@@ -1069,13 +1047,9 @@ class observer_ptr {
10691047
*/
10701048
template<typename U, typename enable = std::enable_if_t<std::is_convertible_v<U*, T*>>>
10711049
observer_ptr& operator=(observer_ptr<U>&& value) noexcept {
1072-
if (data) {
1073-
pop_ref_();
1074-
}
1050+
set_data_(value.block, value.data);
10751051

1076-
block = value.block;
10771052
value.block = nullptr;
1078-
data = value.data;
10791053
value.data = nullptr;
10801054

10811055
return *this;
@@ -1207,11 +1181,11 @@ bool operator!= (const observer_ptr<T>& first, const observer_ptr<U>& second) no
12071181
*/
12081182
template<typename T>
12091183
class enable_observer_from_this {
1210-
observer_ptr<T> this_observer;
1184+
mutable observer_ptr<T> this_observer;
12111185

12121186
// Friendship is required for assignement of the observer.
12131187
template<typename U, typename D>
1214-
friend class observable_unique_ptr_base;
1188+
friend class details::observable_unique_ptr_base;
12151189

12161190
protected:
12171191
enable_observer_from_this() noexcept = default;

0 commit comments

Comments
 (0)