1 #ifndef MSP_GAME_ACCESSGUARD_H_
2 #define MSP_GAME_ACCESSGUARD_H_
8 #include <msp/core/noncopyable.h>
9 #include <msp/debug/demangle.h>
13 class invalid_access: public std::logic_error
16 invalid_access(const std::string &w): logic_error(w) { }
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(); };
28 template<typename T = void>
29 struct BlockForScope: NonCopyable
31 BlockForScope() { get_instance().block<T>(); }
32 ~BlockForScope() { get_instance().unblock<T>(); }
36 const uint8_t UNBLOCKED = 0;
37 const uint8_t BLOCKED = 1;
39 std::uint8_t default_flag = UNBLOCKED;
40 std::vector<std::uint8_t> flags;
42 static thread_local AccessGuard *instance;
46 AccessGuard(AccessGuard &&);
47 AccessGuard &operator=(AccessGuard &&);
50 static AccessGuard &get_instance();
56 static unsigned get_next_index();
59 static unsigned get_index();
66 void block() { get<T>() = BLOCKED; }
69 void unblock() { get<T>() = UNBLOCKED; }
77 inline unsigned AccessGuard::get_index()
79 static unsigned index = get_next_index();
84 inline std::uint8_t &AccessGuard::get()
86 unsigned index = get_index<T>();
87 if(flags.size()<=index)
88 flags.resize(index+1, default_flag);
93 inline void AccessGuard::block<void>()
97 inline void AccessGuard::unblock<void>()
101 inline void AccessGuard::check()
103 unsigned index = get_index<T>();
104 if((index<flags.size() ? flags[index] : default_flag) != UNBLOCKED)
105 throw invalid_access(T::describe());
110 inline std::string AccessGuard::Read<T>::describe()
112 return "read "+Debug::demangle(typeid(T).name());
116 inline std::string AccessGuard::Write<T>::describe()
118 return "write "+Debug::demangle(typeid(T).name());
121 } // namespace Msp::Game