1/*
2 * LegacyClonk
3 *
4 * Copyright (c) 2023, The LegacyClonk Team and contributors
5 *
6 * Distributed under the terms of the ISC license; see accompanying file
7 * "COPYING" for details.
8 *
9 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
10 * See accompanying file "TRADEMARK" for details.
11 *
12 * To redistribute this file separately, substitute the full license texts
13 * for the above references.
14 */
15
16#pragma once
17
18#include <cassert>
19#include <utility>
20
21class C4DeletionTrackable
22{
23 class Tracker
24 {
25 public:
26 constexpr Tracker(C4DeletionTrackable *const tracked) noexcept : tracked{tracked}
27 {
28 assert(!tracked->tracker);
29 tracked->tracker = this;
30 }
31
32 Tracker(const Tracker &) = delete;
33
34 constexpr Tracker(Tracker &&other) noexcept : tracked{std::exchange(obj&: other.tracked, new_val: nullptr)}, isDeleted{other.isDeleted}
35 {
36 if (!tracked)
37 {
38 return;
39 }
40
41 assert(tracked->tracker == &other);
42 tracked->tracker = this;
43 }
44
45 Tracker &operator=(const Tracker &) = delete;
46
47 constexpr Tracker &operator=(Tracker &&other) noexcept
48 {
49 Clear();
50 tracked = std::exchange(obj&: other.tracked, new_val: nullptr);
51 isDeleted = other.isDeleted;
52
53 if (tracked)
54 {
55 assert(tracked->tracker == &other);
56 tracked->tracker = this;
57 }
58
59 return *this;
60 }
61
62 constexpr ~Tracker() noexcept
63 {
64 Clear();
65 }
66
67 constexpr bool IsDeleted() const noexcept
68 {
69 return isDeleted;
70 }
71
72 private:
73 constexpr void Clear() noexcept
74 {
75 if (tracked && !isDeleted)
76 {
77 assert(tracked->tracker == this);
78 tracked->tracker = nullptr;
79 }
80 }
81
82 C4DeletionTrackable *tracked{nullptr};
83 bool isDeleted{false};
84
85 friend C4DeletionTrackable;
86 };
87
88public:
89 constexpr ~C4DeletionTrackable() noexcept
90 {
91 if (tracker)
92 {
93 tracker->isDeleted = true;
94 }
95 }
96
97 [[nodiscard]] constexpr Tracker TrackDeletion() noexcept
98 {
99 return {this};
100 }
101
102private:
103 Tracker *tracker{nullptr};
104};
105