1 #ifndef MSP_GAME_ACCESSGUARD_H_
2 #define MSP_GAME_ACCESSGUARD_H_
8 #include <msp/core/noncopyable.h>
9 #include <msp/debug/demangle.h>
10 #include "mspgame_api.h"
14 class MSPGAME_API invalid_access: public std::logic_error
17 invalid_access(const std::string &w): logic_error(w) { }
21 class MSPGAME_API AccessGuard
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(); };
29 template<typename T = void>
30 struct BlockForScope: NonCopyable
32 BlockForScope() { get_instance().block<T>(); }
33 ~BlockForScope() { get_instance().unblock<T>(); }
37 const uint8_t UNBLOCKED = 0;
38 const uint8_t BLOCKED = 1;
40 std::uint8_t default_flag = UNBLOCKED;
41 std::vector<std::uint8_t> flags;
43 static thread_local AccessGuard *instance;
47 AccessGuard(AccessGuard &&);
48 AccessGuard &operator=(AccessGuard &&);
51 static AccessGuard &get_instance();
57 static unsigned get_next_index();
60 static unsigned get_index();
67 void block() { get<T>() = BLOCKED; }
70 void unblock() { get<T>() = UNBLOCKED; }
78 inline unsigned AccessGuard::get_index()
80 static unsigned index = get_next_index();
85 inline std::uint8_t &AccessGuard::get()
87 unsigned index = get_index<T>();
88 if(flags.size()<=index)
89 flags.resize(index+1, default_flag);
94 inline void AccessGuard::block<void>()
98 inline void AccessGuard::unblock<void>()
102 inline void AccessGuard::check()
104 unsigned index = get_index<T>();
105 if((index<flags.size() ? flags[index] : default_flag) != UNBLOCKED)
106 throw invalid_access(T::describe());
111 inline std::string AccessGuard::Read<T>::describe()
113 return "read "+Debug::demangle(typeid(T).name());
117 inline std::string AccessGuard::Write<T>::describe()
119 return "write "+Debug::demangle(typeid(T).name());
122 } // namespace Msp::Game