diff options
Diffstat (limited to 'lib/LuaBridge/Source')
24 files changed, 7206 insertions, 0 deletions
diff --git a/lib/LuaBridge/Source/CMakeLists.txt b/lib/LuaBridge/Source/CMakeLists.txt new file mode 100644 index 0000000..e351990 --- /dev/null +++ b/lib/LuaBridge/Source/CMakeLists.txt @@ -0,0 +1,43 @@ +set (LUABRIDGE_HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/List.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/LuaBridge.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/Map.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/RefCountedObject.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/RefCountedPtr.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/UnorderedMap.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/Vector.h +) +source_group ("LuaBridge" FILES ${LUABRIDGE_HEADERS}) + +set (LUABRIDGE_DETAIL_HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/CFunctions.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/ClassInfo.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Config.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Constructor.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/dump.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/FuncTraits.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Iterator.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/LuaException.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/LuaHelpers.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/LuaRef.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Namespace.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Stack.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/TypeList.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/TypeTraits.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Userdata.h +) +source_group ("LuaBridge\\detail" FILES ${LUABRIDGE_DETAIL_HEADERS}) + +add_library (LuaBridge INTERFACE) +target_sources (LuaBridge INTERFACE + ${LUABRIDGE_HEADERS} + ${LUABRIDGE_DETAIL_HEADERS} +) +target_include_directories (LuaBridge INTERFACE .) + +if (MSVC) + add_custom_target (LuaBridgeLibrary SOURCES + ${LUABRIDGE_HEADERS} + ${LUABRIDGE_DETAIL_HEADERS} + ) +endif () diff --git a/lib/LuaBridge/Source/LuaBridge/List.h b/lib/LuaBridge/Source/LuaBridge/List.h new file mode 100644 index 0000000..3969f32 --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/List.h @@ -0,0 +1,50 @@ +// https://github.com/vinniefalco/LuaBridge +// +// Copyright 2018, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#include <LuaBridge/detail/Stack.h> + +#include <list> + +namespace luabridge { + +template <class T> +struct Stack <std::list <T> > +{ + static void push (lua_State* L, std::list <T> const& list) + { + lua_createtable (L, static_cast <int> (list.size ()), 0); + typename std::list <T>::const_iterator item = list.begin (); + for (std::size_t i = 1; i <= list.size (); ++i) + { + lua_pushinteger (L, static_cast <lua_Integer> (i)); + Stack <T>::push (L, *item); + lua_settable (L, -3); + ++item; + } + } + + static std::list <T> get (lua_State* L, int index) + { + if (!lua_istable (L, index)) + { + luaL_error (L, "#%d argments must be table", index); + } + + std::list <T> list; + + int const absindex = lua_absindex (L, index); + lua_pushnil (L); + while (lua_next (L, absindex) != 0) + { + list.push_back (Stack <T>::get (L, -1)); + lua_pop (L, 1); + } + return list; + } +}; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/LuaBridge.h b/lib/LuaBridge/Source/LuaBridge/LuaBridge.h new file mode 100644 index 0000000..866acc3 --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/LuaBridge.h @@ -0,0 +1,59 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + Copyright 2007, Nathan Reed + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +// All #include dependencies are listed here +// instead of in the individual header files. +// + +#define LUABRIDGE_MAJOR_VERSION 2 +#define LUABRIDGE_MINOR_VERSION 3 +#define LUABRIDGE_VERSION 203 + +#ifndef LUA_VERSION_NUM +#error "Lua headers must be included prior to LuaBridge ones" +#endif + + +#include <LuaBridge/detail/LuaHelpers.h> +#include <LuaBridge/detail/TypeTraits.h> +#include <LuaBridge/detail/TypeList.h> +#include <LuaBridge/detail/FuncTraits.h> +#include <LuaBridge/detail/Constructor.h> +#include <LuaBridge/detail/ClassInfo.h> +#include <LuaBridge/detail/LuaException.h> +#include <LuaBridge/detail/LuaRef.h> +#include <LuaBridge/detail/Iterator.h> +#include <LuaBridge/detail/Userdata.h> +#include <LuaBridge/detail/CFunctions.h> +#include <LuaBridge/detail/Security.h> +#include <LuaBridge/detail/Stack.h> +#include <LuaBridge/detail/Namespace.h> diff --git a/lib/LuaBridge/Source/LuaBridge/Map.h b/lib/LuaBridge/Source/LuaBridge/Map.h new file mode 100644 index 0000000..890c87a --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/Map.h @@ -0,0 +1,50 @@ +// https://github.com/vinniefalco/LuaBridge +// +// Copyright 2018, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#include <LuaBridge/detail/Stack.h> + +#include <map> + +namespace luabridge { + +template <class K, class V> +struct Stack <std::map <K, V> > +{ + typedef std::map <K, V> Map; + + static void push (lua_State* L, const Map& map) + { + lua_createtable (L, 0, static_cast <int> (map.size ())); + typedef typename Map::const_iterator ConstIter; + for (ConstIter i = map.begin (); i != map.end (); ++i) + { + Stack <K>::push (L, i->first); + Stack <V>::push (L, i->second); + lua_settable (L, -3); + } + } + + static Map get (lua_State* L, int index) + { + if (!lua_istable (L, index)) + { + luaL_error (L, "#%d argments must be table", index); + } + + Map map; + int const absindex = lua_absindex (L, index); + lua_pushnil (L); + while (lua_next (L, absindex) != 0) + { + map.emplace (Stack <K>::get (L, -2), Stack <V>::get (L, -1)); + lua_pop (L, 1); + } + return map; + } +}; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/RefCountedObject.h b/lib/LuaBridge/Source/LuaBridge/RefCountedObject.h new file mode 100644 index 0000000..ebc749e --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/RefCountedObject.h @@ -0,0 +1,356 @@ +//============================================================================== +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + Copyright 2004-11 by Raw Material Software Ltd. + + This is a derivative work used by permission from part of + JUCE, available at http://www.rawaterialsoftware.com + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + This file incorporates work covered by the following copyright and + permission notice: + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-11 by Raw Material Software Ltd. +*/ +//============================================================================== + +#pragma once + +//#define LUABRIDGE_COMPILER_SUPPORTS_MOVE_SEMANTICS 1 + +#include <LuaBridge/detail/TypeTraits.h> + +#include <cassert> + +namespace luabridge { + +//============================================================================== +/** + Adds reference-counting to an object. + + To add reference-counting to a class, derive it from this class, and + use the RefCountedObjectPtr class to point to it. + + e.g. @code + class MyClass : public RefCountedObjectType + { + void foo(); + + // This is a neat way of declaring a typedef for a pointer class, + // rather than typing out the full templated name each time.. + typedef RefCountedObjectPtr<MyClass> Ptr; + }; + + MyClass::Ptr p = new MyClass(); + MyClass::Ptr p2 = p; + p = 0; + p2->foo(); + @endcode + + Once a new RefCountedObjectType has been assigned to a pointer, be + careful not to delete the object manually. +*/ +template <class CounterType> +class RefCountedObjectType +{ +public: + //============================================================================== + /** Increments the object's reference count. + + This is done automatically by the smart pointer, but is public just + in case it's needed for nefarious purposes. + */ + inline void incReferenceCount() const + { + ++refCount; + } + + /** Decreases the object's reference count. + + If the count gets to zero, the object will be deleted. + */ + inline void decReferenceCount() const + { + assert (getReferenceCount() > 0); + + if (--refCount == 0) + delete this; + } + + /** Returns the object's current reference count. */ + inline int getReferenceCount() const + { + return static_cast <int> (refCount); + } + +protected: + //============================================================================== + /** Creates the reference-counted object (with an initial ref count of zero). */ + RefCountedObjectType() : refCount () + { + } + + /** Destructor. */ + virtual ~RefCountedObjectType() + { + // it's dangerous to delete an object that's still referenced by something else! + assert (getReferenceCount() == 0); + } + +private: + //============================================================================== + CounterType mutable refCount; +}; + +//============================================================================== + +/** Non thread-safe reference counted object. + + This creates a RefCountedObjectType that uses a non-atomic integer + as the counter. +*/ +typedef RefCountedObjectType <int> RefCountedObject; + +//============================================================================== +/** + A smart-pointer class which points to a reference-counted object. + + The template parameter specifies the class of the object you want to point + to - the easiest way to make a class reference-countable is to simply make + it inherit from RefCountedObjectType, but if you need to, you could roll + your own reference-countable class by implementing a pair of methods called + incReferenceCount() and decReferenceCount(). + + When using this class, you'll probably want to create a typedef to + abbreviate the full templated name - e.g. + + @code + + typedef RefCountedObjectPtr <MyClass> MyClassPtr; + + @endcode +*/ +template <class ReferenceCountedObjectClass> +class RefCountedObjectPtr +{ +public: + /** The class being referenced by this pointer. */ + typedef ReferenceCountedObjectClass ReferencedType; + + //============================================================================== + /** Creates a pointer to a null object. */ + inline RefCountedObjectPtr() : referencedObject (0) + { + } + + /** Creates a pointer to an object. + + This will increment the object's reference-count if it is non-null. + */ + inline RefCountedObjectPtr (ReferenceCountedObjectClass* const refCountedObject) + : referencedObject (refCountedObject) + { + if (refCountedObject != 0) + refCountedObject->incReferenceCount(); + } + + /** Copies another pointer. + This will increment the object's reference-count (if it is non-null). + */ + inline RefCountedObjectPtr (const RefCountedObjectPtr& other) + : referencedObject (other.referencedObject) + { + if (referencedObject != 0) + referencedObject->incReferenceCount(); + } + +#if LUABRIDGE_COMPILER_SUPPORTS_MOVE_SEMANTICS + /** Takes-over the object from another pointer. */ + inline RefCountedObjectPtr (RefCountedObjectPtr&& other) + : referencedObject (other.referencedObject) + { + other.referencedObject = 0; + } +#endif + + /** Copies another pointer. + This will increment the object's reference-count (if it is non-null). + */ + template <class DerivedClass> + inline RefCountedObjectPtr (const RefCountedObjectPtr<DerivedClass>& other) + : referencedObject (static_cast <ReferenceCountedObjectClass*> (other.getObject())) + { + if (referencedObject != 0) + referencedObject->incReferenceCount(); + } + + /** Changes this pointer to point at a different object. + + The reference count of the old object is decremented, and it might be + deleted if it hits zero. The new object's count is incremented. + */ + RefCountedObjectPtr& operator= (const RefCountedObjectPtr& other) + { + return operator= (other.referencedObject); + } + + /** Changes this pointer to point at a different object. + + The reference count of the old object is decremented, and it might be + deleted if it hits zero. The new object's count is incremented. + */ + template <class DerivedClass> + RefCountedObjectPtr& operator= (const RefCountedObjectPtr<DerivedClass>& other) + { + return operator= (static_cast <ReferenceCountedObjectClass*> (other.getObject())); + } + +#if LUABRIDGE_COMPILER_SUPPORTS_MOVE_SEMANTICS + /** Takes-over the object from another pointer. */ + RefCountedObjectPtr& operator= (RefCountedObjectPtr&& other) + { + std::swap (referencedObject, other.referencedObject); + return *this; + } +#endif + + /** Changes this pointer to point at a different object. + + The reference count of the old object is decremented, and it might be + deleted if it hits zero. The new object's count is incremented. + */ + RefCountedObjectPtr& operator= (ReferenceCountedObjectClass* const newObject) + { + if (referencedObject != newObject) + { + if (newObject != 0) + newObject->incReferenceCount(); + + ReferenceCountedObjectClass* const oldObject = referencedObject; + referencedObject = newObject; + + if (oldObject != 0) + oldObject->decReferenceCount(); + } + + return *this; + } + + /** Destructor. + + This will decrement the object's reference-count, and may delete it if it + gets to zero. + */ + inline ~RefCountedObjectPtr() + { + if (referencedObject != 0) + referencedObject->decReferenceCount(); + } + + /** Returns the object that this pointer references. + The pointer returned may be zero, of course. + */ + inline operator ReferenceCountedObjectClass*() const + { + return referencedObject; + } + + // the -> operator is called on the referenced object + inline ReferenceCountedObjectClass* operator->() const + { + return referencedObject; + } + + /** Returns the object that this pointer references. + The pointer returned may be zero, of course. + */ + inline ReferenceCountedObjectClass* getObject() const + { + return referencedObject; + } + +private: + //============================================================================== + ReferenceCountedObjectClass* referencedObject; +}; + +/** Compares two ReferenceCountedObjectPointers. */ +template <class ReferenceCountedObjectClass> +bool operator== (const RefCountedObjectPtr<ReferenceCountedObjectClass>& object1, ReferenceCountedObjectClass* const object2) +{ + return object1.getObject() == object2; +} + +/** Compares two ReferenceCountedObjectPointers. */ +template <class ReferenceCountedObjectClass> +bool operator== (const RefCountedObjectPtr<ReferenceCountedObjectClass>& object1, const RefCountedObjectPtr<ReferenceCountedObjectClass>& object2) +{ + return object1.getObject() == object2.getObject(); +} + +/** Compares two ReferenceCountedObjectPointers. */ +template <class ReferenceCountedObjectClass> +bool operator== (ReferenceCountedObjectClass* object1, RefCountedObjectPtr<ReferenceCountedObjectClass>& object2) +{ + return object1 == object2.getObject(); +} + +/** Compares two ReferenceCountedObjectPointers. */ +template <class ReferenceCountedObjectClass> +bool operator!= (const RefCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectClass* object2) +{ + return object1.getObject() != object2; +} + +/** Compares two ReferenceCountedObjectPointers. */ +template <class ReferenceCountedObjectClass> +bool operator!= (const RefCountedObjectPtr<ReferenceCountedObjectClass>& object1, RefCountedObjectPtr<ReferenceCountedObjectClass>& object2) +{ + return object1.getObject() != object2.getObject(); +} + +/** Compares two ReferenceCountedObjectPointers. */ +template <class ReferenceCountedObjectClass> +bool operator!= (ReferenceCountedObjectClass* object1, RefCountedObjectPtr<ReferenceCountedObjectClass>& object2) +{ + return object1 != object2.getObject(); +} + +//============================================================================== + +template <class T> +struct ContainerTraits <RefCountedObjectPtr <T> > +{ + typedef T Type; + + static T* get (RefCountedObjectPtr <T> const& c) + { + return c.getObject (); + } +}; + +//============================================================================== + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/RefCountedPtr.h b/lib/LuaBridge/Source/LuaBridge/RefCountedPtr.h new file mode 100644 index 0000000..4db103f --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/RefCountedPtr.h @@ -0,0 +1,244 @@ +//============================================================================== +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + Copyright 2007, Nathan Reed + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include <unordered_map> +#include "RefCountedObject.h" + +namespace luabridge { + +//============================================================================== +/** + Support for our RefCountedPtr. +*/ +struct RefCountedPtrBase +{ + // Declaration of container for the refcounts + typedef std::unordered_map <const void *, int> RefCountsType; + +protected: + RefCountsType& getRefCounts () const + { + static RefCountsType refcounts; + return refcounts ; + } +}; + +//============================================================================== +/** + A reference counted smart pointer. + + The api is compatible with boost::RefCountedPtr and std::RefCountedPtr, in the + sense that it implements a strict subset of the functionality. + + This implementation uses a hash table to look up the reference count + associated with a particular pointer. + + @tparam T The class type. + + @todo Decompose RefCountedPtr using a policy. At a minimum, the underlying + reference count should be policy based (to support atomic operations) + and the delete behavior should be policy based (to support custom + disposal methods). + + @todo Provide an intrusive version of RefCountedPtr. +*/ +template <class T> +class RefCountedPtr : private RefCountedPtrBase +{ +public: + template <typename Other> + struct rebind + { + typedef RefCountedPtr <Other> other; + }; + + /** Construct as nullptr or from existing pointer to T. + + @param p The optional, existing pointer to assign from. + */ + RefCountedPtr (T* p = 0) : m_p (p) + { + ++getRefCounts () [m_p]; + } + + /** Construct from another RefCountedPtr. + + @param rhs The RefCountedPtr to assign from. + */ + RefCountedPtr (RefCountedPtr <T> const& rhs) : m_p (rhs.get()) + { + ++getRefCounts () [m_p]; + } + + /** Construct from a RefCountedPtr of a different type. + + @invariant A pointer to U must be convertible to a pointer to T. + + @param rhs The RefCountedPtr to assign from. + @tparam U The other object type. + */ + template <typename U> + RefCountedPtr (RefCountedPtr <U> const& rhs) : m_p (static_cast <T*> (rhs.get())) + { + ++getRefCounts () [m_p]; + } + + /** Release the object. + + If there are no more references then the object is deleted. + */ + ~RefCountedPtr () + { + reset(); + } + + /** Assign from another RefCountedPtr. + + @param rhs The RefCountedPtr to assign from. + @return A reference to the RefCountedPtr. + */ + RefCountedPtr <T>& operator= (RefCountedPtr <T> const& rhs) + { + if (m_p != rhs.m_p) + { + reset (); + m_p = rhs.m_p; + ++getRefCounts () [m_p]; + } + return *this; + } + + /** Assign from another RefCountedPtr of a different type. + + @note A pointer to U must be convertible to a pointer to T. + + @tparam U The other object type. + @param rhs The other RefCountedPtr to assign from. + @return A reference to the RefCountedPtr. + */ + template <typename U> + RefCountedPtr <T>& operator= (RefCountedPtr <U> const& rhs) + { + reset (); + m_p = static_cast <T*> (rhs.get()); + ++getRefCounts () [m_p]; + return *this; + } + + /** Retrieve the raw pointer. + + @return A pointer to the object. + */ + T* get () const + { + return m_p; + } + + /** Retrieve the raw pointer. + + @return A pointer to the object. + */ + T* operator* () const + { + return m_p; + } + + /** Retrieve the raw pointer. + + @return A pointer to the object. + */ + T* operator-> () const + { + return m_p; + } + + /** Determine the number of references. + + @note This is not thread-safe. + + @return The number of active references. + */ + long use_count () const + { + return getRefCounts () [m_p]; + } + + /** Release the pointer. + + The reference count is decremented. If the reference count reaches + zero, the object is deleted. + */ + void reset () + { + if (m_p != 0) + { + if (--getRefCounts () [m_p] <= 0) + delete m_p; + + m_p = 0; + } + } + +private: + T* m_p; +}; + +template <class T> +bool operator== (const RefCountedPtr <T>& lhs, const RefCountedPtr <T>& rhs) +{ + return lhs.get () == rhs.get (); +} + +template <class T> +bool operator!= (const RefCountedPtr <T>& lhs, const RefCountedPtr <T>& rhs) +{ + return lhs.get() != rhs.get(); +} + +//============================================================================== + +// forward declaration +template <class T> +struct ContainerTraits; + +template <class T> +struct ContainerTraits <RefCountedPtr <T> > +{ + typedef T Type; + + static T* get (RefCountedPtr <T> const& c) + { + return c.get (); + } +}; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/UnorderedMap.h b/lib/LuaBridge/Source/LuaBridge/UnorderedMap.h new file mode 100644 index 0000000..415996b --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/UnorderedMap.h @@ -0,0 +1,50 @@ +// https://github.com/vinniefalco/LuaBridge +// +// Copyright 2019, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#include <LuaBridge/detail/Stack.h> + +#include <unordered_map> + +namespace luabridge { + +template <class K, class V> +struct Stack <std::unordered_map <K, V>> +{ + typedef std::unordered_map <K, V> Map; + + static void push (lua_State* L, const Map& map) + { + lua_createtable (L, 0, static_cast <int> (map.size ())); + typedef typename Map::const_iterator ConstIter; + for (ConstIter i = map.begin (); i != map.end (); ++i) + { + Stack <K>::push (L, i->first); + Stack <V>::push (L, i->second); + lua_settable (L, -3); + } + } + + static Map get (lua_State* L, int index) + { + if (!lua_istable (L, index)) + { + luaL_error (L, "#%d argments must be table", index); + } + + Map map; + int const absindex = lua_absindex (L, index); + lua_pushnil (L); + while (lua_next (L, absindex) != 0) + { + map.emplace (Stack <K>::get (L, -2), Stack <V>::get (L, -1)); + lua_pop (L, 1); + } + return map; + } +}; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/Vector.h b/lib/LuaBridge/Source/LuaBridge/Vector.h new file mode 100644 index 0000000..f1b711d --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/Vector.h @@ -0,0 +1,49 @@ +// https://github.com/vinniefalco/LuaBridge +// +// Copyright 2018, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#include <LuaBridge/detail/Stack.h> + +#include <vector> + +namespace luabridge { + +template <class T> +struct Stack <std::vector <T> > +{ + static void push (lua_State* L, std::vector <T> const& vector) + { + lua_createtable (L, static_cast <int> (vector.size ()), 0); + for (std::size_t i = 0; i < vector.size (); ++i) + { + lua_pushinteger (L, static_cast <lua_Integer> (i + 1)); + Stack <T>::push (L, vector [i]); + lua_settable (L, -3); + } + } + + static std::vector <T> get (lua_State* L, int index) + { + if (!lua_istable (L, index)) + { + luaL_error (L, "#%d argments must be table", index); + } + + std::vector <T> vector; + vector.reserve (static_cast <std::size_t> (get_length (L, index))); + + int const absindex = lua_absindex (L, index); + lua_pushnil (L); + while (lua_next (L, absindex) != 0) + { + vector.push_back (Stack <T>::get (L, -1)); + lua_pop (L, 1); + } + return vector; + } +}; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/CFunctions.h b/lib/LuaBridge/Source/LuaBridge/detail/CFunctions.h new file mode 100644 index 0000000..d4ae0cc --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/CFunctions.h @@ -0,0 +1,495 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include <LuaBridge/detail/Config.h> +#include <LuaBridge/detail/FuncTraits.h> + +#include <string> + +namespace luabridge { + +// We use a structure so we can define everything in the header. +// +struct CFunc +{ + static void addGetter (lua_State* L, const char* name, int tableIndex) + { + assert (lua_istable (L, tableIndex)); + assert (lua_iscfunction (L, -1)); // Stack: getter + + lua_rawgetp (L, tableIndex, getPropgetKey ()); // Stack: getter, propget table (pg) + lua_pushvalue (L, -2); // Stack: getter, pg, getter + rawsetfield (L, -2, name); // Stack: getter, pg + lua_pop (L, 2); // Stack: - + } + + static void addSetter (lua_State* L, const char* name, int tableIndex) + { + assert (lua_istable (L, tableIndex)); + assert (lua_iscfunction (L, -1)); // Stack: setter + + lua_rawgetp (L, tableIndex, getPropsetKey ()); // Stack: setter, propset table (ps) + lua_pushvalue (L, -2); // Stack: setter, ps, setter + rawsetfield (L, -2, name); // Stack: setter, ps + lua_pop (L, 2); // Stack: - + } + + //---------------------------------------------------------------------------- + /** + __index metamethod for a namespace or class static and non-static members. + Retrieves functions from metatables and properties from propget tables. + Looks through the class hierarchy if inheritance is present. + */ + static int indexMetaMethod (lua_State* L) + { + assert (lua_istable (L, 1) || lua_isuserdata (L, 1)); // Stack (further not shown): table | userdata, name + + lua_getmetatable (L, 1); // Stack: class/const table (mt) + assert (lua_istable (L, -1)); + + for (;;) + { + lua_pushvalue (L, 2); // Stack: mt, field name + lua_rawget (L, -2); // Stack: mt, field | nil + + if (lua_iscfunction (L, -1)) // Stack: mt, field + { + lua_remove (L, -2); // Stack: field + return 1; + } + + assert (lua_isnil (L, -1)); // Stack: mt, nil + lua_pop (L, 1); // Stack: mt + + lua_rawgetp (L, -1, getPropgetKey ()); // Stack: mt, propget table (pg) + assert (lua_istable (L, -1)); + + lua_pushvalue (L, 2); // Stack: mt, pg, field name + lua_rawget (L, -2); // Stack: mt, pg, getter | nil + lua_remove (L, -2); // Stack: mt, getter | nil + + if (lua_iscfunction (L, -1)) // Stack: mt, getter + { + lua_remove (L, -2); // Stack: getter + lua_pushvalue (L, 1); // Stack: getter, table | userdata + lua_call (L, 1, 1); // Stack: value + return 1; + } + + assert (lua_isnil (L, -1)); // Stack: mt, nil + lua_pop (L, 1); // Stack: mt + + // It may mean that the field may be in const table and it's constness violation. + // Don't check that, just return nil + + // Repeat the lookup in the parent metafield, + // or return nil if the field doesn't exist. + lua_rawgetp (L, -1, getParentKey ()); // Stack: mt, parent mt | nil + + if (lua_isnil (L, -1)) // Stack: mt, nil + { + lua_remove (L, -2); // Stack: nil + return 1; + } + + // Removethe metatable and repeat the search in the parent one. + assert (lua_istable (L, -1)); // Stack: mt, parent mt + lua_remove (L, -2); // Stack: parent mt + } + + // no return + } + + //---------------------------------------------------------------------------- + /** + __newindex metamethod for namespace or class static members. + Retrieves properties from propset tables. + */ + static int newindexStaticMetaMethod (lua_State* L) + { + return newindexMetaMethod (L, false); + } + + //---------------------------------------------------------------------------- + /** + __newindex metamethod for non-static members. + Retrieves properties from propset tables. + */ + static int newindexObjectMetaMethod (lua_State* L) + { + return newindexMetaMethod (L, true); + } + + static int newindexMetaMethod (lua_State* L, bool pushSelf) + { + assert (lua_istable (L, 1) || lua_isuserdata (L, 1)); // Stack (further not shown): table | userdata, name, new value + + lua_getmetatable (L, 1); // Stack: metatable (mt) + assert (lua_istable (L, -1)); + + for (;;) + { + lua_rawgetp (L, -1, getPropsetKey ()); // Stack: mt, propset table (ps) | nil + + if (lua_isnil (L, -1)) // Stack: mt, nil + { + lua_pop (L, 2); // Stack: - + return luaL_error (L, "No member named '%s'", lua_tostring (L, 2)); + } + + assert (lua_istable (L, -1)); + + lua_pushvalue (L, 2); // Stack: mt, ps, field name + lua_rawget (L, -2); // Stack: mt, ps, setter | nil + lua_remove (L, -2); // Stack: mt, setter | nil + + if (lua_iscfunction (L, -1)) // Stack: mt, setter + { + lua_remove (L, -2); // Stack: setter + if (pushSelf) + { + lua_pushvalue (L, 1); // Stack: setter, table | userdata + } + lua_pushvalue (L, 3); // Stack: setter, table | userdata, new value + lua_call (L, pushSelf ? 2 : 1, 0); // Stack: - + return 0; + } + + assert (lua_isnil (L, -1)); // Stack: mt, nil + lua_pop (L, 1); // Stack: mt + + lua_rawgetp (L, -1, getParentKey ()); // Stack: mt, parent mt | nil + + if (lua_isnil (L, -1)) // Stack: mt, nil + { + lua_pop (L, 1); // Stack: - + return luaL_error (L, "No writable member '%s'", lua_tostring (L, 2)); + } + + assert (lua_istable (L, -1)); // Stack: mt, parent mt + lua_remove (L, -2); // Stack: parent mt + // Repeat the search in the parent + } + + // no return + } + + //---------------------------------------------------------------------------- + /** + lua_CFunction to report an error writing to a read-only value. + + The name of the variable is in the first upvalue. + */ + static int readOnlyError (lua_State* L) + { + std::string s; + + s = s + "'" + lua_tostring (L, lua_upvalueindex (1)) + "' is read-only"; + + return luaL_error (L, s.c_str ()); + } + + //---------------------------------------------------------------------------- + /** + lua_CFunction to get a variable. + + This is used for global variables or class static data members. + + The pointer to the data is in the first upvalue. + */ + template <class T> + static int getVariable (lua_State* L) + { + assert (lua_islightuserdata (L, lua_upvalueindex (1))); + T const* ptr = static_cast <T const*> (lua_touserdata (L, lua_upvalueindex (1))); + assert (ptr != 0); + Stack <T>::push (L, *ptr); + return 1; + } + + //---------------------------------------------------------------------------- + /** + lua_CFunction to set a variable. + + This is used for global variables or class static data members. + + The pointer to the data is in the first upvalue. + */ + template <class T> + static int setVariable (lua_State* L) + { + assert (lua_islightuserdata (L, lua_upvalueindex (1))); + T* ptr = static_cast <T*> (lua_touserdata (L, lua_upvalueindex (1))); + assert (ptr != 0); + *ptr = Stack <T>::get (L, 1); + return 0; + } + + //---------------------------------------------------------------------------- + /** + lua_CFunction to call a function with a return value. + + This is used for global functions, global properties, class static methods, + and class static properties. + + The function pointer (lightuserdata) in the first upvalue. + */ + template <class FnPtr> + struct Call + { + typedef typename FuncTraits <FnPtr>::Params Params; + typedef typename FuncTraits <FnPtr>::ReturnType ReturnType; + + static int f (lua_State* L) + { + assert (lua_islightuserdata (L, lua_upvalueindex (1))); + FnPtr fnptr = reinterpret_cast <FnPtr> (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + return Invoke <ReturnType, Params, 1>::run (L, fnptr); + } + }; + + //---------------------------------------------------------------------------- + /** + lua_CFunction to call a class member function with a return value. + + The member function pointer is in the first upvalue. + The class userdata object is at the top of the Lua stack. + */ + template <class MemFnPtr> + struct CallMember + { + typedef typename FuncTraits <MemFnPtr>::ClassType T; + typedef typename FuncTraits <MemFnPtr>::Params Params; + typedef typename FuncTraits <MemFnPtr>::ReturnType ReturnType; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + T* const t = Userdata::get <T> (L, 1, false); + MemFnPtr const& fnptr = *static_cast <MemFnPtr const*> (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + return Invoke <ReturnType, Params, 2>::run (L, t, fnptr); + } + }; + + template <class MemFnPtr> + struct CallConstMember + { + typedef typename FuncTraits <MemFnPtr>::ClassType T; + typedef typename FuncTraits <MemFnPtr>::Params Params; + typedef typename FuncTraits <MemFnPtr>::ReturnType ReturnType; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + T const* const t = Userdata::get <T> (L, 1, true); + MemFnPtr const& fnptr = *static_cast <MemFnPtr const*> (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + return Invoke <ReturnType, Params, 2>::run (L, t, fnptr); + } + }; + + //-------------------------------------------------------------------------- + /** + lua_CFunction to call a class member lua_CFunction. + + The member function pointer is in the first upvalue. + The object userdata ('this') value is at top ot the Lua stack. + */ + template <class T> + struct CallMemberCFunction + { + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + typedef int (T::*MFP) (lua_State* L); + T* const t = Userdata::get <T> (L, 1, false); + MFP const& fnptr = *static_cast <MFP const*> (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + return (t->*fnptr) (L); + } + }; + + template <class T> + struct CallConstMemberCFunction + { + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + typedef int (T::*MFP) (lua_State* L); + T const* const t = Userdata::get <T> (L, 1, true); + MFP const& fnptr = *static_cast <MFP const*> (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + return (t->*fnptr) (L); + } + }; + +#ifdef LUABRIDGE_CXX11 + + //-------------------------------------------------------------------------- + /** + lua_CFunction to call on a object. + + The proxy function pointer (lightuserdata) is in the first upvalue. + The class userdata object is at the top of the Lua stack. + */ + template <class FnPtr> + struct CallProxyFunction + { + using Params = typename FuncTraits <FnPtr>::Params; + using ReturnType = typename FuncTraits <FnPtr>::ReturnType; + + static int f (lua_State* L) + { + assert (lua_islightuserdata (L, lua_upvalueindex (1))); + auto fnptr = reinterpret_cast <FnPtr> (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + return Invoke <ReturnType, Params, 1>::run (L, fnptr); + } + }; + + template <class Functor> + struct CallProxyFunctor + { + using Params = typename FuncTraits <Functor>::Params; + using ReturnType = typename FuncTraits <Functor>::ReturnType; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + Functor& fn = *static_cast <Functor*> (lua_touserdata (L, lua_upvalueindex (1))); + return Invoke <ReturnType, Params, 1>::run (L, fn); + } + }; + +#endif + + //-------------------------------------------------------------------------- + + // SFINAE Helpers + + template <class MemFnPtr, bool isConst> + struct CallMemberFunctionHelper + { + static void add (lua_State* L, char const* name, MemFnPtr mf) + { + new (lua_newuserdata (L, sizeof (MemFnPtr))) MemFnPtr (mf); + lua_pushcclosure (L, &CallConstMember <MemFnPtr>::f, 1); + lua_pushvalue (L, -1); + rawsetfield (L, -5, name); // const table + rawsetfield (L, -3, name); // class table + } + }; + + template <class MemFnPtr> + struct CallMemberFunctionHelper <MemFnPtr, false> + { + static void add (lua_State* L, char const* name, MemFnPtr mf) + { + new (lua_newuserdata (L, sizeof (MemFnPtr))) MemFnPtr (mf); + lua_pushcclosure (L, &CallMember <MemFnPtr>::f, 1); + rawsetfield (L, -3, name); // class table + } + }; + + //-------------------------------------------------------------------------- + /** + __gc metamethod for a class. + */ + template <class C> + static int gcMetaMethod (lua_State* L) + { + Userdata* const ud = Userdata::getExact <C> (L, 1); + ud->~Userdata (); + return 0; + } + + /** + __gc metamethod for an arbitrary class. + */ + template <class T> + static int gcMetaMethodAny (lua_State* L) + { + assert (isfulluserdata (L, 1)); + T* t = static_cast <T*> (lua_touserdata (L, 1)); + t->~T (); + return 0; + } + + //-------------------------------------------------------------------------- + /** + lua_CFunction to get a class data member. + + The pointer-to-member is in the first upvalue. + The class userdata object is at the top of the Lua stack. + */ + template <class C, typename T> + static int getProperty (lua_State* L) + { + C* const c = Userdata::get <C> (L, 1, true); + T C::** mp = static_cast <T C::**> (lua_touserdata (L, lua_upvalueindex (1))); + try + { + Stack <T&>::push (L, c->**mp); + } + catch (const std::exception& e) + { + luaL_error (L, e.what ()); + } + return 1; + } + + //-------------------------------------------------------------------------- + /** + lua_CFunction to set a class data member. + + The pointer-to-member is in the first upvalue. + The class userdata object is at the top of the Lua stack. + */ + template <class C, typename T> + static int setProperty (lua_State* L) + { + C* const c = Userdata::get <C> (L, 1, false); + T C::** mp = static_cast <T C::**> (lua_touserdata (L, lua_upvalueindex (1))); + try + { + c->**mp = Stack <T>::get (L, 2); + } + catch (const std::exception& e) + { + luaL_error (L, e.what ()); + } + return 0; + } +}; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/ClassInfo.h b/lib/LuaBridge/Source/LuaBridge/detail/ClassInfo.h new file mode 100644 index 0000000..ca83f93 --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/ClassInfo.h @@ -0,0 +1,169 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +namespace luabridge { + +/** + * A unique key for a type name in a metatable. + */ +inline const void* getTypeKey () +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast <void*> (0x71); +#endif +} + +/** + * The key of a const table in another metatable. + */ +inline const void* getConstKey () +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast <void*> (0xc07); +#endif +} + +/** + * The key of a class table in another metatable. + */ +inline const void* getClassKey () +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast <void*> (0xc1a); +#endif +} + +/** + * The key of a propget table in another metatable. + */ +inline const void* getPropgetKey () +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast <void*> (0x6e7); +#endif +} + +/** + * The key of a propset table in another metatable. + */ +inline const void* getPropsetKey () +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast <void*> (0x5e7); +#endif +} + +/** + * The key of a static table in another metatable. + */ +inline const void* getStaticKey () +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast <void*> (0x57a); +#endif +} + +/** + * The key of a parent table in another metatable. + */ +inline const void* getParentKey () +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast <void*> (0xdad); +#endif +} + +/** Unique Lua registry keys for a class. + + Each registered class inserts three keys into the registry, whose + values are the corresponding static, class, and const metatables. This + allows a quick and reliable lookup for a metatable from a template type. +*/ +template <class T> +class ClassInfo +{ +public: + /** Get the key for the static table. + + The static table holds the static data members, static properties, and + static member functions for a class. + */ + static void const* getStaticKey () + { + static char value; + return &value; + } + + /** Get the key for the class table. + + The class table holds the data members, properties, and member functions + of a class. Read-only data and properties, and const member functions are + also placed here (to save a lookup in the const table). + */ + static void const* getClassKey () + { + static char value; + return &value; + } + + /** Get the key for the const table. + + The const table holds read-only data members and properties, and const + member functions of a class. + */ + static void const* getConstKey () + { + static char value; + return &value; + } +}; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/Config.h b/lib/LuaBridge/Source/LuaBridge/detail/Config.h new file mode 100644 index 0000000..76b3d42 --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/Config.h @@ -0,0 +1,10 @@ +// https://github.com/vinniefalco/LuaBridge +// +// Copyright 2019, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#if !defined (LUABRIDGE_NO_CXX11) && (__cplusplus >= 201103L || (defined (_MSC_VER) && _MSC_VER >= 1900)) +#define LUABRIDGE_CXX11 +#endif diff --git a/lib/LuaBridge/Source/LuaBridge/detail/Constructor.h b/lib/LuaBridge/Source/LuaBridge/detail/Constructor.h new file mode 100644 index 0000000..04b3dab --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/Constructor.h @@ -0,0 +1,205 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + Copyright 2007, Nathan Reed + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +namespace luabridge { + +/* +* Constructor generators. These templates allow you to call operator new and +* pass the contents of a type/value list to the Constructor. Like the +* function pointer containers, these are only defined up to 8 parameters. +*/ + +/** Constructor generators. + + These templates call operator new with the contents of a type/value + list passed to the Constructor with up to 8 parameters. Two versions + of call() are provided. One performs a regular new, the other performs + a placement new. +*/ +template <class T, typename List> +struct Constructor {}; + +template <class T> +struct Constructor <T, None> +{ + static T* call (TypeListValues <None> const&) + { + return new T; + } + static T* call (void* mem, TypeListValues <None> const&) + { + return new (mem) T; + } +}; + +template <class T, class P1> +struct Constructor <T, TypeList <P1> > +{ + static T* call (const TypeListValues<TypeList <P1> > &tvl) + { + return new T(tvl.hd); + } + static T* call (void* mem, const TypeListValues<TypeList <P1> > &tvl) + { + return new (mem) T(tvl.hd); + } +}; + +template <class T, class P1, class P2> +struct Constructor <T, TypeList <P1, TypeList <P2> > > +{ + static T* call (const TypeListValues<TypeList <P1, TypeList <P2> > > &tvl) + { + return new T(tvl.hd, tvl.tl.hd); + } + static T* call (void* mem, const TypeListValues<TypeList <P1, TypeList <P2> > > &tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd); + } +}; + +template <class T, class P1, class P2, class P3> +struct Constructor <T, TypeList <P1, TypeList <P2, TypeList <P3> > > > +{ + static T* call (const TypeListValues<TypeList <P1, TypeList <P2, + TypeList <P3> > > > &tvl) + { + return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); + } + static T* call (void* mem, const TypeListValues<TypeList <P1, TypeList <P2, + TypeList <P3> > > > &tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); + } +}; + +template <class T, class P1, class P2, class P3, class P4> +struct Constructor <T, TypeList <P1, TypeList <P2, TypeList <P3, + TypeList <P4> > > > > +{ + static T* call (const TypeListValues<TypeList <P1, TypeList <P2, + TypeList <P3, TypeList <P4> > > > > &tvl) + { + return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd); + } + static T* call (void* mem, const TypeListValues<TypeList <P1, TypeList <P2, + TypeList <P3, TypeList <P4> > > > > &tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd); + } +}; + +template <class T, class P1, class P2, class P3, class P4, + class P5> +struct Constructor <T, TypeList <P1, TypeList <P2, TypeList <P3, + TypeList <P4, TypeList <P5> > > > > > +{ + static T* call (const TypeListValues<TypeList <P1, TypeList <P2, + TypeList <P3, TypeList <P4, TypeList <P5> > > > > > &tvl) + { + return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd); + } + static T* call (void* mem, const TypeListValues<TypeList <P1, TypeList <P2, + TypeList <P3, TypeList <P4, TypeList <P5> > > > > > &tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd); + } +}; + +template <class T, class P1, class P2, class P3, class P4, + class P5, class P6> +struct Constructor <T, TypeList <P1, TypeList <P2, TypeList <P3, + TypeList <P4, TypeList <P5, TypeList <P6> > > > > > > +{ + static T* call (const TypeListValues<TypeList <P1, TypeList <P2, + TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6> > > > > > > &tvl) + { + return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd); + } + static T* call (void* mem, const TypeListValues<TypeList <P1, TypeList <P2, + TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6> > > > > > > &tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd); + } +}; + +template <class T, class P1, class P2, class P3, class P4, + class P5, class P6, class P7> +struct Constructor <T, TypeList <P1, TypeList <P2, TypeList <P3, + TypeList <P4, TypeList <P5, TypeList <P6, TypeList <P7> > > > > > > > +{ + static T* call (const TypeListValues<TypeList <P1, TypeList <P2, + TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6, + TypeList <P7> > > > > > > > &tvl) + { + return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd); + } + static T* call (void* mem, const TypeListValues<TypeList <P1, TypeList <P2, + TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6, + TypeList <P7> > > > > > > > &tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd); + } +}; + +template <class T, class P1, class P2, class P3, class P4, + class P5, class P6, class P7, class P8> +struct Constructor <T, TypeList <P1, TypeList <P2, TypeList <P3, + TypeList <P4, TypeList <P5, TypeList <P6, TypeList <P7, + TypeList <P8> > > > > > > > > +{ + static T* call (const TypeListValues<TypeList <P1, TypeList <P2, + TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6, + TypeList <P7, TypeList <P8> > > > > > > > > &tvl) + { + return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.tl.hd); + } + static T* call (void* mem, const TypeListValues<TypeList <P1, TypeList <P2, + TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6, + TypeList <P7, TypeList <P8> > > > > > > > > &tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.tl.hd); + } +}; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/FuncTraits.h b/lib/LuaBridge/Source/LuaBridge/detail/FuncTraits.h new file mode 100644 index 0000000..a66e296 --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/FuncTraits.h @@ -0,0 +1,942 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include <LuaBridge/detail/Config.h> + +#ifdef LUABRIDGE_CXX11 +#include <functional> +#endif + +namespace luabridge { + +/** + Since the throw specification is part of a function signature, the FuncTraits + family of templates needs to be specialized for both types. The + LUABRIDGE_THROWSPEC macro controls whether we use the 'throw ()' form, or + 'noexcept' (if C++11 is available) to distinguish the functions. +*/ +#if defined (__APPLE_CPP__) || defined (__APPLE_CC__) || defined (__clang__) || defined (__GNUC__) || \ + (defined (_MSC_VER) && (_MSC_VER >= 1700)) +// Do not define LUABRIDGE_THROWSPEC since the Xcode and gcc compilers do not +// distinguish the throw specification in the function signature. +#define LUABRIDGE_THROWSPEC +#else +// Visual Studio 10 and earlier pay too much mind to useless throw () spec. +// +# define LUABRIDGE_THROWSPEC throw () +#endif + +//============================================================================== +/** + * Traits class for unrolling the type list values into function arguments. + */ +template <class ReturnType, size_t NUM_PARAMS> +struct Caller; + +template <class ReturnType> +struct Caller <ReturnType, 0> +{ + template <class Fn, class Params> + static ReturnType f (Fn& fn, TypeListValues <Params>& params) + { + return fn (); + } + + template <class T, class MemFn, class Params> + static ReturnType f (T* obj, MemFn& fn, TypeListValues <Params>&) + { + return (obj->*fn) (); + } +}; + +template <class ReturnType> +struct Caller <ReturnType, 1> +{ + template <class Fn, class Params> + static ReturnType f (Fn& fn, TypeListValues <Params>& tvl) + { + return fn (tvl.hd); + } + + template <class T, class MemFn, class Params> + static ReturnType f (T* obj, MemFn& fn, TypeListValues <Params>& tvl) + { + return (obj->*fn) (tvl.hd); + } +}; + +template <class ReturnType> +struct Caller <ReturnType, 2> +{ + template <class Fn, class Params> + static ReturnType f (Fn& fn, TypeListValues <Params>& tvl) + { + return fn (tvl.hd, tvl.tl.hd); + } + + template <class T, class MemFn, class Params> + static ReturnType f (T* obj, MemFn& fn, TypeListValues <Params>& tvl) + { + return (obj->*fn) (tvl.hd, tvl.tl.hd); + } +}; + +template <class ReturnType> +struct Caller <ReturnType, 3> +{ + template <class Fn, class Params> + static ReturnType f (Fn& fn, TypeListValues <Params>& tvl) + { + return fn (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); + } + + template <class T, class MemFn, class Params> + static ReturnType f (T* obj, MemFn& fn, TypeListValues <Params>& tvl) + { + return (obj->*fn) (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); + } +}; + +template <class ReturnType> +struct Caller <ReturnType, 4> +{ + template <class Fn, class Params> + static ReturnType f (Fn& fn, TypeListValues <Params>& tvl) + { + return fn (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd); + } + + template <class T, class MemFn, class Params> + static ReturnType f (T* obj, MemFn& fn, TypeListValues <Params>& tvl) + { + return (obj->*fn) (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd); + } +}; + +template <class ReturnType> +struct Caller <ReturnType, 5> +{ + template <class Fn, class Params> + static ReturnType f (Fn& fn, TypeListValues <Params>& tvl) + { + return fn (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd); + } + + template <class T, class MemFn, class Params> + static ReturnType f (T* obj, MemFn& fn, TypeListValues <Params>& tvl) + { + return (obj->*fn) (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd); + } +}; + +template <class ReturnType> +struct Caller <ReturnType, 6> +{ + template <class Fn, class Params> + static ReturnType f (Fn& fn, TypeListValues <Params>& tvl) + { + return fn (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd); + } + + template <class T, class MemFn, class Params> + static ReturnType f (T* obj, MemFn& fn, TypeListValues <Params>& tvl) + { + return (obj->*fn) (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd); + } +}; + +template <class ReturnType> +struct Caller <ReturnType, 7> +{ + template <class Fn, class Params> + static ReturnType f (Fn& fn, TypeListValues <Params>& tvl) + { + return fn (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.hd); + } + + template <class T, class MemFn, class Params> + static ReturnType f (T* obj, MemFn& fn, TypeListValues <Params>& tvl) + { + return (obj->*fn) (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.hd); + } +}; + +template <class ReturnType> +struct Caller <ReturnType, 8> +{ + template <class Fn, class Params> + static ReturnType f (Fn& fn, TypeListValues <Params>& tvl) + { + return fn (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.tl.hd); + } + + template <class T, class MemFn, class Params> + static ReturnType f (T* obj, MemFn& fn, TypeListValues <Params>& tvl) + { + return (obj->*fn) (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.tl.hd); + } +}; + +template <class ReturnType> +struct Caller <ReturnType, 9> +{ + template <class Fn, class Params> + static ReturnType f (Fn& fn, TypeListValues <Params>& tvl) + { + return fn (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.tl.tl.hd); + } + + template <class T, class MemFn, class Params> + static ReturnType f (T* obj, MemFn& fn, TypeListValues <Params>& tvl) + { + return (obj->*fn) (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.tl.tl.hd); + } +}; + +template <class ReturnType, class Fn, class Params> +ReturnType doCall (Fn& fn, TypeListValues <Params>& tvl) +{ + return Caller <ReturnType, TypeListSize <Params>::value>::f (fn, tvl); +} + +template <class ReturnType, class T, class MemFn, class Params> +static ReturnType doCall(T* obj, MemFn& fn, TypeListValues <Params>& tvl) +{ + return Caller <ReturnType, TypeListSize <Params>::value>::f (obj, fn, tvl); +} + +//============================================================================== +/** + Traits for function pointers. + + There are three types of functions: global, non-const member, and const + member. These templates determine the type of function, which class type it + belongs to if it is a class member, the const-ness if it is a member + function, and the type information for the return value and argument list. + + Expansions are provided for functions with up to 8 parameters. This can be + manually extended, or expanded to an arbitrary amount using C++11 features. +*/ +template <class MemFn, class D = MemFn> +struct FuncTraits +{ +}; + +#ifndef LUABRIDGE_CXX11 + +/* Ordinary function pointers. */ + +template <class R, class D> +struct FuncTraits <R (*) () LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef None Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class D> +struct FuncTraits <R (*) (P1) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1> Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class D> +struct FuncTraits <R (*) (P1, P2) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2> > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class P3, class D> +struct FuncTraits <R (*) (P1, P2, P3) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3> > > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class P3, class P4, class D> +struct FuncTraits <R (*) (P1, P2, P3, P4) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4> > > > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class P3, class P4, class P5, class D> +struct FuncTraits <R (*) (P1, P2, P3, P4, P5) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5> > > > > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class P3, class P4, class P5, class P6, class D> +struct FuncTraits <R (*) (P1, P2, P3, P4, P5, P6) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6> > > > > > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class D> +struct FuncTraits <R (*) (P1, P2, P3, P4, P5, P6, P7) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6, TypeList <P7> > > > > > > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class D> +struct FuncTraits <R (*) (P1, P2, P3, P4, P5, P6, P7, P8) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6, TypeList <P7, TypeList <P8> > > > > > > > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +/* Windows: WINAPI (a.k.a. __stdcall) function pointers. */ + +#ifdef _M_IX86 // Windows 32bit only + +template <class R, class D> +struct FuncTraits <R (__stdcall *) (), D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef None Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class D> +struct FuncTraits <R (__stdcall *) (P1), D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1> Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class D> +struct FuncTraits <R (__stdcall *) (P1, P2), D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2> > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class P3, class D> +struct FuncTraits <R (__stdcall *) (P1, P2, P3), D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3> > > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class P3, class P4, class D> +struct FuncTraits <R (__stdcall *) (P1, P2, P3, P4), D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4> > > > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class P3, class P4, class P5, class D> +struct FuncTraits <R (__stdcall *) (P1, P2, P3, P4, P5), D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5> > > > > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class P3, class P4, class P5, class P6, class D> +struct FuncTraits <R (__stdcall *) (P1, P2, P3, P4, P5, P6), D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6> > > > > > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class D> +struct FuncTraits <R (__stdcall *) (P1, P2, P3, P4, P5, P6, P7), D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6, TypeList <P7> > > > > > > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +template <class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class D> +struct FuncTraits <R (__stdcall *) (P1, P2, P3, P4, P5, P6, P7, P8), D> +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6, TypeList <P7, TypeList <P8> > > > > > > > Params; + static R call (D fp, TypeListValues <Params> tvl) + { + return doCall <R> (fp, tvl); + } +}; + +#endif // _M_IX86 + +/* Non-const member function pointers. */ + +template <class T, class R, class D> +struct FuncTraits <R (T::*) () LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef None Params; + static R call (T* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class D> +struct FuncTraits <R (T::*) (P1) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1> Params; + static R call (T* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class D> +struct FuncTraits <R (T::*) (P1, P2) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2> > Params; + static R call (T* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class P3, class D> +struct FuncTraits <R (T::*) (P1, P2, P3) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3> > > Params; + static R call (T* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class P3, class P4, class D> +struct FuncTraits <R (T::*) (P1, P2, P3, P4) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4> > > > Params; + static R call (T* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class P3, class P4, class P5, class D> +struct FuncTraits <R (T::*) (P1, P2, P3, P4, P5) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5> > > > > Params; + static R call (T* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class P3, class P4, class P5, class P6, class D> +struct FuncTraits <R (T::*) (P1, P2, P3, P4, P5, P6) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6> > > > > > Params; + static R call (T* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class D> +struct FuncTraits <R (T::*) (P1, P2, P3, P4, P5, P6, P7) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6, TypeList <P7> > > > > > > Params; + static R call (T* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class D> +struct FuncTraits <R (T::*) (P1, P2, P3, P4, P5, P6, P7, P8) LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6, TypeList <P7, TypeList <P8> > > > > > > > Params; + static R call (T* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +/* Const member function pointers. */ + +template <class T, class R, class D> +struct FuncTraits <R (T::*) () const LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef None Params; + static R call (T const* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class D> +struct FuncTraits <R (T::*) (P1) const LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1> Params; + static R call (T const* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class D> +struct FuncTraits <R (T::*) (P1, P2) const LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2> > Params; + static R call (T const* obj, R (T::*fp) (P1, P2) const, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class P3, class D> +struct FuncTraits <R (T::*) (P1, P2, P3) const LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3> > > Params; + static R call (T const* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class P3, class P4, class D> +struct FuncTraits <R (T::*) (P1, P2, P3, P4) const LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4> > > > Params; + static R call (T const* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class P3, class P4, class P5, class D> +struct FuncTraits <R (T::*) (P1, P2, P3, P4, P5) const LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5> > > > > Params; + static R call (T const* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class P3, class P4, class P5, class P6, class D> +struct FuncTraits <R (T::*) (P1, P2, P3, P4, P5, P6) const LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6> > > > > > Params; + static R call (T const* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class D> +struct FuncTraits <R (T::*) (P1, P2, P3, P4, P5, P6, P7) const LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6, TypeList <P7> > > > > > > Params; + static R call (T const* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +template <class T, class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class D> +struct FuncTraits <R (T::*) (P1, P2, P3, P4, P5, P6, P7, P8) const LUABRIDGE_THROWSPEC, D> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList <P1, TypeList <P2, TypeList <P3, TypeList <P4, TypeList <P5, TypeList <P6, TypeList <P7, TypeList <P8> > > > > > > > Params; + static R call (T const* obj, D fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +#else // ifndef LUABRIDGE_CXX11 + +/* Ordinary function pointers. */ + +template <class R, class... ParamList> +struct FuncTraits <R (*) (ParamList...)> +{ + static bool const isMemberFunction = false; + using DeclType = R (*) (ParamList...); + using ReturnType = R; + using Params = typename MakeTypeList <ParamList...>::Result; + + static R call (const DeclType& fp, TypeListValues <Params>& tvl) + { + return doCall <R> (fp, tvl); + } +}; + +/* Windows: WINAPI (a.k.a. __stdcall) function pointers. */ + +#ifdef _M_IX86 // Windows 32bit only + +template <class R, class... ParamList> +struct FuncTraits <R (__stdcall *) (ParamList...)> +{ + static bool const isMemberFunction = false; + using DeclType = R (__stdcall *) (ParamList...); + using ReturnType = R; + using Params = typename MakeTypeList <ParamList...>::Result; + + static R call (const DeclType& fp, TypeListValues <Params>& tvl) + { + return doCall <R> (fp, tvl); + } +}; + +#endif // _M_IX86 + +/* Non-const member function pointers. */ + +template <class T, class R, class... ParamList> +struct FuncTraits <R (T::*) (ParamList...)> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + using DeclType = R (T::*) (ParamList...); + using ClassType = T; + using ReturnType = R; + using Params = typename MakeTypeList <ParamList...>::Result; + + static R call (ClassType* obj, const DeclType& fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +/* Const member function pointers. */ + +template <class T, class R, class... ParamList> +struct FuncTraits <R (T::*) (ParamList...) const> +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + using DeclType = R (T::*) (ParamList...) const; + using ClassType = T; + using ReturnType = R; + using Params = typename MakeTypeList <ParamList...>::Result; + + static R call (const ClassType* obj, const DeclType& fp, TypeListValues <Params> tvl) + { + return doCall <R> (obj, fp, tvl); + } +}; + +/* std::function */ + +template <class R, class... ParamList> +struct FuncTraits <std::function <R (ParamList...)>> +{ + static bool const isMemberFunction = false; + static bool const isConstMemberFunction = false; + using DeclType = std::function <R (ParamList...)>; + using ReturnType = R; + using Params = typename MakeTypeList <ParamList...>::Result; + + static ReturnType call (DeclType& fn, TypeListValues <Params>& tvl) + { + return doCall <ReturnType> (fn, tvl); + } +}; + +#endif // ifndef LUABRIDGE_CXX11 + +template <class ReturnType, class Params, int startParam> +struct Invoke +{ + template <class Fn> + static int run (lua_State* L, Fn& fn) + { + try + { + ArgList <Params, startParam> args (L); + Stack <ReturnType>::push (L, FuncTraits <Fn>::call (fn, args)); + return 1; + } + catch (const std::exception& e) + { + return luaL_error (L, e.what ()); + } + } + + template <class T, class MemFn> + static int run (lua_State* L, T* object, const MemFn& fn) + { + try + { + ArgList <Params, startParam> args (L); + Stack <ReturnType>::push (L, FuncTraits <MemFn>::call (object, fn, args)); + return 1; + } + catch (const std::exception& e) + { + return luaL_error (L, e.what ()); + } + } +}; + +template <class Params, int startParam> +struct Invoke <void, Params, startParam> +{ + template <class Fn> + static int run (lua_State* L, Fn& fn) + { + try + { + ArgList <Params, startParam> args (L); + FuncTraits <Fn>::call (fn, args); + return 0; + } + catch (const std::exception& e) + { + return luaL_error (L, e.what ()); + } + } + + template <class T, class MemFn> + static int run (lua_State* L, T* object, const MemFn& fn) + { + try + { + ArgList <Params, startParam> args (L); + FuncTraits <MemFn>::call (object, fn, args); + return 0; + } + catch (const std::exception& e) + { + return luaL_error (L, e.what ()); + } + } +}; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/Iterator.h b/lib/LuaBridge/Source/LuaBridge/detail/Iterator.h new file mode 100644 index 0000000..6c17623 --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/Iterator.h @@ -0,0 +1,154 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2018, Dmitry Tarakanov + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include <LuaBridge/detail/LuaRef.h> + +#include <utility> + + +namespace luabridge { + +/** Allows table iteration. +*/ +class Iterator +{ + lua_State* m_L; + LuaRef m_table; + LuaRef m_key; + LuaRef m_value; + + void next () + { + m_table.push (); + m_key.push (); + if (lua_next (m_L, -2)) + { + m_value.pop (); + m_key.pop (); + } + else + { + m_key = Nil (); + m_value = Nil (); + } + lua_pop (m_L, 1); + } + +public: + explicit Iterator (const LuaRef& table, bool isEnd = false) + : m_L (table.state ()) + , m_table (table) + , m_key (table.state ()) // m_key is nil + , m_value (table.state ()) // m_value is nil + { + if (!isEnd) + { + next (); // get the first (key, value) pair from table + } + } + + lua_State* state () const + { + return m_L; + } + + std::pair <LuaRef, LuaRef> operator* () const + { + return std::make_pair (m_key, m_value); + } + + LuaRef operator-> () const + { + return m_value; + } + + bool operator!= (const Iterator& rhs) const + { + assert (m_L == rhs.m_L); + return !m_table.rawequal (rhs.m_table) || !m_key.rawequal (rhs.m_key); + } + + Iterator& operator++ () + { + if (isNil ()) + { + // if the iterator reaches the end, do nothing + return *this; + } + else + { + next (); + return *this; + } + } + + bool isNil () const + { + return m_key.isNil (); + } + + LuaRef key () const + { + return m_key; + } + + LuaRef value () const + { + return m_value; + } + +private: + // Don't use postfix increment, it is less efficient + Iterator operator++ (int); +}; + +class Range +{ + Iterator m_begin; + Iterator m_end; + +public: + Range (const Iterator& begin, const Iterator& end) + : m_begin (begin) + , m_end (end) + { + } + + const Iterator& begin () const { return m_begin; } + const Iterator& end () const { return m_end; } +}; + +inline Range pairs (const LuaRef& table) +{ + return Range (Iterator (table, false), Iterator (table, true)); +} + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/LuaException.h b/lib/LuaBridge/Source/LuaBridge/detail/LuaException.h new file mode 100644 index 0000000..6ca9818 --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/LuaException.h @@ -0,0 +1,122 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + Copyright 2008, Nigel Atkinson <suprapilot+LuaCode@gmail.com> + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include <exception> +#include <string> + +namespace luabridge { + +class LuaException : public std::exception +{ +private: + lua_State* m_L; + std::string m_what; + +public: + //---------------------------------------------------------------------------- + /** + Construct a LuaException after a lua_pcall(). + */ + LuaException (lua_State* L, int /*code*/) + : m_L (L) + { + whatFromStack (); + } + + //---------------------------------------------------------------------------- + + LuaException (lua_State *L, + char const*, + char const*, + long) + : m_L (L) + { + whatFromStack (); + } + + //---------------------------------------------------------------------------- + + ~LuaException() throw () + { + } + + //---------------------------------------------------------------------------- + + char const* what() const throw () + { + return m_what.c_str(); + } + + //============================================================================ + /** + Throw an exception. + + This centralizes all the exceptions thrown, so that we can set + breakpoints before the stack is unwound, or otherwise customize the + behavior. + */ + template <class Exception> + static void Throw (Exception e) + { + throw e; + } + + //---------------------------------------------------------------------------- + /** + Wrapper for lua_pcall that throws. + */ + static void pcall (lua_State* L, int nargs = 0, int nresults = 0, int msgh = 0) + { + int code = lua_pcall (L, nargs, nresults, msgh); + + if (code != LUABRIDGE_LUA_OK) + Throw (LuaException (L, code)); + } + + //---------------------------------------------------------------------------- + +protected: + void whatFromStack () + { + if (lua_gettop (m_L) > 0) + { + char const* s = lua_tostring (m_L, -1); + m_what = s ? s : ""; + } + else + { + // stack is empty + m_what = "missing error"; + } + } +}; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/LuaHelpers.h b/lib/LuaBridge/Source/LuaBridge/detail/LuaHelpers.h new file mode 100644 index 0000000..e336cf2 --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/LuaHelpers.h @@ -0,0 +1,151 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + Copyright 2007, Nathan Reed + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include <cassert> + +namespace luabridge { + +// These are for Lua versions prior to 5.2.0. +// +#if LUA_VERSION_NUM < 502 +inline int lua_absindex (lua_State* L, int idx) +{ + if (idx > LUA_REGISTRYINDEX && idx < 0) + return lua_gettop (L) + idx + 1; + else + return idx; +} + +inline void lua_rawgetp (lua_State* L, int idx, void const* p) +{ + idx = lua_absindex (L, idx); + lua_pushlightuserdata (L, const_cast <void*> (p)); + lua_rawget (L,idx); +} + +inline void lua_rawsetp (lua_State* L, int idx, void const* p) +{ + idx = lua_absindex (L, idx); + lua_pushlightuserdata (L, const_cast <void*> (p)); + // put key behind value + lua_insert (L, -2); + lua_rawset (L, idx); +} + +#define LUA_OPEQ 1 +#define LUA_OPLT 2 +#define LUA_OPLE 3 + +inline int lua_compare (lua_State* L, int idx1, int idx2, int op) +{ + switch (op) + { + case LUA_OPEQ: + return lua_equal (L, idx1, idx2); + break; + + case LUA_OPLT: + return lua_lessthan (L, idx1, idx2); + break; + + case LUA_OPLE: + return lua_equal (L, idx1, idx2) || lua_lessthan (L, idx1, idx2); + break; + + default: + return 0; + }; +} + +inline int get_length (lua_State* L, int idx) +{ + return int (lua_objlen (L, idx)); +} + +#else +inline int get_length (lua_State* L, int idx) +{ + lua_len (L, idx); + int len = int (luaL_checknumber (L, -1)); + lua_pop (L, 1); + return len; +} + +#endif + +#ifndef LUA_OK +# define LUABRIDGE_LUA_OK 0 +#else +# define LUABRIDGE_LUA_OK LUA_OK +#endif + +/** Get a table value, bypassing metamethods. +*/ +inline void rawgetfield (lua_State* L, int index, char const* key) +{ + assert (lua_istable (L, index)); + index = lua_absindex (L, index); + lua_pushstring (L, key); + lua_rawget (L, index); +} + +/** Set a table value, bypassing metamethods. +*/ +inline void rawsetfield (lua_State* L, int index, char const* key) +{ + assert (lua_istable (L, index)); + index = lua_absindex (L, index); + lua_pushstring (L, key); + lua_insert (L, -2); + lua_rawset (L, index); +} + +/** Returns true if the value is a full userdata (not light). +*/ +inline bool isfulluserdata (lua_State* L, int index) +{ + return lua_isuserdata (L, index) && !lua_islightuserdata (L, index); +} + +/** Test lua_State objects for global equality. + + This can determine if two different lua_State objects really point + to the same global state, such as when using coroutines. + + @note This is used for assertions. +*/ +inline bool equalstates (lua_State* L1, lua_State* L2) +{ + return lua_topointer (L1, LUA_REGISTRYINDEX) == + lua_topointer (L2, LUA_REGISTRYINDEX); +} + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/LuaRef.h b/lib/LuaBridge/Source/LuaBridge/detail/LuaRef.h new file mode 100644 index 0000000..d7ec8f7 --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/LuaRef.h @@ -0,0 +1,1034 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2018, Dmitry Tarakanov + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + Copyright 2008, Nigel Atkinson <suprapilot+LuaCode@gmail.com> + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include <LuaBridge/detail/LuaException.h> +#include <LuaBridge/detail/Stack.h> + +#include <iostream> +#include <string> +#include <vector> +#include <map> + +namespace luabridge { + +//------------------------------------------------------------------------------ +/** + Type tag for representing LUA_TNIL. + + Construct one of these using `Nil ()` to represent a Lua nil. This is faster + than creating a reference in the registry to nil. Example: + + LuaRef t (LuaRef::createTable (L)); + ... + t ["k"] = Nil (); // assign nil +*/ +struct Nil +{ +}; + + +//------------------------------------------------------------------------------ +/** + Stack specialization for Nil. +*/ +template <> +struct Stack <Nil> +{ + static void push (lua_State* L, Nil) + { + lua_pushnil (L); + } +}; + +/** + * Base class for LuaRef and table value proxy classes. + */ +template <class Impl, class LuaRef> +class LuaRefBase +{ +protected: + //---------------------------------------------------------------------------- + /** + Pop the Lua stack. + + Pops the specified number of stack items on destruction. We use this + when returning objects, to avoid an explicit temporary variable, since + the destructor executes after the return statement. For example: + + template <class U> + U cast (lua_State* L) + { + StackPop p (L, 1); + ... + return U (); // dtor called after this line + } + + @note The `StackPop` object must always be a named local variable. + */ + class StackPop + { + public: + /** Create a StackPop object. + + @param count The number of stack entries to pop on destruction. + */ + StackPop (lua_State* L, int count) + : m_L (L) + , m_count (count) + { + } + + ~StackPop () + { + lua_pop (m_L, m_count); + } + + private: + lua_State* m_L; + int m_count; + }; + + friend struct Stack <LuaRef>; + + //---------------------------------------------------------------------------- + /** + Type tag for stack construction. + */ + struct FromStack { }; + + LuaRefBase (lua_State* L) + : m_L (L) + { + } + + //---------------------------------------------------------------------------- + /** + Create a reference to this ref. + + This is used internally. + */ + int createRef () const + { + impl ().push (); + return luaL_ref (m_L, LUA_REGISTRYINDEX); + } + +public: + //---------------------------------------------------------------------------- + /** + converts to a string using luas tostring function + */ + std::string tostring () const + { + lua_getglobal (m_L, "tostring"); + impl ().push (); + lua_call (m_L, 1, 1); + const char* str = lua_tostring (m_L, -1); + lua_pop (m_L, 1); + return str; + } + + //---------------------------------------------------------------------------- + /** + Print a text description of the value to a stream. + + This is used for diagnostics. + */ + void print (std::ostream& os) const + { + switch (type ()) + { + case LUA_TNIL: + os << "nil"; + break; + + case LUA_TNUMBER: + os << cast <lua_Number> (); + break; + + case LUA_TBOOLEAN: + os << (cast <bool> () ? "true" : "false"); + break; + + case LUA_TSTRING: + os << '"' << cast <std::string> () << '"'; + break; + + case LUA_TTABLE: + os << "table: " << tostring (); + break; + + case LUA_TFUNCTION: + os << "function: " << tostring (); + break; + + case LUA_TUSERDATA: + os << "userdata: " << tostring (); + break; + + case LUA_TTHREAD: + os << "thread: " << tostring (); + break; + + case LUA_TLIGHTUSERDATA: + os << "lightuserdata: " << tostring (); + break; + + default: + os << "unknown"; + break; + } + } + + //------------------------------------------------------------------------------ + /** + Write a LuaRef to a stream. + + This allows LuaRef and table proxies to work with streams. + */ + friend std::ostream& operator<< (std::ostream& os, LuaRefBase const& ref) + { + ref.print (os); + return os; + } + + //============================================================================ + // + // This group of member functions is mirrored in Proxy + // + + /** Retrieve the lua_State associated with the reference. + */ + lua_State* state () const + { + return m_L; + } + + //---------------------------------------------------------------------------- + /** + Place the object onto the Lua stack. + */ + void push (lua_State* L) const + { + assert (equalstates (L, m_L)); + (void) L; + impl ().push (); + } + + //---------------------------------------------------------------------------- + /** + Pop the top of Lua stack and assign the ref to m_ref + */ + void pop (lua_State* L) + { + assert (equalstates (L, m_L)); + (void) L; + impl ().pop (); + } + + //---------------------------------------------------------------------------- + /** + Determine the object type. + + The return values are the same as for `lua_type`. + */ + /** @{ */ + int type () const + { + impl ().push (); + StackPop p (m_L, 1); + return lua_type (m_L, -1); + } + + // should never happen + // bool isNone () const { return m_ref == LUA_NOREF; } + + bool isNil () const { return type () == LUA_TNIL; } + bool isBool () const { return type () == LUA_TBOOLEAN; } + bool isNumber () const { return type () == LUA_TNUMBER; } + bool isString () const { return type () == LUA_TSTRING; } + bool isTable () const { return type () == LUA_TTABLE; } + bool isFunction () const { return type () == LUA_TFUNCTION; } + bool isUserdata () const { return type () == LUA_TUSERDATA; } + bool isThread () const { return type () == LUA_TTHREAD; } + bool isLightUserdata () const { return type () == LUA_TLIGHTUSERDATA; } + + /** @} */ + + //---------------------------------------------------------------------------- + /** + Perform an explicit conversion. + */ + template <class T> + T cast () const + { + StackPop p (m_L, 1); + impl ().push (); + return Stack <T>::get (m_L, -1); + } + + //---------------------------------------------------------------------------- + /** + Universal implicit conversion operator. + + NOTE: Visual Studio 2010 and 2012 have a bug where this function + is not used. See: + + http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/e30b2664-a92d-445c-9db2-e8e0fbde2014 + https://connect.microsoft.com/VisualStudio/feedback/details/771509/correct-code-doesnt-compile + + // This code snippet fails to compile in vs2010,vs2012 + struct S { + template <class T> operator T () const { return T (); } + }; + int main () { + S () || false; + return 0; + } + */ + template <class T> + operator T () const + { + return cast <T> (); + } + + //---------------------------------------------------------------------------- + /** + Universal comparison operators. + */ + /** @{ */ + template <class T> + bool operator== (T rhs) const + { + StackPop p (m_L, 2); + impl ().push (); + Stack <T>::push (m_L, rhs); + return lua_compare (m_L, -2, -1, LUA_OPEQ) == 1; + } + + template <class T> + bool operator< (T rhs) const + { + StackPop p (m_L, 2); + impl ().push ();; + Stack <T>::push (m_L, rhs); + int lhsType = lua_type (m_L, -2); + int rhsType = lua_type (m_L, -1); + if (lhsType != rhsType) + { + return lhsType < rhsType; + } + return lua_compare (m_L, -2, -1, LUA_OPLT) == 1; + } + + template <class T> + bool operator<= (T rhs) const + { + StackPop p (m_L, 2); + impl ().push ();; + Stack <T>::push (m_L, rhs); + int lhsType = lua_type (m_L, -2); + int rhsType = lua_type (m_L, -1); + if (lhsType != rhsType) + { + return lhsType <= rhsType; + } + return lua_compare (m_L, -2, -1, LUA_OPLE) == 1; + } + + template <class T> + bool operator> (T rhs) const + { + StackPop p (m_L, 2); + impl ().push ();; + Stack <T>::push (m_L, rhs); + int lhsType = lua_type (m_L, -2); + int rhsType = lua_type (m_L, -1); + if (lhsType != rhsType) + { + return lhsType > rhsType; + } + return lua_compare (m_L, -1, -2, LUA_OPLT) == 1; + } + + template <class T> + bool operator>= (T rhs) const + { + StackPop p (m_L, 2); + impl ().push ();; + Stack <T>::push (m_L, rhs); + int lhsType = lua_type (m_L, -2); + int rhsType = lua_type (m_L, -1); + if (lhsType != rhsType) + { + return lhsType >= rhsType; + } + return lua_compare (m_L, -1, -2, LUA_OPLE) == 1; + } + + template <class T> + bool rawequal (T rhs) const + { + StackPop p (m_L, 2); + impl ().push ();; + Stack <T>::push (m_L, rhs); + return lua_rawequal (m_L, -1, -2) == 1; + } + /** @} */ + + //---------------------------------------------------------------------------- + /** + Append a value to the table. + + If the table is a sequence this will add another element to it. + */ + template <class T> + void append (T v) const + { + impl ().push ();; + Stack <T>::push (m_L, v); + luaL_ref (m_L, -2); + lua_pop (m_L, 1); + } + + //---------------------------------------------------------------------------- + /** + Call the length operator. + + This is identical to applying the Lua # operator. + */ + int length () const + { + StackPop p (m_L, 1); + impl ().push ();; + return get_length (m_L, -1); + } + + //---------------------------------------------------------------------------- + /** + Call Lua code. + + These overloads allow Lua code to be called with up to 8 parameters. + The return value is provided as a LuaRef (which may be LUA_REFNIL). + If an error occurs, a LuaException is thrown. + */ + /** @{ */ + LuaRef operator() () const + { + impl ().push ();; + LuaException::pcall (m_L, 0, 1); + return LuaRef::fromStack (m_L); + } + + template <class P1> + LuaRef operator() (P1 p1) const + { + impl ().push ();; + Stack <P1>::push (m_L, p1); + LuaException::pcall (m_L, 1, 1); + return LuaRef::fromStack (m_L); + } + + template <class P1, class P2> + LuaRef operator() (P1 p1, P2 p2) const + { + impl ().push ();; + Stack <P1>::push (m_L, p1); + Stack <P2>::push (m_L, p2); + LuaException::pcall (m_L, 2, 1); + return LuaRef::fromStack (m_L); + } + + template <class P1, class P2, class P3> + LuaRef operator() (P1 p1, P2 p2, P3 p3) const + { + impl ().push ();; + Stack <P1>::push (m_L, p1); + Stack <P2>::push (m_L, p2); + Stack <P3>::push (m_L, p3); + LuaException::pcall (m_L, 3, 1); + return LuaRef::fromStack (m_L); + } + + template <class P1, class P2, class P3, class P4> + LuaRef operator() (P1 p1, P2 p2, P3 p3, P4 p4) const + { + impl ().push ();; + Stack <P1>::push (m_L, p1); + Stack <P2>::push (m_L, p2); + Stack <P3>::push (m_L, p3); + Stack <P4>::push (m_L, p4); + LuaException::pcall (m_L, 4, 1); + return LuaRef::fromStack (m_L); + } + + template <class P1, class P2, class P3, class P4, class P5> + LuaRef operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) const + { + impl ().push ();; + Stack <P1>::push (m_L, p1); + Stack <P2>::push (m_L, p2); + Stack <P3>::push (m_L, p3); + Stack <P4>::push (m_L, p4); + Stack <P5>::push (m_L, p5); + LuaException::pcall (m_L, 5, 1); + return LuaRef::fromStack (m_L); + } + + template <class P1, class P2, class P3, class P4, class P5, class P6> + LuaRef operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) const + { + impl ().push ();; + Stack <P1>::push (m_L, p1); + Stack <P2>::push (m_L, p2); + Stack <P3>::push (m_L, p3); + Stack <P4>::push (m_L, p4); + Stack <P5>::push (m_L, p5); + Stack <P6>::push (m_L, p6); + LuaException::pcall (m_L, 6, 1); + return LuaRef::fromStack (m_L); + } + + template <class P1, class P2, class P3, class P4, class P5, class P6, class P7> + LuaRef operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) const + { + impl ().push ();; + Stack <P1>::push (m_L, p1); + Stack <P2>::push (m_L, p2); + Stack <P3>::push (m_L, p3); + Stack <P4>::push (m_L, p4); + Stack <P5>::push (m_L, p5); + Stack <P6>::push (m_L, p6); + Stack <P7>::push (m_L, p7); + LuaException::pcall (m_L, 7, 1); + return LuaRef::fromStack (m_L); + } + + template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8> + LuaRef operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) const + { + impl ().push (); + Stack <P1>::push (m_L, p1); + Stack <P2>::push (m_L, p2); + Stack <P3>::push (m_L, p3); + Stack <P4>::push (m_L, p4); + Stack <P5>::push (m_L, p5); + Stack <P6>::push (m_L, p6); + Stack <P7>::push (m_L, p7); + Stack <P8>::push (m_L, p8); + LuaException::pcall (m_L, 8, 1); + return LuaRef::fromStack (m_L); + } + /** @} */ + + //============================================================================ + +protected: + lua_State* m_L; + +private: + const Impl& impl () const + { + return static_cast <const Impl&> (*this); + } + + Impl& impl () + { + return static_cast <Impl&> (*this); + } +}; + +//------------------------------------------------------------------------------ +/** + Lightweight reference to a Lua object. + + The reference is maintained for the lifetime of the C++ object. +*/ +class LuaRef : public LuaRefBase <LuaRef, LuaRef> +{ + //---------------------------------------------------------------------------- + /** + A proxy for representing table values. + */ + class Proxy : public LuaRefBase <Proxy, LuaRef> + { + friend class LuaRef; + + public: + //-------------------------------------------------------------------------- + /** + Construct a Proxy from a table value. + + The table is in the registry, and the key is at the top of the stack. + The key is popped off the stack. + */ + Proxy (lua_State* L, int tableRef) + : LuaRefBase (L) + , m_tableRef (LUA_NOREF) + , m_keyRef (luaL_ref (L, LUA_REGISTRYINDEX)) + { + lua_rawgeti (m_L, LUA_REGISTRYINDEX, tableRef); + m_tableRef = luaL_ref (L, LUA_REGISTRYINDEX); + } + + //-------------------------------------------------------------------------- + /** + Create a Proxy via copy constructor. + + It is best to avoid code paths that invoke this, because it creates + an extra temporary Lua reference. Typically this is done by passing + the Proxy parameter as a `const` reference. + */ + Proxy (Proxy const& other) + : LuaRefBase (other.m_L) + , m_tableRef (LUA_NOREF) + , m_keyRef (LUA_NOREF) + { + lua_rawgeti (m_L, LUA_REGISTRYINDEX, other.m_tableRef); + m_tableRef = luaL_ref (m_L, LUA_REGISTRYINDEX); + + lua_rawgeti (m_L, LUA_REGISTRYINDEX, other.m_keyRef); + m_keyRef = luaL_ref (m_L, LUA_REGISTRYINDEX); + } + + //-------------------------------------------------------------------------- + /** + Destroy the proxy. + + This does not destroy the table value. + */ + ~Proxy () + { + luaL_unref (m_L, LUA_REGISTRYINDEX, m_keyRef); + luaL_unref (m_L, LUA_REGISTRYINDEX, m_tableRef); + } + + //-------------------------------------------------------------------------- + /** + Assign a new value to this table key. + + This may invoke metamethods. + */ + template <class T> + Proxy& operator= (T v) + { + StackPop p (m_L, 1); + lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_tableRef); + lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_keyRef); + Stack <T>::push (m_L, v); + lua_settable (m_L, -3); + return *this; + } + + //-------------------------------------------------------------------------- + /** + Assign a new value to this table key. + + The assignment is raw, no metamethods are invoked. + */ + template <class T> + Proxy& rawset (T v) + { + StackPop p (m_L, 1); + lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_tableRef); + lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_keyRef); + Stack <T>::push (m_L, v); + lua_rawset (m_L, -3); + return *this; + } + + //-------------------------------------------------------------------------- + /** + Push the value onto the Lua stack. + */ + using LuaRefBase::push; + + void push () const + { + lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_tableRef); + lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_keyRef); + lua_gettable (m_L, -2); + lua_remove (m_L, -2); // remove the table + } + + //-------------------------------------------------------------------------- + /** + Access a table value using a key. + + This invokes metamethods. + */ + template <class T> + Proxy operator[] (T key) const + { + return LuaRef (*this) [key]; + } + + //-------------------------------------------------------------------------- + /** + Access a table value using a key. + + The operation is raw, metamethods are not invoked. The result is + passed by value and may not be modified. + */ + template <class T> + LuaRef rawget (T key) const + { + return LuaRef (*this).rawget (key); + } + + private: + int m_tableRef; + int m_keyRef; + }; + + friend struct Stack <Proxy>; + friend struct Stack <Proxy&>; + + //---------------------------------------------------------------------------- + /** + Create a reference to an object at the top of the Lua stack and pop it. + + This constructor is private and not invoked directly. + Instead, use the `fromStack` function. + + @note The object is popped. + */ + LuaRef (lua_State* L, FromStack) + : LuaRefBase (L) + , m_ref (luaL_ref (m_L, LUA_REGISTRYINDEX)) + { + } + + //---------------------------------------------------------------------------- + /** + Create a reference to an object on the Lua stack. + + This constructor is private and not invoked directly. + Instead, use the `fromStack` function. + + @note The object is not popped. + */ + LuaRef (lua_State* L, int index, FromStack) + : LuaRefBase (L) + , m_ref (LUA_NOREF) + { + lua_pushvalue (m_L, index); + m_ref = luaL_ref (m_L, LUA_REGISTRYINDEX); + } + + +public: + //---------------------------------------------------------------------------- + /** + Create a nil reference. + + The LuaRef may be assigned later. + */ + LuaRef (lua_State* L) + : LuaRefBase (L) + , m_ref (LUA_NOREF) + { + } + + //---------------------------------------------------------------------------- + /** + Create a reference to a value. + */ + template <class T> + LuaRef (lua_State* L, T v) + : LuaRefBase (L) + , m_ref (LUA_NOREF) + { + Stack <T>::push (m_L, v); + m_ref = luaL_ref (m_L, LUA_REGISTRYINDEX); + } + + //---------------------------------------------------------------------------- + /** + Create a reference to a table value. + */ + LuaRef (Proxy const& v) + : LuaRefBase (v.state ()) + , m_ref (v.createRef ()) + { + } + + //---------------------------------------------------------------------------- + /** + Create a new reference to an existing reference. + */ + LuaRef (LuaRef const& other) + : LuaRefBase (other.m_L) + , m_ref (other.createRef ()) + { + } + + //---------------------------------------------------------------------------- + /** + Destroy a reference. + + The corresponding Lua registry reference will be released. + + @note If the state refers to a thread, it is the responsibility of the + caller to ensure that the thread still exists when the LuaRef + is destroyed. + */ + ~LuaRef () + { + luaL_unref (m_L, LUA_REGISTRYINDEX, m_ref); + } + + //---------------------------------------------------------------------------- + /** + Return a LuaRef from a top stack item. + + The stack item is not popped. + */ + static LuaRef fromStack (lua_State* L) + { + return LuaRef (L, FromStack ()); + } + + //---------------------------------------------------------------------------- + /** + Return a LuaRef from a stack item. + + The stack item is not popped. + */ + static LuaRef fromStack (lua_State* L, int index) + { + lua_pushvalue (L, index); + return LuaRef (L, FromStack ()); + } + + //---------------------------------------------------------------------------- + /** + Create a new empty table and return a reference to it. + + It is also possible to use the free function `newTable`. + + @see ::luabridge::newTable + */ + static LuaRef newTable (lua_State* L) + { + lua_newtable (L); + return LuaRef (L, FromStack ()); + } + + //---------------------------------------------------------------------------- + /** + Return a reference to a named global. + + It is also possible to use the free function `getGlobal`. + + @see ::luabridge::getGlobal + */ + static LuaRef getGlobal (lua_State *L, char const* name) + { + lua_getglobal (L, name); + return LuaRef (L, FromStack ()); + } + + //---------------------------------------------------------------------------- + /** + Assign another LuaRef to this LuaRef. + */ + LuaRef& operator= (LuaRef const& rhs) + { + LuaRef ref (rhs); + swap (ref); + return *this; + } + + //---------------------------------------------------------------------------- + /** + Assign Proxy to this LuaRef. + */ + LuaRef& operator= (LuaRef::Proxy const& rhs) + { + LuaRef ref (rhs); + swap (ref); + return *this; + } + + //---------------------------------------------------------------------------- + /** + Assign nil to this LuaRef. + */ + LuaRef& operator= (Nil const&) + { + LuaRef ref (m_L); + swap (ref); + return *this; + } + + //---------------------------------------------------------------------------- + /** + Assign a different value to this LuaRef. + */ + template <class T> + LuaRef& operator= (T rhs) + { + LuaRef ref (m_L, rhs); + swap (ref); + return *this; + } + + //---------------------------------------------------------------------------- + /** + Place the object onto the Lua stack. + */ + using LuaRefBase::push; + + void push () const + { + lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_ref); + } + + //---------------------------------------------------------------------------- + /** + Pop the top of Lua stack and assign the ref to m_ref + */ + void pop () + { + luaL_unref (m_L, LUA_REGISTRYINDEX, m_ref); + m_ref = luaL_ref (m_L, LUA_REGISTRYINDEX); + } + + //---------------------------------------------------------------------------- + /** + Access a table value using a key. + + This invokes metamethods. + */ + template <class T> + Proxy operator[] (T key) const + { + Stack <T>::push (m_L, key); + return Proxy (m_L, m_ref); + } + + //-------------------------------------------------------------------------- + /** + Access a table value using a key. + + The operation is raw, metamethods are not invoked. The result is + passed by value and may not be modified. + */ + template <class T> + LuaRef rawget (T key) const + { + StackPop (m_L, 1); + push (m_L); + Stack <T>::push (m_L, key); + lua_rawget (m_L, -2); + return LuaRef (m_L, FromStack ()); + } + +private: + void swap (LuaRef& other) + { + std::swap (m_L, other.m_L); + std::swap (m_ref, other.m_ref); + } + + int m_ref; +}; + +//------------------------------------------------------------------------------ +/** + * Stack specialization for `LuaRef`. + */ +template <> +struct Stack <LuaRef> +{ + // The value is const& to prevent a copy construction. + // + static void push (lua_State* L, LuaRef const& v) + { + v.push (L); + } + + static LuaRef get (lua_State* L, int index) + { + return LuaRef::fromStack (L, index); + } +}; + +//------------------------------------------------------------------------------ +/** + * Stack specialization for `Proxy`. + */ +template <> +struct Stack <LuaRef::Proxy> +{ + // The value is const& to prevent a copy construction. + // + static void push (lua_State* L, LuaRef::Proxy const& v) + { + v.push (L); + } +}; + +//------------------------------------------------------------------------------ +/** + Create a reference to a new, empty table. + + This is a syntactic abbreviation for LuaRef::newTable (). +*/ +inline LuaRef newTable (lua_State* L) +{ + return LuaRef::newTable (L); +} + +//------------------------------------------------------------------------------ +/** + Create a reference to a value in the global table. + + This is a syntactic abbreviation for LuaRef::getGlobal (). +*/ +inline LuaRef getGlobal (lua_State *L, char const* name) +{ + return LuaRef::getGlobal (L, name); +} + +//------------------------------------------------------------------------------ + +// more C++-like cast syntax +// +template <class T> +T LuaRef_cast (LuaRef const& lr) +{ + return lr.cast <T> (); +} + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/Namespace.h b/lib/LuaBridge/Source/LuaBridge/detail/Namespace.h new file mode 100644 index 0000000..870e6e6 --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/Namespace.h @@ -0,0 +1,1224 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + Copyright 2007, Nathan Reed + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include <LuaBridge/detail/Config.h> +#include <LuaBridge/detail/ClassInfo.h> +#include <LuaBridge/detail/Security.h> +#include <LuaBridge/detail/TypeTraits.h> + +#include <stdexcept> +#include <string> + +namespace luabridge { + +namespace detail { + +/** + * Base for class and namespace registration. + * Maintains Lua stack in the proper state. + * Once beginNamespace, beginClass or deriveClass is called the parent + * object upon its destruction may no longer clear the Lua stack. + * Then endNamespace or endClass is called, a new parent is created + * and the child transfers the responsibility for clearing stack to it. + * So there can be maximum one "active" registrar object. + */ +class Registrar +{ +protected: + lua_State* const L; + int mutable m_stackSize; + + Registrar (lua_State* L) + : L (L) + , m_stackSize (0) + { + } + + Registrar (const Registrar& rhs) + : L (rhs.L) + , m_stackSize (rhs.m_stackSize) + { + rhs.m_stackSize = 0; + } + +#ifndef _MSC_VER + // MS compiler thinks it's the 2nd copy ctor + Registrar(Registrar& rhs) + : L (rhs.L) + , m_stackSize (rhs.m_stackSize) + { + rhs.m_stackSize = 0; + } +#endif // ifndef _MSC_VER + + Registrar& operator= (const Registrar& rhs) + { + Registrar tmp (rhs); + std::swap (m_stackSize, tmp.m_stackSize); + return *this; + } + + ~Registrar () + { + if (m_stackSize > 0) + { + assert (m_stackSize <= lua_gettop (L)); + lua_pop (L, m_stackSize); + } + } + + void assertIsActive () const + { + if (m_stackSize == 0) + { + throw std::logic_error ("Unable to continue registration"); + } + } +}; + +} // namespace detail + +/** Provides C++ to Lua registration capabilities. + + This class is not instantiated directly, call `getGlobalNamespace` to start + the registration process. +*/ +class Namespace : public detail::Registrar +{ + //============================================================================ + /** + Error reporting. + + VF: This function looks handy, why aren't we using it? + */ +#if 0 + static int luaError (lua_State* L, std::string message) + { + assert (lua_isstring (L, lua_upvalueindex (1))); + std::string s; + + // Get information on the caller's caller to format the message, + // so the error appears to originate from the Lua source. + lua_Debug ar; + int result = lua_getstack (L, 2, &ar); + if (result != 0) + { + lua_getinfo (L, "Sl", &ar); + s = ar.short_src; + if (ar.currentline != -1) + { + // poor mans int to string to avoid <strstrream>. + lua_pushnumber (L, ar.currentline); + s = s + ":" + lua_tostring (L, -1) + ": "; + lua_pop (L, 1); + } + } + + s = s + message; + + return luaL_error (L, s.c_str ()); + } +#endif + + /** + Factored base to reduce template instantiations. + */ + class ClassBase : public detail::Registrar + { + public: + explicit ClassBase (Namespace& parent) + : Registrar (parent) + { + } + + using Registrar::operator=; + + protected: + //-------------------------------------------------------------------------- + /** + Create the const table. + */ + void createConstTable (const char* name, bool trueConst = true) + { + std::string type_name = std::string (trueConst ? "const " : "") + name; + + // Stack: namespace table (ns) + lua_newtable (L); // Stack: ns, const table (co) + lua_pushvalue (L, -1); // Stack: ns, co, co + lua_setmetatable (L, -2); // co.__metatable = co. Stack: ns, co + + lua_pushstring (L, type_name.c_str ()); + lua_rawsetp (L, -2, getTypeKey ()); // co [typeKey] = name. Stack: ns, co + + lua_pushcfunction (L, &CFunc::indexMetaMethod); + rawsetfield (L, -2, "__index"); + + lua_pushcfunction (L, &CFunc::newindexObjectMetaMethod); + rawsetfield (L, -2, "__newindex"); + + lua_newtable (L); + lua_rawsetp (L, -2, getPropgetKey ()); + + if (Security::hideMetatables ()) + { + lua_pushnil (L); + rawsetfield (L, -2, "__metatable"); + } + } + + //-------------------------------------------------------------------------- + /** + Create the class table. + + The Lua stack should have the const table on top. + */ + void createClassTable (char const* name) + { + // Stack: namespace table (ns), const table (co) + + // Class table is the same as const table except the propset table + createConstTable (name, false); // Stack: ns, co, cl + + lua_newtable (L); // Stack: ns, co, cl, propset table (ps) + lua_rawsetp (L, -2, getPropsetKey ()); // cl [propsetKey] = ps. Stack: ns, co, cl + + lua_pushvalue (L, -2); // Stack: ns, co, cl, co + lua_rawsetp(L, -2, getConstKey ()); // cl [constKey] = co. Stack: ns, co, cl + + lua_pushvalue (L, -1); // Stack: ns, co, cl, cl + lua_rawsetp (L, -3, getClassKey ()); // co [classKey] = cl. Stack: ns, co, cl + } + + //-------------------------------------------------------------------------- + /** + Create the static table. + */ + void createStaticTable (char const* name) + { + // Stack: namespace table (ns), const table (co), class table (cl) + lua_newtable (L); // Stack: ns, co, cl, visible static table (vst) + lua_newtable (L); // Stack: ns, co, cl, st, static metatable (st) + lua_pushvalue (L, -1); // Stack: ns, co, cl, vst, st, st + lua_setmetatable (L, -3); // st.__metatable = mt. Stack: ns, co, cl, vst, st + lua_insert (L, -2); // Stack: ns, co, cl, st, vst + rawsetfield (L, -5, name); // ns [name] = vst. Stack: ns, co, cl, st + +#if 0 + lua_pushlightuserdata (L, this); + lua_pushcclosure (L, &tostringMetaMethod, 1); + rawsetfield (L, -2, "__tostring"); +#endif + lua_pushcfunction (L, &CFunc::indexMetaMethod); + rawsetfield (L, -2, "__index"); + + lua_pushcfunction (L, &CFunc::newindexStaticMetaMethod); + rawsetfield (L, -2, "__newindex"); + + lua_newtable (L); // Stack: ns, co, cl, st, proget table (pg) + lua_rawsetp (L, -2, getPropgetKey ()); // st [propgetKey] = pg. Stack: ns, co, cl, st + + lua_newtable (L); // Stack: ns, co, cl, st, propset table (ps) + lua_rawsetp (L, -2, getPropsetKey ()); // st [propsetKey] = pg. Stack: ns, co, cl, st + + lua_pushvalue (L, -2); // Stack: ns, co, cl, st, cl + lua_rawsetp(L, -2, getClassKey()); // st [classKey] = cl. Stack: ns, co, cl, st + + if (Security::hideMetatables ()) + { + lua_pushnil (L); + rawsetfield (L, -2, "__metatable"); + } + } + + //========================================================================== + /** + lua_CFunction to construct a class object wrapped in a container. + */ + template <class Params, class C> + static int ctorContainerProxy (lua_State* L) + { + typedef typename ContainerTraits <C>::Type T; + ArgList <Params, 2> args (L); + T* const p = Constructor <T, Params>::call (args); + UserdataSharedHelper <C, false>::push (L, p); + return 1; + } + + //-------------------------------------------------------------------------- + /** + lua_CFunction to construct a class object in-place in the userdata. + */ + template <class Params, class T> + static int ctorPlacementProxy (lua_State* L) + { + ArgList <Params, 2> args (L); + Constructor <T, Params>::call (UserdataValue <T>::place (L), args); + return 1; + } + + void assertStackState () const + { + // Stack: const table (co), class table (cl), static table (st) + assert (lua_istable (L, -3)); + assert (lua_istable (L, -2)); + assert (lua_istable (L, -1)); + } + }; + + //============================================================================ + // + // Class + // + //============================================================================ + /** + Provides a class registration in a lua_State. + + After construction the Lua stack holds these objects: + -1 static table + -2 class table + -3 const table + -4 enclosing namespace table + */ + template <class T> + class Class : public ClassBase + { + public: + //========================================================================== + /** + Register a new class or add to an existing class registration. + */ + Class (char const* name, Namespace& parent) + : ClassBase (parent) + { + assert (lua_istable (L, -1)); // Stack: namespace table (ns) + rawgetfield (L, -1, name); // Stack: ns, static table (st) | nil + + if (lua_isnil (L, -1)) // Stack: ns, nil + { + lua_pop (L, 1); // Stack: ns + + createConstTable (name); // Stack: ns, const table (co) + lua_pushcfunction (L, &CFunc::gcMetaMethod <T>); // Stack: ns, co, function + rawsetfield (L, -2, "__gc"); // Stack: ns, co + ++m_stackSize; + + createClassTable (name); // Stack: ns, co, class table (cl) + lua_pushcfunction (L, &CFunc::gcMetaMethod <T>); // Stack: ns, co, cl, function + rawsetfield (L, -2, "__gc"); // Stack: ns, co, cl + ++m_stackSize; + + createStaticTable (name); // Stack: ns, co, cl, st + ++m_stackSize; + + // Map T back to its tables. + lua_pushvalue (L, -1); // Stack: ns, co, cl, st, st + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getStaticKey ()); // Stack: ns, co, cl, st + lua_pushvalue (L, -2); // Stack: ns, co, cl, st, cl + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ()); // Stack: ns, co, cl, st + lua_pushvalue (L, -3); // Stack: ns, co, cl, st, co + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getConstKey ()); // Stack: ns, co, cl, st + } + else + { + assert (lua_istable (L, -1)); // Stack: ns, st + ++m_stackSize; + + // Map T back from its stored tables + + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getConstKey ()); // Stack: ns, st, co + lua_insert (L, -2); // Stack: ns, co, st + ++m_stackSize; + + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ()); // Stack: ns, co, st, cl + lua_insert (L, -2); // Stack: ns, co, cl, st + ++m_stackSize; + } + } + + //========================================================================== + /** + Derive a new class. + */ + Class (char const* name, Namespace& parent, void const* const staticKey) + : ClassBase (parent) + { + assert (lua_istable (L, -1)); // Stack: namespace table (ns) + + createConstTable (name); // Stack: ns, const table (co) + lua_pushcfunction (L, &CFunc::gcMetaMethod <T>); // Stack: ns, co, function + rawsetfield (L, -2, "__gc"); // Stack: ns, co + ++m_stackSize; + + createClassTable (name); // Stack: ns, co, class table (cl) + lua_pushcfunction (L, &CFunc::gcMetaMethod <T>); // Stack: ns, co, cl, function + rawsetfield (L, -2, "__gc"); // Stack: ns, co, cl + ++m_stackSize; + + createStaticTable (name); // Stack: ns, co, cl, st + ++m_stackSize; + + lua_rawgetp (L, LUA_REGISTRYINDEX, staticKey); // Stack: ns, co, cl, st, parent st (pst) | nil + if (lua_isnil (L, -1)) // Stack: ns, co, cl, st, nil + { + ++m_stackSize; + throw std::runtime_error ("Base class is not registered"); + } + + assert (lua_istable (L, -1)); // Stack: ns, co, cl, st, pst + + lua_rawgetp (L, -1, getClassKey ()); // Stack: ns, co, cl, st, pst, parent cl (pcl) + assert (lua_istable (L, -1)); + + lua_rawgetp (L, -1, getConstKey ()); // Stack: ns, co, cl, st, pst, pcl, parent co (pco) + assert (lua_istable (L, -1)); + + lua_rawsetp (L, -6, getParentKey ()); // co [parentKey] = pco. Stack: ns, co, cl, st, pst, pcl + lua_rawsetp (L, -4, getParentKey ()); // cl [parentKey] = pcl. Stack: ns, co, cl, st, pst + lua_rawsetp (L, -2, getParentKey ()); // st [parentKey] = pst. Stack: ns, co, cl, st + + lua_pushvalue (L, -1); // Stack: ns, co, cl, st, st + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getStaticKey ()); // Stack: ns, co, cl, st + lua_pushvalue (L, -2); // Stack: ns, co, cl, st, cl + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ()); // Stack: ns, co, cl, st + lua_pushvalue (L, -3); // Stack: ns, co, cl, st, co + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getConstKey ()); // Stack: ns, co, cl, st + } + + //-------------------------------------------------------------------------- + /** + Continue registration in the enclosing namespace. + */ + Namespace endClass () + { + assert (m_stackSize > 3); + m_stackSize -= 3; + lua_pop (L, 3); + return Namespace (*this); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a static data member. + */ + template <class U> + Class <T>& addStaticProperty (char const* name, U* pu, bool isWritable = true) + { + return addStaticData (name, pu, isWritable); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a static data member. + */ + template <class U> + Class <T>& addStaticData (char const* name, U* pu, bool isWritable = true) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + lua_pushlightuserdata (L, pu); // Stack: co, cl, st, pointer + lua_pushcclosure (L, &CFunc::getVariable <U>, 1); // Stack: co, cl, st, getter + CFunc::addGetter (L, name, -2); // Stack: co, cl, st + + if (isWritable) + { + lua_pushlightuserdata (L, pu); // Stack: co, cl, st, ps, pointer + lua_pushcclosure (L, &CFunc::setVariable <U>, 1); // Stack: co, cl, st, ps, setter + } + else + { + lua_pushstring (L, name); // Stack: co, cl, st, name + lua_pushcclosure (L, &CFunc::readOnlyError, 1); // Stack: co, cl, st, error_fn + } + CFunc::addSetter (L, name, -2); // Stack: co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a static property member. + + If the set function is null, the property is read-only. + */ + template <class U> + Class <T>& addStaticProperty (char const* name, U (*get) (), void (*set) (U) = 0) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + lua_pushlightuserdata (L, reinterpret_cast <void*> (get)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::Call <U (*) ()>::f, 1); // Stack: co, cl, st, getter + CFunc::addGetter (L, name, -2); // Stack: co, cl, st + + if (set != 0) + { + lua_pushlightuserdata (L, reinterpret_cast <void*> (set)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::Call <void (*) (U)>::f, 1); // Stack: co, cl, st, setter + } + else + { + lua_pushstring (L, name); // Stack: co, cl, st, ps, name + lua_pushcclosure (L, &CFunc::readOnlyError, 1); // Stack: co, cl, st, error_fn + } + CFunc::addSetter (L, name, -2); // Stack: co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a static member function. + */ + template <class FP> + Class <T>& addStaticFunction (char const* name, FP const fp) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + lua_pushlightuserdata (L, reinterpret_cast <void*> (fp)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::Call <FP>::f, 1); // co, cl, st, function + rawsetfield (L, -2, name); // co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a lua_CFunction. + */ + Class <T>& addStaticFunction (char const* name, int (*const fp) (lua_State*)) + { + return addStaticCFunction (name, fp); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a lua_CFunction. + */ + Class <T>& addStaticCFunction (char const* name, int (*const fp) (lua_State*)) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcfunction (L, fp); // co, cl, st, function + rawsetfield (L, -2, name); // co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a data member. + */ + template <class U> + Class <T>& addProperty (char const* name, U T::* mp, bool isWritable = true) + { + return addData (name, mp, isWritable); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a data member. + */ + template <class U> + Class <T>& addData (char const* name, U T::* mp, bool isWritable = true) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + typedef const U T::*mp_t; + new (lua_newuserdata (L, sizeof (mp_t))) mp_t (mp); // Stack: co, cl, st, field ptr + lua_pushcclosure (L, &CFunc::getProperty <T, U>, 1); // Stack: co, cl, st, getter + lua_pushvalue (L, -1); // Stack: co, cl, st, getter, getter + CFunc::addGetter (L, name, -5); // Stack: co, cl, st, getter + CFunc::addGetter (L, name, -3); // Stack: co, cl, st + + if (isWritable) + { + new (lua_newuserdata (L, sizeof (mp_t))) mp_t (mp); // Stack: co, cl, st, field ptr + lua_pushcclosure (L, &CFunc::setProperty <T, U>, 1); // Stack: co, cl, st, setter + CFunc::addSetter (L, name, -3); // Stack: co, cl, st + } + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a property member. + */ + template <class TG, class TS = TG> + Class <T>& addProperty (char const* name, TG (T::* get) () const, void (T::* set) (TS) = 0) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + typedef TG (T::*get_t) () const; + new (lua_newuserdata (L, sizeof (get_t))) get_t (get); // Stack: co, cl, st, funcion ptr + lua_pushcclosure (L, &CFunc::CallConstMember <get_t>::f, 1); // Stack: co, cl, st, getter + lua_pushvalue (L, -1); // Stack: co, cl, st, getter, getter + CFunc::addGetter (L, name, -5); // Stack: co, cl, st, getter + CFunc::addGetter (L, name, -3); // Stack: co, cl, st + + if (set != 0) + { + typedef void (T::* set_t) (TS); + new (lua_newuserdata (L, sizeof (set_t))) set_t (set); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::CallMember <set_t>::f, 1); // Stack: co, cl, st, setter + CFunc::addSetter (L, name, -3); // Stack: co, cl, st + } + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a property member. + */ + template <class TG, class TS = TG> + Class <T>& addProperty (char const* name, TG (T::* get) (lua_State*) const, void (T::* set) (TS, lua_State*) = 0) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + typedef TG (T::*get_t) (lua_State*) const; + new (lua_newuserdata (L, sizeof (get_t))) get_t (get); // Stack: co, cl, st, funcion ptr + lua_pushcclosure (L, &CFunc::CallConstMember <get_t>::f, 1); // Stack: co, cl, st, getter + lua_pushvalue (L, -1); // Stack: co, cl, st, getter, getter + CFunc::addGetter (L, name, -5); // Stack: co, cl, st, getter + CFunc::addGetter (L, name, -3); // Stack: co, cl, st + + if (set != 0) + { + typedef void (T::* set_t) (TS, lua_State*); + new (lua_newuserdata (L, sizeof (set_t))) set_t (set); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::CallMember <set_t>::f, 1); // Stack: co, cl, st, setter + CFunc::addSetter (L, name, -3); // Stack: co, cl, st + } + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a property member, by proxy. + + When a class is closed for modification and does not provide (or cannot + provide) the function signatures necessary to implement get or set for + a property, this will allow non-member functions act as proxies. + + Both the get and the set functions require a T const* and T* in the first + argument respectively. + */ + template <class TG, class TS = TG> + Class <T>& addProperty (char const* name, TG (*get) (T const*), void (*set) (T*, TS) = 0) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + lua_pushlightuserdata (L, reinterpret_cast <void*> (get)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::Call <TG (*) (const T*)>::f, 1); // Stack: co, cl, st, getter + lua_pushvalue (L, -1); // Stack: co, cl, st,, getter, getter + CFunc::addGetter (L, name, -5); // Stack: co, cl, st, getter + CFunc::addGetter (L, name, -3); // Stack: co, cl, st + + if (set != 0) + { + lua_pushlightuserdata (L, reinterpret_cast <void*> (set)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::Call <void (*) (T*, TS)>::f, 1); // Stack: co, cl, st, setter + CFunc::addSetter (L, name, -3); // Stack: co, cl, st + } + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a property member, by proxy C-function. + + When a class is closed for modification and does not provide (or cannot + provide) the function signatures necessary to implement get or set for + a property, this will allow non-member functions act as proxies. + + The object userdata ('this') value is at the index 1. + The new value for set function is at the index 2. + */ + Class <T>& addProperty (char const* name, int (*get) (lua_State*), int (*set) (lua_State*) = 0) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcfunction (L, get); + lua_pushvalue (L, -1); // Stack: co, cl, st,, getter, getter + CFunc::addGetter (L, name, -5); // Stack: co, cl, st,, getter + CFunc::addGetter (L, name, -3); // Stack: co, cl, st, + + if (set != 0) + { + lua_pushcfunction (L, set); + CFunc::addSetter (L, name, -3); // Stack: co, cl, st, + } + + return *this; + } + +#ifdef LUABRIDGE_CXX11 + template <class TG, class TS = TG> + Class <T>& addProperty (char const* name, + std::function <TG (const T*)> get, + std::function <void (T*, TS)> set = nullptr) + { + using GetType = decltype (get); + new (lua_newuserdata (L, sizeof (get))) GetType (std::move (get)); // Stack: co, cl, st, function userdata (ud) + lua_newtable (L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction (L, &CFunc::gcMetaMethodAny <GetType>); // Stack: co, cl, st, ud, mt, gc function + rawsetfield (L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable (L, -2); // Stack: co, cl, st, ud + lua_pushcclosure (L, &CFunc::CallProxyFunctor <GetType>::f, 1); // Stack: co, cl, st, getter + lua_pushvalue (L, -1); // Stack: co, cl, st, getter, getter + CFunc::addGetter (L, name, -4); // Stack: co, cl, st, getter + CFunc::addGetter (L, name, -4); // Stack: co, cl, st + + if (set != nullptr) + { + using SetType = decltype (set); + new (lua_newuserdata (L, sizeof (set))) SetType (std::move (set)); // Stack: co, cl, st, function userdata (ud) + lua_newtable (L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction (L, &CFunc::gcMetaMethodAny <SetType>); // Stack: co, cl, st, ud, mt, gc function + rawsetfield (L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable (L, -2); // Stack: co, cl, st, ud + lua_pushcclosure (L, &CFunc::CallProxyFunctor <SetType>::f, 1); // Stack: co, cl, st, setter + CFunc::addSetter (L, name, -3); // Stack: co, cl, st + } + + return *this; + } + +#endif // LUABRIDGE_CXX11 + +#ifndef LUABRIDGE_CXX11 + + //-------------------------------------------------------------------------- + /** + Add or replace a member function. + */ + template <class MemFn> + Class <T>& addFunction (char const* name, MemFn mf) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + static const std::string GC = "__gc"; + if (name == GC) + { + throw std::logic_error (GC + " metamethod registration is forbidden"); + } + CFunc::CallMemberFunctionHelper <MemFn, FuncTraits <MemFn>::isConstMemberFunction>::add (L, name, mf); + return *this; + } + +#else // ifndef LUABRIDGE_CXX11 + + //-------------------------------------------------------------------------- + /** + Add or replace a member function by std::function. + */ + template <class ReturnType, class... Params> + Class <T>& addFunction (char const* name, std::function <ReturnType (T*, Params...)> function) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + using FnType = decltype (function); + new (lua_newuserdata (L, sizeof (function))) FnType (std::move (function)); // Stack: co, cl, st, function userdata (ud) + lua_newtable (L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction (L, &CFunc::gcMetaMethodAny <FnType>); // Stack: co, cl, st, ud, mt, gc function + rawsetfield (L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable (L, -2); // Stack: co, cl, st, ud + lua_pushcclosure (L, &CFunc::CallProxyFunctor <FnType>::f, 1); // Stack: co, cl, st, function + rawsetfield (L, -3, name); // Stack: co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a const member function by std::function. + */ + template <class ReturnType, class... Params> + Class <T>& addFunction (char const* name, std::function <ReturnType (const T*, Params...)> function) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + using FnType = decltype (function); + new (lua_newuserdata (L, sizeof (function))) FnType (std::move (function)); // Stack: co, cl, st, function userdata (ud) + lua_newtable (L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction (L, &CFunc::gcMetaMethodAny <FnType>); // Stack: co, cl, st, ud, mt, gc function + rawsetfield (L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable (L, -2); // Stack: co, cl, st, ud + lua_pushcclosure (L, &CFunc::CallProxyFunctor <FnType>::f, 1); // Stack: co, cl, st, function + lua_pushvalue (L, -1); // Stack: co, cl, st, function, function + rawsetfield (L, -4, name); // Stack: co, cl, st, function + rawsetfield (L, -4, name); // Stack: co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a member function. + */ + template <class ReturnType, class... Params> + Class <T>& addFunction (char const* name, ReturnType (T::* mf) (Params...)) + { + using MemFn = ReturnType (T::*) (Params...); + + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + static const std::string GC = "__gc"; + if (name == GC) + { + throw std::logic_error (GC + " metamethod registration is forbidden"); + } + CFunc::CallMemberFunctionHelper <MemFn, false>::add (L, name, mf); + return *this; + } + + template <class ReturnType, class... Params> + Class <T>& addFunction (char const* name, ReturnType (T::* mf) (Params...) const) + { + using MemFn = ReturnType (T::*) (Params...) const; + + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + static const std::string GC = "__gc"; + if (name == GC) + { + throw std::logic_error (GC + " metamethod registration is forbidden"); + } + CFunc::CallMemberFunctionHelper <MemFn, true>::add (L, name, mf); + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a proxy function. + */ + template <class ReturnType, class... Params> + Class <T>& addFunction (char const* name, ReturnType (*proxyFn) (T* object, Params...)) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + static const std::string GC = "__gc"; + if (name == GC) + { + throw std::logic_error (GC + " metamethod registration is forbidden"); + } + using FnType = decltype (proxyFn); + lua_pushlightuserdata (L, reinterpret_cast <void*> (proxyFn)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::CallProxyFunction <FnType>::f, 1); // Stack: co, cl, st, function + rawsetfield (L, -3, name); // Stack: co, cl, st + return *this; + } + + template <class ReturnType, class... Params> + Class <T>& addFunction (char const* name, ReturnType (*proxyFn) (const T* object, Params...)) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + static const std::string GC = "__gc"; + if (name == GC) + { + throw std::logic_error (GC + " metamethod registration is forbidden"); + } + using FnType = decltype (proxyFn); + lua_pushlightuserdata (L, reinterpret_cast <void*> (proxyFn)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::CallProxyFunction <FnType>::f, 1); // Stack: co, cl, st, function + lua_pushvalue (L, -1); // Stack: co, cl, st, function, function + rawsetfield (L, -4, name); // Stack: co, cl, st, function + rawsetfield (L, -4, name); // Stack: co, cl, st + return *this; + } + +#endif + + //-------------------------------------------------------------------------- + /** + Add or replace a member lua_CFunction. + */ + Class <T>& addFunction (char const* name, int (T::*mfp) (lua_State*)) + { + return addCFunction (name, mfp); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a member lua_CFunction. + */ + Class <T>& addCFunction (char const* name, int (T::*mfp) (lua_State*)) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + typedef int (T::*MFP) (lua_State*); + new (lua_newuserdata (L, sizeof (mfp))) MFP (mfp); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::CallMemberCFunction <T>::f, 1); // Stack: co, cl, st, function + rawsetfield (L, -3, name); // Stack: co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a const member lua_CFunction. + */ + Class <T>& addFunction (char const* name, int (T::*mfp) (lua_State*) const) + { + return addCFunction (name, mfp); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a const member lua_CFunction. + */ + Class <T>& addCFunction (char const* name, int (T::*mfp) (lua_State*) const) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + typedef int (T::*MFP) (lua_State*) const; + new (lua_newuserdata (L, sizeof (mfp))) MFP (mfp); + lua_pushcclosure (L, &CFunc::CallConstMemberCFunction <T>::f, 1); + lua_pushvalue (L, -1); // Stack: co, cl, st, function, function + rawsetfield (L, -4, name); // Stack: co, cl, st, function + rawsetfield (L, -4, name); // Stack: co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a primary Constructor. + + The primary Constructor is invoked when calling the class type table + like a function. + + The template parameter should be a function pointer type that matches + the desired Constructor (since you can't take the address of a Constructor + and pass it as an argument). + */ + template <class MemFn, class C> + Class <T>& addConstructor () + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcclosure (L, &ctorContainerProxy <typename FuncTraits <MemFn>::Params, C>, 0); + rawsetfield (L, -2, "__call"); + + return *this; + } + + template <class MemFn> + Class <T>& addConstructor () + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcclosure (L, &ctorPlacementProxy <typename FuncTraits <MemFn>::Params, T>, 0); + rawsetfield (L, -2, "__call"); + + return *this; + } + }; + +private: + //---------------------------------------------------------------------------- + /** + Open the global namespace for registrations. + */ + explicit Namespace (lua_State* L) + : Registrar (L) + { + lua_getglobal (L, "_G"); + ++m_stackSize; + } + + //---------------------------------------------------------------------------- + /** + Open a namespace for registrations. + + The namespace is created if it doesn't already exist. + The parent namespace is at the top of the Lua stack. + */ + Namespace (char const* name, Namespace& parent) + : Registrar (parent) + { + assert (lua_istable (L, -1)); // Stack: parent namespace (pns) + + rawgetfield (L, -1, name); // Stack: pns, namespace (ns) | nil + + if (lua_isnil (L, -1)) // Stack: pns, nil + { + lua_pop (L, 1); // Stack: pns + + lua_newtable (L); // Stack: pns, ns + lua_pushvalue (L, -1); // Stack: pns, ns, ns + + // na.__metatable = ns + lua_setmetatable (L, -2); // Stack: pns, ns + + // ns.__index = indexMetaMethod + lua_pushcfunction (L, &CFunc::indexMetaMethod); + rawsetfield (L, -2, "__index"); // Stack: pns, ns + + // ns.__newindex = newindexMetaMethod + lua_pushcfunction (L, &CFunc::newindexStaticMetaMethod); + rawsetfield (L, -2, "__newindex"); // Stack: pns, ns + + lua_newtable (L); // Stack: pns, ns, propget table (pg) + lua_rawsetp (L, -2, getPropgetKey ()); // ns [propgetKey] = pg. Stack: pns, ns + + lua_newtable (L); // Stack: pns, ns, propset table (ps) + lua_rawsetp (L, -2, getPropsetKey ()); // ns [propsetKey] = ps. Stack: pns, ns + + // pns [name] = ns + lua_pushvalue (L, -1); // Stack: pns, ns, ns + rawsetfield (L, -3, name); // Stack: pns, ns +#if 0 + lua_pushcfunction (L, &tostringMetaMethod); + rawsetfield (L, -2, "__tostring"); +#endif + } + + ++m_stackSize; + } + + //---------------------------------------------------------------------------- + /** + Close the class and continue the namespace registrations. + */ + explicit Namespace (ClassBase& child) + : Registrar (child) + { + } + + using Registrar::operator=; + + static int throwAtPanic (lua_State* L) + { + throw std::runtime_error (lua_tostring (L, 1)); + } + +public: + //---------------------------------------------------------------------------- + /** + Open the global namespace. + */ + static Namespace getGlobalNamespace (lua_State* L) + { + lua_atpanic (L, throwAtPanic); + return Namespace (L); + } + + //---------------------------------------------------------------------------- + /** + Open a new or existing namespace for registrations. + */ + Namespace beginNamespace (char const* name) + { + assertIsActive (); + return Namespace (name, *this); + } + + //---------------------------------------------------------------------------- + /** + Continue namespace registration in the parent. + + Do not use this on the global namespace. + */ + Namespace endNamespace () + { + if (m_stackSize == 1) + { + throw std::logic_error ("endNamespace () called on global namespace"); + } + + assert (m_stackSize > 1); + --m_stackSize; + lua_pop (L, 1); + return Namespace (*this); + } + + //---------------------------------------------------------------------------- + /** + Add or replace a variable. + */ + template <class T> + Namespace& addProperty (char const* name, T* pt, bool isWritable = true) + { + return addVariable (name, pt, isWritable); + } + + //---------------------------------------------------------------------------- + /** + Add or replace a variable. + */ + template <class T> + Namespace& addVariable (char const* name, T* pt, bool isWritable = true) + { + if (m_stackSize == 1) + { + throw std::logic_error ("addProperty () called on global namespace"); + } + + assert (lua_istable (L, -1)); // Stack: namespace table (ns) + + lua_pushlightuserdata (L, pt); // Stack: ns, pointer + lua_pushcclosure (L, &CFunc::getVariable <T>, 1); // Stack: ns, getter + CFunc::addGetter (L, name, -2); // Stack: ns + + if (isWritable) + { + lua_pushlightuserdata (L, pt); // Stack: ns, pointer + lua_pushcclosure (L, &CFunc::setVariable <T>, 1); // Stack: ns, setter + } + else + { + lua_pushstring (L, name); // Stack: ns, ps, name + lua_pushcclosure (L, &CFunc::readOnlyError, 1); // Stack: ns, error_fn + } + CFunc::addSetter (L, name, -2); // Stack: ns + + return *this; + } + + //---------------------------------------------------------------------------- + /** + Add or replace a property. + + If the set function is omitted or null, the property is read-only. + */ + template <class TG, class TS = TG> + Namespace& addProperty (char const* name, TG (*get) (), void (*set) (TS) = 0) + { + if (m_stackSize == 1) + { + throw std::logic_error ("addProperty () called on global namespace"); + } + + assert (lua_istable (L, -1)); // Stack: namespace table (ns) + + lua_pushlightuserdata (L, reinterpret_cast <void*> (get)); // Stack: ns, function ptr + lua_pushcclosure (L, &CFunc::Call <TG (*) ()>::f, 1); // Stack: ns, getter + CFunc::addGetter (L, name, -2); + + if (set != 0) + { + lua_pushlightuserdata(L, reinterpret_cast <void*> (set)); // Stack: ns, function ptr + lua_pushcclosure (L, &CFunc::Call <void (*) (TS)>::f, 1); + } + else + { + lua_pushstring (L, name); + lua_pushcclosure (L, &CFunc::readOnlyError, 1); + } + CFunc::addSetter (L, name, -2); + + return *this; + } + + //---------------------------------------------------------------------------- + /** + Add or replace a free function. + */ + template <class FP> + Namespace& addFunction (char const* name, FP const fp) + { + assert (lua_istable (L, -1)); // Stack: namespace table (ns) + + lua_pushlightuserdata (L, reinterpret_cast <void*> (fp)); // Stack: ns, function ptr + lua_pushcclosure (L, &CFunc::Call <FP>::f, 1); // Stack: ns, function + rawsetfield (L, -2, name); // Stack: ns + + return *this; + } + + //---------------------------------------------------------------------------- + /** + Add or replace a lua_CFunction. + */ + Namespace& addFunction (char const* name, int (*const fp) (lua_State*)) + { + return addCFunction (name, fp); + } + + //---------------------------------------------------------------------------- + /** + Add or replace a lua_CFunction. + */ + Namespace& addCFunction (char const* name, int (*const fp) (lua_State*)) + { + assert (lua_istable (L, -1)); // Stack: namespace table (ns) + + lua_pushcfunction (L, fp); // Stack: ns, function + rawsetfield (L, -2, name); // Stack: ns + + return *this; + } + + //---------------------------------------------------------------------------- + /** + Open a new or existing class for registrations. + */ + template <class T> + Class <T> beginClass (char const* name) + { + assertIsActive (); + return Class <T> (name, *this); + } + + //---------------------------------------------------------------------------- + /** + Derive a new class for registrations. + + To continue registrations for the class later, use beginClass (). + Do not call deriveClass () again. + */ + template <class Derived, class Base> + Class <Derived> deriveClass (char const* name) + { + assertIsActive (); + return Class <Derived> (name, *this, ClassInfo <Base>::getStaticKey ()); + } +}; + +//------------------------------------------------------------------------------ +/** + Retrieve the global namespace. + + It is recommended to put your namespace inside the global namespace, and + then add your classes and functions to it, rather than adding many classes + and functions directly to the global namespace. +*/ +inline Namespace getGlobalNamespace (lua_State* L) +{ + return Namespace::getGlobalNamespace (L); +} + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/Security.h b/lib/LuaBridge/Source/LuaBridge/detail/Security.h new file mode 100644 index 0000000..ae5053e --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/Security.h @@ -0,0 +1,72 @@ +#pragma once + +namespace luabridge { + +//------------------------------------------------------------------------------ +/** +security options. +*/ +class Security +{ +public: + static bool hideMetatables() + { + return getSettings().hideMetatables; + } + + static void setHideMetatables(bool shouldHide) + { + getSettings().hideMetatables = shouldHide; + } + +private: + struct Settings + { + Settings() : hideMetatables(true) + { + } + + bool hideMetatables; + }; + + static Settings& getSettings() + { + static Settings settings; + return settings; + } +}; + +//------------------------------------------------------------------------------ +/** +Push an object onto the Lua stack. +*/ +template <class T> +inline void push(lua_State* L, T t) +{ + Stack <T>::push(L, t); +} + +//------------------------------------------------------------------------------ +/** +Set a global value in the lua_State. + +@note This works on any type specialized by `Stack`, including `LuaRef` and +its table proxies. +*/ +template <class T> +inline void setGlobal(lua_State* L, T t, char const* name) +{ + push(L, t); + lua_setglobal(L, name); +} + +//------------------------------------------------------------------------------ +/** +Change whether or not metatables are hidden (on by default). +*/ +inline void setHideMetatables(bool shouldHide) +{ + Security::setHideMetatables(shouldHide); +} + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/Stack.h b/lib/LuaBridge/Source/LuaBridge/detail/Stack.h new file mode 100644 index 0000000..567f059 --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/Stack.h @@ -0,0 +1,489 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + Copyright 2007, Nathan Reed + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include <LuaBridge/detail/LuaHelpers.h> +#include <LuaBridge/detail/Userdata.h> + +#include <string> + +namespace luabridge { + +template <class T> +struct Stack; + +template <> +struct Stack <void> +{ + static void push () + { + } +}; + +//------------------------------------------------------------------------------ +/** + Receive the lua_State* as an argument. +*/ +template <> +struct Stack <lua_State*> +{ + static lua_State* get (lua_State* L, int) + { + return L; + } +}; + +//------------------------------------------------------------------------------ +/** + Push a lua_CFunction. +*/ +template <> +struct Stack <lua_CFunction> +{ + static void push (lua_State* L, lua_CFunction f) + { + lua_pushcfunction (L, f); + } + + static lua_CFunction get (lua_State* L, int index) + { + return lua_tocfunction (L, index); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `int`. +*/ +template <> +struct Stack <int> +{ + static void push (lua_State* L, int value) + { + lua_pushinteger (L, static_cast <lua_Integer> (value)); + } + + static int get (lua_State* L, int index) + { + return static_cast <int> (luaL_checkinteger (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned int`. +*/ +template <> +struct Stack <unsigned int> +{ + static void push (lua_State* L, unsigned int value) + { + lua_pushinteger (L, static_cast <lua_Integer> (value)); + } + + static unsigned int get (lua_State* L, int index) + { + return static_cast <unsigned int> (luaL_checkinteger (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned char`. +*/ +template <> +struct Stack <unsigned char> +{ + static void push (lua_State* L, unsigned char value) + { + lua_pushinteger (L, static_cast <lua_Integer> (value)); + } + + static unsigned char get (lua_State* L, int index) + { + return static_cast <unsigned char> (luaL_checkinteger (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `short`. +*/ +template <> +struct Stack <short> +{ + static void push (lua_State* L, short value) + { + lua_pushinteger (L, static_cast <lua_Integer> (value)); + } + + static short get (lua_State* L, int index) + { + return static_cast <short> (luaL_checkinteger (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned short`. +*/ +template <> +struct Stack <unsigned short> +{ + static void push (lua_State* L, unsigned short value) + { + lua_pushinteger (L, static_cast <lua_Integer> (value)); + } + + static unsigned short get (lua_State* L, int index) + { + return static_cast <unsigned short> (luaL_checkinteger (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `long`. +*/ +template <> +struct Stack <long> +{ + static void push (lua_State* L, long value) + { + lua_pushinteger (L, static_cast <lua_Integer> (value)); + } + + static long get (lua_State* L, int index) + { + return static_cast <long> (luaL_checkinteger (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned long`. +*/ +template <> +struct Stack <unsigned long> +{ + static void push (lua_State* L, unsigned long value) + { + lua_pushinteger (L, static_cast <lua_Integer> (value)); + } + + static unsigned long get (lua_State* L, int index) + { + return static_cast <unsigned long> (luaL_checkinteger (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** + * Stack specialization for `long long`. + */ +template <> +struct Stack <long long> +{ + static void push (lua_State* L, long long value) + { + lua_pushinteger (L, static_cast <lua_Integer> (value)); + } + static long long get (lua_State* L, int index) + { + return static_cast <long long> (luaL_checkinteger (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** + * Stack specialization for `unsigned long long`. + */ +template <> +struct Stack <unsigned long long> +{ + static void push (lua_State* L, unsigned long long value) + { + lua_pushinteger (L, static_cast <lua_Integer> (value)); + } + static unsigned long long get (lua_State* L, int index) + { + return static_cast <unsigned long long> (luaL_checkinteger (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `float`. +*/ +template <> +struct Stack <float> +{ + static void push (lua_State* L, float value) + { + lua_pushnumber (L, static_cast <lua_Number> (value)); + } + + static float get (lua_State* L, int index) + { + return static_cast <float> (luaL_checknumber (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `double`. +*/ +template <> +struct Stack <double> +{ + static void push (lua_State* L, double value) + { + lua_pushnumber (L, static_cast <lua_Number> (value)); + } + + static double get (lua_State* L, int index) + { + return static_cast <double> (luaL_checknumber (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `bool`. +*/ +template <> +struct Stack <bool> +{ + static void push (lua_State* L, bool value) + { + lua_pushboolean (L, value ? 1 : 0); + } + + static bool get (lua_State* L, int index) + { + return lua_toboolean (L, index) ? true : false; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `char`. +*/ +template <> +struct Stack <char> +{ + static void push (lua_State* L, char value) + { + lua_pushlstring (L, &value, 1); + } + + static char get (lua_State* L, int index) + { + return luaL_checkstring (L, index) [0]; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `const char*`. +*/ +template <> +struct Stack <char const*> +{ + static void push (lua_State* L, char const* str) + { + if (str != 0) + lua_pushstring (L, str); + else + lua_pushnil (L); + } + + static char const* get (lua_State* L, int index) + { + return lua_isnil (L, index) ? 0 : luaL_checkstring (L, index); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `std::string`. +*/ +template <> +struct Stack <std::string> +{ + static void push (lua_State* L, std::string const& str) + { + lua_pushlstring (L, str.data (), str.size ()); + } + + static std::string get (lua_State* L, int index) + { + size_t len; + const char *str = luaL_checklstring (L, index, &len); + return std::string (str, len); + } +}; + + +template <class T> +struct StackOpSelector <T&, false> +{ + typedef T ReturnType; + + static void push (lua_State* L, T& value) + { + Stack <T>::push (L, value); + } + + static ReturnType get (lua_State* L, int index) + { + return Stack <T>::get (L, index); + } +}; + +template <class T> +struct StackOpSelector <const T&, false> +{ + typedef T ReturnType; + + static void push (lua_State* L, const T& value) + { + Stack <T>::push (L, value); + } + + static ReturnType get (lua_State* L, int index) + { + return Stack <T>::get (L, index); + } +}; + +template <class T> +struct StackOpSelector <T*, false> +{ + typedef T ReturnType; + + static void push (lua_State* L, T* value) + { + Stack <T>::push (L, *value); + } + + static ReturnType get (lua_State* L, int index) + { + return Stack <T>::get (L, index); + } +}; + +template <class T> +struct StackOpSelector <const T*, false> +{ + typedef T ReturnType; + + static void push (lua_State* L, const T* value) + { + Stack <T>::push (L, *value); + } + + static ReturnType get (lua_State* L, int index) + { + return Stack <T>::get (L, index); + } +}; + + +template <class T> +struct Stack <T&> +{ + typedef StackOpSelector <T&, IsUserdata <T>::value> Helper; + typedef typename Helper::ReturnType ReturnType; + + static void push (lua_State* L, T& value) + { + Helper::push (L, value); + } + + static ReturnType get (lua_State* L, int index) + { + return Helper::get (L, index); + } +}; + +template <class T> +struct Stack <const T&> +{ + typedef StackOpSelector <const T&, IsUserdata <T>::value> Helper; + typedef typename Helper::ReturnType ReturnType; + + static void push (lua_State* L, const T& value) + { + Helper::push (L, value); + } + + static ReturnType get (lua_State* L, int index) + { + return Helper::get (L, index); + } +}; + +template <class T> +struct Stack <T*> +{ + typedef StackOpSelector <T*, IsUserdata <T>::value> Helper; + typedef typename Helper::ReturnType ReturnType; + + static void push (lua_State* L, T* value) + { + Helper::push (L, value); + } + + static ReturnType get (lua_State* L, int index) + { + return Helper::get (L, index); + } +}; + +template <class T> +struct Stack <const T*> +{ + typedef StackOpSelector <const T*, IsUserdata <T>::value> Helper; + typedef typename Helper::ReturnType ReturnType; + + static void push (lua_State* L, const T* value) + { + Helper::push (L, value); + } + + static ReturnType get (lua_State* L, int index) + { + return Helper::get (L, index); + } +}; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/TypeList.h b/lib/LuaBridge/Source/LuaBridge/detail/TypeList.h new file mode 100644 index 0000000..d142f6e --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/TypeList.h @@ -0,0 +1,218 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + Copyright 2007, Nathan Reed + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + This file incorporates work covered by the following copyright and + permission notice: + + The Loki Library + Copyright (c) 2001 by Andrei Alexandrescu + This code accompanies the book: + Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design + Patterns Applied". Copyright (c) 2001. Addison-Wesley. + Permission to use, copy, modify, distribute and sell this software for any + purpose is hereby granted without fee, provided that the above copyright + notice appear in all copies and that both that copyright notice and this + permission notice appear in supporting documentation. + The author or Addison-Welsey Longman make no representations about the + suitability of this software for any purpose. It is provided "as is" + without express or implied warranty. +*/ +//============================================================================== + +#pragma once + +#include <LuaBridge/detail/Config.h> +#include <LuaBridge/detail/Stack.h> + +#include <string> +#include <typeinfo> + +namespace luabridge { + +/** + None type means void parameters or return value. +*/ +typedef void None; + +template <typename Head, typename Tail = None> +struct TypeList +{ + typedef Tail TailType; +}; + +template <class List> +struct TypeListSize +{ + static const size_t value = TypeListSize <typename List::TailType>::value + 1; +}; + +template <> +struct TypeListSize <None> +{ + static const size_t value = 0; +}; + +#ifdef LUABRIDGE_CXX11 + +template <class... Params> +struct MakeTypeList; + +template <class Param, class... Params> +struct MakeTypeList <Param, Params...> +{ + using Result = TypeList <Param, typename MakeTypeList <Params...>::Result>; +}; + +template <> +struct MakeTypeList <> +{ + using Result = None; +}; + +#endif + +/** + A TypeList with actual values. +*/ +template <typename List> +struct TypeListValues +{ + static std::string const tostring (bool) + { + return ""; + } +}; + +/** + TypeListValues recursive template definition. +*/ +template <typename Head, typename Tail> +struct TypeListValues <TypeList <Head, Tail> > +{ + Head hd; + TypeListValues <Tail> tl; + + TypeListValues (Head hd_, TypeListValues <Tail> const& tl_) + : hd (hd_), tl (tl_) + { + } + + static std::string tostring (bool comma = false) + { + std::string s; + + if (comma) + s = ", "; + + s = s + typeid (Head).name (); + + return s + TypeListValues <Tail>::tostring (true); + } +}; + +// Specializations of type/value list for head types that are references and +// const-references. We need to handle these specially since we can't count +// on the referenced object hanging around for the lifetime of the list. + +template <typename Head, typename Tail> +struct TypeListValues <TypeList <Head&, Tail> > +{ + Head hd; + TypeListValues <Tail> tl; + + TypeListValues (Head& hd_, TypeListValues <Tail> const& tl_) + : hd (hd_), tl (tl_) + { + } + + static std::string const tostring (bool comma = false) + { + std::string s; + + if (comma) + s = ", "; + + s = s + typeid (Head).name () + "&"; + + return s + TypeListValues <Tail>::tostring (true); + } +}; + +template <typename Head, typename Tail> +struct TypeListValues <TypeList <Head const&, Tail> > +{ + Head hd; + TypeListValues <Tail> tl; + + TypeListValues (Head const& hd_, const TypeListValues <Tail>& tl_) + : hd (hd_), tl (tl_) + { + } + + static std::string const tostring (bool comma = false) + { + std::string s; + + if (comma) + s = ", "; + + s = s + typeid (Head).name () + " const&"; + + return s + TypeListValues <Tail>::tostring (true); + } +}; + +//============================================================================== +/** + Subclass of a TypeListValues constructable from the Lua stack. +*/ + +template <typename List, int Start = 1> +struct ArgList +{ +}; + +template <int Start> +struct ArgList <None, Start> : public TypeListValues <None> +{ + ArgList (lua_State*) + { + } +}; + +template <typename Head, typename Tail, int Start> +struct ArgList <TypeList <Head, Tail>, Start> + : public TypeListValues <TypeList <Head, Tail> > +{ + ArgList (lua_State* L) + : TypeListValues <TypeList <Head, Tail> > (Stack <Head>::get (L, Start), + ArgList <Tail, Start + 1> (L)) + { + } +}; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/TypeTraits.h b/lib/LuaBridge/Source/LuaBridge/detail/TypeTraits.h new file mode 100644 index 0000000..5fad375 --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/TypeTraits.h @@ -0,0 +1,135 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include <string> + + +namespace luabridge { + +//------------------------------------------------------------------------------ +/** + Container traits. + + Unspecialized ContainerTraits has the isNotContainer typedef for SFINAE. + All user defined containers must supply an appropriate specialization for + ContinerTraits (without the typedef isNotContainer). The containers that + come with LuaBridge also come with the appropriate ContainerTraits + specialization. See the corresponding declaration for details. + + A specialization of ContainerTraits for some generic type ContainerType + looks like this: + + template <class T> + struct ContainerTraits <ContainerType <T> > + { + typedef typename T Type; + + static T* get (ContainerType <T> const& c) + { + return c.get (); // Implementation-dependent on ContainerType + } + }; +*/ +template <class T> +struct ContainerTraits +{ + typedef bool isNotContainer; + typedef T Type; +}; + +//------------------------------------------------------------------------------ +/** + Type traits. + + Specializations return information about a type. +*/ +struct TypeTraits +{ + /** Determine if type T is a container. + + To be considered a container, there must be a specialization of + ContainerTraits with the required fields. + */ + template <typename T> + class isContainer + { + private: + typedef char yes[1]; // sizeof (yes) == 1 + typedef char no [2]; // sizeof (no) == 2 + + template <typename C> + static no& test (typename C::isNotContainer*); + + template <typename> + static yes& test (...); + + public: + static const bool value = sizeof (test <ContainerTraits <T> >(0)) == sizeof (yes); + }; + + /** Determine if T is const qualified. + */ + /** @{ */ + template <class T> + struct isConst + { + static bool const value = false; + }; + + template <class T> + struct isConst <T const> + { + static bool const value = true; + }; + /** @} */ + + /** Remove the const qualifier from T. + */ + /** @{ */ + template <class T> + struct removeConst + { + typedef T Type; + }; + + template <class T> + struct removeConst <T const> + { + typedef T Type; + }; + /**@}*/ +}; + + +template <class T> +struct Stack; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/Userdata.h b/lib/LuaBridge/Source/LuaBridge/detail/Userdata.h new file mode 100644 index 0000000..2b82460 --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/Userdata.h @@ -0,0 +1,742 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include <LuaBridge/detail/ClassInfo.h> + +#include <cassert> +#include <stdexcept> + + +namespace luabridge { + +//============================================================================== +/** + Return the identity pointer for our lightuserdata tokens. + + Because of Lua's dynamic typing and our improvised system of imposing C++ + class structure, there is the possibility that executing scripts may + knowingly or unknowingly cause invalid data to get passed to the C functions + created by LuaBridge. In particular, our security model addresses the + following: + 1. Scripts cannot create a userdata (ignoring the debug lib). + 2. Scripts cannot create a lightuserdata (ignoring the debug lib). + 3. Scripts cannot set the metatable on a userdata. +*/ + +/** + Interface to a class pointer retrievable from a userdata. +*/ +class Userdata +{ +protected: + void* m_p; // subclasses must set this + + //-------------------------------------------------------------------------- + /** + Get an untyped pointer to the contained class. + */ + void* getPointer () + { + return m_p; + } + +private: + //-------------------------------------------------------------------------- + /** + Validate and retrieve a Userdata on the stack. + + The Userdata must exactly match the corresponding class table or + const table, or else a Lua error is raised. This is used for the + __gc metamethod. + */ + static Userdata* getExactClass (lua_State* L, int index, [[maybe_unused]]void const* classKey) + { + return static_cast <Userdata*> (lua_touserdata (L, lua_absindex (L, index))); + } + + //-------------------------------------------------------------------------- + /** + Validate and retrieve a Userdata on the stack. + + The Userdata must be derived from or the same as the given base class, + identified by the key. If canBeConst is false, generates an error if + the resulting Userdata represents to a const object. We do the type check + first so that the error message is informative. + */ + static Userdata* getClass (lua_State* L, + int index, + void const* registryConstKey, + void const* registryClassKey, + bool canBeConst) + { + index = lua_absindex (L, index); + + lua_getmetatable (L, index); // Stack: ot | nil + if (!lua_istable (L, -1)) + { + lua_rawgetp (L, LUA_REGISTRYINDEX, registryClassKey); // Stack: registry metatable (rt) | nil + return throwBadArg (L, index); + } + + lua_rawgetp (L, -1, getConstKey ()); // Stack: ot | nil, const table (co) | nil + assert (lua_istable (L, -1) || lua_isnil (L, -1)); + + // If const table is NOT present, object is const. Use non-const registry table + // if object cannot be const, so constness validation is done automatically. + // E.g. nonConstFn (constObj) + // -> canBeConst = false, isConst = true + // -> 'Class' registry table, 'const Class' object table + // -> 'expected Class, got const Class' + bool isConst = lua_isnil (L, -1); // Stack: ot | nil, nil, rt + if (isConst && canBeConst) + { + lua_rawgetp (L, LUA_REGISTRYINDEX, registryConstKey); // Stack: ot, nil, rt + } + else + { + lua_rawgetp (L, LUA_REGISTRYINDEX, registryClassKey); // Stack: ot, co, rt + } + + lua_insert (L, -3); // Stack: rt, ot, co | nil + lua_pop (L, 1); // Stack: rt, ot + + for (;;) + { + if (lua_rawequal (L, -1, -2)) + { + lua_pop (L, 2); // Stack: - + return static_cast <Userdata*> (lua_touserdata (L, index)); + } + + // Replace current metatable with it's base class. + lua_rawgetp (L, -1, getParentKey ()); // Stack: rt, ot, parent ot (pot) | nil + + if (lua_isnil (L, -1)) // Stack: rt, ot, nil + { + // Drop the object metatable because it may be some parent metatable + lua_pop (L, 2); // Stack: rt + return throwBadArg (L, index); + } + + lua_remove (L, -2); // Stack: rt, pot + } + + // no return + } + + static Userdata* throwBadArg (lua_State* L, int index) + { + assert (lua_istable (L, -1) || lua_isnil (L, -1)); // Stack: rt | nil + + const char* expected = 0; + if (lua_isnil (L, -1)) // Stack: nil + { + expected = "unregistered class"; + } + else + { + lua_rawgetp (L, -1, getTypeKey ()); // Stack: rt, registry type + expected = lua_tostring (L, -1); + } + + const char* got = 0; + if (lua_isuserdata (L, index)) + { + lua_getmetatable (L, index); // Stack: ..., ot | nil + if (lua_istable (L, -1)) // Stack: ..., ot + { + lua_rawgetp (L, -1, getTypeKey ()); // Stack: ..., ot, object type | nil + if (lua_isstring (L, -1)) + { + got = lua_tostring (L, -1); + } + } + } + if (!got) + { + got = lua_typename (L, lua_type (L, index)); + } + + luaL_argerror (L, index, lua_pushfstring (L, "%s expected, got %s", expected, got)); + return 0; + } + +public: + virtual ~Userdata () { } + + //-------------------------------------------------------------------------- + /** + Returns the Userdata* if the class on the Lua stack matches. + + If the class does not match, a Lua error is raised. + */ + template <class T> + static inline Userdata* getExact (lua_State* L, int index) + { + return getExactClass (L, index, ClassInfo <T>::getClassKey ()); + } + + //-------------------------------------------------------------------------- + /** + Get a pointer to the class from the Lua stack. + + If the object is not the class or a subclass, or it violates the + const-ness, a Lua error is raised. + */ + template <class T> + static inline T* get (lua_State* L, int index, bool canBeConst) + { + if (lua_isnil (L, index)) + return 0; + + return static_cast <T*> (getClass ( + L, index, ClassInfo <T>::getConstKey (), + ClassInfo <T>::getClassKey (), + canBeConst)->getPointer ()); + } +}; + +//---------------------------------------------------------------------------- +/** + Wraps a class object stored in a Lua userdata. + + The lifetime of the object is managed by Lua. The object is constructed + inside the userdata using placement new. +*/ +template <class T> +class UserdataValue : public Userdata +{ +private: + UserdataValue <T> (UserdataValue <T> const&); + UserdataValue <T> operator= (UserdataValue <T> const&); + + char m_storage [sizeof (T)]; + + inline T* getObject () + { + // If this fails to compile it means you forgot to provide + // a Container specialization for your container! + // + return reinterpret_cast <T*> (&m_storage [0]); + } + +private: + /** + Used for placement construction. + */ + UserdataValue () + { + m_p = getObject (); + } + + ~UserdataValue () + { + getObject ()->~T (); + } + +public: + /** + Push a T via placement new. + + The caller is responsible for calling placement new using the + returned uninitialized storage. + */ + static void* place (lua_State* const L) + { + UserdataValue <T>* const ud = new ( + lua_newuserdata (L, sizeof (UserdataValue <T>))) UserdataValue <T> (); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ()); + if (!lua_istable (L, -1)) + { + throw std::logic_error ("The class is not registered in LuaBridge"); + } + lua_setmetatable (L, -2); + return ud->getPointer (); + } + + /** + Push T via copy construction from U. + */ + template <class U> + static inline void push (lua_State* const L, U const& u) + { + new (place (L)) U (u); + } +}; + +//---------------------------------------------------------------------------- +/** + Wraps a pointer to a class object inside a Lua userdata. + + The lifetime of the object is managed by C++. +*/ +class UserdataPtr : public Userdata +{ +private: + UserdataPtr (UserdataPtr const&); + UserdataPtr operator= (UserdataPtr const&); + +private: + /** Push a pointer to object using metatable key. + */ + static void push (lua_State* L, const void* p, void const* const key) + { + new (lua_newuserdata (L, sizeof (UserdataPtr))) UserdataPtr (const_cast <void*> (p)); + lua_rawgetp (L, LUA_REGISTRYINDEX, key); + if (!lua_istable (L, -1)) + { + throw std::logic_error ("The class is not registered in LuaBridge"); + } + lua_setmetatable (L, -2); + } + + explicit UserdataPtr (void* const p) + { + m_p = p; + + // Can't construct with a null pointer! + // + assert (m_p != 0); + } + +public: + /** Push non-const pointer to object. + */ + template <class T> + static void push (lua_State* const L, T* const p) + { + if (p) + push (L, p, ClassInfo <T>::getClassKey ()); + else + lua_pushnil (L); + } + + /** Push const pointer to object. + */ + template <class T> + static void push (lua_State* const L, T const* const p) + { + if (p) + push (L, p, ClassInfo <T>::getConstKey ()); + else + lua_pushnil (L); + } +}; + +//============================================================================ +/** + Wraps a container that references a class object. + + The template argument C is the container type, ContainerTraits must be + specialized on C or else a compile error will result. +*/ +template <class C> +class UserdataShared : public Userdata +{ +private: + UserdataShared (UserdataShared <C> const&); + UserdataShared <C>& operator= (UserdataShared <C> const&); + + typedef typename TypeTraits::removeConst < + typename ContainerTraits <C>::Type>::Type T; + + C m_c; + +private: + ~UserdataShared () + { + } + +public: + /** + Construct from a container to the class or a derived class. + */ + template <class U> + explicit UserdataShared (U const& u) : m_c (u) + { + m_p = const_cast <void*> (reinterpret_cast <void const*> ( + (ContainerTraits <C>::get (m_c)))); + } + + /** + Construct from a pointer to the class or a derived class. + */ + template <class U> + explicit UserdataShared (U* u) : m_c (u) + { + m_p = const_cast <void*> (reinterpret_cast <void const*> ( + (ContainerTraits <C>::get (m_c)))); + } +}; + +//---------------------------------------------------------------------------- +// +// SFINAE helpers. +// + +// non-const objects +template <class C, bool makeObjectConst> +struct UserdataSharedHelper +{ + typedef typename TypeTraits::removeConst < + typename ContainerTraits <C>::Type>::Type T; + + static void push (lua_State* L, C const& c) + { + if (ContainerTraits <C>::get (c) != 0) + { + new (lua_newuserdata (L, sizeof (UserdataShared <C>))) UserdataShared <C> (c); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ()); + // If this goes off it means the class T is unregistered! + assert (lua_istable (L, -1)); + lua_setmetatable (L, -2); + } + else + { + lua_pushnil (L); + } + } + + static void push (lua_State* L, T* const t) + { + if (t) + { + new (lua_newuserdata (L, sizeof (UserdataShared <C>))) UserdataShared <C> (t); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ()); + // If this goes off it means the class T is unregistered! + assert (lua_istable (L, -1)); + lua_setmetatable (L, -2); + } + else + { + lua_pushnil (L); + } + } +}; + +// const objects +template <class C> +struct UserdataSharedHelper <C, true> +{ + typedef typename TypeTraits::removeConst < + typename ContainerTraits <C>::Type>::Type T; + + static void push (lua_State* L, C const& c) + { + if (ContainerTraits <C>::get (c) != 0) + { + new (lua_newuserdata (L, sizeof (UserdataShared <C>))) UserdataShared <C> (c); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getConstKey ()); + // If this goes off it means the class T is unregistered! + assert (lua_istable (L, -1)); + lua_setmetatable (L, -2); + } + else + { + lua_pushnil (L); + } + } + + static void push (lua_State* L, T* const t) + { + if (t) + { + new (lua_newuserdata (L, sizeof (UserdataShared <C>))) UserdataShared <C> (t); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getConstKey ()); + // If this goes off it means the class T is unregistered! + assert (lua_istable (L, -1)); + lua_setmetatable (L, -2); + } + else + { + lua_pushnil (L); + } + } +}; + +/** + Pass by container. + + The container controls the object lifetime. Typically this will be a + lifetime shared by C++ and Lua using a reference count. Because of type + erasure, containers like std::shared_ptr will not work. Containers must + either be of the intrusive variety, or in the style of the RefCountedPtr + type provided by LuaBridge (that uses a global hash table). +*/ +template <class C, bool byContainer> +struct StackHelper +{ + static void push (lua_State* L, C const& c) + { + UserdataSharedHelper <C, + TypeTraits::isConst <typename ContainerTraits <C>::Type>::value>::push (L, c); + } + + typedef typename TypeTraits::removeConst < + typename ContainerTraits <C>::Type>::Type T; + + static C get (lua_State* L, int index) + { + return Userdata::get <T> (L, index, true); + } +}; + +/** + Pass by value. + + Lifetime is managed by Lua. A C++ function which accesses a pointer or + reference to an object outside the activation record in which it was + retrieved may result in undefined behavior if Lua garbage collected it. +*/ +template <class T> +struct StackHelper <T, false> +{ + static inline void push (lua_State* L, T const& t) + { + UserdataValue <T>::push (L, t); + } + + static inline T const& get (lua_State* L, int index) + { + return *Userdata::get <T> (L, index, true); + } +}; + + +//------------------------------------------------------------------------------ +/** + Lua stack conversions for pointers and references to class objects. + + Lifetime is managed by C++. Lua code which remembers a reference to the + value may result in undefined behavior if C++ destroys the object. The + handling of the const and volatile qualifiers happens in UserdataPtr. +*/ + +template <class C, bool byContainer> +struct RefStackHelper +{ + typedef C return_type; + + static inline void push (lua_State* L, C const& t) + { + UserdataSharedHelper <C, + TypeTraits::isConst <typename ContainerTraits <C>::Type>::value>::push (L, t); + } + + typedef typename TypeTraits::removeConst < + typename ContainerTraits <C>::Type>::Type T; + + static return_type get (lua_State* L, int index) + { + return Userdata::get <T> (L, index, true); + } +}; + +template <class T> +struct RefStackHelper <T, false> +{ + typedef T& return_type; + + static void push (lua_State* L, T const& t) + { + UserdataPtr::push (L, &t); + } + + static return_type get (lua_State* L, int index) + { + T* t = Userdata::get <T> (L, index, true); + + if (!t) + luaL_error (L, "nil passed to reference"); + return *t; + } +}; + + +/** + * Voider class template. Used to force a comiler to instantiate + * an otherwise probably unused template parameter type T. + * See the C++20 std::void_t <> for details. + */ +template <class T> +struct Void +{ + typedef void Type; +}; + + +/** + * Trait class that selects whether to return a user registered + * class object by value or by reference. + */ + +template <class T, class Enabler = void> +struct UserdataGetter +{ + typedef T* ReturnType; + + static ReturnType get (lua_State* L, int index) + { + return Userdata::get <T> (L, index, false); + } +}; + +template <class T> +struct UserdataGetter <T, typename Void <T (*) ()>::Type> +{ + typedef T ReturnType; + + static ReturnType get (lua_State* L, int index) + { + return StackHelper <T, TypeTraits::isContainer <T>::value>::get (L, index); + } +}; + +//============================================================================== + +/** + Lua stack conversions for class objects passed by value. +*/ +template <class T> +struct Stack +{ + typedef void IsUserdata; + + typedef UserdataGetter <T> Getter; + typedef typename Getter::ReturnType ReturnType; + + static void push (lua_State* L, T const& value) + { + StackHelper <T, TypeTraits::isContainer <T>::value>::push (L, value); + } + + static ReturnType get (lua_State* L, int index) + { + return Getter::get (L, index); + } +}; + + +/** + * Trait class indicating whether the parameter type must be + * a user registered class. The trait checks the existence of + * member type Stack <T>::IsUserdata specialization for detection. + */ +template <class T, class Enable = void> +struct IsUserdata +{ + static const bool value = false; +}; + +template <class T> +struct IsUserdata <T, typename Void <typename Stack <T>::IsUserdata>::Type> +{ + static const bool value = true; +}; + + +/** + * Trait class that selects a specific push/get implemenation. + */ +template <class T, bool isUserdata> +struct StackOpSelector; + +// pointer +template <class T> +struct StackOpSelector <T*, true> +{ + typedef T* ReturnType; + + static void push (lua_State* L, T* value) + { + UserdataPtr::push (L, value); + } + + static T* get (lua_State* L, int index) + { + return Userdata::get <T> (L, index, false); + } +}; + +// pointer to const +template <class T> +struct StackOpSelector <const T*, true> +{ + typedef const T* ReturnType; + + static void push (lua_State* L, const T* value) + { + UserdataPtr::push (L, value); + } + + static const T* get (lua_State* L, int index) + { + return Userdata::get <T> (L, index, true); + } +}; + +// reference +template <class T> +struct StackOpSelector <T&, true> +{ + typedef RefStackHelper <T, TypeTraits::isContainer <T>::value> Helper; + typedef typename Helper::return_type ReturnType; + + static void push (lua_State* L, T& value) + { + UserdataPtr::push (L, &value); + } + + static ReturnType get (lua_State* L, int index) + { + return Helper::get (L, index); + } +}; + +// reference to const +template <class T> +struct StackOpSelector <const T&, true> +{ + typedef RefStackHelper <T, TypeTraits::isContainer <T>::value> Helper; + typedef typename Helper::return_type ReturnType; + + static void push (lua_State* L, const T& value) + { + Helper::push (L, value); + } + + static ReturnType get (lua_State* L, int index) + { + return Helper::get (L, index); + } +}; + +} // namespace luabridge diff --git a/lib/LuaBridge/Source/LuaBridge/detail/dump.h b/lib/LuaBridge/Source/LuaBridge/detail/dump.h new file mode 100644 index 0000000..7e23f9f --- /dev/null +++ b/lib/LuaBridge/Source/LuaBridge/detail/dump.h @@ -0,0 +1,143 @@ +//============================================================================== +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> + Copyright 2007, Nathan Reed + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include "LuaBridge/detail/ClassInfo.h" + +#include <iostream> +#include <string> + + +namespace luabridge { +namespace debug { + +inline void putIndent (std::ostream& stream, unsigned level) +{ + for (unsigned i = 0; i < level; ++i) + { + stream << " "; + } +} + +inline void dumpTable (lua_State* L, int index, std::ostream& stream, unsigned level); + +inline void dumpValue (lua_State* L, int index, std::ostream& stream, unsigned level = 0) +{ + const int type = lua_type (L, index); + switch (type) + { + case LUA_TNIL: + stream << "nil"; + break; + + case LUA_TBOOLEAN: + stream << (lua_toboolean (L, index) ? "true" : "false"); + break; + + case LUA_TNUMBER: + stream << lua_tonumber (L, index); + break; + + case LUA_TSTRING: + stream << '"' << lua_tostring (L, index) << '"'; + break; + + case LUA_TFUNCTION: + if (lua_iscfunction (L, index)) + { + stream << "cfunction@" << lua_topointer (L, index); + } + else + { + stream << "function@" << lua_topointer (L, index); + } + break; + + case LUA_TTHREAD: + stream << "thread@" << lua_tothread (L, index); + break; + + case LUA_TLIGHTUSERDATA: + stream << "lightuserdata@" << lua_touserdata (L, index); + break; + + case LUA_TTABLE: + dumpTable (L, index, stream, level); + break; + + case LUA_TUSERDATA: + stream << "userdata@" << lua_touserdata (L, index); + break; + + default: + stream << lua_typename (L, type);; + break; + } +} + +inline void dumpTable (lua_State* L, int index, std::ostream& stream, unsigned level) +{ + stream << "table@" << lua_topointer (L, index); + + if (level > 0) + { + return; + } + + index = lua_absindex (L, index); + stream << " {"; + lua_pushnil (L); // Initial key + while (lua_next (L, index)) + { + stream << "\n"; + putIndent (stream, level + 1); + dumpValue (L, -2, stream, level + 1); // Key + stream << ": "; + dumpValue (L, -1, stream, level + 1); // Value + lua_pop (L, 1); // Value + } + putIndent (stream, level); + stream << "\n}"; +} + +inline void dumpState (lua_State *L, std::ostream& stream = std::cerr) +{ + int top = lua_gettop (L); + for (int i = 1; i <= top; ++i) + { + stream << "stack #" << i << ": "; + dumpValue (L, i, stream, 0); + stream << "\n"; + } +} + +} // namespace debug +} // namespace luabridge |