diff --git a/CMakeLists.txt b/CMakeLists.txt index 90a0b773..a657a73f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,9 +2,9 @@ cmake_minimum_required(VERSION 3.0) cmake_policy(SET CMP0017 NEW) # need include() with .cmake project(pip) set(_PIP_MAJOR 1) -set(_PIP_MINOR 24) +set(_PIP_MINOR 99) set(_PIP_REVISION 0) -set(_PIP_SUFFIX ) +set(_PIP_SUFFIX _prealpha) set(_PIP_COMPANY SHS) set(_PIP_DOMAIN org.SHS) @@ -67,6 +67,7 @@ set(PIP_SRC_OPENCL "lib/opencl") set(PIP_SRC_IO_UTILS "lib/io_utils") set(PIP_SRC_CONCURRENT "lib/concurrent") set(PIP_SRC_CLOUD "lib/cloud") +set(PIP_SRC_LUA "lib/lua") set(PIP_SRC_DIRS ${PIP_SRC_MAIN} ${PIP_SRC_CONSOLE} ${PIP_SRC_CRYPT} @@ -83,6 +84,7 @@ set(LIBS_MAIN) set(LIBS_STATUS) set(HDRS) set(PHDRS) +set(HDR_DIRS) if (TESTS) include(DownloadGTest) @@ -122,7 +124,6 @@ endif() list(APPEND HDRS "${CMAKE_CURRENT_BINARY_DIR}/piversion.h") message(STATUS "Building PIP version ${PIP_VERSION} (${PIP_LIB_TYPE})") - if(MINGW) find_package(MinGW REQUIRED) list(APPEND CMAKE_LIBRARY_PATH ${MINGW_LIB}) @@ -179,7 +180,7 @@ get_filename_component(C_COMPILER "${CMAKE_C_COMPILER}" NAME) # Sources # Main lib -set(PIP_FOLDERS "." "core" "containers" "thread" "system" "io_devices" "io_utils" "console" "math" "code" "geo" "resources" "opencl" "crypt" "introspection" "concurrent" "cloud") +set(PIP_FOLDERS "." "core" "containers" "thread" "system" "io_devices" "io_utils" "console" "math" "code" "geo" "resources" "opencl" "crypt" "introspection" "concurrent" "cloud" "lua") include_directories("${PIP_SRC_MAIN}") set(PIP_MAIN_FOLDERS) foreach(F ${PIP_FOLDERS}) @@ -216,6 +217,9 @@ gather_src("${PIP_CONCURRENT_TEST}" CPP_CONCURRENT_TEST HDRS PHDRS) # Cloud lib gather_src("${PIP_SRC_CLOUD}" CPP_LIB_CLOUD HDRS PHDRS) +# LUA lib +gather_src("${PIP_SRC_LUA}" CPP_LIB_LUA HDRS PHDRS) + if(PIP_FREERTOS) add_definitions(-DPIP_FREERTOS) set(ICU OFF) @@ -614,11 +618,37 @@ if (NOT CROSSTOOLS) list(APPEND PIP_LIBS_TARGETS pip_cloud) endif() - + # Check Lua support + if(MINGW) + set(LUA_INCLUDE_DIR ${MINGW_INCLUDE}) + endif() + find_package(Lua QUIET) + if (LUA_FOUND) + message(STATUS "Building PIP with Lua support: Lua ${LUA_VERSION_STRING}") + import_version(pip_lua pip) + set_deploy_property(pip_lua ${PIP_LIB_TYPE} + LABEL "PIP Lua support" + FULLNAME "${_PIP_DOMAIN}.pip_lua" + COMPANY "${_PIP_COMPANY}" + INFO "Platform-Independent Primitives") + make_rc(pip_lua _RC) + add_definitions(-DPIP_LUA) + include_directories(${LUA_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib/lua/3rd) + list(APPEND HDR_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/lib/lua/3rd/LuaBridge") + add_library(pip_lua ${PIP_LIB_TYPE} ${CPP_LIB_LUA} ${_RC}) + target_link_libraries(pip_lua pip ${LUA_LIBRARIES}) + list(APPEND PIP_LIBS_TARGETS pip_lua) + else() + message(STATUS "Building PIP without Lua support") + endif() + # Test program if(PIP_UTILS) add_executable(pip_test "main.cpp") target_link_libraries(pip_test pip) + if (LUA_FOUND) + target_link_libraries(pip_test pip_lua ${LUA_LIBRARIES}) + endif() endif() else() @@ -650,6 +680,10 @@ if(LIB) if(MINGW) if (NOT CROSSTOOLS) install(FILES ${HDRS} DESTINATION ${MINGW_INCLUDE}/pip) + install(FILES ${HDRS} DESTINATION ${MINGW_INCLUDE}/pip) + if(HDR_DIRS) + install(DIRECTORY ${HDR_DIRS} DESTINATION ${MINGW_INCLUDE}/pip) + endif() install(TARGETS ${PIP_LIBS_TARGETS} ARCHIVE DESTINATION ${MINGW_LIB}) endif() install(TARGETS ${PIP_LIBS_TARGETS} RUNTIME DESTINATION ${MINGW_BIN}) @@ -668,6 +702,9 @@ if(LIB) else() if (NOT CROSSTOOLS) install(FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip) + if(HDR_DIRS) + install(DIRECTORY ${HDR_DIRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip) + endif() endif() install(TARGETS ${PIP_LIBS_TARGETS} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) endif() @@ -683,6 +720,9 @@ else() install(TARGETS ${PIP_LIBS_TARGETS} DESTINATION lib) endif() install(FILES ${HDRS} DESTINATION include/pip) + if(HDR_DIRS) + install(DIRECTORY ${HDR_DIRS} DESTINATION include/pip) + endif() message(STATUS "Install ${PROJECT_NAME} to local \"bin\", \"lib\" and \"include\"") endif() endif() diff --git a/cmake/FindPIP.cmake b/cmake/FindPIP.cmake index 5b21dc6b..0752e873 100644 --- a/cmake/FindPIP.cmake +++ b/cmake/FindPIP.cmake @@ -10,6 +10,7 @@ Also create imported targets: * PIP::IOUtils * PIP::Concurrent * PIP::Cloud + * PIP::Lua These targets include directories and depends on main library @@ -66,6 +67,7 @@ find_library(PIP_COMPRESS_LIBRARY pip_compress${_pip_suffix} HINTS ${_PIP_LIBDIR find_library(PIP_IO_UTILS_LIBRARY pip_io_utils${_pip_suffix} HINTS ${_PIP_LIBDIR}) find_library(PIP_CONCURRENT_LIBRARY pip_concurrent${_pip_suffix} HINTS ${_PIP_LIBDIR}) find_library(PIP_CLOUD_LIBRARY pip_cloud HINTS${_pip_suffix} ${_PIP_LIBDIR}) +find_library(PIP_LUA_LIBRARY pip_lua HINTS${_pip_suffix} ${_PIP_LIBDIR}) find_file(PIP_H_INCLUDE "pip.h" HINTS ${_PIP_INCDIR} $ENV{SMSDK_DIR}/include/pip) get_filename_component(PIP_INCLUDES ${PIP_H_INCLUDE} PATH) set(__ext "") @@ -94,6 +96,19 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") list(APPEND PIP_LIBRARY ${_PIP_ADD_LIBS_}) endif() endif() +if(PIP_LUA_LIBRARY) + if (NOT LUA_FOUND) + if(MINGW) + set(LUA_INCLUDE_DIR ${MINGW_INCLUDE}) + set(_prev_clp "${CMAKE_LIBRARY_PATH}") + set(CMAKE_LIBRARY_PATH "${MINGW_LIB}") + endif() + find_package(Lua QUIET) + if(MINGW) + set(CMAKE_LIBRARY_PATH "${_prev_clp}") + endif() + endif() +endif() if(NOT PIP_VERSION) include(CheckSymbolExists) @@ -117,7 +132,7 @@ if(PIP_FIND_VERSION VERSION_GREATER PIP_VERSION) message(FATAL_ERROR "PIP version ${PIP_VERSION} is available, but ${PIP_FIND_VERSION} requested!") endif() -set(__modules "USB;Crypt;Console;FFTW;Compress;IOUtils;Concurrent;Cloud") +set(__modules "USB;Crypt;Console;FFTW;Compress;IOUtils;Concurrent;Cloud;Lua") set(__module_USB "${PIP_USB_LIBRARY}" ) set(__module_Console "${PIP_CONSOLE_LIBRARY}" ) set(__module_Crypt "${PIP_CRYPT_LIBRARY}" ) @@ -126,6 +141,7 @@ set(__module_Compress "${PIP_COMPRESS_LIBRARY}" ) set(__module_IOUtils "${PIP_IO_UTILS_LIBRARY}" ) set(__module_Concurrent "${PIP_CONCURRENT_LIBRARY}") set(__module_Cloud "${PIP_CLOUD_LIBRARY}" ) +set(__module_Lua "${PIP_LUA_LIBRARY}" ) if((NOT TARGET PIP) AND PIP_LIBRARY) add_library(PIP UNKNOWN IMPORTED) set_target_properties(PIP PROPERTIES @@ -147,6 +163,9 @@ endif() if(__module_Cloud AND __module_IOUtils) set_target_properties(PIP::Cloud PROPERTIES INTERFACE_LINK_LIBRARIES "PIP::IOUtils") endif() +if(__module_Lua) + set_target_properties(PIP::Lua PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LUA_INCLUDE_DIR}" INTERFACE_LINK_LIBRARIES "PIP;${LUA_LIBRARIES}") +endif() include(PIPMacros) diff --git a/lib/fftw/pifft_p.h b/lib/fftw/pifft_p.h index 92c7f378..b4551a94 100644 --- a/lib/fftw/pifft_p.h +++ b/lib/fftw/pifft_p.h @@ -24,7 +24,6 @@ #define PIFFT_P_H #include "pivector.h" -#include "pimutex.h" #include "picout.h" #if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq) # include "fftw3.h" diff --git a/lib/lua/3rd/LuaBridge/List.h b/lib/lua/3rd/LuaBridge/List.h new file mode 100644 index 00000000..66e0d8fb --- /dev/null +++ b/lib/lua/3rd/LuaBridge/List.h @@ -0,0 +1,55 @@ +// https://github.com/vinniefalco/LuaBridge +// +// Copyright 2018, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include + +namespace luabridge { + +template +struct Stack > +{ + static void push (lua_State* L, std::list const& list) + { + lua_createtable (L, static_cast (list.size ()), 0); + typename std::list ::const_iterator item = list.begin (); + for (std::size_t i = 1; i <= list.size (); ++i) + { + lua_pushinteger (L, static_cast (i)); + Stack ::push (L, *item); + lua_settable (L, -3); + ++item; + } + } + + static std::list get (lua_State* L, int index) + { + if (!lua_istable (L, index)) + { + luaL_error (L, "#%d argument must be a table", index); + } + + std::list list; + + int const absindex = lua_absindex (L, index); + lua_pushnil (L); + while (lua_next (L, absindex) != 0) + { + list.push_back (Stack ::get (L, -1)); + lua_pop (L, 1); + } + return list; + } + + static bool isInstance (lua_State* L, int index) + { + return lua_istable (L, index); + } +}; + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/LuaBridge.h b/lib/lua/3rd/LuaBridge/LuaBridge.h new file mode 100644 index 00000000..866acc39 --- /dev/null +++ b/lib/lua/3rd/LuaBridge/LuaBridge.h @@ -0,0 +1,59 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/lib/lua/3rd/LuaBridge/Map.h b/lib/lua/3rd/LuaBridge/Map.h new file mode 100644 index 00000000..a36d269a --- /dev/null +++ b/lib/lua/3rd/LuaBridge/Map.h @@ -0,0 +1,56 @@ +// https://github.com/vinniefalco/LuaBridge +// +// Copyright 2018, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include + +namespace luabridge { + +template +struct Stack > +{ + typedef std::map Map; + + static void push (lua_State* L, const Map& map) + { + lua_createtable (L, 0, static_cast (map.size ())); + typedef typename Map::const_iterator ConstIter; + for (ConstIter i = map.begin (); i != map.end (); ++i) + { + Stack ::push (L, i->first); + Stack ::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 argument must be a table", index); + } + + Map map; + int const absindex = lua_absindex (L, index); + lua_pushnil (L); + while (lua_next (L, absindex) != 0) + { + map.emplace (Stack ::get (L, -2), Stack ::get (L, -1)); + lua_pop (L, 1); + } + return map; + } + + static bool isInstance (lua_State* L, int index) + { + return lua_istable (L, index); + } +}; + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/RefCountedObject.h b/lib/lua/3rd/LuaBridge/RefCountedObject.h new file mode 100644 index 00000000..ebc749e3 --- /dev/null +++ b/lib/lua/3rd/LuaBridge/RefCountedObject.h @@ -0,0 +1,356 @@ +//============================================================================== +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2012, Vinnie Falco + 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 + +#include + +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 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 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 (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 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 MyClassPtr; + + @endcode +*/ +template +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 + inline RefCountedObjectPtr (const RefCountedObjectPtr& other) + : referencedObject (static_cast (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 + RefCountedObjectPtr& operator= (const RefCountedObjectPtr& other) + { + return operator= (static_cast (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 +bool operator== (const RefCountedObjectPtr& object1, ReferenceCountedObjectClass* const object2) +{ + return object1.getObject() == object2; +} + +/** Compares two ReferenceCountedObjectPointers. */ +template +bool operator== (const RefCountedObjectPtr& object1, const RefCountedObjectPtr& object2) +{ + return object1.getObject() == object2.getObject(); +} + +/** Compares two ReferenceCountedObjectPointers. */ +template +bool operator== (ReferenceCountedObjectClass* object1, RefCountedObjectPtr& object2) +{ + return object1 == object2.getObject(); +} + +/** Compares two ReferenceCountedObjectPointers. */ +template +bool operator!= (const RefCountedObjectPtr& object1, const ReferenceCountedObjectClass* object2) +{ + return object1.getObject() != object2; +} + +/** Compares two ReferenceCountedObjectPointers. */ +template +bool operator!= (const RefCountedObjectPtr& object1, RefCountedObjectPtr& object2) +{ + return object1.getObject() != object2.getObject(); +} + +/** Compares two ReferenceCountedObjectPointers. */ +template +bool operator!= (ReferenceCountedObjectClass* object1, RefCountedObjectPtr& object2) +{ + return object1 != object2.getObject(); +} + +//============================================================================== + +template +struct ContainerTraits > +{ + typedef T Type; + + static T* get (RefCountedObjectPtr const& c) + { + return c.getObject (); + } +}; + +//============================================================================== + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/RefCountedPtr.h b/lib/lua/3rd/LuaBridge/RefCountedPtr.h new file mode 100644 index 00000000..4db103f5 --- /dev/null +++ b/lib/lua/3rd/LuaBridge/RefCountedPtr.h @@ -0,0 +1,244 @@ +//============================================================================== +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco + 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 +#include "RefCountedObject.h" + +namespace luabridge { + +//============================================================================== +/** + Support for our RefCountedPtr. +*/ +struct RefCountedPtrBase +{ + // Declaration of container for the refcounts + typedef std::unordered_map 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 RefCountedPtr : private RefCountedPtrBase +{ +public: + template + struct rebind + { + typedef RefCountedPtr 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 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 + RefCountedPtr (RefCountedPtr const& rhs) : m_p (static_cast (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 & operator= (RefCountedPtr 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 + RefCountedPtr & operator= (RefCountedPtr const& rhs) + { + reset (); + m_p = static_cast (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 +bool operator== (const RefCountedPtr & lhs, const RefCountedPtr & rhs) +{ + return lhs.get () == rhs.get (); +} + +template +bool operator!= (const RefCountedPtr & lhs, const RefCountedPtr & rhs) +{ + return lhs.get() != rhs.get(); +} + +//============================================================================== + +// forward declaration +template +struct ContainerTraits; + +template +struct ContainerTraits > +{ + typedef T Type; + + static T* get (RefCountedPtr const& c) + { + return c.get (); + } +}; + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/UnorderedMap.h b/lib/lua/3rd/LuaBridge/UnorderedMap.h new file mode 100644 index 00000000..78a7acee --- /dev/null +++ b/lib/lua/3rd/LuaBridge/UnorderedMap.h @@ -0,0 +1,55 @@ +// https://github.com/vinniefalco/LuaBridge +// +// Copyright 2019, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include + +namespace luabridge { + +template +struct Stack > +{ + typedef std::unordered_map Map; + + static void push (lua_State* L, const Map& map) + { + lua_createtable (L, 0, static_cast (map.size ())); + typedef typename Map::const_iterator ConstIter; + for (ConstIter i = map.begin (); i != map.end (); ++i) + { + Stack ::push (L, i->first); + Stack ::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 argument must be a table", index); + } + + Map map; + int const absindex = lua_absindex (L, index); + lua_pushnil (L); + while (lua_next (L, absindex) != 0) + { + map.emplace (Stack ::get (L, -2), Stack ::get (L, -1)); + lua_pop (L, 1); + } + return map; + } + + static bool isInstance (lua_State* L, int index) + { + return lua_istable (L, index); + } +}; + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/Vector.h b/lib/lua/3rd/LuaBridge/Vector.h new file mode 100644 index 00000000..cc803136 --- /dev/null +++ b/lib/lua/3rd/LuaBridge/Vector.h @@ -0,0 +1,54 @@ +// https://github.com/vinniefalco/LuaBridge +// +// Copyright 2018, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include + +namespace luabridge { + +template +struct Stack > +{ + static void push (lua_State* L, std::vector const& vector) + { + lua_createtable (L, static_cast (vector.size ()), 0); + for (std::size_t i = 0; i < vector.size (); ++i) + { + lua_pushinteger (L, static_cast (i + 1)); + Stack ::push (L, vector [i]); + lua_settable (L, -3); + } + } + + static std::vector get (lua_State* L, int index) + { + if (!lua_istable (L, index)) + { + luaL_error (L, "#%d argument must be a table", index); + } + + std::vector vector; + vector.reserve (static_cast (get_length (L, index))); + + int const absindex = lua_absindex (L, index); + lua_pushnil (L); + while (lua_next (L, absindex) != 0) + { + vector.push_back (Stack ::get (L, -1)); + lua_pop (L, 1); + } + return vector; + } + + static bool isInstance (lua_State* L, int index) + { + return lua_istable (L, index); + } +}; + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/detail/CFunctions.h b/lib/lua/3rd/LuaBridge/detail/CFunctions.h new file mode 100644 index 00000000..d4ae0cca --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/CFunctions.h @@ -0,0 +1,495 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco + + 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 +#include + +#include + +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 + static int getVariable (lua_State* L) + { + assert (lua_islightuserdata (L, lua_upvalueindex (1))); + T const* ptr = static_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (ptr != 0); + Stack ::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 + static int setVariable (lua_State* L) + { + assert (lua_islightuserdata (L, lua_upvalueindex (1))); + T* ptr = static_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (ptr != 0); + *ptr = Stack ::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 + struct Call + { + typedef typename FuncTraits ::Params Params; + typedef typename FuncTraits ::ReturnType ReturnType; + + static int f (lua_State* L) + { + assert (lua_islightuserdata (L, lua_upvalueindex (1))); + FnPtr fnptr = reinterpret_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + return Invoke ::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 + struct CallMember + { + typedef typename FuncTraits ::ClassType T; + typedef typename FuncTraits ::Params Params; + typedef typename FuncTraits ::ReturnType ReturnType; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + T* const t = Userdata::get (L, 1, false); + MemFnPtr const& fnptr = *static_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + return Invoke ::run (L, t, fnptr); + } + }; + + template + struct CallConstMember + { + typedef typename FuncTraits ::ClassType T; + typedef typename FuncTraits ::Params Params; + typedef typename FuncTraits ::ReturnType ReturnType; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + T const* const t = Userdata::get (L, 1, true); + MemFnPtr const& fnptr = *static_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + return Invoke ::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 + 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 (L, 1, false); + MFP const& fnptr = *static_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + return (t->*fnptr) (L); + } + }; + + template + 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 (L, 1, true); + MFP const& fnptr = *static_cast (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 + struct CallProxyFunction + { + using Params = typename FuncTraits ::Params; + using ReturnType = typename FuncTraits ::ReturnType; + + static int f (lua_State* L) + { + assert (lua_islightuserdata (L, lua_upvalueindex (1))); + auto fnptr = reinterpret_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + return Invoke ::run (L, fnptr); + } + }; + + template + struct CallProxyFunctor + { + using Params = typename FuncTraits ::Params; + using ReturnType = typename FuncTraits ::ReturnType; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + Functor& fn = *static_cast (lua_touserdata (L, lua_upvalueindex (1))); + return Invoke ::run (L, fn); + } + }; + +#endif + + //-------------------------------------------------------------------------- + + // SFINAE Helpers + + template + 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 ::f, 1); + lua_pushvalue (L, -1); + rawsetfield (L, -5, name); // const table + rawsetfield (L, -3, name); // class table + } + }; + + template + struct CallMemberFunctionHelper + { + static void add (lua_State* L, char const* name, MemFnPtr mf) + { + new (lua_newuserdata (L, sizeof (MemFnPtr))) MemFnPtr (mf); + lua_pushcclosure (L, &CallMember ::f, 1); + rawsetfield (L, -3, name); // class table + } + }; + + //-------------------------------------------------------------------------- + /** + __gc metamethod for a class. + */ + template + static int gcMetaMethod (lua_State* L) + { + Userdata* const ud = Userdata::getExact (L, 1); + ud->~Userdata (); + return 0; + } + + /** + __gc metamethod for an arbitrary class. + */ + template + static int gcMetaMethodAny (lua_State* L) + { + assert (isfulluserdata (L, 1)); + T* t = static_cast (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 + static int getProperty (lua_State* L) + { + C* const c = Userdata::get (L, 1, true); + T C::** mp = static_cast (lua_touserdata (L, lua_upvalueindex (1))); + try + { + Stack ::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 + static int setProperty (lua_State* L) + { + C* const c = Userdata::get (L, 1, false); + T C::** mp = static_cast (lua_touserdata (L, lua_upvalueindex (1))); + try + { + c->**mp = Stack ::get (L, 2); + } + catch (const std::exception& e) + { + luaL_error (L, e.what ()); + } + return 0; + } +}; + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/detail/ClassInfo.h b/lib/lua/3rd/LuaBridge/detail/ClassInfo.h new file mode 100644 index 00000000..ca83f93d --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/ClassInfo.h @@ -0,0 +1,169 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2012, Vinnie Falco + + 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 (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 (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 (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 (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 (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 (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 (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 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/lua/3rd/LuaBridge/detail/Config.h b/lib/lua/3rd/LuaBridge/detail/Config.h new file mode 100644 index 00000000..76b3d420 --- /dev/null +++ b/lib/lua/3rd/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/lua/3rd/LuaBridge/detail/Constructor.h b/lib/lua/3rd/LuaBridge/detail/Constructor.h new file mode 100644 index 00000000..04b3dab0 --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/Constructor.h @@ -0,0 +1,205 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2012, Vinnie Falco + 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 +struct Constructor {}; + +template +struct Constructor +{ + static T* call (TypeListValues const&) + { + return new T; + } + static T* call (void* mem, TypeListValues const&) + { + return new (mem) T; + } +}; + +template +struct Constructor > +{ + static T* call (const TypeListValues > &tvl) + { + return new T(tvl.hd); + } + static T* call (void* mem, const TypeListValues > &tvl) + { + return new (mem) T(tvl.hd); + } +}; + +template +struct Constructor > > +{ + static T* call (const TypeListValues > > &tvl) + { + return new T(tvl.hd, tvl.tl.hd); + } + static T* call (void* mem, const TypeListValues > > &tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd); + } +}; + +template +struct Constructor > > > +{ + static T* call (const TypeListValues > > > &tvl) + { + return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); + } + static T* call (void* mem, const TypeListValues > > > &tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); + } +}; + +template +struct Constructor > > > > +{ + static T* call (const TypeListValues > > > > &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 > > > > &tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd); + } +}; + +template +struct Constructor > > > > > +{ + static T* call (const TypeListValues > > > > > &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 > > > > > &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 +struct Constructor > > > > > > +{ + static T* call (const TypeListValues > > > > > > &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 > > > > > > &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 +struct Constructor > > > > > > > +{ + static T* call (const TypeListValues > > > > > > > &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 > > > > > > > &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 +struct Constructor > > > > > > > > +{ + static T* call (const TypeListValues > > > > > > > > &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 > > > > > > > > &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/lua/3rd/LuaBridge/detail/FuncTraits.h b/lib/lua/3rd/LuaBridge/detail/FuncTraits.h new file mode 100644 index 00000000..22b15863 --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/FuncTraits.h @@ -0,0 +1,942 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2020, Dmitry Tarakanov + Copyright 2012, Vinnie Falco + + 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 + +#ifdef LUABRIDGE_CXX11 +#include +#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 +struct Caller; + +template +struct Caller +{ + template + static ReturnType f (Fn& fn, TypeListValues & params) + { + return fn (); + } + + template + static ReturnType f (T* obj, MemFn& fn, TypeListValues &) + { + return (obj->*fn) (); + } +}; + +template +struct Caller +{ + template + static ReturnType f (Fn& fn, TypeListValues & tvl) + { + return fn (tvl.hd); + } + + template + static ReturnType f (T* obj, MemFn& fn, TypeListValues & tvl) + { + return (obj->*fn) (tvl.hd); + } +}; + +template +struct Caller +{ + template + static ReturnType f (Fn& fn, TypeListValues & tvl) + { + return fn (tvl.hd, tvl.tl.hd); + } + + template + static ReturnType f (T* obj, MemFn& fn, TypeListValues & tvl) + { + return (obj->*fn) (tvl.hd, tvl.tl.hd); + } +}; + +template +struct Caller +{ + template + static ReturnType f (Fn& fn, TypeListValues & tvl) + { + return fn (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); + } + + template + static ReturnType f (T* obj, MemFn& fn, TypeListValues & tvl) + { + return (obj->*fn) (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); + } +}; + +template +struct Caller +{ + template + static ReturnType f (Fn& fn, TypeListValues & tvl) + { + return fn (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd); + } + + template + static ReturnType f (T* obj, MemFn& fn, TypeListValues & tvl) + { + return (obj->*fn) (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd); + } +}; + +template +struct Caller +{ + template + static ReturnType f (Fn& fn, TypeListValues & tvl) + { + return fn (tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd); + } + + template + static ReturnType f (T* obj, MemFn& fn, TypeListValues & 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 +struct Caller +{ + template + static ReturnType f (Fn& fn, TypeListValues & 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 + static ReturnType f (T* obj, MemFn& fn, TypeListValues & 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 +struct Caller +{ + template + static ReturnType f (Fn& fn, TypeListValues & 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 + static ReturnType f (T* obj, MemFn& fn, TypeListValues & 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 +struct Caller +{ + template + static ReturnType f (Fn& fn, TypeListValues & 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 + static ReturnType f (T* obj, MemFn& fn, TypeListValues & 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 +struct Caller +{ + template + static ReturnType f (Fn& fn, TypeListValues & 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 + static ReturnType f (T* obj, MemFn& fn, TypeListValues & 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 +ReturnType doCall (Fn& fn, TypeListValues & tvl) +{ + return Caller ::value>::f (fn, tvl); +} + +template +static ReturnType doCall(T* obj, MemFn& fn, TypeListValues & tvl) +{ + return Caller ::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 +struct FuncTraits +{ +}; + +#ifndef LUABRIDGE_CXX11 + +/* Ordinary function pointers. */ + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef None Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > > > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > > > > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > > > > > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > > > > > > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > > > > > > > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +/* Windows: WINAPI (a.k.a. __stdcall) function pointers. */ + +#ifdef _M_IX86 // Windows 32bit only + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef None Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > > > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > > > > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > > > > > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > > > > > > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + typedef D DeclType; + typedef R ReturnType; + typedef TypeList > > > > > > > Params; + static R call (D fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +#endif // _M_IX86 + +/* Non-const member function pointers. */ + +template +struct FuncTraits +{ + 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 & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList Params; + static R call (T* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > Params; + static R call (T* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > > Params; + static R call (T* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > > > Params; + static R call (T* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > > > > Params; + static R call (T* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > > > > > Params; + static R call (T* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > > > > > > Params; + static R call (T* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > > > > > > > Params; + static R call (T* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +/* Const member function pointers. */ + +template +struct FuncTraits +{ + 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 & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList Params; + static R call (T const* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > Params; + static R call (T const* obj, R (T::*fp) (P1, P2) const, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > > Params; + static R call (T const* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > > > Params; + static R call (T const* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > > > > Params; + static R call (T const* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > > > > > Params; + static R call (T const* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > > > > > > Params; + static R call (T const* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + typedef D DeclType; + typedef T ClassType; + typedef R ReturnType; + typedef TypeList > > > > > > > Params; + static R call (T const* obj, D fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +#else // ifndef LUABRIDGE_CXX11 + +/* Ordinary function pointers. */ + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + using DeclType = R (*) (ParamList...); + using ReturnType = R; + using Params = typename MakeTypeList ::Result; + + static R call (const DeclType& fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +/* Windows: WINAPI (a.k.a. __stdcall) function pointers. */ + +#ifdef _M_IX86 // Windows 32bit only + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + using DeclType = R (__stdcall *) (ParamList...); + using ReturnType = R; + using Params = typename MakeTypeList ::Result; + + static R call (const DeclType& fp, TypeListValues & tvl) + { + return doCall (fp, tvl); + } +}; + +#endif // _M_IX86 + +/* Non-const member function pointers. */ + +template +struct FuncTraits +{ + 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 ::Result; + + static R call (ClassType* obj, const DeclType& fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +/* Const member function pointers. */ + +template +struct FuncTraits +{ + 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 ::Result; + + static R call (const ClassType* obj, const DeclType& fp, TypeListValues & tvl) + { + return doCall (obj, fp, tvl); + } +}; + +/* std::function */ + +template +struct FuncTraits > +{ + static bool const isMemberFunction = false; + static bool const isConstMemberFunction = false; + using DeclType = std::function ; + using ReturnType = R; + using Params = typename MakeTypeList ::Result; + + static ReturnType call (DeclType& fn, TypeListValues & tvl) + { + return doCall (fn, tvl); + } +}; + +#endif // ifndef LUABRIDGE_CXX11 + +template +struct Invoke +{ + template + static int run (lua_State* L, Fn& fn) + { + try + { + ArgList args (L); + Stack ::push (L, FuncTraits ::call (fn, args)); + return 1; + } + catch (const std::exception& e) + { + return luaL_error (L, e.what ()); + } + } + + template + static int run (lua_State* L, T* object, const MemFn& fn) + { + try + { + ArgList args (L); + Stack ::push (L, FuncTraits ::call (object, fn, args)); + return 1; + } + catch (const std::exception& e) + { + return luaL_error (L, e.what ()); + } + } +}; + +template +struct Invoke +{ + template + static int run (lua_State* L, Fn& fn) + { + try + { + ArgList args (L); + FuncTraits ::call (fn, args); + return 0; + } + catch (const std::exception& e) + { + return luaL_error (L, e.what ()); + } + } + + template + static int run (lua_State* L, T* object, const MemFn& fn) + { + try + { + ArgList args (L); + FuncTraits ::call (object, fn, args); + return 0; + } + catch (const std::exception& e) + { + return luaL_error (L, e.what ()); + } + } +}; + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/detail/Iterator.h b/lib/lua/3rd/LuaBridge/detail/Iterator.h new file mode 100644 index 00000000..6c176232 --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/Iterator.h @@ -0,0 +1,154 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2018, Dmitry Tarakanov + Copyright 2012, Vinnie Falco + + 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 + +#include + + +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 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/lua/3rd/LuaBridge/detail/LuaException.h b/lib/lua/3rd/LuaBridge/detail/LuaException.h new file mode 100644 index 00000000..836cb852 --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/LuaException.h @@ -0,0 +1,144 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2012, Vinnie Falco + Copyright 2008, Nigel Atkinson + + 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 +#include + +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 + 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)); + } + + //---------------------------------------------------------------------------- + /** + Initializes error handling. Subsequent Lua errors are translated to C++ exceptions. + */ + static void enableExceptions (lua_State* L) + { + lua_atpanic (L, throwAtPanic); + } + +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"; + } + } + +private: + static int throwAtPanic (lua_State* L) + { + throw LuaException (L, -1); + } +}; + +//---------------------------------------------------------------------------- +/** + Initializes error handling. Subsequent Lua errors are translated to C++ exceptions. +*/ +static void enableExceptions (lua_State* L) +{ + LuaException::enableExceptions (L); +} + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/detail/LuaHelpers.h b/lib/lua/3rd/LuaBridge/detail/LuaHelpers.h new file mode 100644 index 00000000..e336cf2b --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/LuaHelpers.h @@ -0,0 +1,151 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2012, Vinnie Falco + 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 + +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 (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 (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/lua/3rd/LuaBridge/detail/LuaRef.h b/lib/lua/3rd/LuaBridge/detail/LuaRef.h new file mode 100644 index 00000000..995c4650 --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/LuaRef.h @@ -0,0 +1,1051 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2018, Dmitry Tarakanov + Copyright 2012, Vinnie Falco + Copyright 2008, Nigel Atkinson + + 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 +#include + +#include +#include +#include +#include + +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 +{ + static void push (lua_State* L, Nil) + { + lua_pushnil (L); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TTABLE; + } +}; + +/** + * Base class for LuaRef and table value proxy classes. + */ +template +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 + 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 ; + + //---------------------------------------------------------------------------- + /** + 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 (); + break; + + case LUA_TBOOLEAN: + os << (cast () ? "true" : "false"); + break; + + case LUA_TSTRING: + os << '"' << cast () << '"'; + 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 + T cast () const + { + StackPop p (m_L, 1); + impl ().push (); + return Stack ::get (m_L, -1); + } + + //---------------------------------------------------------------------------- + /** + Type check + */ + template + bool isInstance () const + { + StackPop p (m_L, 1); + impl ().push (); + return Stack ::isInstance (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 operator T () const { return T (); } + }; + int main () { + S () || false; + return 0; + } + */ + template + operator T () const + { + return cast (); + } + + //---------------------------------------------------------------------------- + /** + Universal comparison operators. + */ + /** @{ */ + template + bool operator== (T rhs) const + { + StackPop p (m_L, 2); + impl ().push (); + Stack ::push (m_L, rhs); + return lua_compare (m_L, -2, -1, LUA_OPEQ) == 1; + } + + template + bool operator< (T rhs) const + { + StackPop p (m_L, 2); + impl ().push ();; + Stack ::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 + bool operator<= (T rhs) const + { + StackPop p (m_L, 2); + impl ().push ();; + Stack ::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 + bool operator> (T rhs) const + { + StackPop p (m_L, 2); + impl ().push ();; + Stack ::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 + bool operator>= (T rhs) const + { + StackPop p (m_L, 2); + impl ().push ();; + Stack ::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 + bool rawequal (T rhs) const + { + StackPop p (m_L, 2); + impl ().push ();; + Stack ::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 + void append (T v) const + { + impl ().push ();; + Stack ::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 + LuaRef operator() (P1 p1) const + { + impl ().push ();; + Stack ::push (m_L, p1); + LuaException::pcall (m_L, 1, 1); + return LuaRef::fromStack (m_L); + } + + template + LuaRef operator() (P1 p1, P2 p2) const + { + impl ().push ();; + Stack ::push (m_L, p1); + Stack ::push (m_L, p2); + LuaException::pcall (m_L, 2, 1); + return LuaRef::fromStack (m_L); + } + + template + LuaRef operator() (P1 p1, P2 p2, P3 p3) const + { + impl ().push ();; + Stack ::push (m_L, p1); + Stack ::push (m_L, p2); + Stack ::push (m_L, p3); + LuaException::pcall (m_L, 3, 1); + return LuaRef::fromStack (m_L); + } + + template + LuaRef operator() (P1 p1, P2 p2, P3 p3, P4 p4) const + { + impl ().push ();; + Stack ::push (m_L, p1); + Stack ::push (m_L, p2); + Stack ::push (m_L, p3); + Stack ::push (m_L, p4); + LuaException::pcall (m_L, 4, 1); + return LuaRef::fromStack (m_L); + } + + template + LuaRef operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) const + { + impl ().push ();; + Stack ::push (m_L, p1); + Stack ::push (m_L, p2); + Stack ::push (m_L, p3); + Stack ::push (m_L, p4); + Stack ::push (m_L, p5); + LuaException::pcall (m_L, 5, 1); + return LuaRef::fromStack (m_L); + } + + template + LuaRef operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) const + { + impl ().push ();; + Stack ::push (m_L, p1); + Stack ::push (m_L, p2); + Stack ::push (m_L, p3); + Stack ::push (m_L, p4); + Stack ::push (m_L, p5); + Stack ::push (m_L, p6); + LuaException::pcall (m_L, 6, 1); + return LuaRef::fromStack (m_L); + } + + template + LuaRef operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) const + { + impl ().push ();; + Stack ::push (m_L, p1); + Stack ::push (m_L, p2); + Stack ::push (m_L, p3); + Stack ::push (m_L, p4); + Stack ::push (m_L, p5); + Stack ::push (m_L, p6); + Stack ::push (m_L, p7); + LuaException::pcall (m_L, 7, 1); + return LuaRef::fromStack (m_L); + } + + template + LuaRef operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) const + { + impl ().push (); + Stack ::push (m_L, p1); + Stack ::push (m_L, p2); + Stack ::push (m_L, p3); + Stack ::push (m_L, p4); + Stack ::push (m_L, p5); + Stack ::push (m_L, p6); + Stack ::push (m_L, p7); + Stack ::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 (*this); + } + + Impl& impl () + { + return static_cast (*this); + } +}; + +//------------------------------------------------------------------------------ +/** + Lightweight reference to a Lua object. + + The reference is maintained for the lifetime of the C++ object. +*/ +class LuaRef : public LuaRefBase +{ + //---------------------------------------------------------------------------- + /** + A proxy for representing table values. + */ + class Proxy : public LuaRefBase + { + 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 + 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 ::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 + 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 ::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 + 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 + LuaRef rawget (T key) const + { + return LuaRef (*this).rawget (key); + } + + private: + int m_tableRef; + int m_keyRef; + }; + + friend struct Stack ; + friend struct Stack ; + + //---------------------------------------------------------------------------- + /** + 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 + LuaRef (lua_State* L, T v) + : LuaRefBase (L) + , m_ref (LUA_NOREF) + { + Stack ::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 + 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 + Proxy operator[] (T key) const + { + Stack ::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 + LuaRef rawget (T key) const + { + StackPop (m_L, 1); + push (m_L); + Stack ::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 +{ + // 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 +{ + // 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 +T LuaRef_cast (LuaRef const& lr) +{ + return lr.cast (); +} + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/detail/Namespace.h b/lib/lua/3rd/LuaBridge/detail/Namespace.h new file mode 100644 index 00000000..68ae21fa --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/Namespace.h @@ -0,0 +1,1252 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco + 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 +#include +#include +#include +#include + +#include +#include + +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 . + 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 + static int ctorContainerProxy (lua_State* L) + { + typedef typename ContainerTraits ::Type T; + ArgList args (L); + T* const p = Constructor ::call (args); + UserdataSharedHelper ::push (L, p); + return 1; + } + + //-------------------------------------------------------------------------- + /** + lua_CFunction to construct a class object in-place in the userdata. + */ + template + static int ctorPlacementProxy (lua_State* L) + { + ArgList args (L); + UserdataValue * value = UserdataValue ::place (L); + Constructor ::call (value->getObject (), args); + value->commit (); + 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 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 ); // Stack: ns, co, function + rawsetfield (L, -2, "__gc"); // co ["__gc"] = function. Stack: ns, co + ++m_stackSize; + + createClassTable (name); // Stack: ns, co, class table (cl) + lua_pushcfunction (L, &CFunc::gcMetaMethod ); // Stack: ns, co, cl, function + rawsetfield (L, -2, "__gc"); // cl ["__gc"] = function. 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 ::getStaticKey ()); // Stack: ns, co, cl, st + lua_pushvalue (L, -2); // Stack: ns, co, cl, st, cl + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo ::getClassKey ()); // Stack: ns, co, cl, st + lua_pushvalue (L, -3); // Stack: ns, co, cl, st, co + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo ::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 ::getConstKey ()); // Stack: ns, st, co + lua_insert (L, -2); // Stack: ns, co, st + ++m_stackSize; + + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::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 ); // Stack: ns, co, function + rawsetfield (L, -2, "__gc"); // co ["__gc"] = function. Stack: ns, co + ++m_stackSize; + + createClassTable (name); // Stack: ns, co, class table (cl) + lua_pushcfunction (L, &CFunc::gcMetaMethod ); // Stack: ns, co, cl, function + rawsetfield (L, -2, "__gc"); // cl ["__gc"] = function. 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 ::getStaticKey ()); // Stack: ns, co, cl, st + lua_pushvalue (L, -2); // Stack: ns, co, cl, st, cl + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo ::getClassKey ()); // Stack: ns, co, cl, st + lua_pushvalue (L, -3); // Stack: ns, co, cl, st, co + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo ::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 & addStaticProperty (char const* name, U* pu, bool isWritable = true) + { + return addStaticData (name, pu, isWritable); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a static data member. + */ + template + Class & 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 , 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 , 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 & 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 (get)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::Call ::f, 1); // Stack: co, cl, st, getter + CFunc::addGetter (L, name, -2); // Stack: co, cl, st + + if (set != 0) + { + lua_pushlightuserdata (L, reinterpret_cast (set)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::Call ::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 & addStaticFunction (char const* name, FP const fp) + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + lua_pushlightuserdata (L, reinterpret_cast (fp)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::Call ::f, 1); // co, cl, st, function + rawsetfield (L, -2, name); // co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a lua_CFunction. + */ + Class & addStaticFunction (char const* name, int (*const fp) (lua_State*)) + { + return addStaticCFunction (name, fp); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a lua_CFunction. + */ + Class & 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 & addProperty (char const* name, U T::* mp, bool isWritable = true) + { + return addData (name, mp, isWritable); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a data member. + */ + template + Class & 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 , 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 , 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 & 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 ::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 ::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 & 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 ::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 ::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 & 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 (get)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::Call ::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 (set)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::Call ::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 & 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 & addProperty (char const* name, + std::function get, + std::function 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 ); // 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 ::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 ); // 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 ::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 & 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 ::isConstMemberFunction>::add (L, name, mf); + return *this; + } + +#else // ifndef LUABRIDGE_CXX11 + + //-------------------------------------------------------------------------- + /** + Add or replace a member function by std::function. + */ + template + Class & addFunction (char const* name, std::function 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 ); // 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 ::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 & addFunction (char const* name, std::function 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 ); // 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 ::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 & 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 ::add (L, name, mf); + return *this; + } + + template + Class & 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 ::add (L, name, mf); + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a proxy function. + */ + template + Class & 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 (proxyFn)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::CallProxyFunction ::f, 1); // Stack: co, cl, st, function + rawsetfield (L, -3, name); // Stack: co, cl, st + return *this; + } + + template + Class & 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 (proxyFn)); // Stack: co, cl, st, function ptr + lua_pushcclosure (L, &CFunc::CallProxyFunction ::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 & addFunction (char const* name, int (T::*mfp) (lua_State*)) + { + return addCFunction (name, mfp); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a member lua_CFunction. + */ + Class & 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 ::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 & addFunction (char const* name, int (T::*mfp) (lua_State*) const) + { + return addCFunction (name, mfp); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a const member lua_CFunction. + */ + Class & 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 ::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 & addConstructor () + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcclosure (L, &ctorContainerProxy ::Params, C>, 0); + rawsetfield (L, -2, "__call"); + + return *this; + } + + template + Class & addConstructor () + { + assertStackState (); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcclosure (L, &ctorPlacementProxy ::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=; + +public: + //---------------------------------------------------------------------------- + /** + Open the global namespace. + */ + static Namespace getGlobalNamespace (lua_State* L) + { + enableExceptions (L); + 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 + Namespace& addProperty (char const* name, T* pt, bool isWritable = true) + { + return addVariable (name, pt, isWritable); + } + + //---------------------------------------------------------------------------- + /** + Add or replace a variable. + */ + template + 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 , 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 , 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 + 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 (get)); // Stack: ns, function ptr + lua_pushcclosure (L, &CFunc::Call ::f, 1); // Stack: ns, getter + CFunc::addGetter (L, name, -2); + + if (set != 0) + { + lua_pushlightuserdata(L, reinterpret_cast (set)); // Stack: ns, function ptr + lua_pushcclosure (L, &CFunc::Call ::f, 1); + } + else + { + lua_pushstring (L, name); + lua_pushcclosure (L, &CFunc::readOnlyError, 1); + } + CFunc::addSetter (L, name, -2); + + return *this; + } + + //---------------------------------------------------------------------------- + /** + Add or replace a property. + If the set function is omitted or null, the property is read-only. + */ + Namespace& addProperty (char const* name, int (*get) (lua_State*), int (*set) (lua_State*) = 0) + { + if (m_stackSize == 1) + { + throw std::logic_error ("addProperty () called on global namespace"); + } + + assert (lua_istable (L, -1)); // Stack: namespace table (ns) + lua_pushcfunction (L, get); // Stack: ns, getter + CFunc::addGetter (L, name, -2); // Stack: ns + if (set != 0) + { + lua_pushcfunction(L, set); // Stack: ns, setter + CFunc::addSetter(L, name, -2); // Stack: ns + } + else + { + lua_pushstring(L, name); // Stack: ns, name + lua_pushcclosure(L, &CFunc::readOnlyError, 1); // Stack: ns, name, readOnlyError + CFunc::addSetter(L, name, -2); // Stack: ns + } + + return *this; + } + +//---------------------------------------------------------------------------- + /** + Add or replace a free function. + */ + template + Namespace& addFunction (char const* name, FP const fp) + { + assert (lua_istable (L, -1)); // Stack: namespace table (ns) + + lua_pushlightuserdata (L, reinterpret_cast (fp)); // Stack: ns, function ptr + lua_pushcclosure (L, &CFunc::Call ::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 beginClass (char const* name) + { + assertIsActive (); + return Class (name, *this); + } + + //---------------------------------------------------------------------------- + /** + Derive a new class for registrations. + + To continue registrations for the class later, use beginClass (). + Do not call deriveClass () again. + */ + template + Class deriveClass (char const* name) + { + assertIsActive (); + return Class (name, *this, ClassInfo ::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/lua/3rd/LuaBridge/detail/Security.h b/lib/lua/3rd/LuaBridge/detail/Security.h new file mode 100644 index 00000000..51725456 --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/Security.h @@ -0,0 +1,62 @@ +#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; + } +}; + +//------------------------------------------------------------------------------ +/** +Set a global value in the lua_State. + +@note This works on any type specialized by `Stack`, including `LuaRef` and +its table proxies. +*/ +template +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/lua/3rd/LuaBridge/detail/Stack.h b/lib/lua/3rd/LuaBridge/detail/Stack.h new file mode 100644 index 00000000..f00b9c9d --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/Stack.h @@ -0,0 +1,622 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco + 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 +#include + +#include + +namespace luabridge { + +template +struct Stack; + +template <> +struct Stack +{ + static void push (lua_State* L) + { + } +}; + +//------------------------------------------------------------------------------ +/** + Receive the lua_State* as an argument. +*/ +template <> +struct Stack +{ + static lua_State* get (lua_State* L, int) + { + return L; + } +}; + +//------------------------------------------------------------------------------ +/** + Push a lua_CFunction. +*/ +template <> +struct Stack +{ + 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); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_iscfunction (L, index); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `int`. +*/ +template <> +struct Stack +{ + static void push (lua_State* L, int value) + { + lua_pushinteger (L, static_cast (value)); + } + + static int get (lua_State* L, int index) + { + return static_cast (luaL_checkinteger (L, index)); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TNUMBER; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned int`. +*/ +template <> +struct Stack +{ + static void push (lua_State* L, unsigned int value) + { + lua_pushinteger (L, static_cast (value)); + } + + static unsigned int get (lua_State* L, int index) + { + return static_cast (luaL_checkinteger (L, index)); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TNUMBER; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned char`. +*/ +template <> +struct Stack +{ + static void push (lua_State* L, unsigned char value) + { + lua_pushinteger (L, static_cast (value)); + } + + static unsigned char get (lua_State* L, int index) + { + return static_cast (luaL_checkinteger (L, index)); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TNUMBER; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `short`. +*/ +template <> +struct Stack +{ + static void push (lua_State* L, short value) + { + lua_pushinteger (L, static_cast (value)); + } + + static short get (lua_State* L, int index) + { + return static_cast (luaL_checkinteger (L, index)); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TNUMBER; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned short`. +*/ +template <> +struct Stack +{ + static void push (lua_State* L, unsigned short value) + { + lua_pushinteger (L, static_cast (value)); + } + + static unsigned short get (lua_State* L, int index) + { + return static_cast (luaL_checkinteger (L, index)); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TNUMBER; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `long`. +*/ +template <> +struct Stack +{ + static void push (lua_State* L, long value) + { + lua_pushinteger (L, static_cast (value)); + } + + static long get (lua_State* L, int index) + { + return static_cast (luaL_checkinteger (L, index)); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TNUMBER; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned long`. +*/ +template <> +struct Stack +{ + static void push (lua_State* L, unsigned long value) + { + lua_pushinteger (L, static_cast (value)); + } + + static unsigned long get (lua_State* L, int index) + { + return static_cast (luaL_checkinteger (L, index)); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TNUMBER; + } +}; + +//------------------------------------------------------------------------------ +/** + * Stack specialization for `long long`. + */ +template <> +struct Stack +{ + static void push (lua_State* L, long long value) + { + lua_pushinteger (L, static_cast (value)); + } + + static long long get (lua_State* L, int index) + { + return static_cast (luaL_checkinteger (L, index)); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TNUMBER; + } +}; + +//------------------------------------------------------------------------------ +/** + * Stack specialization for `unsigned long long`. + */ +template <> +struct Stack +{ + static void push (lua_State* L, unsigned long long value) + { + lua_pushinteger (L, static_cast (value)); + } + static unsigned long long get (lua_State* L, int index) + { + return static_cast (luaL_checkinteger (L, index)); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TNUMBER; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `float`. +*/ +template <> +struct Stack +{ + static void push (lua_State* L, float value) + { + lua_pushnumber (L, static_cast (value)); + } + + static float get (lua_State* L, int index) + { + return static_cast (luaL_checknumber (L, index)); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TNUMBER; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `double`. +*/ +template <> +struct Stack +{ + static void push (lua_State* L, double value) + { + lua_pushnumber (L, static_cast (value)); + } + + static double get (lua_State* L, int index) + { + return static_cast (luaL_checknumber (L, index)); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TNUMBER; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `bool`. +*/ +template <> +struct Stack +{ + 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; + } + + static bool isInstance (lua_State* L, int index) + { + return lua_isboolean (L, index); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `char`. +*/ +template <> +struct Stack +{ + 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]; + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TSTRING; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `const char*`. +*/ +template <> +struct Stack +{ + 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); + } + + static bool isInstance (lua_State* L, int index) + { + return lua_isnil (L, index) || lua_type (L, index) == LUA_TSTRING; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `std::string`. +*/ +template <> +struct Stack +{ + 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; + if (lua_type (L, index) == LUA_TSTRING) + { + const char* str = lua_tolstring (L, index, &len); + return std::string (str, len); + } + + // Lua reference manual: + // If the value is a number, then lua_tolstring also changes the actual value in the stack to a string. + // (This change confuses lua_next when lua_tolstring is applied to keys during a table traversal.) + lua_pushvalue (L, index); + const char* str = lua_tolstring(L, -1, &len); + std::string string (str, len); + lua_pop (L, 1); // Pop the temporary string + return string; + } + + static bool isInstance (lua_State* L, int index) + { + return lua_type (L, index) == LUA_TSTRING; + } +}; + + +template +struct StackOpSelector +{ + typedef T ReturnType; + + static void push (lua_State* L, T& value) + { + Stack ::push (L, value); + } + + static ReturnType get (lua_State* L, int index) + { + return Stack ::get (L, index); + } + + static bool isInstance (lua_State* L, int index) + { + return Stack ::isInstance (L, index); + } +}; + +template +struct StackOpSelector +{ + typedef T ReturnType; + + static void push (lua_State* L, const T& value) + { + Stack ::push (L, value); + } + + static ReturnType get (lua_State* L, int index) + { + return Stack ::get (L, index); + } + + static bool isInstance (lua_State* L, int index) + { + return Stack ::isInstance (L, index); + } +}; + +template +struct StackOpSelector +{ + typedef T ReturnType; + + static void push (lua_State* L, T* value) + { + Stack ::push (L, *value); + } + + static ReturnType get (lua_State* L, int index) + { + return Stack ::get (L, index); + } + + static bool isInstance (lua_State* L, int index) + { + return Stack ::isInstance (L, index); + } +}; + +template +struct StackOpSelector +{ + typedef T ReturnType; + + static void push (lua_State* L, const T* value) + { + Stack ::push (L, *value); + } + + static ReturnType get (lua_State* L, int index) + { + return Stack ::get (L, index); + } + + static bool isInstance (lua_State* L, int index) + { + return Stack ::isInstance (L, index); + } +}; + + +template +struct Stack +{ + typedef StackOpSelector ::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 +struct Stack +{ + typedef StackOpSelector ::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 +struct Stack +{ + typedef StackOpSelector ::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 +struct Stack +{ + typedef StackOpSelector ::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); + } +}; + +//------------------------------------------------------------------------------ +/** + * Push an object onto the Lua stack. + */ +template +inline void push (lua_State* L, T t) +{ + Stack ::push (L, t); +} + +//------------------------------------------------------------------------------ +/** + * Check whether an object on the Lua stack is of type T. + */ +template +inline bool isInstance (lua_State* L, int index) +{ + return Stack ::isInstance (L, index); +} + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/detail/TypeList.h b/lib/lua/3rd/LuaBridge/detail/TypeList.h new file mode 100644 index 00000000..d142f6e1 --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/TypeList.h @@ -0,0 +1,218 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2012, Vinnie Falco + 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 +#include + +#include +#include + +namespace luabridge { + +/** + None type means void parameters or return value. +*/ +typedef void None; + +template +struct TypeList +{ + typedef Tail TailType; +}; + +template +struct TypeListSize +{ + static const size_t value = TypeListSize ::value + 1; +}; + +template <> +struct TypeListSize +{ + static const size_t value = 0; +}; + +#ifdef LUABRIDGE_CXX11 + +template +struct MakeTypeList; + +template +struct MakeTypeList +{ + using Result = TypeList ::Result>; +}; + +template <> +struct MakeTypeList <> +{ + using Result = None; +}; + +#endif + +/** + A TypeList with actual values. +*/ +template +struct TypeListValues +{ + static std::string const tostring (bool) + { + return ""; + } +}; + +/** + TypeListValues recursive template definition. +*/ +template +struct TypeListValues > +{ + Head hd; + TypeListValues tl; + + TypeListValues (Head hd_, TypeListValues 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 ::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 +struct TypeListValues > +{ + Head hd; + TypeListValues tl; + + TypeListValues (Head& hd_, TypeListValues 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 ::tostring (true); + } +}; + +template +struct TypeListValues > +{ + Head hd; + TypeListValues tl; + + TypeListValues (Head const& hd_, const TypeListValues & 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 ::tostring (true); + } +}; + +//============================================================================== +/** + Subclass of a TypeListValues constructable from the Lua stack. +*/ + +template +struct ArgList +{ +}; + +template +struct ArgList : public TypeListValues +{ + ArgList (lua_State*) + { + } +}; + +template +struct ArgList , Start> + : public TypeListValues > +{ + ArgList (lua_State* L) + : TypeListValues > (Stack ::get (L, Start), + ArgList (L)) + { + } +}; + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/detail/TypeTraits.h b/lib/lua/3rd/LuaBridge/detail/TypeTraits.h new file mode 100644 index 00000000..5fad3756 --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/TypeTraits.h @@ -0,0 +1,135 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco + + 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 + + +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 + struct ContainerTraits > + { + typedef typename T Type; + + static T* get (ContainerType const& c) + { + return c.get (); // Implementation-dependent on ContainerType + } + }; +*/ +template +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 + class isContainer + { + private: + typedef char yes[1]; // sizeof (yes) == 1 + typedef char no [2]; // sizeof (no) == 2 + + template + static no& test (typename C::isNotContainer*); + + template + static yes& test (...); + + public: + static const bool value = sizeof (test >(0)) == sizeof (yes); + }; + + /** Determine if T is const qualified. + */ + /** @{ */ + template + struct isConst + { + static bool const value = false; + }; + + template + struct isConst + { + static bool const value = true; + }; + /** @} */ + + /** Remove the const qualifier from T. + */ + /** @{ */ + template + struct removeConst + { + typedef T Type; + }; + + template + struct removeConst + { + typedef T Type; + }; + /**@}*/ +}; + + +template +struct Stack; + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/detail/Userdata.h b/lib/lua/3rd/LuaBridge/detail/Userdata.h new file mode 100644 index 00000000..ef13d9fc --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/Userdata.h @@ -0,0 +1,829 @@ +//------------------------------------------------------------------------------ +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco + + 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 + +#include +#include + + +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 + + Userdata() : m_p (0) + { + } + + //-------------------------------------------------------------------------- + /** + 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, void const* /*classKey*/) + { + return static_cast (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: object metatable (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)) // Stack: rt, ot + { + lua_pop (L, 2); // Stack: - + return static_cast (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 bool isInstance (lua_State* L, int index, void const* registryClassKey) + { + index = lua_absindex (L, index); + + int result = lua_getmetatable (L, index); // Stack: object metatable (ot) | nothing + if (result == 0) + { + return false; // Nothing was pushed on the stack + } + if (!lua_istable (L, -1)) + { + lua_pop (L, 1); // Stack: - + return false; + } + + lua_rawgetp (L, LUA_REGISTRYINDEX, registryClassKey); // Stack: ot, rt + lua_insert (L, -2); // Stack: rt, ot + + for (;;) + { + if (lua_rawequal (L, -1, -2)) // Stack: rt, ot + { + lua_pop (L, 2); // Stack: - + return true; + } + + // 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 + { + lua_pop (L, 3); // Stack: - + return false; + } + + lua_remove (L, -2); // Stack: rt, pot + } + } + + 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 + static Userdata* getExact (lua_State* L, int index) + { + return getExactClass (L, index, ClassInfo ::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 + static T* get (lua_State* L, int index, bool canBeConst) + { + if (lua_isnil (L, index)) + return 0; + + return static_cast (getClass ( + L, index, ClassInfo ::getConstKey (), + ClassInfo ::getClassKey (), + canBeConst)->getPointer ()); + } + + template + static bool isInstance (lua_State* L, int index) + { + return isInstance (L, index, ClassInfo ::getClassKey ()); + } +}; + +//---------------------------------------------------------------------------- +/** + 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 UserdataValue : public Userdata +{ +private: + UserdataValue (UserdataValue const&); + UserdataValue operator= (UserdataValue const&); + + char m_storage [sizeof (T)]; + +private: + /** + Used for placement construction. + */ + UserdataValue () + { + m_p = 0; + } + + ~UserdataValue () + { + if (getPointer () != 0) + { + getObject ()->~T (); + } + } + +public: + /** + Push a T via placement new. + + The caller is responsible for calling placement new using the + returned uninitialized storage. + */ + static UserdataValue * place (lua_State* const L) + { + UserdataValue * const ud = new ( + lua_newuserdata (L, sizeof (UserdataValue ))) UserdataValue (); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::getClassKey ()); + if (!lua_istable (L, -1)) + { + throw std::logic_error ("The class is not registered in LuaBridge"); + } + lua_setmetatable (L, -2); + return ud; + } + + /** + Push T via copy construction from U. + */ + template + static inline void push (lua_State* const L, U const& u) + { + UserdataValue * ud = place (L); + new (ud->getObject ()) U (u); + ud->commit (); + } + + /** + Confirm object construction. + */ + void commit () + { + m_p = getObject (); + } + + T* getObject () + { + // If this fails to compile it means you forgot to provide + // a Container specialization for your container! + // + return reinterpret_cast (&m_storage [0]); + } +}; + +//---------------------------------------------------------------------------- +/** + 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 (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 + static void push (lua_State* const L, T* const p) + { + if (p) + push (L, p, ClassInfo ::getClassKey ()); + else + lua_pushnil (L); + } + + /** Push const pointer to object. + */ + template + static void push (lua_State* const L, T const* const p) + { + if (p) + push (L, p, ClassInfo ::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 UserdataShared : public Userdata +{ +private: + UserdataShared (UserdataShared const&); + UserdataShared & operator= (UserdataShared const&); + + typedef typename TypeTraits::removeConst < + typename ContainerTraits ::Type>::Type T; + + C m_c; + +private: + ~UserdataShared () + { + } + +public: + /** + Construct from a container to the class or a derived class. + */ + template + explicit UserdataShared (U const& u) : m_c (u) + { + m_p = const_cast (reinterpret_cast ( + (ContainerTraits ::get (m_c)))); + } + + /** + Construct from a pointer to the class or a derived class. + */ + template + explicit UserdataShared (U* u) : m_c (u) + { + m_p = const_cast (reinterpret_cast ( + (ContainerTraits ::get (m_c)))); + } +}; + +//---------------------------------------------------------------------------- +// +// SFINAE helpers. +// + +// non-const objects +template +struct UserdataSharedHelper +{ + typedef typename TypeTraits::removeConst < + typename ContainerTraits ::Type>::Type T; + + static void push (lua_State* L, C const& c) + { + if (ContainerTraits ::get (c) != 0) + { + new (lua_newuserdata (L, sizeof (UserdataShared ))) UserdataShared (c); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::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 ))) UserdataShared (t); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::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 +struct UserdataSharedHelper +{ + typedef typename TypeTraits::removeConst < + typename ContainerTraits ::Type>::Type T; + + static void push (lua_State* L, C const& c) + { + if (ContainerTraits ::get (c) != 0) + { + new (lua_newuserdata (L, sizeof (UserdataShared ))) UserdataShared (c); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::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 ))) UserdataShared (t); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::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 +struct StackHelper +{ + static void push (lua_State* L, C const& c) + { + UserdataSharedHelper ::Type>::value>::push (L, c); + } + + typedef typename TypeTraits::removeConst < + typename ContainerTraits ::Type>::Type T; + + static C get (lua_State* L, int index) + { + return Userdata::get (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 +struct StackHelper +{ + static inline void push (lua_State* L, T const& t) + { + UserdataValue ::push (L, t); + } + + static inline T const& get (lua_State* L, int index) + { + return *Userdata::get (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 +struct RefStackHelper +{ + typedef C return_type; + + static inline void push (lua_State* L, C const& t) + { + UserdataSharedHelper ::Type>::value>::push (L, t); + } + + typedef typename TypeTraits::removeConst < + typename ContainerTraits ::Type>::Type T; + + static return_type get (lua_State* L, int index) + { + return Userdata::get (L, index, true); + } +}; + +template +struct RefStackHelper +{ + 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 (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 +struct Void +{ + typedef void Type; +}; + + +/** + * Trait class that selects whether to return a user registered + * class object by value or by reference. + */ + +template +struct UserdataGetter +{ + typedef T* ReturnType; + + static ReturnType get (lua_State* L, int index) + { + return Userdata::get (L, index, false); + } +}; + +template +struct UserdataGetter ::Type> +{ + typedef T ReturnType; + + static ReturnType get (lua_State* L, int index) + { + return StackHelper ::value>::get (L, index); + } +}; + +//============================================================================== + +/** + Lua stack conversions for class objects passed by value. +*/ +template +struct Stack +{ + typedef void IsUserdata; + + typedef UserdataGetter Getter; + typedef typename Getter::ReturnType ReturnType; + + static void push (lua_State* L, T const& value) + { + StackHelper ::value>::push (L, value); + } + + static ReturnType get (lua_State* L, int index) + { + return Getter::get (L, index); + } + + static bool isInstance (lua_State* L, int index) + { + return Userdata::isInstance (L, index); + } +}; + + +/** + * Trait class indicating whether the parameter type must be + * a user registered class. The trait checks the existence of + * member type Stack ::IsUserdata specialization for detection. + */ +template +struct IsUserdata +{ + static const bool value = false; +}; + +template +struct IsUserdata ::IsUserdata>::Type> +{ + static const bool value = true; +}; + + +/** + * Trait class that selects a specific push/get implemenation. + */ +template +struct StackOpSelector; + +// pointer +template +struct StackOpSelector +{ + 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 (L, index, false); + } + + static bool isInstance (lua_State* L, int index) + { + return Userdata::isInstance (L, index); + } +}; + +// pointer to const +template +struct StackOpSelector +{ + 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 (L, index, true); + } + + static bool isInstance (lua_State* L, int index) + { + return Userdata::isInstance (L, index); + } +}; + +// reference +template +struct StackOpSelector +{ + typedef RefStackHelper ::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); + } + + static bool isInstance (lua_State* L, int index) + { + return Userdata::isInstance (L, index); + } +}; + +// reference to const +template +struct StackOpSelector +{ + typedef RefStackHelper ::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); + } + + static bool isInstance (lua_State* L, int index) + { + return Userdata::isInstance (L, index); + } +}; + +} // namespace luabridge diff --git a/lib/lua/3rd/LuaBridge/detail/dump.h b/lib/lua/3rd/LuaBridge/detail/dump.h new file mode 100644 index 00000000..7e23f9f5 --- /dev/null +++ b/lib/lua/3rd/LuaBridge/detail/dump.h @@ -0,0 +1,143 @@ +//============================================================================== +/* + https://github.com/vinniefalco/LuaBridge + + Copyright 2019, Dmitry Tarakanov + Copyright 2012, Vinnie Falco + 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 +#include + + +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 diff --git a/lib/lua/piluaprogram.cpp b/lib/lua/piluaprogram.cpp new file mode 100644 index 00000000..93603e86 --- /dev/null +++ b/lib/lua/piluaprogram.cpp @@ -0,0 +1,53 @@ +/* + PIP - Platform Independent Primitives + PILuaProgram + Andrey Bychkov work.a.b@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ +#include "piluaprogram.h" + + +PRIVATE_DEFINITION_START(PILuaProgram) + lua_State * lua_state; +PRIVATE_DEFINITION_END(PILuaProgram) + + +PILuaProgram::PILuaProgram() { + PRIVATE->lua_state = luaL_newstate(); + luaL_openlibs(PRIVATE->lua_state); +} + + +bool PILuaProgram::load(const PIString & script) { + int ret = luaL_dostring(PRIVATE->lua_state, script.dataUTF8()); + if (ret != 0) return false; + return true; +} + + +bool PILuaProgram::prepare() { + return (lua_pcall(PRIVATE->lua_state, 0, 0, 0) == 0); +} + + +luabridge::LuaRef PILuaProgram::getGlobal(const PIString & name) { + return luabridge::getGlobal(PRIVATE->lua_state, name.dataUTF8()); +} + + +luabridge::Namespace PILuaProgram::getGlobalNamespace() { + return luabridge::getGlobalNamespace(PRIVATE->lua_state); +} + diff --git a/lib/main/concurrent/piconditionlock.h b/lib/main/concurrent/piconditionlock.h index b44e4633..eba7a8a3 100644 --- a/lib/main/concurrent/piconditionlock.h +++ b/lib/main/concurrent/piconditionlock.h @@ -20,7 +20,7 @@ #ifndef PICONDITIONLOCK_H #define PICONDITIONLOCK_H -#include "pimutex.h" +#include "pibase.h" /** @@ -28,6 +28,7 @@ */ class PIP_EXPORT PIConditionLock { public: + NO_COPY_CLASS(PIConditionLock) explicit PIConditionLock(); ~PIConditionLock(); @@ -43,7 +44,6 @@ public: void * handle(); private: - NO_COPY_CLASS(PIConditionLock) PRIVATE_DECLARATION }; diff --git a/lib/main/concurrent/piconditionvar.h b/lib/main/concurrent/piconditionvar.h index dc32d43d..4d011187 100644 --- a/lib/main/concurrent/piconditionvar.h +++ b/lib/main/concurrent/piconditionvar.h @@ -32,6 +32,7 @@ */ class PIP_EXPORT PIConditionVariable { public: + NO_COPY_CLASS(PIConditionVariable) explicit PIConditionVariable(); virtual ~PIConditionVariable(); @@ -111,7 +112,6 @@ public: virtual bool waitFor(PIConditionLock& lk, int timeoutMs, const std::function& condition); private: - NO_COPY_CLASS(PIConditionVariable) PRIVATE_DECLARATION }; diff --git a/lib/main/console/pikbdlistener.h b/lib/main/console/pikbdlistener.h index 8da6553c..5ea90cd6 100644 --- a/lib/main/console/pikbdlistener.h +++ b/lib/main/console/pikbdlistener.h @@ -133,11 +133,7 @@ public: bool direction; }; -#ifdef PIP_CXX11_SUPPORT typedef std::function KBFunc; -#else - typedef void (*KBFunc)(KeyEvent, void * ); -#endif //! Constructs keyboard listener with external function "slot" and custom data "data" explicit PIKbdListener(KBFunc slot = 0, void * data = 0, bool startNow = true); @@ -154,10 +150,8 @@ public: //! Set external function to "slot" void setSlot(KBFunc slot) {ret_func = slot;} -#ifdef PIP_CXX11_SUPPORT //! Set external function to "slot" void setSlot(std::function slot) {ret_func = [slot](KeyEvent e, void *){slot(e);};} -#endif //! Returns if exit key if awaiting bool exitCaptured() const {return exit_enabled;} diff --git a/lib/main/containers/pideque.h b/lib/main/containers/pideque.h index f9c24a15..d8c8de06 100644 --- a/lib/main/containers/pideque.h +++ b/lib/main/containers/pideque.h @@ -364,7 +364,6 @@ public: return ret; } -#ifdef PIP_CXX11_SUPPORT const PIDeque & forEach(std::function f) const { for (uint i = 0; i < pid_size; ++i) f(pid_data[i + pid_start]); @@ -388,7 +387,6 @@ public: ret << f(pid_data[i + pid_start]); return ret; } -#endif private: inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;} diff --git a/lib/main/containers/pivector.h b/lib/main/containers/pivector.h index 2f4ae66e..d943af3d 100644 --- a/lib/main/containers/pivector.h +++ b/lib/main/containers/pivector.h @@ -358,7 +358,6 @@ public: return ret; } -#ifdef PIP_CXX11_SUPPORT const PIVector & forEach(std::function f) const { for (uint i = 0; i < piv_size; ++i) f(piv_data[i]); @@ -382,7 +381,6 @@ public: ret << f(piv_data[i]); return ret; } -#endif private: inline void _reset() {piv_size = piv_rsize = 0; piv_data = 0;} diff --git a/lib/main/core/pibase.h b/lib/main/core/pibase.h index cad880fd..0fb52771 100644 --- a/lib/main/core/pibase.h +++ b/lib/main/core/pibase.h @@ -96,9 +96,7 @@ #endif -#ifdef PIP_CXX11_SUPPORT -# include -#endif +#include #include #ifdef WINDOWS @@ -220,8 +218,8 @@ #define PRIVATEWB __privateinitializer__.p #define NO_COPY_CLASS(name) \ - explicit name(const name & ); \ - void operator =(const name & ); + name(const name&) = delete; \ + name& operator=(const name&) = delete; #ifdef FREERTOS # define PIP_MIN_MSLEEP 10. @@ -255,15 +253,9 @@ typedef unsigned long long ullong; typedef long long llong; typedef long double ldouble; -#ifdef PIP_CXX11_SUPPORT -#define piMove(v) std::move(v) -#else -#define piMove(v) v -#endif - /*! \brief Templated function for swap two values * \details Example:\n \snippet piincludes.cpp swap */ -template inline void piSwap(T & f, T & s) {T t(piMove(f)); f = piMove(s); s = piMove(t);} +template inline void piSwap(T & f, T & s) {T t(std::move(f)); f = std::move(s); s = std::move(t);} /*! \brief Templated function for swap two values without "=" * \details Example:\n \snippet piincludes.cpp swapBinary */ diff --git a/lib/main/core/piincludes.h b/lib/main/core/piincludes.h index 14a45a27..1027228f 100644 --- a/lib/main/core/piincludes.h +++ b/lib/main/core/piincludes.h @@ -26,9 +26,12 @@ #ifdef PIP_STD_IOSTREAM # include #endif +#include +#include +typedef std::mutex PIMutex; +//typedef std::lock_guard PIMutexLocker; class PIObject; -class PIMutex; class PIString; class PIByteArray; class PIInit; diff --git a/lib/main/core/piobject.cpp b/lib/main/core/piobject.cpp index 5d190f99..9d420f6f 100644 --- a/lib/main/core/piobject.cpp +++ b/lib/main/core/piobject.cpp @@ -313,7 +313,6 @@ bool PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_ } -#ifdef PIP_CXX11_SUPPORT bool PIObject::piConnectLS(PIObject * src, const PIString & sig, std::function * f, const char * loc) { if (src == 0) { delete f; @@ -345,7 +344,6 @@ bool PIObject::piConnectLS(PIObject * src, const PIString & sig, std::function__stat_eh_##event##__, functor), LOCATION); -#endif +#define CONNECTL(src, event, functor) PIObject::piConnectLS(src, PIStringAscii(#event), PIObject::__newFunctor(&(src)->__stat_eh_##event##__, functor), LOCATION); #define CONNECT0(ret, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*))(&(src)->__stat_eh_##event##__), 0, LOCATION); #define CONNECT1(ret, a0, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0))(&(src)->__stat_eh_##event##__), 1, LOCATION); @@ -499,21 +497,13 @@ class PIP_EXPORT PIObject { typedef void __Parent__; friend class PIIntrospection; public: - + NO_COPY_CLASS(PIObject) + //! Contructs PIObject with name "name" explicit PIObject(const PIString & name = PIString()); virtual ~PIObject(); -#ifdef PIP_CXX11_SUPPORT - explicit PIObject(const PIObject & ) = delete; - void operator =(const PIObject & ) = delete; -#else -private: - explicit PIObject(const PIObject & ); - void operator =(const PIObject & ); -#endif - private: uint _signature_; @@ -607,13 +597,11 @@ public: // / Direct connect static void piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc); static bool piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer = 0); -#ifdef PIP_CXX11_SUPPORT static bool piConnectLS(PIObject * src, const PIString & sig, std::function * f, const char * loc); template static std::function * __newFunctor(void(*stat_handler)(void*,TYPES...), INPUT functor) { return (std::function*)(new std::function(functor)); } -#endif // / Through names and mixed static void piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h); @@ -635,11 +623,9 @@ public: for (int j = 0; j < sender->connections.size_s(); ++j) { __Connection i(sender->connections[j]); if (i.eventID != eventID) continue; -#ifdef PIP_CXX11_SUPPORT if (i.functor) { (*(i.functor))(); } else { -#endif if (i.performer) { i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender)); } else { @@ -652,9 +638,7 @@ public: if (ts) i.dest_o->mutex_.unlock(); } } -#ifdef PIP_CXX11_SUPPORT } -#endif if (!sender->isPIObject()) break; } } @@ -664,11 +648,9 @@ public: for (int j = 0; j < sender->connections.size_s(); ++j) { __Connection i(sender->connections[j]); if (i.eventID != eventID) continue; -#ifdef PIP_CXX11_SUPPORT if (i.functor) { (*((std::function*)i.functor))(v0); } else { -#endif if (i.performer) { PIVector vl; if (i.args_count > 0) vl << PIVariant::fromValue(v0); @@ -684,9 +666,7 @@ public: if (ts) i.dest_o->mutex_.unlock(); } } -#ifdef PIP_CXX11_SUPPORT } -#endif if (!sender->isPIObject()) break; } } @@ -695,11 +675,9 @@ public: for (int j = 0; j < sender->connections.size_s(); ++j) { __Connection i(sender->connections[j]); if (i.eventID != eventID) continue; -#ifdef PIP_CXX11_SUPPORT if (i.functor) { (*((std::function*)i.functor))(v0, v1); } else { -#endif if (i.performer) { PIVector vl; if (i.args_count > 0) vl << PIVariant::fromValue(v0); @@ -719,9 +697,7 @@ public: if (ts) i.dest_o->mutex_.unlock(); } } -#ifdef PIP_CXX11_SUPPORT } -#endif if (!sender->isPIObject()) break; } } @@ -730,11 +706,9 @@ public: for (int j = 0; j < sender->connections.size_s(); ++j) { __Connection i(sender->connections[j]); if (i.eventID != eventID) continue; -#ifdef PIP_CXX11_SUPPORT if (i.functor) { (*((std::function*)i.functor))(v0, v1, v2); } else { -#endif if (i.performer) { PIVector vl; if (i.args_count > 0) vl << PIVariant::fromValue(v0); @@ -756,9 +730,7 @@ public: if (ts) i.dest_o->mutex_.unlock(); } } -#ifdef PIP_CXX11_SUPPORT } -#endif if (!sender->isPIObject()) break; } } @@ -767,11 +739,9 @@ public: for (int j = 0; j < sender->connections.size_s(); ++j) { __Connection i(sender->connections[j]); if (i.eventID != eventID) continue; -#ifdef PIP_CXX11_SUPPORT if (i.functor) { (*((std::function*)i.functor))(v0, v1, v2, v3); } else { -#endif if (i.performer) { PIVector vl; if (i.args_count > 0) vl << PIVariant::fromValue(v0); @@ -795,9 +765,7 @@ public: if (ts) i.dest_o->mutex_.unlock(); } } -#ifdef PIP_CXX11_SUPPORT } -#endif if (!sender->isPIObject()) break; } } @@ -897,16 +865,12 @@ private: dest = d; args_count = ac; performer = p; -#ifdef PIP_CXX11_SUPPORT functor = 0; -#endif } void destroy(); void * slot; void * signal; -#ifdef PIP_CXX11_SUPPORT std::function * functor; -#endif PIString event; uint eventID; PIObject * dest_o; diff --git a/lib/main/introspection/piintrospection_base.h b/lib/main/introspection/piintrospection_base.h index 6b86771d..e21f9830 100644 --- a/lib/main/introspection/piintrospection_base.h +++ b/lib/main/introspection/piintrospection_base.h @@ -23,7 +23,6 @@ #include "pibase.h" class PIString; -class PIMutex; class PIThread; class PITimer; class PIPeer; diff --git a/lib/main/io_devices/piiodevice.h b/lib/main/io_devices/piiodevice.h index 74a6e8b7..a9d1d227 100644 --- a/lib/main/io_devices/piiodevice.h +++ b/lib/main/io_devices/piiodevice.h @@ -54,6 +54,7 @@ class PIP_EXPORT PIIODevice: public PIThread PIOBJECT_SUBCLASS(PIIODevice, PIThread) friend void __DevicePool_threadReadDP(void * ddp); public: + NO_COPY_CLASS(PIIODevice) //! Constructs a empty PIIODevice explicit PIIODevice(); @@ -388,8 +389,6 @@ protected: void * ret_data_; private: - NO_COPY_CLASS(PIIODevice) - EVENT_HANDLER2(void, check_start, void * , data, int, delim); EVENT_HANDLER(void, write_func); diff --git a/lib/main/io_devices/pipeer.h b/lib/main/io_devices/pipeer.h index c142b81b..155d6055 100644 --- a/lib/main/io_devices/pipeer.h +++ b/lib/main/io_devices/pipeer.h @@ -120,11 +120,11 @@ public: EVENT1(peerConnectedEvent, const PIString &, name) EVENT1(peerDisconnectedEvent, const PIString &, name) - bool lockedEth() const {return eth_mutex.isLocked();} - bool lockedPeers() const {return peers_mutex.isLocked();} - bool lockedMBcasts() const {return mc_mutex.isLocked();} - bool lockedSends() const {return send_mutex.isLocked();} - bool lockedMCSends() const {return send_mc_mutex.isLocked();} +// bool lockedEth() const {return eth_mutex.isLocked();} +// bool lockedPeers() const {return peers_mutex.isLocked();} +// bool lockedMBcasts() const {return mc_mutex.isLocked();} +// bool lockedSends() const {return send_mutex.isLocked();} +// bool lockedMCSends() const {return send_mc_mutex.isLocked();} protected: virtual void dataReceived(const PIString & from, const PIByteArray & data) {;} diff --git a/lib/main/io_utils/pidiagnostics.h b/lib/main/io_utils/pidiagnostics.h index 74a69348..9815bb19 100644 --- a/lib/main/io_utils/pidiagnostics.h +++ b/lib/main/io_utils/pidiagnostics.h @@ -32,12 +32,13 @@ class PIP_EXPORT PIDiagnostics: public PITimer PIOBJECT_SUBCLASS(PIDiagnostics, PITimer) friend class PIConnection; public: + NO_COPY_CLASS(PIDiagnostics) //! Constructs an empty diagnostics and if "start_" start it PIDiagnostics(bool start_ = true); virtual ~PIDiagnostics(); - + //! Connection quality enum Quality { Unknown /** Unknown, no one packet received yet */ = 1, @@ -122,8 +123,6 @@ public: //! \} private: - NO_COPY_CLASS(PIDiagnostics) - struct Entry { Entry() {bytes_ok = bytes_fail = 0; cnt_ok = cnt_fail = 0; empty = true;} ullong bytes_ok; diff --git a/lib/main/lua/piluaprogram.h b/lib/main/lua/piluaprogram.h new file mode 100644 index 00000000..a21b075a --- /dev/null +++ b/lib/main/lua/piluaprogram.h @@ -0,0 +1,50 @@ +/*! \file piluaprogram.h + * \brief Lua Program +*/ +/* + PIP - Platform Independent Primitives + PILuaProgram + Andrey Bychkov work.a.b@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PILUAPROGRAM_H +#define PILUAPROGRAM_H + +#include "pip_lua.h" + +class PILuaProgram +{ +public: + //! Constructs an empty PILuaProgram, initialize Lua context + PILuaProgram(); + + //! Load Lua script from PIString + bool load(const PIString & script); + + //! Execute script + bool prepare(); + + //! Get Lua Object or Function + luabridge::LuaRef getGlobal(const PIString & name); + + //! Return Lua global namespace + luabridge::Namespace getGlobalNamespace(); + +private: + PRIVATE_DECLARATION +}; + +#endif // PILUAPROGRAM_H diff --git a/lib/main/lua/pip_lua.h b/lib/main/lua/pip_lua.h new file mode 100644 index 00000000..a9b94167 --- /dev/null +++ b/lib/main/lua/pip_lua.h @@ -0,0 +1,58 @@ +/*! \file pip_lua.h + * \brief PIP Lua bindings + * + * This file declare conversions for PIP types via LuaBridge +*/ +/* + PIP - Platform Independent Primitives + PIP Lua bindings + Andrey Bychkov work.a.b@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ +#ifndef PIP_LUA_H +#define PIP_LUA_H + +#include "lua.hpp" +#include +#include "pistring.h" + +namespace luabridge { + +template <> +struct Stack { + static void push (lua_State* L, PIString const& str) { + lua_pushstring(L, str.dataUTF8()); + } + + static PIString get (lua_State* L, int index) { + if (lua_type(L, index) == LUA_TSTRING) { + const char* str = lua_tostring(L, index); + return PIString::fromUTF8(str); + } + + lua_pushvalue(L, index); + const char* str = lua_tostring(L, -1); + PIString string = PIString::fromUTF8(str); + lua_pop(L, 1); + return string; + } + + static bool isInstance (lua_State* L, int index) { + return lua_type(L, index) == LUA_TSTRING; + } +}; + +} +#endif // PIP_LUA_H diff --git a/lib/main/math/pimathcomplex.h b/lib/main/math/pimathcomplex.h index 4c1ffe1b..2bcc7fea 100644 --- a/lib/main/math/pimathcomplex.h +++ b/lib/main/math/pimathcomplex.h @@ -68,15 +68,10 @@ inline complexd sign(const complexd & x) {return complexd(sign(x.real()), sign(x inline complexd round(const complexd & c) {return complexd(piRound(c.real()), piRound(c.imag()));} inline complexd floor(const complexd & c) {return complexd(floor(c.real()), floor(c.imag()));} inline complexd ceil (const complexd & c) {return complexd(ceil(c.real()), ceil(c.imag()));} -#ifdef PIP_CXX11_SUPPORT -# define acosc acos -# define asinc asin -# define atanc atan -#else -inline complexd atanc(const complexd & c) {return complexd(0., 0.5) * log((complexd_1 - complexd_i * c) / (complexd_1 + complexd_i * c));} -inline complexd asinc(const complexd & c) {return -complexd_i * log(complexd_i * c + sqrt(complexd_1 - c * c));} -inline complexd acosc(const complexd & c) {return -complexd_i * log(c + complexd_i * sqrt(complexd_1 - c * c));} -#endif + +#define acosc acos +#define asinc asin +#define atanc atan #ifdef CC_GCC # if CC_GCC_VERSION <= 0x025F diff --git a/lib/main/piplatform.h b/lib/main/piplatform.h index 597520b8..73eebc88 100644 --- a/lib/main/piplatform.h +++ b/lib/main/piplatform.h @@ -20,10 +20,6 @@ #ifndef PIPLATFORM_H #define PIPLATFORM_H -#if (__cplusplus >= 201103L) // стандарт C++ 11 или выше - #define PIP_CXX11_SUPPORT -#endif - #if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) # define WINDOWS # define ARCH_BITS_64 diff --git a/lib/main/thread/pimutex.cpp b/lib/main/thread/pimutex.cpp deleted file mode 100644 index efdf9918..00000000 --- a/lib/main/thread/pimutex.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - PIP - Platform Independent Primitives - Mutex - Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -/** \class PIMutex - * \brief Mutex - * \details - * \section PIMutex_sec0 Synopsis - * %PIMutex provides synchronization blocks between several threads. - * Using mutex guarantees execution of some code only one of threads. - * Mutex contains logic state and functions to change it: \a lock(), - * \a unlock() and \a tryLock(). - * - * \section PIMutex_sec1 Usage - * Block of code that should to be executed only one thread simultaniously - * should to be started with \a lock() and ended with \a unlock(). - * \snippet pimutex.cpp main - * "mutex" in this example is one for all threads. - * - * */ - -#include "pimutex.h" -#include "piincludes_p.h" -#ifdef BLACKBERRY -# include -#endif - - -PRIVATE_DEFINITION_START(PIMutex) -#ifdef WINDOWS - HANDLE -#else - pthread_mutex_t -#endif - mutex; -PRIVATE_DEFINITION_END(PIMutex) - - -PIMutex::PIMutex(): inited_(false) { - //printf("new Mutex %p\n", this); -#ifdef WINDOWS - PRIVATE->mutex = 0; -#endif - init(); -} - - -PIMutex::~PIMutex() { - //printf("del Mutex %p\n", this); - destroy(); -} - - -void PIMutex::lock() { -#ifdef WINDOWS -// std::cout << (ullong)PRIVATE->mutex << "locking..." << std::endl; -// DWORD wr = - WaitForSingleObject(PRIVATE->mutex, INFINITE); -// std::cout << (ullong)PRIVATE->mutex << " lock wr=" << wr << std::endl; -#else - pthread_mutex_lock(&(PRIVATE->mutex)); -#endif - locked = true; -} - - -void PIMutex::unlock() { -#ifdef WINDOWS -// BOOL wr = -// ReleaseMutex(PRIVATE->mutex); - SetEvent(PRIVATE->mutex); -// std::cout << (ullong)PRIVATE->mutex << " unlock wr=" << wr << std::endl; -#else - pthread_mutex_unlock(&(PRIVATE->mutex)); -#endif - locked = false; -} - - -bool PIMutex::tryLock() { - bool ret = -#ifdef WINDOWS - (WaitForSingleObject(PRIVATE->mutex, 0) == WAIT_OBJECT_0); -#else - (pthread_mutex_trylock(&(PRIVATE->mutex)) == 0); -#endif - locked = true; - return ret; -} - - -bool PIMutex::isLocked() const { -// std::cout << "test " << (ullong)PRIVATE->mutex << std::endl; - return locked; -} - - -void PIMutex::init() { - if (inited_) destroy(); -#ifdef WINDOWS - PRIVATE->mutex = CreateEvent(NULL, FALSE, TRUE, NULL); -// std::cout << "create " << (ullong)PRIVATE->mutex << std::endl; -#else - pthread_mutexattr_t attr; - memset(&attr, 0, sizeof(attr)); - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); - memset(&(PRIVATE->mutex), 0, sizeof(PRIVATE->mutex)); - pthread_mutex_init(&(PRIVATE->mutex), &attr); - pthread_mutexattr_destroy(&attr); -#endif - locked = false; - inited_ = true; -} - - -void PIMutex::destroy() { - if (inited_) { -#ifdef WINDOWS -// std::cout << "destroy " << (ullong)PRIVATE->mutex << std::endl; - if (PRIVATE->mutex) CloseHandle(PRIVATE->mutex); - PRIVATE->mutex = 0; -#else - pthread_mutex_destroy(&(PRIVATE->mutex)); -#endif - } - locked = inited_ = false; -} diff --git a/lib/main/thread/pimutex.h b/lib/main/thread/pimutex.h index ac4277e5..02892916 100644 --- a/lib/main/thread/pimutex.h +++ b/lib/main/thread/pimutex.h @@ -1,9 +1,9 @@ /*! \file pimutex.h - * \brief Mutex + * \brief PIMutexLocker */ /* PIP - Platform Independent Primitives - Mutex + PIMutexLocker Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru This program is free software: you can redistribute it and/or modify @@ -25,53 +25,22 @@ #include "piinit.h" -class PIP_EXPORT PIMutex -{ -public: - //! Constructs unlocked mutex - explicit PIMutex(); - - //! Destroy mutex - ~PIMutex(); - - - //! \brief Lock mutex - //! \details If mutex is unlocked it set to locked state and returns immediate. - //! If mutex is already locked function blocks until mutex will be unlocked - void lock(); - - //! \brief Unlock mutex - //! \details In any case this function returns immediate - void unlock(); - - //! \brief Try to lock mutex - //! \details If mutex is unlocked it set to locked state and returns "true" immediate. - //! If mutex is already locked function returns immediate an returns "false" - bool tryLock(); - - //! Returns if mutex is locked - bool isLocked() const; - -private: - NO_COPY_CLASS(PIMutex) - - void init(); - void destroy(); - bool inited_; - bool locked; - PRIVATE_DECLARATION -}; - - +//! \brief PIMutexLocker +//! \details Same as std::lock_guard. +//! When a PIMutexLocker object is created, it attempts to lock the mutex it is given, if "condition" true. +//! When control leaves the scope in which the PIMutexLocker object was created, +//! the PIMutexLocker is destructed and the mutex is released, if "condition" true. +//! If "condition" false this class do nothing. +//! The PIMutexLocker class is non-copyable. class PIP_EXPORT PIMutexLocker { public: - PIMutexLocker(PIMutex * m, bool condition = true): mutex(m), cond(condition) {if (cond) mutex->lock();} - PIMutexLocker(PIMutex & m, bool condition = true): mutex(&m), cond(condition) {if (cond) mutex->lock();} - ~PIMutexLocker() {if (cond) mutex->unlock();} + NO_COPY_CLASS(PIMutexLocker) + PIMutexLocker(PIMutex & m, bool condition = true): mutex(m), cond(condition) {if (cond) mutex.lock();} + ~PIMutexLocker() {if (cond) mutex.unlock();} private: - PIMutex * mutex; - volatile bool cond; + PIMutex & mutex; + std::atomic_bool cond; }; #endif // PIMUTEX_H diff --git a/lib/main/thread/pithread.cpp b/lib/main/thread/pithread.cpp index 9fdd98eb..5ce598e8 100644 --- a/lib/main/thread/pithread.cpp +++ b/lib/main/thread/pithread.cpp @@ -184,7 +184,6 @@ PIThread::PIThread(void * data, ThreadFunc func, bool startNow, int timer_delay) } -#ifdef PIP_CXX11_SUPPORT PIThread::PIThread(std::function func, bool startNow, int timer_delay) { PIINTROSPECTION_THREAD_NEW(this); tid_ = -1; @@ -196,7 +195,6 @@ PIThread::PIThread(std::function func, bool startNow, int timer_delay) delay_ = timer_delay; if (startNow) start(timer_delay); } -#endif PIThread::PIThread(bool startNow, int timer_delay): PIObject() { diff --git a/lib/main/thread/pithread.h b/lib/main/thread/pithread.h index a2805bea..2e08aa68 100644 --- a/lib/main/thread/pithread.h +++ b/lib/main/thread/pithread.h @@ -60,25 +60,20 @@ public: static __PIThreadCollection_Initializer__ __PIThreadCollection_initializer__; -#ifdef PIP_CXX11_SUPPORT typedef std::function ThreadFunc; -#else -typedef void (*ThreadFunc)(void * ); -#endif class PIP_EXPORT PIThread: public PIObject { PIOBJECT_SUBCLASS(PIThread, PIObject) friend class PIIntrospectionThreads; public: - + NO_COPY_CLASS(PIThread) + //! Contructs thread with custom data "data", external function "func" and main loop delay "loop_delay". PIThread(void * data, ThreadFunc func, bool startNow = false, int loop_delay = -1); -#ifdef PIP_CXX11_SUPPORT //! Contructs thread with external function "func" and main loop delay "loop_delay". PIThread(std::function func, bool startNow = false, int loop_delay = -1); -#endif //! Contructs thread with main loop delay "loop_delay". PIThread(bool startNow = false, int loop_delay = -1); @@ -98,10 +93,8 @@ public: EVENT_HANDLER1(bool, start, int, timer_delay); bool start(ThreadFunc func) {return start(func, -1);} bool start(ThreadFunc func, int timer_delay) {ret_func = func; return start(timer_delay);} -#ifdef PIP_CXX11_SUPPORT bool start(std::function func) {return start(func, -1);} bool start(std::function func, int timer_delay) {ret_func = [func](void*){func();}; return start(timer_delay);} -#endif EVENT_HANDLER0(bool, startOnce); EVENT_HANDLER1(bool, startOnce, ThreadFunc, func) {ret_func = func; return startOnce();} EVENT_HANDLER0(void, stop) {stop(false);} @@ -114,10 +107,8 @@ public: //! \brief Set external function that will be executed after every \a run() void setSlot(ThreadFunc func) {ret_func = func;} -#ifdef PIP_CXX11_SUPPORT //! \brief Set external function that will be executed after every \a run() void setSlot(std::function func) {ret_func = [func](void*){func();};} -#endif //! \brief Set priority of thread void setPriority(PIThread::Priority prior); @@ -160,11 +151,9 @@ public: //! and automatically delete it on function finish static void runOnce(PIObject * object, const char * handler, const PIString & name = PIString()); -#ifdef PIP_CXX11_SUPPORT //! \brief Start function \"func\" in separate thread with name \"name\" //! and automatically delete it on function finish static void runOnce(std::function func, const PIString & name = PIString()); -#endif //! \handlers //! \{ @@ -246,7 +235,7 @@ protected: //! Function executed once at the end of thread. virtual void end() {;} - volatile bool terminating, running_, lockRun; + std::atomic_bool terminating, running_, lockRun; int delay_, policy_; llong tid_; void * data_; @@ -257,8 +246,6 @@ protected: PRIVATE_DECLARATION private: - NO_COPY_CLASS(PIThread) - bool _startThread(void * func); void _beginThread(); void _runThread(); diff --git a/lib/main/thread/pitimer.cpp b/lib/main/thread/pitimer.cpp index f3a68a64..b2878f42 100644 --- a/lib/main/thread/pitimer.cpp +++ b/lib/main/thread/pitimer.cpp @@ -479,7 +479,6 @@ PITimer::PITimer(TimerEvent slot, void * data, PITimer::TimerImplementation ti): } -#ifdef PIP_CXX11_SUPPORT PITimer::PITimer(std::function slot, PITimer::TimerImplementation ti) { imp_mode = ti; initFirst(); @@ -493,7 +492,7 @@ PITimer::PITimer(std::function slot, void * data, PITimer::TimerI data_t = data; ret_func = [slot](void *d, int){slot(d);}; } -#endif + PITimer::~PITimer() { destroy(); diff --git a/lib/main/thread/pitimer.h b/lib/main/thread/pitimer.h index 2d58b847..842af062 100644 --- a/lib/main/thread/pitimer.h +++ b/lib/main/thread/pitimer.h @@ -26,11 +26,7 @@ #include "pithread.h" #include "pitime.h" -#ifdef PIP_CXX11_SUPPORT typedef std::function TimerEvent; -#else -typedef void (*TimerEvent)(void *, int); -#endif class PITimer; @@ -68,7 +64,7 @@ protected: double interval_, deferred_delay; bool deferred_, deferred_mode; // mode: true - date, false - delay - volatile bool running_; + std::atomic_bool running_; PIDateTime deferred_datetime; }; @@ -78,7 +74,8 @@ protected: class PIP_EXPORT PITimer: public PIObject { PIOBJECT_SUBCLASS(PITimer, PIObject) public: - + NO_COPY_CLASS(PITimer) + //! \brief Constructs timer with PITimer::Thread implementation explicit PITimer(); @@ -96,13 +93,11 @@ public: //! \brief Constructs timer with "slot" slot void(void *,int), "data" data and "ti" implementation explicit PITimer(TimerEvent slot, void * data = 0, TimerImplementation ti = Thread); -#ifdef PIP_CXX11_SUPPORT //! \brief Constructs timer with "slot" slot void(), and "ti" implementation explicit PITimer(std::function slot, TimerImplementation ti = Thread); //! \brief Constructs timer with "slot" slot void(void *), "data" data and "ti" implementation explicit PITimer(std::function slot, void * data, TimerImplementation ti = Thread); -#endif virtual ~PITimer(); @@ -159,13 +154,11 @@ public: //! \brief Set timer tick function void setSlot(TimerEvent slot) {ret_func = slot;} -#ifdef PIP_CXX11_SUPPORT //! \brief Set timer tick function void setSlot(std::function slot) {ret_func = [slot](void *, int){slot();};} //! \brief Set timer tick function void setSlot(std::function slot) {ret_func = [slot](void *d, int){slot(d);};} -#endif //! \brief Returns common data passed to tick functions void * data() const {return data_t;} @@ -185,13 +178,11 @@ public: //! \brief Add frequency delimiter \b delim with optional delimiter slot \b slot. void addDelimiter(int delim, TimerEvent slot = 0) {delims << Delimiter(slot, delim);} -#ifdef PIP_CXX11_SUPPORT //! \brief Add frequency delimiter \b delim with optional delimiter slot \b slot. void addDelimiter(int delim, std::function slot) {delims << Delimiter([slot](void *, int){slot();}, delim);} //! \brief Add frequency delimiter \b delim with optional delimiter slot \b slot. void addDelimiter(int delim, std::function slot) {delims << Delimiter([slot](void *d, int){slot(d);}, delim);} -#endif //! \brief Remove all frequency delimiters \b delim. void removeDelimiter(int delim) {for (int i = 0; i < delims.size_s(); ++i) if (delims[i].delim == delim) {delims.remove(i); i--;}} @@ -254,17 +245,13 @@ protected: virtual void tick(void * data_, int delimiter) {} void * data_t; - volatile bool lockRun, callEvents; + std::atomic_bool lockRun, callEvents; PIMutex mutex_; TimerEvent ret_func; TimerImplementation imp_mode; PIVector delims; mutable _PITimerBase * imp; - -private: - NO_COPY_CLASS(PITimer) - }; diff --git a/main.cpp b/main.cpp index dafd934c..d78cedcf 100644 --- a/main.cpp +++ b/main.cpp @@ -1,309 +1,32 @@ #include "pip.h" -#include -#include -#include -/*#include -#include +#ifdef PIP_LUA +#include "piluaprogram.h" -void print(PIConfig::Entry*e, PIString indent = "") { - piCout << indent << e->name() << "=" << e->value(); - indent += " "; - e->children().forEach([=](PIConfig::Entry*e)->PIConfig::Entry*{print(e, indent); return e;}); +static const char * script += "-- script.lua \n" + "test()\n" + "testString = \"LuaBridge works ававава!\" \n" + "number = 42 \n"; + + +void test() { + piCout << "C function test"; } -class AsyncIOWatcher: public PIThread { - PIOBJECT_SUBCLASS(AsyncIOWatcher, PIThread) -public: - AsyncIOWatcher() { - pipe_fd[0] = pipe_fd[1] = 0; - if (pipe(pipe_fd) != 0) { - piCoutObj << "Warning: can`t create pipe," << errorString(); - } else { - fd_list << pipe_fd[0]; - } - piCout << pipe_fd[0] << pipe_fd[1]; - fd_list_changed = false; - start(); - } - ~AsyncIOWatcher() { - stop(); - breakSelect(); - if (!waitForFinish(2000)) - terminate(); - if (pipe_fd[0]) ::close(pipe_fd[0]); - if (pipe_fd[1]) ::close(pipe_fd[1]); - } - - void add(int fd) { - que_mutex.lock(); - fd_list_changed = true; - if (!add_que.contains(fd)) - add_que.enqueue(fd); - que_mutex.unlock(); - breakSelect(); - } - void remove(int fd) { - que_mutex.lock(); - fd_list_changed = true; - if (!remove_que.contains(fd)) - remove_que.enqueue(fd); - que_mutex.unlock(); - breakSelect(); - } - -private: - virtual void run() { - que_mutex.lock(); - if (fd_list_changed) { - for (int i = 0; i < add_que.size_s(); ++i) { - if (!fd_list.contains(add_que[i])) - fd_list << add_que[i]; - } - for (int i = 0; i < remove_que.size_s(); ++i) { - fd_list.removeAll(remove_que[i]); - } - add_que.clear(); - remove_que.clear(); - } - fd_list_changed = false; - que_mutex.unlock(); - - s_tv.tv_sec = 1; - s_tv.tv_usec = 0; - FD_ZERO(&s_set); - int max_fd = 0; - piForeachC (int fd, fd_list) { - FD_SET(fd, &s_set); - if (max_fd < fd) - max_fd = fd; - } - int ret = select(max_fd + 1, &s_set, 0, 0, 0); - piCout << "select" << ret; - if (ret <= 0) return; - read_buff.resize(1024); - uint ibuff = 0; - piForeachC (int fd, fd_list) { - if (!FD_ISSET(fd, &s_set)) continue; - if (fd == pipe_fd[0]) { - read(fd, &ibuff, sizeof(ibuff)); - piCoutObj << "breaked"; - continue; - } - int readed = read(fd, read_buff.data(), read_buff.size_s()); - piCout << "readed" << fd << readed; - } - } - void breakSelect() { - if (pipe_fd[1]) - ::write(pipe_fd[1], "\0", 1); - } - - PIQueue add_que, remove_que; - PIDeque fd_list; - PIByteArray read_buff; - PIMutex que_mutex; - bool fd_list_changed; - int pipe_fd[2]; - - fd_set s_set; - struct timeval s_tv; - -}; -*/ -struct A { - double arr[1000]; -}; - - -//PIKbdListener kbd(0, 0, false); - -// void swap(int & x, int & y) {int t = x; x = y; y = t;} -// void swap2(int & x, int & y) {int t(std::move(x)); x = y; y = t;} -// void swap(uint & x, uint & y) {uint t = x; x = y; y = t;} -// void swap2(uint & x, uint & y) {uint t(std::move(x)); x = y; y = t;} -// void swap(ullong & x, ullong & y) {ullong t = x; x = y; y = t;} -// void swap2(ullong & x, ullong & y) {ullong t{std::move(x)}; x = y; y = t;} -// void swap(llong & x, llong & y) {llong t = x; x = y; y = t;} -// void swap2(llong & x, llong & y) {llong t{std::move(x)}; x = y; y = t;} -// void swap(double & x, double & y) {double t = x; x = y; y = t;} -// void swap2(double & x, double & y) {double t(std::move(x)); x = std::move(y); y = std::move(t);} -// void swap(float & x, float & y) {float t = x; x = y; y = t;} -// void swap2(float & x, float & y) {float t(std::move(x)); x = std::move(y); y = std::move(t);} -// void swap(PIString & x, PIString & y) {PIString t = x; x = y; y = t;} -// void swap2(PIString & x, PIString & y) {PIString t(std::move(x)); x = std::move(y); y = std::move(t);} -// void swap(std::string & x, std::string & y) {std::string t = x; x = y; y = t;} -// void swap2(std::string & x, std::string & y) {std::string t{std::move(x)}; x = std::move(y); y = std::move(t);} -// void swap(A & x, A & y) {A t = x; x = y; y = t;} -// void swap2(A & x, A & y) {A t{std::move(x)}; x = std::move(y); y = std::move(t);} -//void swap(PIObject & x, PIObject & y) {A t = x; x = y; y = t;} -//void swap2(PIObject & x, PIObject & y) {A t(std::move(x)); x = std::move(y); y = std::move(t);} - -int main(int argc, char * argv[]) { - // PITimeMeasurer tm; - // int m = 100000; - // int a = 99, b = 77; - // piCout << "int"; - // tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap(a,b); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap2(a,b); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwapBinary(a,b); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwap(a,b); - // } - // piCout << tm.elapsed_s(); - - // piCout << "size_t"; - // size_t ta = 99, tb = 77; - // tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap(ta,tb); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap2(ta,tb); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwapBinary(ta,tb); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwap(ta,tb); - // } - // piCout << tm.elapsed_s(); - - // piCout << "ullong"; - // ullong lla = 99, llb = 77; - // tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap(lla,llb); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap2(lla,llb); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwapBinary(lla,llb); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwap(lla,llb); - // } - // piCout << tm.elapsed_s(); - - // piCout << "double"; - // double da = 0.99,db = 77.77; - // tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap(da,db); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap2(da,db); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwapBinary(da,db); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwap(da,db); - // } - // piCout << tm.elapsed_s(); - - // piCout << "float"; - // float fa = 0.99,fb = 77.77; - // tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap(fa,fb); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap2(fa,fb); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwapBinary(fa,fb); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwap(fa,fb); - // } - // piCout << tm.elapsed_s(); - - // piCout << "A"; - // A aa,ab; - // tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap(aa,ab); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap2(aa,ab); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwapBinary(aa,ab); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwap(aa,ab); - // } - // piCout << tm.elapsed_s(); - - // piCout << "std::string"; - // std::string ia = "123456789012345678901vfsdvsd2345678",ib = "qwertyvsdfvvsdvfsuiopqwertyuikolsdfghjklsdfghjk"; - // tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap(ia,ib); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap2(ia,ib); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // ia.swap(ib); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwap(ia,ib); - // } - // piCout << tm.elapsed_s(); - - - // PIString sa = "123456789012345678901vfsdvsd2345678",sb = "qwertyvsdfvvsdvfsuiopqwertyuikolsdfghjklsdfghjk"; - // piCout << "PIString"; - // tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap(sa,sb); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // swap2(sa, sb); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // sa.swap(sb); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwapBinary(sa, sb); - // } - // piCout << tm.elapsed_s(); tm.reset(); - // for (int i = 0; i < m; ++i) { - // piSwap(sa, sb); - // } - // piCout << tm.elapsed_s(); +int main() { + PILuaProgram p; + p.getGlobalNamespace().addFunction("test", test); + if (!p.load(PIString::fromUTF8(script))) piCout << "error"; + p.prepare(); + luabridge::LuaRef s = p.getGlobal("testString"); + luabridge::LuaRef n = p.getGlobal("number"); + PIString luaString = s.cast(); + int answer = n.cast(); + piCout << luaString; + piCout << "And here's our number:" << answer; +} +#else +int main() { return 0; } +#endif diff --git a/utils/system_daemon/main.cpp b/utils/system_daemon/main.cpp index 40962fa0..b1ed08d4 100755 --- a/utils/system_daemon/main.cpp +++ b/utils/system_daemon/main.cpp @@ -164,19 +164,20 @@ public: tl->content << TileSimple::Row("Quality: " + PIString::fromNumber((int)ds.quality), CellFormat()); } void updatePeerInfo() { - bool pm = daemon_.lockedPeers(); +// bool pm = daemon_.lockedPeers(); screen->lock(); daemon_.lock(); peers_tl->content.clear(); addrs_tl->content.clear(); peerinfo_tl->content.clear(); peermap_tl->content.clear(); - peers_tl->content << TileList::Row("this | 0 | 0 | " + PIString::fromNumber(daemon_.allPeers().size_s()) + - " [em = " + PIString::fromBool(daemon_.lockedEth()) + ", " - "mm = " + PIString::fromBool(daemon_.lockedMBcasts()) + ", " - "sm = " + PIString::fromBool(daemon_.lockedSends()) + ", " - "ms = " + PIString::fromBool(daemon_.lockedMCSends()) + ", " - "pm = " + PIString::fromBool(pm) + "]", CellFormat()); + peers_tl->content << TileList::Row("this | 0 | 0 | " + PIString::fromNumber(daemon_.allPeers().size_s()) +// + " [em = " + PIString::fromBool(daemon_.lockedEth()) + ", " +// "mm = " + PIString::fromBool(daemon_.lockedMBcasts()) + ", " +// "sm = " + PIString::fromBool(daemon_.lockedSends()) + ", " +// "ms = " + PIString::fromBool(daemon_.lockedMCSends()) + ", " +// "pm = " + PIString::fromBool(pm) + "]" + , CellFormat()); piForeachC(PIPeer::PeerInfo &p , daemon_.allPeers()) peers_tl->content << TileList::Row(p.name + " | d = " + PIString::fromNumber(p.dist) + " | p = " + PIString::fromNumber(p.ping()) +