Ardour  9.0-pre0-582-g084a23a80d
Userdata.h
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
2 /*
3  https://github.com/vinniefalco/LuaBridge
4 
5  Copyright 2016, Robin Gareus <robin@gareus.org>
6  Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
7 
8  License: The MIT License (http://www.opensource.org/licenses/mit-license.php)
9 
10  Permission is hereby granted, free of charge, to any person obtaining a copy
11  of this software and associated documentation files (the "Software"), to deal
12  in the Software without restriction, including without limitation the rights
13  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  copies of the Software, and to permit persons to whom the Software is
15  furnished to do so, subject to the following conditions:
16 
17  The above copyright notice and this permission notice shall be included in all
18  copies or substantial portions of the Software.
19 
20  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  SOFTWARE.
27 */
28 //==============================================================================
29 
30 //==============================================================================
55 #ifdef PLATFORM_WINDOWS
56 # ifdef COMPILER_MSVC
57 #include "LuaBridge/LuaBridge.h" /* Needed for LuaBridge_API */
59 # else
60 extern void* getIdentityKey ();
61 # endif
62 #else
63 inline void* getIdentityKey ()
64 {
65  static char value;
66  return &value;
67 }
68 #endif
69 
73 class Userdata
74 {
75 protected:
76  void* m_p; // subclasses must set this
77 
78  //--------------------------------------------------------------------------
82  inline void* getPointer () const
83  {
84  return m_p;
85  }
86 
87 private:
88  //--------------------------------------------------------------------------
97  int narg,
98  void const* classKey)
99  {
100  Userdata* ud = 0;
101  int const index = lua_absindex (L, narg);
102 
103  bool mismatch = false;
104  char const* got = 0;
105 
106  lua_rawgetp (L, LUA_REGISTRYINDEX, classKey);
107  assert (lua_istable (L, -1));
108 
109  // Make sure we have a userdata.
110  if (!lua_isuserdata (L, index))
111  mismatch = true;
112 
113  // Make sure it's metatable is ours.
114  if (!mismatch)
115  {
116  lua_getmetatable (L, index);
117  lua_rawgetp (L, -1, getIdentityKey ());
118  if (lua_isboolean (L, -1))
119  {
120  lua_pop (L, 1);
121  }
122  else
123  {
124  lua_pop (L, 2);
125  mismatch = true;
126  }
127  }
128 
129  if (!mismatch)
130  {
131  if (lua_rawequal (L, -1, -2))
132  {
133  // Matches class table.
134  lua_pop (L, 2);
135  ud = static_cast <Userdata*> (lua_touserdata (L, index));
136  }
137  else
138  {
139  rawgetfield (L, -2, "__const");
140  if (lua_rawequal (L, -1, -2))
141  {
142  // Matches const table
143  lua_pop (L, 3);
144  ud = static_cast <Userdata*> (lua_touserdata (L, index));
145  }
146  else
147  {
148  // Mismatch, but its one of ours so get a type name.
149  rawgetfield (L, -2, "__type");
150  lua_insert (L, -4);
151  lua_pop (L, 2);
152  got = lua_tostring (L, -2);
153  mismatch = true;
154  }
155  }
156  }
157 
158  if (mismatch)
159  {
160  rawgetfield (L, -1, "__type");
161  assert (lua_type (L, -1) == LUA_TSTRING);
162  char const* const expected = lua_tostring (L, -1);
163 
164  if (got == 0)
165  got = lua_typename (L, lua_type (L, index));
166 
167  char const* const msg = lua_pushfstring (
168  L, "%s expected, got %s", expected, got);
169 
170  if (narg > 0)
171  luaL_argerror (L, narg, msg);
172  else
173  lua_error (L);
174  }
175 
176  return ud;
177  }
178 
179  //--------------------------------------------------------------------------
189  int index,
190  void const* baseClassKey,
191  bool canBeConst,
192  bool errorOnMismatch = true)
193  {
194  assert (index > 0);
195  Userdata* ud = 0;
196 
197  bool mismatch = false;
198  char const* got = 0;
199 
200  lua_rawgetp (L, LUA_REGISTRYINDEX, baseClassKey);
201  assert (lua_istable (L, -1));
202 
203  // Make sure we have a userdata.
204  if (lua_isuserdata (L, index))
205  {
206  // Make sure it's metatable is ours.
207  lua_getmetatable (L, index);
208  lua_rawgetp (L, -1, getIdentityKey ());
209  if (lua_isboolean (L, -1))
210  {
211  lua_pop (L, 1);
212 
213  // If __const is present, object is NOT const.
214  rawgetfield (L, -1, "__const");
215  assert (lua_istable (L, -1) || lua_isnil (L, -1));
216  bool const isConst = lua_isnil (L, -1);
217  lua_pop (L, 1);
218 
219  // Replace the class table with the const table if needed.
220  if (isConst)
221  {
222  rawgetfield (L, -2, "__const");
223  assert (lua_istable (L, -1));
224  lua_replace (L, -3);
225  }
226 
227  for (;;)
228  {
229  if (lua_rawequal (L, -1, -2))
230  {
231  lua_pop (L, 2);
232 
233  // Match, now check const-ness.
234  if (isConst && !canBeConst)
235  {
236  luaL_argerror (L, index, "cannot be const");
237  }
238  else
239  {
240  ud = static_cast <Userdata*> (lua_touserdata (L, index));
241  break;
242  }
243  }
244  else
245  {
246  // Replace current metatable with it's base class.
247  rawgetfield (L, -1, "__parent");
248 /*
249 ud
250 class metatable
251 ud metatable
252 ud __parent (nil)
253 */
254 
255  if (lua_isnil (L, -1))
256  {
257  lua_remove (L, -1);
258  // Mismatch, but its one of ours so get a type name.
259  rawgetfield (L, -1, "__type");
260  lua_insert (L, -3);
261  lua_pop (L, 1);
262  got = lua_tostring (L, -2);
263  mismatch = true;
264  break;
265  }
266  else
267  {
268  lua_remove (L, -2);
269  }
270  }
271  }
272  }
273  else
274  {
275  lua_pop (L, 2);
276  mismatch = true;
277  }
278  }
279  else
280  {
281  mismatch = true;
282  }
283 
284  if (mismatch && errorOnMismatch)
285  {
286  assert (lua_type (L, -1) == LUA_TTABLE);
287  rawgetfield (L, -1, "__type");
288  assert (lua_type (L, -1) == LUA_TSTRING);
289  char const* const expected = lua_tostring (L, -1);
290 
291  if (got == 0)
292  got = lua_typename (L, lua_type (L, index));
293 
294  char const* const msg = lua_pushfstring (
295  L, "%s expected, got %s", expected, got);
296 
297  luaL_argerror (L, index, msg);
298  }
299 
300  return ud;
301  }
302 
303 public:
304  virtual ~Userdata () { }
305 
306  static void* get_ptr (lua_State* L, int index) {
307  Userdata* ud = static_cast <Userdata*> (lua_touserdata (L, index));
308  return ud->m_p;
309  }
310 
311  //--------------------------------------------------------------------------
317  template <class T>
318  static inline Userdata* getExact (lua_State* L, int index)
319  {
320  return getExactClass (L, index, ClassInfo <T>::getClassKey ());
321  }
322 
323  //--------------------------------------------------------------------------
330  template <class T>
331  static inline T* get (lua_State* L, int index, bool canBeConst)
332  {
333  if (lua_isnil (L, index))
334  return 0;
335  else
336  return static_cast <T*> (getClass (L, index,
337  ClassInfo <T>::getClassKey (), canBeConst)->getPointer ());
338  }
339 
340  template <class T>
341  static inline T* try_get (lua_State* L, int index, bool canBeConst)
342  {
343  if (!lua_isnil (L, index)) {
344  Userdata* ud = getClass (L, index, ClassInfo <T>::getClassKey (), canBeConst, false);
345  if (ud) {
346  return static_cast <T*> (ud->getPointer ());
347  }
348  }
349  return 0;
350  }
351 };
352 
353 //----------------------------------------------------------------------------
360 template <class T>
361 class UserdataValue : public Userdata
362 {
363 private:
366 
367  char m_storage [sizeof (T)];
368 
369  inline T* getObject ()
370  {
371  // If this fails to compile it means you forgot to provide
372  // a Container specialization for your container!
373  //
374  return reinterpret_cast <T*> (&m_storage [0]);
375  }
376 
377 private:
382  {
383  m_p = getObject ();
384  }
385 
387  {
388  getObject ()->~T ();
389  }
390 
391 public:
398  static void* place (lua_State* const L)
399  {
400  UserdataValue <T>* const ud = new (
403  // If this goes off it means you forgot to register the class!
404  assert (lua_istable (L, -1));
405  lua_setmetatable (L, -2);
406  return ud->getPointer ();
407  }
408 
412  template <class U>
413  static inline void push (lua_State* const L, U const& u)
414  {
415  new (place (L)) U (u);
416  }
417 };
418 
419 //----------------------------------------------------------------------------
425 class UserdataPtr : public Userdata
426 {
427 private:
430 
431 private:
434  static void push (lua_State* L, void* const p, void const* const key)
435  {
436  if (p)
437  {
438  new (lua_newuserdata (L, sizeof (UserdataPtr))) UserdataPtr (p);
439  lua_rawgetp (L, LUA_REGISTRYINDEX, key);
440  // If this goes off it means you forgot to register the class!
441  assert (lua_istable (L, -1));
442  lua_setmetatable (L, -2);
443  }
444  else
445  {
446  lua_pushnil (L);
447  }
448  }
449 
452  static void push (lua_State* L, void const* const p, void const* const key)
453  {
454  if (p)
455  {
456  new (lua_newuserdata (L, sizeof (UserdataPtr)))
457  UserdataPtr (const_cast <void*> (p));
458  lua_rawgetp (L, LUA_REGISTRYINDEX, key);
459  // If this goes off it means you forgot to register the class!
460  assert (lua_istable (L, -1));
461  lua_setmetatable (L, -2);
462  }
463  else
464  {
465  lua_pushnil (L);
466  }
467  }
468 
469  explicit UserdataPtr (void* const p)
470  {
471  m_p = p;
472 
473  // Can't construct with a null pointer!
474  //
475  assert (m_p != 0);
476  }
477 
478  friend class LuaRef;
479  static inline void push_raw (lua_State* const L, void* p, const void* classkey)
480  {
481  new (lua_newuserdata (L, sizeof (UserdataPtr))) UserdataPtr (p);
482  lua_rawgetp (L, LUA_REGISTRYINDEX, classkey);
483  assert (lua_istable (L, -1));
484  lua_setmetatable (L, -2);
485  }
486 
487 public:
490  template <class T>
491  static inline void push (lua_State* const L, T* const p)
492  {
493  if (p)
494  push (L, p, ClassInfo <T>::getClassKey ());
495  else
496  lua_pushnil (L);
497  }
498 
501  template <class T>
502  static inline void push (lua_State* const L, T const* const p)
503  {
504  if (p)
505  push (L, p, ClassInfo <T>::getConstKey ());
506  else
507  lua_pushnil (L);
508  }
509 };
510 
511 //============================================================================
518 template <class C>
519 class UserdataShared : public Userdata
520 {
521 private:
524 
525  typedef typename TypeTraits::removeConst <
526  typename ContainerTraits <C>::Type>::Type T;
527 
528  C m_c;
529 
530 private:
532  {
533  }
534 
535 public:
539  template <class U>
540  explicit UserdataShared (U const& u) : m_c (u)
541  {
542  m_p = const_cast <void*> (reinterpret_cast <void const*> (
544  }
545 
549  template <class U>
550  explicit UserdataShared (U* u) : m_c (u)
551  {
552  m_p = const_cast <void*> (reinterpret_cast <void const*> (
554  }
555 };
556 
557 //----------------------------------------------------------------------------
558 
559 template <class C, bool makeObjectConst>
561 {
562 private:
563 
564  typedef typename TypeTraits::removeConst <
565  typename ContainerTraits <C>::Type>::Type T;
566 
567 public:
568 
569  static void push (lua_State* L, C const& c)
570  {
571  if (ContainerTraits <C>::get (c) != 0)
572  {
573  new (lua_newuserdata (L, sizeof (UserdataShared <C>))) UserdataShared <C> (c);
574  if constexpr (makeObjectConst) {
576  } else {
578  }
579  // If this goes off it means the class T is unregistered!
580  assert (lua_istable (L, -1));
581  lua_setmetatable (L, -2);
582  }
583  else
584  {
585  lua_pushnil (L);
586  }
587  }
588 
589  static void push (lua_State* L, T* const t)
590  {
591  if (t)
592  {
593  new (lua_newuserdata (L, sizeof (UserdataShared <C>))) UserdataShared <C> (t);
594  if constexpr (makeObjectConst) {
596  } else {
598  }
599  // If this goes off it means the class T is unregistered!
600  assert (lua_istable (L, -1));
601  lua_setmetatable (L, -2);
602  }
603  else
604  {
605  lua_pushnil (L);
606  }
607  }
608 };
609 
610 //==============================================================================
611 
616 template <class T>
617 struct Stack
618 {
619 private:
620 
632 
641  static constexpr bool passByValueNotEnum = !passByContainer && !std::is_enum_v<T>;
642  static constexpr bool passByValueEnum = !passByContainer && std::is_enum_v<T>;
643 
644 public:
645 
646  static inline void push (lua_State* L, T const& t)
647  {
648  if constexpr (passByValueNotEnum) {
649 
651 
652  } else if constexpr (passByValueEnum) {
653 
654  int v = static_cast <int> (t);
655  lua_pushinteger (L, static_cast <lua_Integer> (v));
656 
657  } else {
658 
661 
662  }
663  }
664 
665  static inline
666  std::conditional_t<passByValueNotEnum, T const&, T>
667  get (lua_State* L, int index)
668  {
669  if constexpr (passByValueNotEnum) {
670 
671  return *Userdata::get <T> (L, index, true);
672 
673  } else if constexpr (passByValueEnum) {
674 
675  int v = static_cast <int> (luaL_checkinteger (L, index));
676  return T (v);
677 
678  } else {
679 
680  typedef typename TypeTraits::removeConst <
681  typename ContainerTraits <T>::Type>::Type U;
682 
683  return Userdata::get <U> (L, index, true);
684 
685  }
686  }
687 
688 };
689 
690 //------------------------------------------------------------------------------
699 // pointer
700 template <class T>
701 struct Stack <T*>
702 {
703  static inline void push (lua_State* L, T* const p)
704  {
705  UserdataPtr::push (L, p);
706  }
707 
708  static inline T* get (lua_State* L, int index)
709  {
710  return Userdata::get <T> (L, index, false);
711  }
712 };
713 
714 // Strips the const off the right side of *
715 template <class T>
716 struct Stack <T* const>
717 {
718  static inline void push (lua_State* L, T* const p)
719  {
720  UserdataPtr::push (L, p);
721  }
722 
723  static inline T* get (lua_State* L, int index)
724  {
725  return Userdata::get <T> (L, index, false);
726  }
727 };
728 
729 // pointer to const
730 template <class T>
731 struct Stack <T const*>
732 {
733  static inline void push (lua_State* L, T const* const p)
734  {
735  UserdataPtr::push (L, p);
736  }
737 
738  static inline T const* get (lua_State* L, int index)
739  {
740  return Userdata::get <T> (L, index, true);
741  }
742 };
743 
744 // Strips the const off the right side of *
745 template <class T>
746 struct Stack <T const* const>
747 {
748  static inline void push (lua_State* L, T const* const p)
749  {
750  UserdataPtr::push (L, p);
751  }
752 
753  static inline T const* get (lua_State* L, int index)
754  {
755  return Userdata::get <T> (L, index, true);
756  }
757 };
758 
759 // const references to class-instance pointers
760 // e.g. std::list<T*>::push_back ( const T* & )
761 template <class T>
762 struct Stack <T* const&>
763 {
764  static inline void push (lua_State* L, T* const& p)
765  {
766  UserdataPtr::push (L, p);
767  }
768 
769  static inline T* get (lua_State* L, int index)
770  {
771  return Userdata::get <T> (L, index, true);
772  }
773 };
774 
775 // reference
776 template <class T>
777 struct Stack <T&>
778 {
779  static inline void push (lua_State* L, T& t)
780  {
781  UserdataPtr::push (L, &t);
782  }
783 
784  static T& get (lua_State* L, int index)
785  {
786  T* const t = Userdata::get <T> (L, index, false);
787  if (!t)
788  luaL_error (L, "nil passed to reference");
789  return *t;
790  }
791 };
792 
793 // reference to const
794 template <class T>
795 struct Stack <T const&>
796 {
797 private:
798 
800 
801 public:
802 
803  static inline void push (lua_State* L, T const& t)
804  {
805  if constexpr (passByContainer) {
806 
809 
810  } else {
811 
812  UserdataPtr::push (L, &t);
813 
814  }
815  }
816 
817  static
818  std::conditional_t<passByContainer, T, T const&>
819  get (lua_State* L, int index)
820  {
821  if constexpr (passByContainer) {
822 
823  typedef typename TypeTraits::removeConst <
824  typename ContainerTraits <T>::Type>::Type U;
825 
826  return Userdata::get <U> (L, index, true);
827 
828  } else {
829 
830  T const* const t = Userdata::get <T> (L, index, true);
831 
832  if (!t)
833  luaL_error (L, "nil passed to reference");
834  return *t;
835 
836  }
837  }
838 
839 };
#define LuaBridge_API
Definition: ClassInfo.h:36
void rawgetfield(lua_State *L, int index, char const *key)
Definition: LuaHelpers.h:106
void * getIdentityKey()
Definition: Userdata.h:63
Definition: LuaRef.h:52
static void push(lua_State *const L, T *const p)
Definition: Userdata.h:491
static void push_raw(lua_State *const L, void *p, const void *classkey)
Definition: Userdata.h:479
static void push(lua_State *const L, T const *const p)
Definition: Userdata.h:502
static void push(lua_State *L, void const *const p, void const *const key)
Definition: Userdata.h:452
static void push(lua_State *L, void *const p, void const *const key)
Definition: Userdata.h:434
UserdataPtr(void *const p)
Definition: Userdata.h:469
UserdataPtr operator=(UserdataPtr const &)
UserdataPtr(UserdataPtr const &)
UserdataShared(U const &u)
Definition: Userdata.h:540
UserdataShared(U *u)
Definition: Userdata.h:550
UserdataShared(UserdataShared< C > const &)
TypeTraits::removeConst< typename ContainerTraits< C >::Type >::Type T
Definition: Userdata.h:526
UserdataShared< C > & operator=(UserdataShared< C > const &)
UserdataValue(UserdataValue< T > const &)
char m_storage[sizeof(T)]
Definition: Userdata.h:367
static void * place(lua_State *const L)
Definition: Userdata.h:398
static void push(lua_State *const L, U const &u)
Definition: Userdata.h:413
T * getObject()
Definition: Userdata.h:369
UserdataValue< T > operator=(UserdataValue< T > const &)
static Userdata * getExactClass(lua_State *L, int narg, void const *classKey)
Definition: Userdata.h:96
static T * get(lua_State *L, int index, bool canBeConst)
Definition: Userdata.h:331
static Userdata * getClass(lua_State *L, int index, void const *baseClassKey, bool canBeConst, bool errorOnMismatch=true)
Definition: Userdata.h:188
static T * try_get(lua_State *L, int index, bool canBeConst)
Definition: Userdata.h:341
static Userdata * getExact(lua_State *L, int index)
Definition: Userdata.h:318
void * getPointer() const
Definition: Userdata.h:82
void * m_p
Definition: Userdata.h:76
static void * get_ptr(lua_State *L, int index)
Definition: Userdata.h:306
virtual ~Userdata()
Definition: Userdata.h:304
int() luaL_error(lua_State *L, const char *fmt,...)
lua_Integer() luaL_checkinteger(lua_State *L, int arg)
int() luaL_argerror(lua_State *L, int arg, const char *extramsg)
int() lua_absindex(lua_State *L, int idx)
Definition: LuaHelpers.h:33
#define lua_replace(L, idx)
#define lua_istable(L, n)
#define lua_insert(L, idx)
int() lua_rawgetp(lua_State *L, int idx, const void *p)
Definition: LuaHelpers.h:41
#define LUA_TTABLE
Definition: lua-5.3.5/lua.h:69
int() lua_error(lua_State *L)
#define LUA_REGISTRYINDEX
Definition: lua-5.3.5/lua.h:42
LUA_INTEGER lua_Integer
Definition: lua-5.3.5/lua.h:93
int() lua_rawequal(lua_State *L, int idx1, int idx2)
int() lua_setmetatable(lua_State *L, int objindex)
#define LUA_TSTRING
Definition: lua-5.3.5/lua.h:68
void *() lua_newuserdata(lua_State *L, size_t sz)
const char *() lua_pushfstring(lua_State *L, const char *fmt,...)
void() lua_pushinteger(lua_State *L, lua_Integer n)
int() lua_type(lua_State *L, int idx)
#define lua_remove(L, idx)
void *() lua_touserdata(lua_State *L, int idx)
#define lua_isnil(L, n)
void() lua_pushnil(lua_State *L)
#define lua_pop(L, n)
int() lua_getmetatable(lua_State *L, int objindex)
int() lua_isuserdata(lua_State *L, int idx)
#define lua_tostring(L, i)
const char *() lua_typename(lua_State *L, int tp)
#define lua_isboolean(L, n)
void push(lua_State *L, T t)
Definition: LuaBridge.h:159
static T * get(lua_State *L, int index)
Definition: Userdata.h:708
static void push(lua_State *L, T *const p)
Definition: Userdata.h:703
static T * get(lua_State *L, int index)
Definition: Userdata.h:723
static void push(lua_State *L, T *const p)
Definition: Userdata.h:718
static T * get(lua_State *L, int index)
Definition: Userdata.h:769
static void push(lua_State *L, T *const &p)
Definition: Userdata.h:764
static T & get(lua_State *L, int index)
Definition: Userdata.h:784
static void push(lua_State *L, T &t)
Definition: Userdata.h:779
static void push(lua_State *L, T const *const p)
Definition: Userdata.h:733
static T const * get(lua_State *L, int index)
Definition: Userdata.h:738
static T const * get(lua_State *L, int index)
Definition: Userdata.h:753
static void push(lua_State *L, T const *const p)
Definition: Userdata.h:748
static std::conditional_t< passByContainer, T, T const & > get(lua_State *L, int index)
Definition: Userdata.h:819
static void push(lua_State *L, T const &t)
Definition: Userdata.h:803
static constexpr bool passByContainer
Definition: Userdata.h:631
static constexpr bool passByValueEnum
Definition: Userdata.h:642
static std::conditional_t< passByValueNotEnum, T const &, T > get(lua_State *L, int index)
Definition: Userdata.h:667
static void push(lua_State *L, T const &t)
Definition: Userdata.h:646
static constexpr bool passByValueNotEnum
Definition: Userdata.h:641
static void push(lua_State *L, C const &c)
Definition: Userdata.h:569
TypeTraits::removeConst< typename ContainerTraits< C >::Type >::Type T
Definition: Userdata.h:565
static void push(lua_State *L, T *const t)
Definition: Userdata.h:589