]> git.tdb.fi Git - libs/game.git/blob - source/game/accessguard.h
Enforce no creation or destruction of objects during tick
[libs/game.git] / source / game / accessguard.h
1 #ifndef MSP_GAME_ACCESSGUARD_H_
2 #define MSP_GAME_ACCESSGUARD_H_
3
4 #include <cstdint>
5 #include <stdexcept>
6 #include <string>
7 #include <vector>
8 #include <msp/core/noncopyable.h>
9
10 namespace Msp::Game {
11
12 class invalid_access: public std::logic_error
13 {
14 public:
15         invalid_access(const std::string &w): logic_error(w) { }
16 };
17
18
19 class AccessGuard
20 {
21 public:
22         struct Create { static std::string describe() { return "create"; } };
23         struct Destroy { static std::string describe() { return "destroy"; } };
24
25         template<typename T = void>
26         struct BlockForScope: NonCopyable
27         {
28                 BlockForScope() { get_instance().block<T>(); }
29                 ~BlockForScope() { get_instance().unblock<T>(); }
30         };
31
32 private:
33         const uint8_t UNBLOCKED = 0;
34         const uint8_t BLOCKED = 1;
35
36         std::uint8_t default_flag = UNBLOCKED;
37         std::vector<std::uint8_t> flags;
38
39         static thread_local AccessGuard *instance;
40
41 public:
42         AccessGuard();
43         AccessGuard(AccessGuard &&);
44         AccessGuard &operator=(AccessGuard &&);
45         ~AccessGuard();
46
47         static AccessGuard &get_instance();
48
49         void block_all();
50         void unblock_all();
51
52 private:
53         static unsigned get_next_index();
54
55         template<typename T>
56         static unsigned get_index();
57
58         template<typename T>
59         std::uint8_t &get();
60
61 public:
62         template<typename T>
63         void block() { get<T>() = BLOCKED; }
64
65         template<typename T>
66         void unblock() { get<T>() = UNBLOCKED; }
67
68         template<typename T>
69         void check() { if(get<T>()!=UNBLOCKED) throw invalid_access(T::describe()); }
70 };
71
72
73 template<typename T>
74 inline unsigned AccessGuard::get_index()
75 {
76         static unsigned index = get_next_index();
77         return index;
78 }
79
80 template<typename T>
81 inline std::uint8_t &AccessGuard::get()
82 {
83         unsigned index = get_index<T>();
84         if(flags.size()<=index)
85                 flags.resize(index+1, default_flag);
86         return flags[index];
87 }
88
89 template<>
90 inline void AccessGuard::block<void>()
91 { block_all(); }
92
93 template<>
94 inline void AccessGuard::unblock<void>()
95 { unblock_all(); }
96
97 } // namespace Msp::Game
98
99 #endif