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