]> git.tdb.fi Git - libs/game.git/blob - source/game/accessguard.h
Minor optimization to AccessGuard::check
[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();
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 template<typename T>
101 inline void AccessGuard::check()
102 {
103         unsigned index = get_index<T>();
104         if((index<flags.size() ? flags[index] : default_flag) != UNBLOCKED)
105                 throw invalid_access(T::describe());
106 }
107
108
109 template<typename T>
110 inline std::string AccessGuard::Read<T>::describe()
111 {
112         return "read "+Debug::demangle(typeid(T).name());
113 }
114
115 template<typename T>
116 inline std::string AccessGuard::Write<T>::describe()
117 {
118         return "write "+Debug::demangle(typeid(T).name());
119 }
120
121 } // namespace Msp::Game
122
123 #endif