Libsaki
Core library of Pancake Mahjong
lua_managed_ref.h
1 #ifndef SAKI_APP_LUA_MANAGED_REF_H
2 #define SAKI_APP_LUA_MANAGED_REF_H
3 
4 #include "lua_user_error_handler.h"
5 #include "../3rd/sol.hpp"
6 #include "../util/misc.h"
7 
8 #include <functional>
9 #include <tuple>
10 
11 
12 namespace saki
13 {
14 
15 
16 
17 template <typename T>
19 {
20 public:
21  LuaManagedRef(T *data, LuaUserErrorHandler &error, bool isOwning, bool isConst)
22  : mData(data)
23  , mError(error)
24  , mIsOwning(isOwning)
25  , mIsConst(isConst)
26  {
27  }
28 
29  LuaManagedRef(const T *data, LuaUserErrorHandler &error, bool isOwning)
30  : LuaManagedRef(const_cast<T *>(data), error, isOwning, true)
31  {
32  }
33 
34  ~LuaManagedRef()
35  {
36  if (mIsOwning)
37  delete mData;
38  }
39 
40  LuaManagedRef(LuaManagedRef &&that) noexcept
41  : mData(that.mData)
42  , mError(that.mError)
43  , mIsOwning(that.mIsOwning)
44  , mIsConst(that.mIsConst)
45  {
46  that.mData = nullptr;
47  }
48 
49  void dispose()
50  {
51  mData = nullptr;
52  }
53 
54  auto data() const -> const T *
55  {
56  return mData;
57  }
58 
59  auto error() const -> LuaUserErrorHandler &
60  {
61  return mError;
62  }
63 
64  template<typename Ret, typename ... Args>
65  static auto makeConstMethod(Ret (T::*method)(Args...) const) -> std::function<Ret(LuaManagedRef *, Args...)>
66  {
67  return [method](LuaManagedRef *thiz, Args ... args) {
68  if (thiz->isBadReference(false))
69  return Ret();
70 
71  return (thiz->mData->*method)(args...);
72  };
73  }
74 
75  template<typename Ret, typename ... Args>
76  static auto makeMutableMethod(Ret (T::*method)(Args...)) -> std::function<Ret(LuaManagedRef *, Args...)>
77  {
78  return [method](LuaManagedRef *thiz, Args ... args) {
79  if (thiz->isBadReference(true))
80  return Ret();
81 
82  return (thiz->mData->*method)(args...);
83  };
84  }
85 
86  template<typename Ret, typename ... Args>
87  static auto makeConstMethodAsTable(Ret (T::*method)(Args...) const)
88  -> std::function<sol::as_table_t<sol::meta::unqualified_t<Ret>>(LuaManagedRef *, Args...)>
89  {
90  return [method](LuaManagedRef *thiz, Args ... args) {
91  if (thiz->isBadReference(false))
92  return sol::as_table_t<sol::meta::unqualified_t<Ret>>();
93 
94  return sol::as_table((thiz->mData->*method)(args...));
95  };
96  }
97 
98  template<typename Ret, typename ... Args>
99  static auto makeMutableMethodAsTable(Ret (T::*method)(Args...))
100  -> std::function<sol::as_table_t<sol::meta::unqualified_t<Ret>>(LuaManagedRef *, Args...)>
101  {
102  return [method](LuaManagedRef *thiz, Args ... args) {
103  if (thiz->isBadReference(true))
104  return sol::as_table_t<sol::meta::unqualified_t<Ret>>();
105 
106  return sol::as_table((thiz->mData->*method)(args...));
107  };
108  }
109 
110  template<typename Ret, typename ... Args>
111  static auto makeConstMethodAsConstRef(const Ret &(T::*method)(Args...) const)
112  -> std::function<std::unique_ptr<LuaManagedRef<Ret>>(LuaManagedRef *, Args...)>
113  {
114  return [method](LuaManagedRef *thiz, Args ... args) -> std::unique_ptr<LuaManagedRef<Ret>> {
115  if (thiz->isBadReference(false))
116  return nullptr;
117 
118  const Ret &r = (thiz->mData->*method)(args...);
119  return std::make_unique<LuaManagedRef<Ret>>(&r, thiz->mError, false);
120  };
121  }
122 
123  template<typename Ret, typename ... Args>
124  static auto makeConstFunction(Ret (*method)(const T &, Args...))
125  -> std::function<Ret(LuaManagedRef *, Args...)>
126  {
127  return [method](LuaManagedRef *thiz, Args ... args) {
128  if (thiz->isBadReference(false))
129  return Ret();
130 
131  return method(*thiz->mData, args...);
132  };
133  }
134 
135  template<typename Ret, typename ... Args>
136  static auto makeMutableFunction(Ret (*method)(T &, Args...))
137  -> std::function<Ret(LuaManagedRef *, Args...)>
138  {
139  return [method](LuaManagedRef *thiz, Args ... args) {
140  if (thiz->isBadReference(true))
141  return Ret();
142 
143  return method(*thiz->mData, args...);
144  };
145  }
146 
147  template<typename Ret, typename ... Args>
148  static auto makeConstFunctionError(Ret (*method)(LuaUserErrorHandler &, const T &, Args...))
149  -> std::function<Ret(LuaManagedRef *, Args...)>
150  {
151  return [method](LuaManagedRef *thiz, Args ... args) {
152  if (thiz->isBadReference(false))
153  return Ret();
154 
155  return method(thiz->mError, *thiz->mData, args...);
156  };
157  }
158 
159  template<typename Ret, typename ... Args>
160  static auto makeMutableFunctionError(Ret (*method)(LuaUserErrorHandler &, T &, Args...))
161  -> std::function<Ret(LuaManagedRef *, Args...)>
162  {
163  return [method](LuaManagedRef *thiz, Args ... args) {
164  if (thiz->isBadReference(true))
165  return Ret();
166 
167  return method(thiz->mError, *thiz->mData, args...);
168  };
169  }
170 
171 private:
172  auto isBadReference(bool modifying) -> bool
173  {
174  if (mData == nullptr) {
175  mError.handleUserError("ERefNil");
176  return true;
177  }
178 
179  if (modifying && mIsConst) {
180  mError.handleUserError("ERefCon");
181  return true;
182  }
183 
184  return false;
185  }
186 
187 private:
188  T *mData = nullptr;
189  LuaUserErrorHandler &mError;
190  bool mIsOwning = false;
191  bool mIsConst = false;
192 };
193 
194 template<typename ...Ts>
196 {
197 public:
198  LuaDisposeRefGuard(std::unique_ptr<LuaManagedRef<Ts>> & ... pointers)
199  {
200  mPointers = std::make_tuple(pointers.get() ...);
201  }
202 
204  {
205  std::apply([](auto ...p) { (p->dispose(), ...); }, mPointers);
206  }
207 
208 private:
209  std::tuple<LuaManagedRef<Ts> * ...> mPointers;
210 };
211 
212 
213 
214 } // namespace saki
215 
216 
217 
218 #endif // SAKI_APP_LUA_MANAGED_REF_H
Definition: lua_managed_ref.h:195
Definition: lua_user_error_handler.h:11
Definition: lua_managed_ref.h:18
Definition: sol.hpp:1261
Definition: ai.cpp:18