]> git.tdb.fi Git - libs/game.git/blob - source/game/accessguard.h
Enforce correct access to buffered components
[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 #include <msp/debug/demangle.h>
10
11 namespace Msp::Game {
12
13 class invalid_access: public std::logic_error
14 {
15 public:
16         invalid_access(const std::string &w): logic_error(w) { }
17 };
18
19
20 class AccessGuard
21 {
22 public:
23         struct Create { static std::string describe() { return "create"; } };
24         struct Destroy { static std::string describe() { return "destroy"; } };
25         template<typename T> struct Read { static std::string describe(); };
26         template<typename T> struct Write { static std::string describe(); };
27
28         template<typename T = void>
29         struct BlockForScope: NonCopyable
30         {
31                 BlockForScope() { get_instance().block<T>(); }
32                 ~BlockForScope() { get_instance().unblock<T>(); }
33         };
34
35 private:
36         const uint8_t UNBLOCKED = 0;
37         const uint8_t BLOCKED = 1;
38
39         std::uint8_t default_flag = UNBLOCKED;
40         std::vector<std::uint8_t> flags;
41
42         static thread_local AccessGuard *instance;
43
44 public:
45         AccessGuard();
46         AccessGuard(AccessGuard &&);
47         AccessGuard &operator=(AccessGuard &&);
48         ~AccessGuard();
49
50         static AccessGuard &get_instance();
51
52         void block_all();
53         void unblock_all();
54
55 private:
56         static unsigned get_next_index();
57
58         template<typename T>
59         static unsigned get_index();
60
61         template<typename T>
62         std::uint8_t &get();
63
64 public:
65         template<typename T>
66         void block() { get<T>() = BLOCKED; }
67
68         template<typename T>
69         void unblock() { get<T>() = UNBLOCKED; }
70
71         template<typename T>
72         void check() { if(get<T>()!=UNBLOCKED) throw invalid_access(T::describe()); }
73 };
74
75
76 template<typename T>
77 inline unsigned AccessGuard::get_index()
78 {
79         static unsigned index = get_next_index();
80         return index;
81 }
82
83 template<typename T>
84 inline std::uint8_t &AccessGuard::get()
85 {
86         unsigned index = get_index<T>();
87         if(flags.size()<=index)
88                 flags.resize(index+1, default_flag);
89         return flags[index];
90 }
91
92 template<>
93 inline void AccessGuard::block<void>()
94 { block_all(); }
95
96 template<>
97 inline void AccessGuard::unblock<void>()
98 { unblock_all(); }
99
100
101 template<typename T>
102 inline std::string AccessGuard::Read<T>::describe()
103 {
104         return "read "+Debug::demangle(typeid(T).name());
105 }
106
107 template<typename T>
108 inline std::string AccessGuard::Write<T>::describe()
109 {
110         return "write "+Debug::demangle(typeid(T).name());
111 }
112
113 } // namespace Msp::Game
114
115 #endif