diff --git a/BambooEngine/include/RenderNodes/IRenderNode.h b/BambooEngine/include/RenderNodes/IRenderNode.h index 218d2b0..9c8f1eb 100644 --- a/BambooEngine/include/RenderNodes/IRenderNode.h +++ b/BambooEngine/include/RenderNodes/IRenderNode.h @@ -160,7 +160,6 @@ class Bamboo::IRenderNode /*! \name Internal helper methods */ //@{ void ItlSendTransformMatrices(); /// AssimpWrapper::LoadModel(std::strin aiProcess_CalcTangentSpace | aiProcess_ValidateDataStructure | aiProcess_Triangulate | - aiProcess_PreTransformVertices | + // aiProcess_PreTransformVertices | //aiProcess_JoinIdenticalVertices | aiProcess_GenSmoothNormals | aiProcess_ImproveCacheLocality | diff --git a/BambooEngine/src/DeferredNodeTranslator/LoadedModel_RuleObject.cpp b/BambooEngine/src/DeferredNodeTranslator/LoadedModel_RuleObject.cpp index 1045d51..94082b7 100644 --- a/BambooEngine/src/DeferredNodeTranslator/LoadedModel_RuleObject.cpp +++ b/BambooEngine/src/DeferredNodeTranslator/LoadedModel_RuleObject.cpp @@ -29,20 +29,32 @@ void DeferredNodeTranslator::LoadedModel_RuleObject::Action() // add rendering nodes, if environment mapping is activated but not handled yet if (!m_spCubemapDeferredNode && m_spSemNode->GetEnvironmentMapping()) { - m_spCubemapCamera = Bamboo::PerspectiveCamera::Create(90.0f, 1.0f, 0.01f, 100.0f, glm::vec3(), 0.0f, 0.0f); + m_spCubemapCamera = Bamboo::PerspectiveCamera::Create(90.0f, 1.0f, 0.001f, 100.0f, glm::vec3(), 0.0f, 0.0f); m_spCubemapCameraNode = std::shared_ptr (new Bamboo::RN_Camera(m_spCubemapCamera.get())); - m_spCubemapDeferredNode = std::shared_ptr (new Bamboo::RN_Deferred(256, 256, true)); + m_spCubemapDeferredNode = std::shared_ptr (new Bamboo::RN_Deferred(128, 128, true)); m_spCubemapCameraNode->AddChild(m_spCubemapDeferredNode); GLuint nDeferredAlbedoTexture = m_spCubemapDeferredNode->GetAlbedoTexture(); - m_spCorrespondingRenderingNode->SetEnvironmentMap(nDeferredAlbedoTexture); + m_spCorrespondingRenderingNode->SetEnvironmentMapping(true, nDeferredAlbedoTexture); m_pTranslator->m_spRootNode->AddChild(m_spCubemapCameraNode); } + // remove rendering nodes, if environment mapping is deactivated but notes created + if (m_spCubemapDeferredNode && !m_spSemNode->GetEnvironmentMapping()) + { + m_pTranslator->m_spRootNode->RemoveChild(m_spCubemapCameraNode); + + m_spCubemapCamera.reset(); + m_spCubemapCameraNode.reset(); + m_spCubemapDeferredNode.reset(); + + m_spCorrespondingRenderingNode->SetEnvironmentMapping(false, 0); + } + if (m_spCubemapDeferredNode) { glm::mat4 mTrans = m_spSemNode->GetTransformMatrix(); diff --git a/BambooEngine/src/RenderNode.cpp b/BambooEngine/src/RenderNode.cpp index de58f65..3a1d097 100644 --- a/BambooEngine/src/RenderNode.cpp +++ b/BambooEngine/src/RenderNode.cpp @@ -115,7 +115,7 @@ Bamboo::IRenderNode::IRenderNode() Bamboo::IRenderNode::~IRenderNode() { - + ClearChilds(); } @@ -157,6 +157,8 @@ bool Bamboo::IRenderNode::RemoveChild(std::shared_ptr spNod break; } + + iterator++; } diff --git a/BambooEngine/src/RenderNodes/RenderNode_Camera.cpp b/BambooEngine/src/RenderNodes/RenderNode_Camera.cpp index 93f2d93..5c0ab5f 100644 --- a/BambooEngine/src/RenderNodes/RenderNode_Camera.cpp +++ b/BambooEngine/src/RenderNodes/RenderNode_Camera.cpp @@ -110,7 +110,12 @@ Bamboo::RN_Camera::RN_Camera(Bamboo::ICamera * pCamera, bool bSetMatrices) if (error != GL_NO_ERROR) Logger::error() << "glGetError: " << TranslateGLerror(error) << Logger::endl; - Logger::debug() << "SceneObject_Camera created" << Logger::endl; + Logger::debug() << "RN_Camera created" << Logger::endl; +} + +Bamboo::RN_Camera::~RN_Camera() +{ + Logger::debug() << "RN_Camera destroyed" << Logger::endl; } void Bamboo::RN_Camera::Render(std::shared_ptr pCurrentRenderInfo) diff --git a/BambooEngine/src/RenderNodes/RenderNode_Deferred.cpp b/BambooEngine/src/RenderNodes/RenderNode_Deferred.cpp index 3b91fda..18a5c69 100644 --- a/BambooEngine/src/RenderNodes/RenderNode_Deferred.cpp +++ b/BambooEngine/src/RenderNodes/RenderNode_Deferred.cpp @@ -17,11 +17,15 @@ Bamboo::RN_Deferred::RN_Deferred(unsigned int nWidth, unsigned int nHeight, bool ItlCreateFBO(); m_bLayeredFBO = bLayered; + + Logger::debug() << "RN_Deferred created" << Logger::endl; } Bamboo::RN_Deferred::~RN_Deferred() { ItlDeleteFBO(); + + Logger::debug() << "RN_Deferred destroyed" << Logger::endl; } void Bamboo::RN_Deferred::ItlCreateFBO() @@ -387,9 +391,6 @@ void Bamboo::RN_Deferred::ItlPreRender() void Bamboo::RN_Deferred::ItlRender() { - double test[3]; -// glVertex3dv(test); - if (m_bLayeredFBO == false) { glBindFramebuffer(GL_FRAMEBUFFER, m_nFBO); @@ -489,12 +490,12 @@ void Bamboo::RN_Deferred::ItlRender() } else { - static bool bAlreadyPrinted = false; + /*static bool bAlreadyPrinted = false; if (bAlreadyPrinted == false) { Logger::debug() << "Texture id of cube map: " << m_nAlbedoDrawBuffer << Logger::endl; bAlreadyPrinted = true; - } + }*/ } diff --git a/BambooEngine/src/RenderNodes/RenderNode_FBO.cpp b/BambooEngine/src/RenderNodes/RenderNode_FBO.cpp index a5e3126..515050c 100644 --- a/BambooEngine/src/RenderNodes/RenderNode_FBO.cpp +++ b/BambooEngine/src/RenderNodes/RenderNode_FBO.cpp @@ -117,7 +117,7 @@ Bamboo::RN_FBO::RN_FBO(int iWidth, if(status != GL_FRAMEBUFFER_COMPLETE) Logger::fatal() << "Failed to initialize FBO" << Logger::endl; else - Logger::debug() << "Initialized FBO" << Logger::endl; + Logger::debug() << "RN_FBO created, initialized FBO" << Logger::endl; //unbind framebuffer glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -226,7 +226,7 @@ Bamboo::RN_FBO::RN_FBO(int iWidth, if(status != GL_FRAMEBUFFER_COMPLETE) Logger::fatal() << "Failed to initialize FBO" << Logger::endl; else - Logger::debug() << "Initialized FBO" << Logger::endl; + Logger::debug() << "RN_FBO created, initialized FBO" << Logger::endl; //release used texture unit pTextureManager->ReleaseUnit(textureUnit); @@ -252,6 +252,8 @@ Bamboo::RN_FBO::~RN_FBO() //finally, delete the used fbo glDeleteFramebuffers(1, &m_nFramebuffer); + + Logger::debug() << "RN_FBO destroyed" << Logger::endl; } /*! diff --git a/BambooEngine/src/RenderNodes/RenderNode_Generic.cpp b/BambooEngine/src/RenderNodes/RenderNode_Generic.cpp index 638851a..7fb1a69 100644 --- a/BambooEngine/src/RenderNodes/RenderNode_Generic.cpp +++ b/BambooEngine/src/RenderNodes/RenderNode_Generic.cpp @@ -33,17 +33,21 @@ Bamboo::RN_Generic::RN_Generic(std::shared_ptr spOb ItlLoadShader(); ItlPrepareGLBuffers(); ItlPrepareTextures(); + + Logger::debug() << "RN_Generic created" << Logger::endl; } Bamboo::RN_Generic::~RN_Generic() { ItlDeleteBuffers(); ItlDeleteTextures(); + + Logger::debug() << "RN_Generic destroyed" << Logger::endl; } -void Bamboo::RN_Generic::SetEnvironmentMap(GLuint nTextureID) +void Bamboo::RN_Generic::SetEnvironmentMapping(bool bEnabled, GLuint nTextureID /* = 0*/) { - m_bUseEnvironmentMapping = true; + m_bUseEnvironmentMapping = bEnabled; m_nEnvironmentMap = nTextureID; } @@ -62,9 +66,7 @@ void Bamboo::RN_Generic::ItlRender() GLint iLocationIsSphere = pShaderManager->GetUniform("bIsSphere"); - GLuint iTextureUnitForCubeMap = 15;//pTextureManager->RequestFreeUnit(); - - // std::cout << iTextureUnitForCubeMap << std::endl; + GLuint iTextureUnitForCubeMap = pTextureManager->RequestFreeUnit(); if (iLocationIsSphere != -1) { @@ -124,9 +126,10 @@ void Bamboo::RN_Generic::ItlRender() for (unsigned int i=0; i < vUsedTextures.size(); i++) pTextureManager->UnuseTexture(vUsedTextures[i]); - //pTextureManager->ReleaseUnit(iTextureUnitForCubeMap); vUsedTextures.clear(); } + + pTextureManager->ReleaseUnit(iTextureUnitForCubeMap); } diff --git a/BambooEngine/src/RenderNodes/RenderNode_PostEffect.cpp b/BambooEngine/src/RenderNodes/RenderNode_PostEffect.cpp index e399054..bb56923 100644 --- a/BambooEngine/src/RenderNodes/RenderNode_PostEffect.cpp +++ b/BambooEngine/src/RenderNodes/RenderNode_PostEffect.cpp @@ -50,12 +50,12 @@ Bamboo::RN_PostEffect::RN_PostEffect(std::string sShaderToUse) // prepare the vertex array object ItlPrepareVAO(); - Logger::debug() << "SceneObject_PostEffect created" << Logger::endl; + Logger::debug() << "RN_PostEffect created" << Logger::endl; } Bamboo::RN_PostEffect::~RN_PostEffect() { - + Logger::debug() << "RN_PostEffect destroyed" << Logger::endl; } void Bamboo::RN_PostEffect::ItlPreRender() diff --git a/BambooEngine/src/RenderNodes/RenderNode_SpotLight.cpp b/BambooEngine/src/RenderNodes/RenderNode_SpotLight.cpp index 685cf19..067c04e 100644 --- a/BambooEngine/src/RenderNodes/RenderNode_SpotLight.cpp +++ b/BambooEngine/src/RenderNodes/RenderNode_SpotLight.cpp @@ -37,6 +37,8 @@ Bamboo::RN_SpotLight::~RN_SpotLight() { glDeleteFramebuffers(1, &m_nFBO); glDeleteTextures(1, &m_nDepthTexture); + + Logger::debug() << "RN_SpotLight destroyed" << Logger::endl; } void Bamboo::RN_SpotLight::ItlCreateVBO() diff --git a/BambooEngine/src/RenderNodes/RenderNode_SpotLight_Model.cpp b/BambooEngine/src/RenderNodes/RenderNode_SpotLight_Model.cpp index 2275fad..cda45c2 100644 --- a/BambooEngine/src/RenderNodes/RenderNode_SpotLight_Model.cpp +++ b/BambooEngine/src/RenderNodes/RenderNode_SpotLight_Model.cpp @@ -33,7 +33,7 @@ Bamboo::RN_SpotLight_Model::RN_SpotLight_Model(glm::vec3 vPosition, Bamboo::RN_SpotLight_Model::~RN_SpotLight_Model() { - + Logger::debug() << "RN_SpotLight_Model destroyed" << Logger::endl; } void Bamboo::RN_SpotLight_Model::ItlCreateVBO() diff --git a/BambooEngine/src/TextureManager.cpp b/BambooEngine/src/TextureManager.cpp index 24d5461..6c765a2 100644 --- a/BambooEngine/src/TextureManager.cpp +++ b/BambooEngine/src/TextureManager.cpp @@ -60,20 +60,14 @@ void Bamboo::TextureManager::TImpl::ItlInitialize() { ilInit(); - stringstream puffer; //for debugging output - string puffer2; //for debugging output - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &m_iNumTextureUnits); //ask opengl how many texture units are available - puffer << m_iNumTextureUnits; //for debugging output, transform integer to string, read integer in stringstream - puffer >> puffer2; //for debugging output, transform integer to string, write stringstream to string - + //m_iNumTextureUnits = 32; - m_iNumTextureUnits = 14; for (int a=0; a < m_iNumTextureUnits; a++) //push them all in the free_units queue m_lFreeUnits.push_back(a); - Logger::debug() << puffer2 << " texture units available" << Logger::endl; + Logger::debug() << m_iNumTextureUnits << " texture units available" << Logger::endl; m_bDevIL_Initialized = true; @@ -148,7 +142,6 @@ GLuint Bamboo::TextureManager::UseTexture(GLuint nTextureID) m_pImpl->m_mLastBindedTextures[nFreeUnit] = nTextureID; } - return nFreeUnit; } @@ -186,6 +179,8 @@ GLuint Bamboo::TextureManager::RequestFreeUnit() if (m_pImpl->m_bDevIL_Initialized == false) m_pImpl->ItlInitialize(); + assert (m_pImpl->m_lFreeUnits.empty() == false); + GLuint nFreeUnit = m_pImpl->m_lFreeUnits.front(); //get first free unit m_pImpl->m_lFreeUnits.pop_front(); //remove unit from free_units queue @@ -195,6 +190,18 @@ GLuint Bamboo::TextureManager::RequestFreeUnit() void Bamboo::TextureManager::ReleaseUnit(GLuint nUnit) { +#ifdef DEBUG + bool bOk = true; + for (auto iter = m_pImpl->m_lFreeUnits.begin(); iter != m_pImpl->m_lFreeUnits.end() && bOk; iter++) + { + bOk &= (*iter != nUnit); + } + + if (!bOk) + Logger::fatal() << "Texture unit " << nUnit << " is released without being locked (double release?)" << Logger::endl; + +#endif + m_pImpl->m_lFreeUnits.push_back(nUnit); } diff --git a/CMakeLists.txt.user.2.5pre1 b/CMakeLists.txt.user.2.5pre1 new file mode 100644 index 0000000..827bd88 --- /dev/null +++ b/CMakeLists.txt.user.2.5pre1 @@ -0,0 +1,203 @@ + + + + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + + Cpp + + gnu + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + true + 1 + true + 0 + false + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + Desktop + + CMakeProjectManager.DefaultCMakeTarget + 0 + 0 + 0 + + /home/easterbunny/Projekte/Project-Cube/qtcreator-build + ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-64bit./usr/bin/gdb + ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-64bit./usr/bin/gdb + + + -j 6 + + false + Make + + CMakeProjectManager.MakeStep + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + clean + + true + Make + + CMakeProjectManager.MakeStep + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + all + + CMakeProjectManager.CMakeBuildConfiguration + + 1 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + No deployment + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + + + false + false + false + false + false + false + false + false + true + true + 0.01 + 0.01 + 10 + 10 + true + true + 25 + 25 + + + true + true + /usr/bin/valgrind + /usr/bin/valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + project-cube + + false + + /home/easterbunny/Projekte/Project-Cube/Project-Cube + project-cube + + CMakeProjectManager.CMakeRunConfiguration. + 3768 + true + false + false + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.EnvironmentId + {1fbf1ab5-2034-4209-b294-07c43de9365b} + + + ProjectExplorer.Project.Updater.FileVersion + 10 + + diff --git a/include/Gamelogic/IObject.h b/include/Gamelogic/IObject.h index 27f13c3..e680cbb 100644 --- a/include/Gamelogic/IObject.h +++ b/include/Gamelogic/IObject.h @@ -14,7 +14,7 @@ #include #include -#include "SemanticSceneNodes\ISemanticSceneNode.h" +#include "SemanticSceneNodes/ISemanticSceneNode.h" class IObject { diff --git a/include/Gamelogic/Level.h b/include/Gamelogic/Level.h index 7487df9..0328dad 100644 --- a/include/Gamelogic/Level.h +++ b/include/Gamelogic/Level.h @@ -16,11 +16,11 @@ #include "IXMLSerializeable.h" #include "Gamelogic/Cube.h" #include -#include "SemanticSceneNodes\ISemanticSceneNode.h" +#include "SemanticSceneNodes/ISemanticSceneNode.h" #include "Camera.h" -#include "Gamelogic\IObject.h" -#include "Gamelogic\Objects\LightObject.h" -#include "Gamelogic\Objects\Object.h" +#include "Gamelogic/IObject.h" +#include "Gamelogic/Objects/LightObject.h" +#include "Gamelogic/Objects/Object.h" class Level : public ILevel, public IXMLSerializeable diff --git a/include/Gamelogic/Objects/LightObject.h b/include/Gamelogic/Objects/LightObject.h index 0e2a6c3..3afe56a 100644 --- a/include/Gamelogic/Objects/LightObject.h +++ b/include/Gamelogic/Objects/LightObject.h @@ -8,8 +8,8 @@ #ifndef __LIGHTOBJECT_PROJECTCUBE_HEADER #define __LIGHTOBJECT_PROJECTCUBE_HEADER -#include "Gamelogic\IObject.h" -#include "SemanticSceneNodes\Light_SemSceneNode.h" +#include "Gamelogic/IObject.h" +#include "SemanticSceneNodes/Light_SemSceneNode.h" class LightObject: public IObject { @@ -68,4 +68,4 @@ class LightObject: public IObject }; -#endif //__LIGHTOBJECT_PROJECTCUBE_HEADER \ No newline at end of file +#endif //__LIGHTOBJECT_PROJECTCUBE_HEADER diff --git a/include/Gamelogic/Objects/Object.h b/include/Gamelogic/Objects/Object.h index 39aca60..6df64a4 100644 --- a/include/Gamelogic/Objects/Object.h +++ b/include/Gamelogic/Objects/Object.h @@ -8,8 +8,8 @@ #ifndef __OBJECT_PROJECTCUBE_HEADER #define __OBJECT_PROJECTCUBE_HEADER -#include "Gamelogic\IObject.h" -#include "SemanticSceneNodes\LoadedModel_SemSceneNode.h" +#include "Gamelogic/IObject.h" +#include "SemanticSceneNodes/LoadedModel_SemSceneNode.h" class Object: public IObject { @@ -64,4 +64,4 @@ class Object: public IObject }; -#endif //__OBJECT_PROJECTCUBE_HEADER \ No newline at end of file +#endif //__OBJECT_PROJECTCUBE_HEADER diff --git a/include/LuaManager.h b/include/LuaManager.h index c797818..a4a96b8 100644 --- a/include/LuaManager.h +++ b/include/LuaManager.h @@ -52,46 +52,46 @@ void LuaManager::RegisterFunction(const char* name, F f) { Logger::debug() << "Registering function in the LUA environment: " << name << Logger::endl; - luabind::module(m_pLuaState) + luaponte::module(m_pLuaState) [ - luabind::def(name, f) + luaponte::def(name, f) ]; } template R LuaManager::CallLuaFunction(const char* name) { - return luabind::call_function(m_pLuaState, name); + return luaponte::call_function(m_pLuaState, name); } template R LuaManager::CallLuaFunction(const char* name, A a) { - return luabind::call_function(m_pLuaState, name, a); + return luaponte::call_function(m_pLuaState, name, a); } template R LuaManager::CallLuaFunction(const char* name, A a, B b) { - return luabind::call_function(m_pLuaState, name, a, b); + return luaponte::call_function(m_pLuaState, name, a, b); } template R LuaManager::CallLuaFunction(const char* name, A a, B b, C c) { - return luabind::call_function(m_pLuaState, name, a, b, c); + return luaponte::call_function(m_pLuaState, name, a, b, c); } template R LuaManager::CallLuaFunction(const char* name, A a, B b, C c, D d) { - return luabind::call_function(m_pLuaState, name, a, b, c, d); + return luaponte::call_function(m_pLuaState, name, a, b, c, d); } template R LuaManager::CallLuaFunction(const char* name, A a, B b, C c, D d, E e) { - return luabind::call_function(m_pLuaState, name, a, b, c, d, e); + return luaponte::call_function(m_pLuaState, name, a, b, c, d, e); } #endif //__PROJECT_CUBE_LUA_MANAGER_HEADER diff --git a/include/MainApp.h b/include/MainApp.h index 0ec9135..721d4eb 100644 --- a/include/MainApp.h +++ b/include/MainApp.h @@ -47,7 +47,6 @@ class MainApp : public EventManager::IEventListener /*! \name Testing stuff */ //@{ - void StartGraphic_Test(); void StartGraphic_Test2(); void StartGraphic_LuaTest(); //@} @@ -88,7 +87,6 @@ class MainApp : public EventManager::IEventListener /*! \name Internal helper methods */ //@{ - void ItlCreateSceneGraphs(); //@} /*! \name Private members */ diff --git a/include/lua_include.h b/include/lua_include.h index 8d52a18..90a0662 100644 --- a/include/lua_include.h +++ b/include/lua_include.h @@ -4,11 +4,7 @@ #ifndef __PROJECT_CUBE_LUA_INCLUDE #define __PROJECT_CUBE_LUA_INCLUDE -extern "C" { - #include "lua.h" - #include "lualib.h" - #include "lauxlib.h" -} -#include +#include +#include "luaponte/luaponte.hpp" #endif diff --git a/luaponte/adopt_policy.hpp b/luaponte/adopt_policy.hpp new file mode 100644 index 0000000..ad977b3 --- /dev/null +++ b/luaponte/adopt_policy.hpp @@ -0,0 +1,158 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_ADOPT_POLICY_HPP +#define LUAPONTE_ADOPT_POLICY_HPP + +#include +#include +#include +#include +#include + +#include +#include + +namespace luaponte { +namespace detail { + +template +void adjust_backref_ownership(T* ptr, mpl::true_) +{ + if (wrap_base* p = dynamic_cast(ptr)) + { + wrapped_self_t& wrapper = wrap_access::ref(*p); + wrapper.get(wrapper.state()); + wrapper.m_strong_ref.set(wrapper.state()); + } +} + +inline void adjust_backref_ownership(void*, mpl::false_) +{} + +template +struct adopt_pointer : pointer_converter +{ + typedef adopt_pointer type; + + int consumed_args(...) const + { + return 1; + } + + template + T* apply(lua_State* L, by_pointer, int index) + { + T* ptr = pointer_converter::apply( + L, LUAPONTE_DECORATE_TYPE(T*), index); + + object_rep* obj = static_cast( + lua_touserdata(L, index)); + obj->release(); + + adjust_backref_ownership(ptr, boost::is_polymorphic()); + + return ptr; + } + + template + int match(lua_State* L, by_pointer, int index) + { + return pointer_converter::match( + L, LUAPONTE_DECORATE_TYPE(T*), index); + } + + template + void converter_postcall(lua_State*, T, int) {} +}; + +template +struct pointer_or_default +{ + typedef Pointer type; +}; + +template +struct pointer_or_default +{ + typedef std::unique_ptr type; +}; + +template +struct adopt_pointer +{ + typedef adopt_pointer type; + + template + void apply(lua_State* L, T* ptr) + { + if (ptr == 0) + { + lua_pushnil(L); + return; + } + + // if there is a back_reference, then the + // ownership will be removed from the + // back reference and put on the lua stack. + if (luaponte::move_back_reference(L, ptr)) + return; + + typedef typename pointer_or_default::type + pointer_type; + + make_instance(L, pointer_type(ptr)); + } +}; + +template +struct adopt_policy : conversion_policy +{ + static void precall(lua_State*, const index_map&) {} + static void postcall(lua_State*, const index_map&) {} + + struct only_accepts_nonconst_pointers {}; + + template + struct apply + { + typedef luaponte::detail::is_nonconst_pointer is_nonconst_p; + typedef typename boost::mpl::if_< + is_nonconst_p + , adopt_pointer + , only_accepts_nonconst_pointers + >::type type; + }; +}; + +} // namespace detail +} // namespace luaponte + +namespace luaponte { + +template +detail::policy_cons, detail::null_type> +adopt(LUAPONTE_PLACEHOLDER_ARG(N)) +{ + return detail::policy_cons, detail::null_type>(); +} + +template +detail::policy_cons, detail::null_type> +adopt(LUAPONTE_PLACEHOLDER_ARG(N)) +{ + return detail::policy_cons, detail::null_type>(); +} + +} // namespace luaponte + +#endif // LUAPONTE_ADOPT_POLICY_HPP_INCLUDE diff --git a/luaponte/back_reference.hpp b/luaponte/back_reference.hpp new file mode 100644 index 0000000..d4be2c1 --- /dev/null +++ b/luaponte/back_reference.hpp @@ -0,0 +1,95 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_BACK_REFERENCE_HPP +#define LUAPONTE_BACK_REFERENCE_HPP + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace luaponte { +namespace detail { + + namespace mpl = boost::mpl; + + template + wrap_base const* get_back_reference_aux0(T const* p, mpl::true_) + { + return dynamic_cast(p); + } + + template + wrap_base const* get_back_reference_aux0(T const*, mpl::false_) + { + return 0; + } + + template + wrap_base const* get_back_reference_aux1(T const* p) + { + return get_back_reference_aux0(p, boost::is_polymorphic()); + } + + template + typename std::enable_if::value, wrap_base const*>::type + get_back_reference(T const& x) + { + return get_back_reference_aux1(get_pointer(x)); + } + + template + typename std::enable_if::value, wrap_base const*>::type + get_back_reference(T const& x) + { + return get_back_reference_aux1(&x); + } + +} // namespace detail + +template +bool get_back_reference(lua_State* L, T const& x) +{ +#ifndef LUAPONTE_NO_RTTI + if (wrap_base const* w = detail::get_back_reference(x)) + { + detail::wrap_access::ref(*w).get(L); + return true; + } +#endif + return false; +} + +template +bool move_back_reference(lua_State* L, T const& x) +{ +#ifndef LUAPONTE_NO_RTTI + if (wrap_base* w = const_cast(detail::get_back_reference(x))) + { + assert(detail::wrap_access::ref(*w).m_strong_ref.is_valid()); + detail::wrap_access::ref(*w).get(L); + detail::wrap_access::ref(*w).m_strong_ref.reset(); + return true; + } +#endif + return false; +} + +} // namespace luaponte + +#endif // LUAPONTE_BACK_REFERENCE_HPP diff --git a/luaponte/back_reference_fwd.hpp b/luaponte/back_reference_fwd.hpp new file mode 100644 index 0000000..1644595 --- /dev/null +++ b/luaponte/back_reference_fwd.hpp @@ -0,0 +1,26 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_BACK_REFERENCE_FWD_HPP +#define LUAPONTE_BACK_REFERENCE_FWD_HPP + +namespace luaponte { + +template +bool get_back_reference(lua_State* L, T const& x); + +template +bool move_back_reference(lua_State* L, T const& x); + +} // namespace luaponte + +#endif // LUAPONTE_BACK_REFERENCE_FWD_HPP diff --git a/luaponte/class.hpp b/luaponte/class.hpp new file mode 100644 index 0000000..aef9233 --- /dev/null +++ b/luaponte/class.hpp @@ -0,0 +1,876 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_CLASS_HPP +#define LUAPONTE_CLASS_HPP + +/* + ISSUES: + ------------------------------------------------------ + + * solved for member functions, not application operator * + if we have a base class that defines a function a derived class must be able to + override that function (not just overload). Right now we just add the other overload + to the overloads list and will probably get an ambiguity. If we want to support this + each method_rep must include a vector of type_info pointers for each parameter. + Operators do not have this problem, since operators always have to have + it's own type as one of the arguments, no ambiguity can occur. Application + operator, on the other hand, would have this problem. + Properties cannot be overloaded, so they should always be overridden. + If this is to work for application operator, we really need to specify if an application + operator is const or not. + + If one class registers two functions with the same name and the same + signature, there's currently no error. The last registered function will + be the one that's used. + How do we know which class registered the function? If the function was + defined by the base class, it is a legal operation, to override it. + we cannot look at the pointer offset, since it always will be zero for one of the bases. + + + + TODO: + ------------------------------------------------------ + + finish smart pointer support + * the adopt policy should not be able to adopt pointers to held_types. This + must be prohibited. + * name_of_type must recognize holder_types and not return "custom" + + document custom policies, custom converters + + store the instance object for policies. + + support the __concat metamethod. This is a bit tricky, since it cannot be + treated as a normal operator. It is a binary operator but we want to use the + __tostring implementation for both arguments. + +*/ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// to remove the 'this' used in initialization list-warning +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4355) +#endif + +namespace luaponte { + namespace detail + { + struct unspecified {}; + + template struct operator_; + + struct you_need_to_define_a_get_const_holder_function_for_your_smart_ptr {}; + } + + template + struct class_; + + // TODO: this function will only be invoked if the user hasn't defined a correct overload + // maybe we should have a static assert in here? + inline detail::you_need_to_define_a_get_const_holder_function_for_your_smart_ptr* + get_const_holder(...) + { + return 0; + } + + template + std::shared_ptr* get_const_holder(std::shared_ptr*) + { + return 0; + } + + template < + BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT( + LUAPONTE_MAX_BASES, class A, detail::null_type) + > + struct bases + {}; + + typedef bases no_bases; + + namespace detail + { + template + struct is_bases + : mpl::false_ + {}; + + template + struct is_bases > + : mpl::true_ + {}; + + template + struct is_unspecified + : mpl::apply1 + {}; + + template + struct is_unspecified + : mpl::true_ + {}; + + template + struct is_unspecified_mfn + { + template + struct apply + : is_unspecified + {}; + }; + + template + struct get_predicate + { + typedef mpl::protect > type; + }; + + template + struct result_or_default + { + typedef Result type; + }; + + template + struct result_or_default + { + typedef Default type; + }; + + template + struct extract_parameter + { + typedef typename get_predicate::type pred; + typedef typename boost::mpl::find_if::type iterator; + typedef typename result_or_default< + typename iterator::type, DefaultValue + >::type type; + }; + + // prints the types of the values on the stack, in the + // range [start_index, lua_gettop()] + + LUAPONTE_API std::string stack_content_by_name(lua_State* L, int start_index); + + struct LUAPONTE_API create_class + { + static int stage1(lua_State* L); + static int stage2(lua_State* L); + }; + + } // detail + + namespace detail { + + template + struct static_scope + { + static_scope(T& self_) : self(self_) + { + } + + T& operator[](scope s) const + { + self.add_inner_scope(s); + return self; + } + + private: + template void operator,(U const&) const; + void operator=(static_scope const&); + + T& self; + }; + + struct class_registration; + + struct LUAPONTE_API class_base : scope + { + public: + class_base(char const* name); + + struct base_desc + { + type_id type; + int ptr_offset; + }; + + void init( + type_id const& type, class_id id + , type_id const& wrapped_type, class_id wrapper_id); + + void add_base(type_id const& base, cast_function cast); + + void add_member(registration* member); + void add_default_member(registration* member); + + const char* name() const; + + void add_static_constant(const char* name, int val); + void add_inner_scope(scope& s); + + void add_cast(class_id src, class_id target, cast_function cast); + + private: + class_registration* m_registration; + }; + +// MSVC complains about member being sensitive to alignment (C4121) +// when F is a pointer to member of a class with virtual bases. +# ifdef BOOST_MSVC +# pragma pack(push) +# pragma pack(16) +# endif + + template + struct memfun_registration : registration + { + memfun_registration(char const* name, F f, Policies const& policies) + : name(name) + , f(f) + , policies(policies) + {} + + void register_(lua_State* L) const + { + object fn = make_function( + L, f, deduce_signature(f, (Class*)0), policies); + + add_overload( + object(from_stack(L, -1)) + , name + , fn + ); + } + + char const* name; + F f; + Policies policies; + }; + +# ifdef BOOST_MSVC +# pragma pack(pop) +# endif + + template + struct default_pointer + { + typedef P type; + }; + + template + struct default_pointer + { + typedef std::unique_ptr type; + }; + + template + struct constructor_registration : registration + { + constructor_registration(Policies const& policies) + : policies(policies) + {} + + void register_(lua_State* L) const + { + typedef typename default_pointer::type pointer; + + object fn = make_function( + L + , construct(), Signature() + , policies + ); + + add_overload( + object(from_stack(L, -1)) + , "__init" + , fn + ); + } + + Policies policies; + }; + + template + struct reference_result + : mpl::if_< + mpl::or_, is_primitive > + , T + , typename boost::add_reference::type + > + {}; + + template + struct reference_argument + : mpl::if_< + mpl::or_, is_primitive > + , T + , typename boost::add_reference< + typename boost::add_const::type + >::type + > + {}; + + template + struct inject_dependency_policy + : mpl::if_< + mpl::or_< + is_primitive + , has_policy + > + , Policies + , policy_cons, Policies> + > + {}; + + template < + class Class + , class Get, class GetPolicies + , class Set = null_type, class SetPolicies = null_type + > + struct property_registration : registration + { + property_registration( + char const* name + , Get const& get + , GetPolicies const& get_policies + , Set const& set = Set() + , SetPolicies const& set_policies = SetPolicies() + ) + : name(name) + , get(get) + , get_policies(get_policies) + , set(set) + , set_policies(set_policies) + {} + + void register_(lua_State* L) const + { + object context(from_stack(L, -1)); + register_aux( + L + , context + , make_get(L, get, boost::is_member_object_pointer()) + , set + ); + } + + template + object make_get(lua_State* L, F const& f, mpl::false_) const + { + return make_function( + L, f, deduce_signature(f, (Class*)0), get_policies); + } + + template + object make_get(lua_State* L, D T::* mem_ptr, mpl::true_) const + { + typedef typename reference_result::type result_type; + typedef typename inject_dependency_policy< + D, GetPolicies>::type policies; + + return make_function( + L + , access_member_ptr(mem_ptr) + , mpl::vector2() + , policies() + ); + } + + template + object make_set(lua_State* L, F const& f, mpl::false_) const + { + return make_function( + L, f, deduce_signature(f, (Class*)0), set_policies); + } + + template + object make_set(lua_State* L, D T::* mem_ptr, mpl::true_) const + { + typedef typename reference_argument::type argument_type; + + return make_function( + L + , access_member_ptr(mem_ptr) + , mpl::vector3() + , set_policies + ); + } + + template + void register_aux( + lua_State* L, object const& context + , object const& get_, S const&) const + { + context[name] = property( + get_ + , make_set(L, set, boost::is_member_object_pointer()) + ); + } + + void register_aux( + lua_State*, object const& context + , object const& get_, null_type) const + { + context[name] = property(get_); + } + + char const* name; + Get get; + GetPolicies get_policies; + Set set; + SetPolicies set_policies; + }; + + } // namespace detail + + // registers a class in the lua environment + template + struct class_: detail::class_base + { + typedef class_ self_t; + + private: + + template + class_(const class_&); + + public: + + typedef boost::mpl::vector4 parameters_type; + + // WrappedType MUST inherit from T + typedef typename detail::extract_parameter< + parameters_type + , boost::is_base_and_derived + , detail::null_type + >::type WrappedType; + + typedef typename detail::extract_parameter< + parameters_type + , boost::mpl::not_< + boost::mpl::or_< + detail::is_bases + , boost::is_base_and_derived + , boost::is_base_and_derived + > + > + , detail::null_type + >::type HeldType; + + template + void add_downcast(Src*, Target*, boost::mpl::true_) + { + add_cast( + detail::registered_class::id + , detail::registered_class::id + , detail::dynamic_cast_::execute + ); + } + + template + void add_downcast(Src*, Target*, boost::mpl::false_) + {} + + // this function generates conversion information + // in the given class_rep structure. It will be able + // to implicitly cast to the given template type + template + void gen_base_info(detail::type_) + { + add_base(typeid(To), detail::static_cast_::execute); + add_cast( + detail::registered_class::id + , detail::registered_class::id + , detail::static_cast_::execute + ); + + add_downcast((To*)0, (T*)0, boost::is_polymorphic()); + } + + void gen_base_info(detail::type_) + {} + +#define LUAPONTE_GEN_BASE_INFO(z, n, text) gen_base_info(detail::type_()); + + template + void generate_baseclass_list(detail::type_ >) + { + BOOST_PP_REPEAT(LUAPONTE_MAX_BASES, LUAPONTE_GEN_BASE_INFO, _) + } + +#undef LUAPONTE_GEN_BASE_INFO + + class_(const char* name = 0): class_base(name), scope(*this) + { +#ifndef NDEBUG + detail::check_link_compatibility(); +#endif + init(); + } + + template + class_& def(const char* name, F f) + { + return this->virtual_def( + name, f, detail::null_type() + , detail::null_type(), boost::mpl::true_()); + } + + // virtual functions + template + class_& def(char const* name, F fn, DefaultOrPolicies default_or_policies) + { + return this->virtual_def( + name, fn, default_or_policies, detail::null_type() + , LUAPONTE_MSVC_TYPENAME detail::is_policy_cons::type()); + } + + template + class_& def(char const* name, F fn + , Default default_, Policies const& policies) + { + return this->virtual_def( + name, fn, default_ + , policies, boost::mpl::false_()); + } + + template + class_& def(constructor sig) + { + return this->def_constructor(&sig, detail::null_type()); + } + + template + class_& def(constructor sig, const Policies& policies) + { + return this->def_constructor(&sig, policies); + } + + template + class_& property(const char* name, Getter g) + { + this->add_member( + new detail::property_registration( + name, g, detail::null_type())); + return *this; + } + + template + class_& property(const char* name, Getter g, MaybeSetter s) + { + return property_impl( + name, g, s + , boost::mpl::bool_::value>() + ); + } + + template + class_& property(const char* name, Getter g, Setter s, const GetPolicies& get_policies) + { + typedef detail::property_registration< + T, Getter, GetPolicies, Setter, detail::null_type + > registration_type; + + this->add_member( + new registration_type(name, g, get_policies, s)); + return *this; + } + + template + class_& property( + const char* name + , Getter g, Setter s + , GetPolicies const& get_policies + , SetPolicies const& set_policies) + { + typedef detail::property_registration< + T, Getter, GetPolicies, Setter, SetPolicies + > registration_type; + + this->add_member( + new registration_type(name, g, get_policies, s, set_policies)); + return *this; + } + + template + class_& def_readonly(const char* name, D C::*mem_ptr) + { + typedef detail::property_registration + registration_type; + + this->add_member( + new registration_type(name, mem_ptr, detail::null_type())); + return *this; + } + + template + class_& def_readonly(const char* name, D C::*mem_ptr, Policies const& policies) + { + typedef detail::property_registration + registration_type; + + this->add_member( + new registration_type(name, mem_ptr, policies)); + return *this; + } + + template + class_& def_readwrite(const char* name, D C::*mem_ptr) + { + typedef detail::property_registration< + T, D C::*, detail::null_type, D C::* + > registration_type; + + this->add_member( + new registration_type( + name, mem_ptr, detail::null_type(), mem_ptr)); + return *this; + } + + template + class_& def_readwrite( + const char* name, D C::*mem_ptr, GetPolicies const& get_policies) + { + typedef detail::property_registration< + T, D C::*, GetPolicies, D C::* + > registration_type; + + this->add_member( + new registration_type( + name, mem_ptr, get_policies, mem_ptr)); + return *this; + } + + template + class_& def_readwrite( + const char* name + , D C::*mem_ptr + , GetPolicies const& get_policies + , SetPolicies const& set_policies + ) + { + typedef detail::property_registration< + T, D C::*, GetPolicies, D C::*, SetPolicies + > registration_type; + + this->add_member( + new registration_type( + name, mem_ptr, get_policies, mem_ptr, set_policies)); + return *this; + } + + template + class_& def(detail::operator_, Policies const& policies) + { + return this->def( + Derived::name() + , &Derived::template apply::execute + , policies + ); + } + + template + class_& def(detail::operator_) + { + return this->def( + Derived::name() + , &Derived::template apply::execute + ); + } + + detail::enum_maker enum_(const char*) + { + return detail::enum_maker(*this); + } + + detail::static_scope scope; + + private: + void operator=(class_ const&); + + void add_wrapper_cast(detail::null_type*) + {} + + template + void add_wrapper_cast(U*) + { + add_cast( + detail::registered_class::id + , detail::registered_class::id + , detail::static_cast_::execute + ); + + add_downcast((T*)0, (U*)0, boost::is_polymorphic()); + } + + void init() + { + typedef typename detail::extract_parameter< + parameters_type + , boost::mpl::or_< + detail::is_bases + , boost::is_base_and_derived + > + , no_bases + >::type bases_t; + + typedef typename + boost::mpl::if_ + , bases_t + , bases + >::type Base; + + class_base::init( + typeid(T) + , detail::registered_class::id + , typeid(WrappedType) + , detail::registered_class::id + ); + + add_wrapper_cast((WrappedType*)0); + + generate_baseclass_list(detail::type_()); + } + + template + class_& property_impl(const char* name, + Getter g, + GetPolicies policies, + boost::mpl::bool_) + { + this->add_member( + new detail::property_registration( + name, g, policies)); + return *this; + } + + template + class_& property_impl(const char* name, + Getter g, + Setter s, + boost::mpl::bool_) + { + typedef detail::property_registration< + T, Getter, detail::null_type, Setter, detail::null_type + > registration_type; + + this->add_member( + new registration_type(name, g, detail::null_type(), s)); + return *this; + } + + // these handle default implementation of virtual functions + template + class_& virtual_def(char const* name, F const& fn + , Policies const&, detail::null_type, boost::mpl::true_) + { + this->add_member( + new detail::memfun_registration( + name, fn, Policies())); + return *this; + } + + template + class_& virtual_def(char const* name, F const& fn + , Default const& default_, Policies const&, boost::mpl::false_) + { + this->add_member( + new detail::memfun_registration( + name, fn, Policies())); + + this->add_default_member( + new detail::memfun_registration( + name, default_, Policies())); + + return *this; + } + + template + class_& def_constructor(Signature*, Policies const&) + { + typedef typename Signature::signature signature; + + typedef typename boost::mpl::if_< + boost::is_same + , T + , WrappedType + >::type construct_type; + + this->add_member( + new detail::constructor_registration< + construct_type, HeldType, signature, Policies>( + Policies())); + + this->add_default_member( + new detail::constructor_registration< + construct_type, HeldType, signature, Policies>( + Policies())); + + return *this; + } + }; + +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif // LUAPONTE_CLASS_HPP diff --git a/luaponte/class_info.hpp b/luaponte/class_info.hpp new file mode 100644 index 0000000..2cc8033 --- /dev/null +++ b/luaponte/class_info.hpp @@ -0,0 +1,39 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_CLASS_INFO_HPP +#define LUAPONTE_CLASS_INFO_HPP + +#include +#include +#include +#include + +namespace luaponte { + +struct LUAPONTE_API class_info +{ + std::string name; + object methods; + object attributes; +}; + +LUAPONTE_API class_info get_class_info(argument const&); + +// returns a table of bound class names +LUAPONTE_API object get_class_names(lua_State* L); + +LUAPONTE_API void bind_class_info(lua_State*); + +} // namespace luaponte + +#endif // LUAPONTE_CLASS_INFO_HPP diff --git a/luaponte/config.hpp b/luaponte/config.hpp new file mode 100644 index 0000000..d61b25d --- /dev/null +++ b/luaponte/config.hpp @@ -0,0 +1,116 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_CONFIG_HPP +#define LUAPONTE_CONFIG_HPP + +#include + +#ifdef BOOST_MSVC + #define LUAPONTE_ANONYMOUS_FIX static +#else + #define LUAPONTE_ANONYMOUS_FIX +#endif + +#if defined (BOOST_MSVC) && (BOOST_MSVC <= 1200) + +#define for if (false) {} else for + +#include + +namespace std { + +using ::strlen; +using ::strcmp; +using ::type_info; + +} + +#endif + +#if defined (BOOST_MSVC) && (BOOST_MSVC <= 1300) + #define LUAPONTE_MSVC_TYPENAME +#else + #define LUAPONTE_MSVC_TYPENAME typename +#endif + +// the maximum number of arguments of functions that's +// registered. Must at least be 2 +#ifndef LUAPONTE_MAX_ARITY + #define LUAPONTE_MAX_ARITY 10 +#elif LUAPONTE_MAX_ARITY <= 1 + #undef LUAPONTE_MAX_ARITY + #define LUAPONTE_MAX_ARITY 2 +#endif + +// the maximum number of classes one class +// can derive from +// max bases must at least be 1 +#ifndef LUAPONTE_MAX_BASES + #define LUAPONTE_MAX_BASES 4 +#elif LUAPONTE_MAX_BASES <= 0 + #undef LUAPONTE_MAX_BASES + #define LUAPONTE_MAX_BASES 1 +#endif + +// LUAPONTE_NO_ERROR_CHECKING +// define this to remove all error checks +// this will improve performance and memory +// footprint. +// if it is defined matchers will only be called on +// overloaded functions, functions that's +// not overloaded will be called directly. The +// parameters on the lua stack are assumed +// to match those of the function. +// exceptions will still be catched when there's +// no error checking. + +// LUAPONTE_NOT_THREADSAFE +// this define will make luabind non-thread safe. That is, +// it will rely on a static variable. You can still have +// multiple lua states and use coroutines, but only +// one of your real threads may run lua code. + +// LUAPONTE_NO_EXCEPTIONS +// this define will disable all usage of try, catch and throw in +// luabind. This will in many cases disable runtime-errors, such +// as invalid casts, when calling lua-functions that fails or +// returns values that cannot be converted by the given policy. +// Luabind requires that no function called directly or indirectly +// by luabind throws an exception (throwing exceptions through +// C code has undefined behavior, lua is written in C). + +#ifdef LUAPONTE_DYNAMIC_LINK +# ifdef BOOST_WINDOWS +# ifdef LUAPONTE_BUILDING +# define LUAPONTE_API __declspec(dllexport) +# else +# define LUAPONTE_API __declspec(dllimport) +# endif +# else +# if defined(_GNUC_) && _GNUC_ >=4 +# define LUAPONTE_API __attribute__ ((visibility("default"))) +# endif +# endif +#endif + +#ifndef LUAPONTE_API +# define LUAPONTE_API +#endif + +namespace luaponte { + +LUAPONTE_API void disable_super_deprecation(); + +} // namespace luaponte + +#endif // LUAPONTE_CONFIG_HPP diff --git a/luaponte/container_policy.hpp b/luaponte/container_policy.hpp new file mode 100644 index 0000000..004cfca --- /dev/null +++ b/luaponte/container_policy.hpp @@ -0,0 +1,132 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_CONTAINER_POLICY_HPP +#define LUAPONTE_CONTAINER_POLICY_HPP + +#include +#include +#include + +namespace luaponte { +namespace detail { + +namespace mpl = boost::mpl; + +template +struct container_converter_lua_to_cpp +{ + int consumed_args(...) const + { + return 1; + } + + template + T apply(lua_State* L, by_const_reference, int index) + { + typedef typename T::value_type value_type; + + typedef typename find_conversion_policy<1, Policies>::type converter_policy; + typename mpl::apply_wrap2::type converter; + + T container; + + lua_pushnil(L); + while (lua_next(L, index)) + { + container.push_back(converter.apply(L, LUAPONTE_DECORATE_TYPE(value_type), -1)); + lua_pop(L, 1); // pop value + } + + return container; + } + + template + T apply(lua_State* L, by_value, int index) + { + return apply(L, by_const_reference(), index); + } + + template + static int match(lua_State* L, by_const_reference, int index) + { + if (lua_istable(L, index)) return 0; else return -1; + } + + template + void converter_postcall(lua_State*, T, int) {} +}; + +template +struct container_converter_cpp_to_lua +{ + template + void apply(lua_State* L, const T& container) + { + typedef typename T::value_type value_type; + + typedef typename find_conversion_policy<1, Policies>::type converter_policy; + typename mpl::apply_wrap2::type converter; + + lua_newtable(L); + + int index = 1; + + for (typename T::const_iterator i = container.begin(); i != container.end(); ++i) + { + converter.apply(L, *i); + lua_rawseti(L, -2, index); + ++index; + } + } +}; + +template +struct container_policy : conversion_policy +{ + static void precall(lua_State*, const index_map&) {} + static void postcall(lua_State*, const index_map&) {} + + struct only_accepts_nonconst_pointers {}; + + template + struct apply + { + typedef typename boost::mpl::if_ + , container_converter_lua_to_cpp + , container_converter_cpp_to_lua + >::type type; + }; +}; + +} // namespace detail +} // namespace luaponte + +namespace luaponte { + +template +detail::policy_cons, detail::null_type> +container(LUAPONTE_PLACEHOLDER_ARG(N)) +{ + return detail::policy_cons, detail::null_type>(); +} + +template +detail::policy_cons, detail::null_type> +container(LUAPONTE_PLACEHOLDER_ARG(N), const Policies&) +{ + return detail::policy_cons, detail::null_type>(); +} + +} // namespace luaponte + +#endif // LUAPONTE_CONTAINER_POLICY_HPP diff --git a/luaponte/copy_policy.hpp b/luaponte/copy_policy.hpp new file mode 100644 index 0000000..ecbed29 --- /dev/null +++ b/luaponte/copy_policy.hpp @@ -0,0 +1,67 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_COPY_POLICY_HPP +# define LUAPONTE_COPY_POLICY_HPP + +# include + +namespace luaponte { + +namespace detail { + + struct copy_converter + { + template + void apply(lua_State* L, T const& x) + { + value_converter().apply(L, x); + } + + template + void apply(lua_State* L, T* x) + { + if (!x) + lua_pushnil(L); + else + apply(L, *x); + } + }; + + template + struct copy_policy : conversion_policy + { + static void precall(lua_State*, index_map const&) + {} + + static void postcall(lua_State*, index_map const&) + {} + + template + struct apply + { + typedef copy_converter type; + }; + }; + +} // namespace detail + +template +detail::policy_cons, detail::null_type> +copy(LUAPONTE_PLACEHOLDER_ARG(N)) +{ + return detail::policy_cons, detail::null_type>(); +} + +} // namespace luaponte + +#endif // LUAPONTE_COPY_POLICY_HPP diff --git a/luaponte/dependency_policy.hpp b/luaponte/dependency_policy.hpp new file mode 100644 index 0000000..78048a7 --- /dev/null +++ b/luaponte/dependency_policy.hpp @@ -0,0 +1,112 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DEPENDENCY_POLICY_HPP +#define LUAPONTE_DEPENDENCY_POLICY_HPP + +#include +#include + +namespace luaponte { +namespace detail { + +// makes A dependent on B, meaning B will outlive A. +// internally A stores a reference to B +template +struct dependency_policy +{ + static void postcall(lua_State* L, const index_map& indices) + { + int nurse_index = indices[A]; + int patient = indices[B]; + + object_rep* nurse = static_cast(lua_touserdata(L, nurse_index)); + + // If the nurse isn't an object_rep, just make this a nop. + if (nurse == 0) + return; + + nurse->add_dependency(L, patient); + } +}; + +} // namespace detail +} // namespace luaponte + +#if defined (BOOST_MSVC) && (BOOST_MSVC <= 1200) + +namespace luaponte { + +// most absurd workaround of all time? +namespace detail { + +template +struct size_char_array +{ + char storage[N + 2]; +}; + +template +size_char_array deduce_size(LUAPONTE_PLACEHOLDER_ARG(N)); + +template +struct get_index_workaround +{ + static T t; + BOOST_STATIC_CONSTANT(int, value = sizeof(deduce_size(t)) - 2); +}; + +} // namespace detail + +template +detail::policy_cons::value + , detail::get_index_workaround::value>, detail::null_type> dependency(A,B) +{ + return detail::policy_cons::value, detail::get_index_workaround::value> + , detail::null_type>(); +} + +template +detail::policy_cons::value>, detail::null_type> +return_internal_reference(A) +{ + return detail::policy_cons::value>, detail::null_type>(); +} + +} // namespace luaponte + +#else + +namespace luaponte { + +template +detail::policy_cons, detail::null_type> +dependency(LUAPONTE_PLACEHOLDER_ARG(A), LUAPONTE_PLACEHOLDER_ARG(B)) +{ + return detail::policy_cons, detail::null_type>(); +} + +template +detail::policy_cons, detail::null_type> +return_internal_reference(LUAPONTE_PLACEHOLDER_ARG(A)) +{ + return detail::policy_cons, detail::null_type>(); +} + +} // namespace luaponte + +#endif + +#endif // LUAPONTE_DEPENDENCY_POLICY_HPP diff --git a/luaponte/detail/call.hpp b/luaponte/detail/call.hpp new file mode 100644 index 0000000..2bed828 --- /dev/null +++ b/luaponte/detail/call.hpp @@ -0,0 +1,332 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !BOOST_PP_IS_ITERATING + +# ifndef LUAPONTE_DETAIL_CALL_HPP +# define LUAPONTE_DETAIL_CALL_HPP + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# include +# include +# include + +namespace luaponte { +namespace detail { + +struct invoke_context; + +struct LUAPONTE_API function_object +{ + function_object(lua_CFunction entry) + : entry(entry) + , next(0) + {} + + virtual ~function_object() + {} + + virtual int call( + lua_State* L, invoke_context& ctx) const = 0; + virtual void format_signature(lua_State* L, char const* function) const = 0; + + lua_CFunction entry; + std::string name; + function_object* next; + object keepalive; +}; + +struct LUAPONTE_API invoke_context +{ + invoke_context() + : best_score((std::numeric_limits::max)()) + , candidate_index(0) + {} + + operator bool() const + { + return candidate_index == 1; + } + + void format_error(lua_State* L, function_object const* overloads) const; + + int best_score; + function_object const* candidates[10]; + int candidate_index; +}; + +template +inline int invoke0( + lua_State* L, function_object const& self, invoke_context& ctx + , F const& f, Signature, Policies const& policies, IsVoid, mpl::true_) +{ + return invoke_member( + L, self, ctx, f, Signature(), policies + , mpl::long_::value - 1>(), IsVoid() + ); +} + +template +inline int invoke0( + lua_State* L, function_object const& self, invoke_context& ctx, + F const& f, Signature, Policies const& policies, IsVoid, mpl::false_) +{ + return invoke_normal( + L, self, ctx, f, Signature(), policies + , mpl::long_::value - 1>(), IsVoid() + ); +} + +template +inline int invoke( + lua_State* L, function_object const& self, invoke_context& ctx + , F const& f, Signature, Policies const& policies) +{ + return invoke0( + L, self, ctx, f, Signature(), policies + , boost::is_void::type>() + , boost::is_member_function_pointer() + ); +} + +inline int maybe_yield_aux(lua_State*, int results, mpl::false_) +{ + return results; +} + +inline int maybe_yield_aux(lua_State* L, int results, mpl::true_) +{ + return lua_yield(L, results); +} + +template +int maybe_yield(lua_State* L, int results, Policies*) +{ + return maybe_yield_aux( + L, results, has_policy()); +} + +inline int sum_scores(int const* first, int const* last) +{ + int result = 0; + + for (; first != last; ++first) + { + if (*first < 0) + return *first; + result += *first; + } + + return result; +} + +# define LUAPONTE_INVOKE_NEXT_ITER(n) \ + typename mpl::next< \ + BOOST_PP_IF( \ + n, BOOST_PP_CAT(iter,BOOST_PP_DEC(n)), first) \ + >::type + +# define LUAPONTE_INVOKE_NEXT_INDEX(n) \ + BOOST_PP_IF( \ + n \ + , BOOST_PP_CAT(index,BOOST_PP_DEC(n)) + \ + BOOST_PP_CAT(c,BOOST_PP_DEC(n)).consumed_args() \ + , 1 \ + ) + +# define LUAPONTE_INVOKE_COMPUTE_ARITY(n) + BOOST_PP_CAT(c,n).consumed_args() + +# define LUAPONTE_INVOKE_DECLARE_CONVERTER(n) \ + typedef LUAPONTE_INVOKE_NEXT_ITER(n) BOOST_PP_CAT(iter,n); \ + typedef typename mpl::deref::type \ + BOOST_PP_CAT(a,n); \ + typedef typename find_conversion_policy::type \ + BOOST_PP_CAT(p,n); \ + typename mpl::apply_wrap2< \ + BOOST_PP_CAT(p,n), BOOST_PP_CAT(a,n), lua_to_cpp>::type BOOST_PP_CAT(c,n); \ + int const BOOST_PP_CAT(index,n) = LUAPONTE_INVOKE_NEXT_INDEX(n); + +# define LUAPONTE_INVOKE_COMPUTE_SCORE(n) \ + , BOOST_PP_CAT(c,n).match( \ + L, LUAPONTE_DECORATE_TYPE(BOOST_PP_CAT(a,n)), BOOST_PP_CAT(index,n)) + +# define LUAPONTE_INVOKE_ARG(z, n, base) \ + BOOST_PP_CAT(c,base(n)).apply( \ + L, LUAPONTE_DECORATE_TYPE(BOOST_PP_CAT(a,base(n))), BOOST_PP_CAT(index,base(n))) + +# define LUAPONTE_INVOKE_CONVERTER_POSTCALL(n) \ + BOOST_PP_CAT(c,n).converter_postcall( \ + L, LUAPONTE_DECORATE_TYPE(BOOST_PP_CAT(a,n)), BOOST_PP_CAT(index,n)); + +# define BOOST_PP_ITERATION_PARAMS_1 \ + (3, (0, LUAPONTE_MAX_ARITY, )) +# include BOOST_PP_ITERATE() + +# define LUAPONTE_INVOKE_VOID +# define BOOST_PP_ITERATION_PARAMS_1 \ + (3, (0, LUAPONTE_MAX_ARITY, )) +# include BOOST_PP_ITERATE() + +# undef LUAPONTE_INVOKE_VOID +# define LUAPONTE_INVOKE_MEMBER +# define BOOST_PP_ITERATION_PARAMS_1 \ + (3, (0, LUAPONTE_MAX_ARITY, )) +# include BOOST_PP_ITERATE() + +# define LUAPONTE_INVOKE_VOID +# define BOOST_PP_ITERATION_PARAMS_1 \ + (3, (0, LUAPONTE_MAX_ARITY, )) +# include BOOST_PP_ITERATE() + +} // namespace detail +} // namespace luaponte + +# endif // LUAPONTE_DETAIL_CALL_HPP + +#else // BOOST_PP_IS_ITERATING + +# ifdef LUAPONTE_INVOKE_MEMBER +# define N BOOST_PP_INC(BOOST_PP_ITERATION()) +# else +# define N BOOST_PP_ITERATION() +# endif + +template +inline int +# ifdef LUAPONTE_INVOKE_MEMBER +invoke_member +# else +invoke_normal +# endif +( + lua_State* L, function_object const& self, invoke_context& ctx + , F const& f, Signature, Policies const&, mpl::long_ +# ifdef LUAPONTE_INVOKE_VOID + , mpl::true_ +# else + , mpl::false_ +# endif +) +{ + typedef typename mpl::begin::type first; +# ifndef LUAPONTE_INVOKE_VOID + typedef typename mpl::deref::type result_type; + typedef typename find_conversion_policy<0, Policies>::type result_policy; + typename mpl::apply_wrap2< + result_policy, result_type, cpp_to_lua>::type result_converter; +# endif + +# if N > 0 +# define BOOST_PP_LOCAL_MACRO(n) LUAPONTE_INVOKE_DECLARE_CONVERTER(n) +# define BOOST_PP_LOCAL_LIMITS (0,N-1) +# include BOOST_PP_LOCAL_ITERATE() +# endif + + int const arity = 0 +# if N > 0 +# define BOOST_PP_LOCAL_MACRO(n) LUAPONTE_INVOKE_COMPUTE_ARITY(n) +# define BOOST_PP_LOCAL_LIMITS (0,N-1) +# include BOOST_PP_LOCAL_ITERATE() +# endif + ; + + int const arguments = lua_gettop(L); + + int score = -1; + + if (arity == arguments) + { + int const scores[] = { + 0 +# if N > 0 +# define BOOST_PP_LOCAL_MACRO(n) LUAPONTE_INVOKE_COMPUTE_SCORE(n) +# define BOOST_PP_LOCAL_LIMITS (0,N-1) +# include BOOST_PP_LOCAL_ITERATE() +# endif + }; + + score = sum_scores(scores + 1, scores + 1 + N); + } + + if (score >= 0 && score < ctx.best_score) + { + ctx.best_score = score; + ctx.candidates[0] = &self; + ctx.candidate_index = 1; + } + else if (score == ctx.best_score) + { + ctx.candidates[ctx.candidate_index++] = &self; + } + + int results = 0; + + if (self.next) + { + results = self.next->call(L, ctx); + } + + if (score == ctx.best_score && ctx.candidate_index == 1) + { +# ifndef LUAPONTE_INVOKE_VOID + result_converter.apply( + L, +# endif +# ifdef LUAPONTE_INVOKE_MEMBER + (c0.apply(L, LUAPONTE_DECORATE_TYPE(a0), index0).*f)( + BOOST_PP_ENUM(BOOST_PP_DEC(N), LUAPONTE_INVOKE_ARG, BOOST_PP_INC) + ) +# else +# define LUAPONTE_INVOKE_IDENTITY(x) x + f( + BOOST_PP_ENUM(N, LUAPONTE_INVOKE_ARG, LUAPONTE_INVOKE_IDENTITY) + ) +# undef LUAPONTE_INVOKE_IDENTITY +# endif +# ifndef LUAPONTE_INVOKE_VOID + ) +# endif + ; + +# if N > 0 +# define BOOST_PP_LOCAL_MACRO(n) LUAPONTE_INVOKE_CONVERTER_POSTCALL(n) +# define BOOST_PP_LOCAL_LIMITS (0,N-1) +# include BOOST_PP_LOCAL_ITERATE() +# endif + + results = maybe_yield(L, lua_gettop(L) - arguments, (Policies*)0); + + int const indices[] = { + arguments + results BOOST_PP_ENUM_TRAILING_PARAMS(N, index) + }; + + policy_list_postcall::apply(L, indices); + } + + return results; +} + +# undef N + +#endif diff --git a/luaponte/detail/call_function.hpp b/luaponte/detail/call_function.hpp new file mode 100644 index 0000000..08ffa8c --- /dev/null +++ b/luaponte/detail/call_function.hpp @@ -0,0 +1,421 @@ +// Luaponte library + +// Copyright (c) 2011-2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !BOOST_PP_IS_ITERATING + +#ifndef LUAPONTE_DETAIL_CALL_FUNCTION_HPP +#define LUAPONTE_DETAIL_CALL_FUNCTION_HPP + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace luaponte { + + namespace detail { + + // if the proxy_function_caller returns non-void + template + class proxy_function_caller + { + public: + + typedef int(*function_t)(lua_State*, int, int); + + proxy_function_caller( + lua_State* L + , int params + , function_t fun + , const Tuple args) + : m_state(L) + , m_params(params) + , m_fun(fun) + , m_args(args) + , m_called(false) + { + } + + proxy_function_caller(const proxy_function_caller& rhs) + : m_state(rhs.m_state) + , m_params(rhs.m_params) + , m_fun(rhs.m_fun) + , m_args(rhs.m_args) + , m_called(rhs.m_called) + { + rhs.m_called = true; + } + + ~proxy_function_caller() + { + if (m_called) return; + + m_called = true; + lua_State* L = m_state; + + int top = lua_gettop(L); + + push_args_from_tuple<1>::apply(L, m_args); + if (m_fun(L, boost::tuples::length::value, 0)) + { + assert(lua_gettop(L) == top - m_params + 1); +#ifndef LUAPONTE_NO_EXCEPTIONS + throw luaponte::error(L); +#else + error_callback_fun e = get_error_callback(); + if (e) e(L); + + assert(0 && "the lua function threw an error and exceptions are disabled." + " If you want to handle the error you can use luaponte::set_error_callback()"); + std::terminate(); + +#endif + } + + // pops the return values from the function call + stack_pop pop(L, lua_gettop(L) - top + m_params); + } + + operator Ret() + { + typename mpl::apply_wrap2::type converter; + + m_called = true; + lua_State* L = m_state; + + int top = lua_gettop(L); + + push_args_from_tuple<1>::apply(L, m_args); + if (m_fun(L, boost::tuples::length::value, 1)) + { + assert(lua_gettop(L) == top - m_params + 1); +#ifndef LUAPONTE_NO_EXCEPTIONS + throw luaponte::error(L); +#else + error_callback_fun e = get_error_callback(); + if (e) e(L); + + assert(0 && "the lua function threw an error and exceptions are disabled." + " If you want to handle the error you can use luaponte::set_error_callback()"); + std::terminate(); +#endif + } + + // pops the return values from the function call + stack_pop pop(L, lua_gettop(L) - top + m_params); + + if (converter.match(L, LUAPONTE_DECORATE_TYPE(Ret), -1) < 0) + { +#ifndef LUAPONTE_NO_EXCEPTIONS + throw cast_failed(L, typeid(Ret)); +#else + cast_failed_callback_fun e = get_cast_failed_callback(); + if (e) e(L, typeid(Ret)); + + assert(0 && "the lua function's return value could not be converted." + " If you want to handle the error you can use luaponte::set_error_callback()"); + std::terminate(); +#endif + } + return converter.apply(L, LUAPONTE_DECORATE_TYPE(Ret), -1); + } + + template + Ret operator[](const Policies& p) + { + typedef typename detail::find_conversion_policy<0, Policies>::type converter_policy; + typename mpl::apply_wrap2::type converter; + + m_called = true; + lua_State* L = m_state; + + int top = lua_gettop(L); + + detail::push_args_from_tuple<1>::apply(L, m_args, p); + if (m_fun(L, boost::tuples::length::value, 1)) + { + assert(lua_gettop(L) == top - m_params + 1); +#ifndef LUAPONTE_NO_EXCEPTIONS + throw error(L); +#else + error_callback_fun e = get_error_callback(); + if (e) e(L); + + assert(0 && "the lua function threw an error and exceptions are disabled." + " If you want to handle the error you can use luaponte::set_error_callback()"); + std::terminate(); +#endif + } + + // pops the return values from the function call + stack_pop pop(L, lua_gettop(L) - top + m_params); + + if (converter.match(L, LUAPONTE_DECORATE_TYPE(Ret), -1) < 0) + { +#ifndef LUAPONTE_NO_EXCEPTIONS + throw cast_failed(L, typeid(Ret)); +#else + cast_failed_callback_fun e = get_cast_failed_callback(); + if (e) e(L, typeid(Ret)); + + assert(0 && "the lua function's return value could not be converted." + " If you want to handle the error you can use luaponte::set_error_callback()"); + std::terminate(); + +#endif + } + + return converter.apply(L, LUAPONTE_DECORATE_TYPE(Ret), -1); + } + + private: + + lua_State* m_state; + int m_params; + function_t m_fun; + Tuple m_args; + mutable bool m_called; + + }; + + // if the proxy_member_caller returns void + template + class proxy_function_void_caller + { + friend class luaponte::object; + public: + + typedef int(*function_t)(lua_State*, int, int); + + proxy_function_void_caller( + lua_State* L + , int params + , function_t fun + , const Tuple args) + : m_state(L) + , m_params(params) + , m_fun(fun) + , m_args(args) + , m_called(false) + { + } + + proxy_function_void_caller(const proxy_function_void_caller& rhs) + : m_state(rhs.m_state) + , m_params(rhs.m_params) + , m_fun(rhs.m_fun) + , m_args(rhs.m_args) + , m_called(rhs.m_called) + { + rhs.m_called = true; + } + + ~proxy_function_void_caller() + { + if (m_called) return; + + m_called = true; + lua_State* L = m_state; + + int top = lua_gettop(L); + + push_args_from_tuple<1>::apply(L, m_args); + if (m_fun(L, boost::tuples::length::value, 0)) + { + assert(lua_gettop(L) == top - m_params + 1); +#ifndef LUAPONTE_NO_EXCEPTIONS + throw luaponte::error(L); +#else + error_callback_fun e = get_error_callback(); + if (e) e(L); + + assert(0 && "the lua function threw an error and exceptions are disabled." + " If you want to handle the error you can use luaponte::set_error_callback()"); + std::terminate(); +#endif + } + // pops the return values from the function call + stack_pop pop(L, lua_gettop(L) - top + m_params); + } + + template + void operator[](const Policies& p) + { + m_called = true; + lua_State* L = m_state; + + int top = lua_gettop(L); + + detail::push_args_from_tuple<1>::apply(L, m_args, p); + if (m_fun(L, boost::tuples::length::value, 0)) + { + assert(lua_gettop(L) == top - m_params + 1); +#ifndef LUAPONTE_NO_EXCEPTIONS + throw error(L); +#else + error_callback_fun e = get_error_callback(); + if (e) e(L); + + assert(0 && "the lua function threw an error and exceptions are disabled." + " If you want to handle the error you can use luaponte::set_error_callback()"); + std::terminate(); +#endif + } + // pops the return values from the function call + stack_pop pop(L, lua_gettop(L) - top + m_params); + } + + private: + + lua_State* m_state; + int m_params; + function_t m_fun; + Tuple m_args; + mutable bool m_called; + + }; + + } + + #define BOOST_PP_ITERATION_PARAMS_1 (4, (0, LUAPONTE_MAX_ARITY, , 1)) + #include BOOST_PP_ITERATE() + +} + +#endif // LUAPONTE_DETAIL_CALL_FUNCTION_HPP + +#else +#if BOOST_PP_ITERATION_FLAGS() == 1 + +#define LUAPONTE_TUPLE_PARAMS(z, n, data) const A##n * +#define LUAPONTE_OPERATOR_PARAMS(z, n, data) const A##n & a##n + + + template + typename boost::mpl::if_ + , luaponte::detail::proxy_function_void_caller > + , luaponte::detail::proxy_function_caller > >::type + call_function(lua_State* L, const char* name BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUAPONTE_OPERATOR_PARAMS, _) ) + { + assert(name && "luaponte::call_function() expects a function name"); + typedef boost::tuples::tuple tuple_t; +#if BOOST_PP_ITERATION() == 0 + tuple_t args; +#else + tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a)); +#endif + typedef typename boost::mpl::if_ + , luaponte::detail::proxy_function_void_caller > + , luaponte::detail::proxy_function_caller > >::type proxy_type; + + lua_getglobal(L, name); + + return proxy_type(L, 1, &detail::pcall, args); + } + + template + typename boost::mpl::if_ + , luaponte::detail::proxy_function_void_caller > + , luaponte::detail::proxy_function_caller > >::type + call_function(luaponte::object const& obj BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUAPONTE_OPERATOR_PARAMS, _) ) + { + typedef boost::tuples::tuple tuple_t; +#if BOOST_PP_ITERATION() == 0 + tuple_t args; +#else + tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a)); +#endif + typedef typename boost::mpl::if_ + , luaponte::detail::proxy_function_void_caller > + , luaponte::detail::proxy_function_caller > >::type proxy_type; + + obj.push(obj.interpreter()); + return proxy_type(obj.interpreter(), 1, &detail::pcall, args); + } + + template + typename boost::mpl::if_ + , luaponte::detail::proxy_function_void_caller > + , luaponte::detail::proxy_function_caller > >::type + resume_function(lua_State* L, const char* name BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUAPONTE_OPERATOR_PARAMS, _) ) + { + assert(name && "luaponte::resume_function() expects a function name"); + typedef boost::tuples::tuple tuple_t; +#if BOOST_PP_ITERATION() == 0 + tuple_t args; +#else + tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a)); +#endif + typedef typename boost::mpl::if_ + , luaponte::detail::proxy_function_void_caller > + , luaponte::detail::proxy_function_caller > >::type proxy_type; + + lua_getglobal(L, name); + + return proxy_type(L, 1, &detail::resume_impl, args); + } + + template + typename boost::mpl::if_ + , luaponte::detail::proxy_function_void_caller > + , luaponte::detail::proxy_function_caller > >::type + resume_function(luaponte::object const& obj BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUAPONTE_OPERATOR_PARAMS, _) ) + { + typedef boost::tuples::tuple tuple_t; +#if BOOST_PP_ITERATION() == 0 + tuple_t args; +#else + tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a)); +#endif + typedef typename boost::mpl::if_ + , luaponte::detail::proxy_function_void_caller > + , luaponte::detail::proxy_function_caller > >::type proxy_type; + + obj.push(obj.interpreter()); + return proxy_type(obj.interpreter(), 1, &detail::resume_impl, args); + } + + template + typename boost::mpl::if_ + , luaponte::detail::proxy_function_void_caller > + , luaponte::detail::proxy_function_caller > >::type + resume(lua_State* L BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUAPONTE_OPERATOR_PARAMS, _) ) + { + typedef boost::tuples::tuple tuple_t; +#if BOOST_PP_ITERATION() == 0 + tuple_t args; +#else + tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a)); +#endif + typedef typename boost::mpl::if_ + , luaponte::detail::proxy_function_void_caller > + , luaponte::detail::proxy_function_caller > >::type proxy_type; + + return proxy_type(L, 0, &detail::resume_impl, args); + } + +#undef LUAPONTE_OPERATOR_PARAMS +#undef LUAPONTE_TUPLE_PARAMS + +#endif +#endif diff --git a/luaponte/detail/call_member.hpp b/luaponte/detail/call_member.hpp new file mode 100644 index 0000000..49b6daf --- /dev/null +++ b/luaponte/detail/call_member.hpp @@ -0,0 +1,348 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !BOOST_PP_IS_ITERATING + +#ifndef LUAPONTE_DETAIL_CALL_MEMBER_HPP +#define LUAPONTE_DETAIL_CALL_MEMBER_HPP + +#include +#include +#include +#include +#include +#include // TODO: REMOVE DEPENDENCY + +#include + +#include +#include +#include + +#include + +namespace luaponte { + + namespace detail { + + namespace mpl = boost::mpl; + + // if the proxy_member_caller returns non-void + template + class proxy_member_caller + { +// friend class luaponte::object; + public: + + proxy_member_caller(lua_State* L_, const Tuple args) + : L(L_) + , m_args(args) + , m_called(false) + { + } + + proxy_member_caller(const proxy_member_caller& rhs) + : L(rhs.L) + , m_args(rhs.m_args) + , m_called(rhs.m_called) + { + rhs.m_called = true; + } + + ~proxy_member_caller() + { + if (m_called) return; + + m_called = true; + + // don't count the function and self-reference + // since those will be popped by pcall + int top = lua_gettop(L) - 2; + + // pcall will pop the function and self reference + // and all the parameters + + push_args_from_tuple<1>::apply(L, m_args); + if (pcall(L, boost::tuples::length::value + 1, 0)) + { + assert(lua_gettop(L) == top + 1); +#ifndef LUAPONTE_NO_EXCEPTIONS + throw luaponte::error(L); +#else + error_callback_fun e = get_error_callback(); + if (e) e(L); + + assert(0 && "the lua function threw an error and exceptions are disabled." + "If you want to handle this error use luaponte::set_error_callback()"); + std::terminate(); +#endif + } + // pops the return values from the function + stack_pop pop(L, lua_gettop(L) - top); + } + + operator Ret() + { + typename mpl::apply_wrap2::type converter; + + m_called = true; + + // don't count the function and self-reference + // since those will be popped by pcall + int top = lua_gettop(L) - 2; + + // pcall will pop the function and self reference + // and all the parameters + push_args_from_tuple<1>::apply(L, m_args); + if (pcall(L, boost::tuples::length::value + 1, 1)) + { + assert(lua_gettop(L) == top + 1); +#ifndef LUAPONTE_NO_EXCEPTIONS + throw luaponte::error(L); +#else + error_callback_fun e = get_error_callback(); + if (e) e(L); + + assert(0 && "the lua function threw an error and exceptions are disabled." + "If you want to handle this error use luaponte::set_error_callback()"); + std::terminate(); +#endif + } + + // pops the return values from the function + stack_pop pop(L, lua_gettop(L) - top); + + if (converter.match(L, LUAPONTE_DECORATE_TYPE(Ret), -1) < 0) + { + assert(lua_gettop(L) == top + 1); +#ifndef LUAPONTE_NO_EXCEPTIONS + throw cast_failed(L, typeid(Ret)); +#else + cast_failed_callback_fun e = get_cast_failed_callback(); + if (e) e(L, typeid(Ret)); + + assert(0 && "the lua function's return value could not be converted." + "If you want to handle this error use luaponte::set_error_callback()"); + std::terminate(); +#endif + } + + return converter.apply(L, LUAPONTE_DECORATE_TYPE(Ret), -1); + } + + template + Ret operator[](const Policies& p) + { + typedef typename find_conversion_policy<0, Policies>::type converter_policy; + typename mpl::apply_wrap2::type converter; + + m_called = true; + + // don't count the function and self-reference + // since those will be popped by pcall + int top = lua_gettop(L) - 2; + + // pcall will pop the function and self reference + // and all the parameters + + detail::push_args_from_tuple<1>::apply(L, m_args, p); + if (pcall(L, boost::tuples::length::value + 1, 1)) + { + assert(lua_gettop(L) == top + 1); +#ifndef LUAPONTE_NO_EXCEPTIONS + throw error(L); +#else + error_callback_fun e = get_error_callback(); + if (e) e(L); + + assert(0 && "the lua function threw an error and exceptions are disabled." + "If you want to handle this error use luaponte::set_error_callback()"); + std::terminate(); +#endif + } + + // pops the return values from the function + stack_pop pop(L, lua_gettop(L) - top); + + if (converter.match(L, LUAPONTE_DECORATE_TYPE(Ret), -1) < 0) + { + assert(lua_gettop(L) == top + 1); +#ifndef LUAPONTE_NO_EXCEPTIONS + throw cast_failed(L, typeid(Ret)); +#else + cast_failed_callback_fun e = get_cast_failed_callback(); + if (e) e(L, typeid(Ret)); + + assert(0 && "the lua function's return value could not be converted." + "If you want to handle this error use luaponte::set_error_callback()"); + std::terminate(); +#endif + } + + return converter.apply(L, LUAPONTE_DECORATE_TYPE(Ret), -1); + } + + private: + + lua_State* L; + Tuple m_args; + mutable bool m_called; + + }; + + // if the proxy_member_caller returns void + template + class proxy_member_void_caller + { + friend class luaponte::object; + public: + + proxy_member_void_caller(lua_State* L_, const Tuple args) + : L(L_) + , m_args(args) + , m_called(false) + { + } + + proxy_member_void_caller(const proxy_member_void_caller& rhs) + : L(rhs.L) + , m_args(rhs.m_args) + , m_called(rhs.m_called) + { + rhs.m_called = true; + } + + ~proxy_member_void_caller() + { + if (m_called) return; + + m_called = true; + + // don't count the function and self-reference + // since those will be popped by pcall + int top = lua_gettop(L) - 2; + + // pcall will pop the function and self reference + // and all the parameters + + push_args_from_tuple<1>::apply(L, m_args); + if (pcall(L, boost::tuples::length::value + 1, 0)) + { + assert(lua_gettop(L) == top + 1); +#ifndef LUAPONTE_NO_EXCEPTIONS + throw luaponte::error(L); +#else + error_callback_fun e = get_error_callback(); + if (e) e(L); + + assert(0 && "the lua function threw an error and exceptions are disabled." + "If you want to handle this error use luaponte::set_error_callback()"); + std::terminate(); +#endif + } + // pops the return values from the function + stack_pop pop(L, lua_gettop(L) - top); + } + + template + void operator[](const Policies& p) + { + m_called = true; + + // don't count the function and self-reference + // since those will be popped by pcall + int top = lua_gettop(L) - 2; + + // pcall will pop the function and self reference + // and all the parameters + + detail::push_args_from_tuple<1>::apply(L, m_args, p); + if (pcall(L, boost::tuples::length::value + 1, 0)) + { + assert(lua_gettop(L) == top + 1); +#ifndef LUAPONTE_NO_EXCEPTIONS + throw error(L); +#else + error_callback_fun e = get_error_callback(); + if (e) e(L); + + assert(0 && "the lua function threw an error and exceptions are disabled." + "If you want to handle this error use luaponte::set_error_callback()"); + std::terminate(); +#endif + } + // pops the return values from the function + stack_pop pop(L, lua_gettop(L) - top); + } + + private: + lua_State* L; + Tuple m_args; + mutable bool m_called; + + }; + + } // detail + + #define BOOST_PP_ITERATION_PARAMS_1 (4, (0, LUAPONTE_MAX_ARITY, , 1)) + #include BOOST_PP_ITERATE() + +} + +#endif // LUAPONTE_DETAIL_CALL_MEMBER_HPP + +#else +#if BOOST_PP_ITERATION_FLAGS() == 1 + +#define LUAPONTE_TUPLE_PARAMS(z, n, data) const A##n * +#define LUAPONTE_OPERATOR_PARAMS(z, n, data) const A##n & a##n + + template + typename boost::mpl::if_ + , luaponte::detail::proxy_member_void_caller > + , luaponte::detail::proxy_member_caller > >::type + call_member(object const& obj, const char* name BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUAPONTE_OPERATOR_PARAMS, _)) + { + typedef boost::tuples::tuple tuple_t; +#if BOOST_PP_ITERATION() == 0 + tuple_t args; +#else + tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a)); +#endif + + typedef typename boost::mpl::if_ + , luaponte::detail::proxy_member_void_caller > + , luaponte::detail::proxy_member_caller > >::type proxy_type; + + // this will be cleaned up by the proxy object + // once the call has been made + + // get the function + obj.push(obj.interpreter()); + lua_pushstring(obj.interpreter(), name); + lua_gettable(obj.interpreter(), -2); + // duplicate the self-object + lua_pushvalue(obj.interpreter(), -2); + // remove the bottom self-object + lua_remove(obj.interpreter(), -3); + + // now the function and self objects + // are on the stack. These will both + // be popped by pcall + return proxy_type(obj.interpreter(), args); + } + +#undef LUAPONTE_OPERATOR_PARAMS +#undef LUAPONTE_TUPLE_PARAMS + +#endif +#endif diff --git a/luaponte/detail/call_operator_iterate.hpp b/luaponte/detail/call_operator_iterate.hpp new file mode 100644 index 0000000..056c55a --- /dev/null +++ b/luaponte/detail/call_operator_iterate.hpp @@ -0,0 +1,55 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define N BOOST_PP_ITERATION() + +#define LUAPONTE_UNWRAP_PARAMETER(z, n, _) \ + typename detail::unwrap_parameter_type::type \ + BOOST_PP_CAT(_, n) + +template +struct BOOST_PP_CAT(call_operator, N) + : detail::operator_< + BOOST_PP_CAT(call_operator, N)< + Self BOOST_PP_ENUM_TRAILING_PARAMS(N, A) + > + > +{ + BOOST_PP_CAT(call_operator, N)(int) {} + + template + struct apply + { + static void execute( + lua_State* L + , typename detail::unwrap_parameter_type::type self + BOOST_PP_ENUM_TRAILING(N, LUAPONTE_UNWRAP_PARAMETER, _) + ) + { + using namespace detail; + operator_result( + L +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + , self(BOOST_PP_ENUM_PARAMS(N, _)) +#else + , (self(BOOST_PP_ENUM_PARAMS(N, _)), detail::operator_void_return()) +#endif + , (Policies*)0 + ); + } + }; + + static char const* name() { return "__call"; } +}; + +#undef LUAPONTE_UNWRAP_PARAMETER +#undef N diff --git a/luaponte/detail/class_registry.hpp b/luaponte/detail/class_registry.hpp new file mode 100644 index 0000000..d3109d5 --- /dev/null +++ b/luaponte/detail/class_registry.hpp @@ -0,0 +1,75 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_CLASS_REGISTRY_HPP +#define LUAPONTE_DETAIL_CLASS_REGISTRY_HPP + +#include + +#include +#include +#include + +namespace luaponte { +namespace detail { + + class class_rep; + + struct LUAPONTE_API class_registry + { + class_registry(lua_State* L); + + static class_registry* get_registry(lua_State* L); + + int cpp_instance() const { return m_instance_metatable; } + int cpp_class() const { return m_cpp_class_metatable; } + + int lua_instance() const { return m_instance_metatable; } + int lua_class() const { return m_lua_class_metatable; } + int lua_function() const { return m_lua_function_metatable; } + + void add_class(type_id const& info, class_rep* crep); + + class_rep* find_class(type_id const& info) const; + + std::map const& get_classes() const + { + return m_classes; + } + + private: + + std::map m_classes; + + // this is a lua reference that points to the lua table + // that is to be used as meta table for all C++ class + // instances. It is a kind of v-table. + int m_instance_metatable; + + // this is a lua reference to the metatable to be used + // for all classes defined in C++. + int m_cpp_class_metatable; + + // this is a lua reference to the metatable to be used + // for all classes defined in lua + int m_lua_class_metatable; + + // this metatable only contains a destructor + // for luaponte::Detail::free_functions::function_rep + int m_lua_function_metatable; + + }; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_CLASS_REGISTRY_HPP diff --git a/luaponte/detail/class_rep.hpp b/luaponte/detail/class_rep.hpp new file mode 100644 index 0000000..a96b771 --- /dev/null +++ b/luaponte/detail/class_rep.hpp @@ -0,0 +1,200 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_CLASS_REP_HPP +#define LUAPONTE_DETAIL_CLASS_REP_HPP + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace luaponte { +namespace detail { + + LUAPONTE_API std::string stack_content_by_name(lua_State* L, int start_index); + + struct class_registration; + + struct conversion_storage; + + // This function is used as a tag to identify "properties". + LUAPONTE_API int property_tag(lua_State*); + + // this is class-specific information, poor man's vtable + // this is allocated statically (removed by the compiler) + // a pointer to this structure is stored in the lua tables' + // metatable with the name __classrep + // it is used when matching parameters to function calls + // to determine possible implicit casts + // it is also used when finding the best match for overloaded + // methods + + class cast_graph; + class class_id_map; + + class LUAPONTE_API class_rep + { + friend struct class_registration; + friend int super_callback(lua_State*); +//TODO: avoid the lua-prefix + friend int lua_class_gettable(lua_State*); + friend int lua_class_settable(lua_State*); + friend int static_class_gettable(lua_State*); + public: + + enum class_type + { + cpp_class = 0, + lua_class = 1 + }; + + // EXPECTS THE TOP VALUE ON THE LUA STACK TO + // BE THE USER DATA WHERE THIS CLASS IS BEING + // INSTANTIATED! + class_rep(type_id const& type + , const char* name + , lua_State* L + ); + + // used when creating a lua class + // EXPECTS THE TOP VALUE ON THE LUA STACK TO + // BE THE USER DATA WHERE THIS CLASS IS BEING + // INSTANTIATED! + class_rep(lua_State* L, const char* name); + + ~class_rep(); + + std::pair allocate(lua_State* L) const; + + // this is called as metamethod __call on the class_rep. + static int constructor_dispatcher(lua_State* L); + + struct base_info + { + int pointer_offset; // the offset added to the pointer to obtain a basepointer (due to multiple-inheritance) + class_rep* base; + }; + + void add_base_class(const base_info& binfo); + + const std::vector& bases() const throw() { return m_bases; } + + void set_type(type_id const& t) { m_type = t; } + type_id const& type() const throw() { return m_type; } + + const char* name() const throw() { return m_name; } + + // the lua reference to the metatable for this class' instances + int metatable_ref() const throw() { return m_instance_metatable; } + + void get_table(lua_State* L) const { m_table.push(L); } + void get_default_table(lua_State* L) const { m_default_table.push(L); } + + class_type get_class_type() const { return m_class_type; } + + void add_static_constant(const char* name, int val); + + static int super_callback(lua_State* L); + + static int lua_settable_dispatcher(lua_State* L); + + // called from the metamethod for __index + // obj is the object pointer + static int static_class_gettable(lua_State* L); + + bool has_operator_in_lua(lua_State*, int id); + + cast_graph const& casts() const + { + return *m_casts; + } + + class_id_map const& classes() const + { + return *m_classes; + } + + private: + + void cache_operators(lua_State*); + + // this is a pointer to the type_info structure for + // this type + // warning: this may be a problem when using dll:s, since + // typeid() may actually return different pointers for the same + // type. + type_id m_type; + + // a list of info for every class this class derives from + // the information stored here is sufficient to do + // type casts to the base classes + std::vector m_bases; + + // the class' name (as given when registered to lua with class_) + const char* m_name; + + // a reference to this structure itself. Since this struct + // is kept inside lua (to let lua collect it when lua_close() + // is called) we need to lock it to prevent collection. + // the actual reference is not currently used. + detail::lua_reference m_self_ref; + + // this should always be used when accessing + // members in instances of a class. + // this table contains c closures for all + // member functions in this class, they + // may point to both static and virtual functions + handle m_table; + + // this table contains default implementations of the + // virtual functions in m_table. + handle m_default_table; + + // the type of this class.. determines if it's written in c++ or lua + class_type m_class_type; + + // this is a lua reference that points to the lua table + // that is to be used as meta table for all instances + // of this class. + int m_instance_metatable; + + std::map m_static_constants; + + // the first time an operator is invoked + // we check the associated lua table + // and cache the result + int m_operator_cache; + + cast_graph* m_casts; + class_id_map* m_classes; + }; + + bool is_class_rep(lua_State* L, int index); + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_CLASS_REP_HPP diff --git a/luaponte/detail/constructor.hpp b/luaponte/detail/constructor.hpp new file mode 100644 index 0000000..96ecff6 --- /dev/null +++ b/luaponte/detail/constructor.hpp @@ -0,0 +1,119 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !BOOST_PP_IS_ITERATING + +# ifndef LUAPONTE_DETAIL_CONSTRUCTOR_HPP +# define LUAPONTE_DETAIL_CONSTRUCTOR_HPP + +# include +# include +# include +# include + +# include +# include +# include +# include +# include + +namespace luaponte { +namespace detail { + +inline void inject_backref(lua_State*, void*, void*) +{} + +template +void inject_backref(lua_State* L, T* p, wrap_base*) +{ + weak_ref(get_main_thread(L), L, 1).swap(wrap_access::ref(*p)); +} + +template +struct construct_aux; + +template +struct construct + : construct_aux::value - 2, T, Pointer, Signature> +{}; + +template +struct construct_aux<0, T, Pointer, Signature> +{ + typedef pointer_holder holder_type; + + void operator()(argument const& self_) const + { + object_rep* self = touserdata(self_); + + std::unique_ptr instance(new T); + inject_backref(self_.interpreter(), instance.get(), instance.get()); + + void* naked_ptr = instance.get(); + Pointer ptr(instance.release()); + + void* storage = self->allocate(sizeof(holder_type)); + + self->set_instance(new (storage) holder_type( + std::move(ptr), registered_class::id, naked_ptr)); + } +}; + +# define BOOST_PP_ITERATION_PARAMS_1 \ + (3, (1, LUAPONTE_MAX_ARITY, )) +# include BOOST_PP_ITERATE() + +} // namespace detail +} // namespace luaponte + +# endif // LUAPONTE_DETAIL_CONSTRUCTOR_HPP + +#else // !BOOST_PP_IS_ITERATING + +# define N BOOST_PP_ITERATION() + +template +struct construct_aux +{ + typedef typename mpl::begin::type first; + typedef typename mpl::next::type iter0; + +# define BOOST_PP_LOCAL_MACRO(n) \ + typedef typename mpl::next< \ + BOOST_PP_CAT(iter,BOOST_PP_DEC(n))>::type BOOST_PP_CAT(iter,n); \ + typedef typename BOOST_PP_CAT(iter,n)::type BOOST_PP_CAT(a,BOOST_PP_DEC(n)); + +# define BOOST_PP_LOCAL_LIMITS (1,N) +# include BOOST_PP_LOCAL_ITERATE() + + typedef pointer_holder holder_type; + + void operator()(argument const& self_, BOOST_PP_ENUM_BINARY_PARAMS(N,a,_)) const + { + object_rep* self = touserdata(self_); + + std::unique_ptr instance(new T(BOOST_PP_ENUM_PARAMS(N,_))); + inject_backref(self_.interpreter(), instance.get(), instance.get()); + + void* naked_ptr = instance.get(); + Pointer ptr(instance.release()); + + void* storage = self->allocate(sizeof(holder_type)); + + self->set_instance(new (storage) holder_type( + std::move(ptr), registered_class::id, naked_ptr)); + } +}; + +# undef N + +#endif diff --git a/luaponte/detail/conversion_storage.hpp b/luaponte/detail/conversion_storage.hpp new file mode 100644 index 0000000..cd1eed3 --- /dev/null +++ b/luaponte/detail/conversion_storage.hpp @@ -0,0 +1,50 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_CONVERSION_STORAGE_HPP +#define LUAPONTE_DETAIL_CONVERSION_STORAGE_HPP + +#include +#include + +namespace luaponte { +namespace detail { + +typedef void(*destruction_function)(void*); + +// This is used by the converters in policy.hpp, and +// class_rep::convert_to as temporary storage when constructing +// holders. + +struct conversion_storage +{ + conversion_storage() + : destructor(0) + {} + + ~conversion_storage() + { + if (destructor) + destructor(&data); + } + + // Unfortunately the converters currently doesn't have access to + // the actual type being converted when this is instantiated, so + // we have to guess a max size. + boost::aligned_storage<128> data; + destruction_function destructor; +}; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_CONVERSION_STORAGE_HPP diff --git a/luaponte/detail/convert_to_lua.hpp b/luaponte/detail/convert_to_lua.hpp new file mode 100644 index 0000000..1c8b395 --- /dev/null +++ b/luaponte/detail/convert_to_lua.hpp @@ -0,0 +1,83 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_CONVERT_TO_LUA_HPP +#define LUAPONTE_DETAIL_CONVERT_TO_LUA_HPP + +#include +#include +#include + +#include + +namespace luaponte { +namespace detail { + +template +struct unwrap_ref +{ + template + static const T& get(const T& r) { return r; } + + template + struct apply + { + typedef T type; + }; +}; + +template<> +struct unwrap_ref +{ + template + static T& get(const boost::reference_wrapper& r) { return r.get(); } + + template + struct apply + { + typedef typename T::type& type; + }; +}; + +namespace mpl = boost::mpl; + +template +void convert_to_lua(lua_State* L, const T& v) +{ + typedef typename mpl::apply_wrap1< + unwrap_ref::value> + , T + >::type value_type; + + typename mpl::apply_wrap2::type converter; + + converter.apply(L, unwrap_ref::value>::get(v)); +} + +template +void convert_to_lua_p(lua_State* L, const T& v, const Policies&) +{ + typedef typename mpl::apply_wrap1< + unwrap_ref::value> + , T + >::type value_type; + + typedef typename find_conversion_policy::type converter_policy; + typename mpl::apply_wrap2::type converter; + + converter.apply(L, unwrap_ref::value>::get(v)); +} + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_CONVERT_TO_LUA_HPP diff --git a/luaponte/detail/debug.hpp b/luaponte/detail/debug.hpp new file mode 100644 index 0000000..930b17d --- /dev/null +++ b/luaponte/detail/debug.hpp @@ -0,0 +1,51 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_DEBUG_HPP +#define LUAPONTE_DETAIL_DEBUG_HPP + +#ifndef NDEBUG + +# include +# include + +namespace luaponte { +namespace detail { + +struct stack_checker_type +{ + stack_checker_type(lua_State* L) + : m_L(L) + , m_stack(lua_gettop(m_L)) + {} + + ~stack_checker_type() + { + assert(m_stack == lua_gettop(m_L)); + } + + lua_State* m_L; + int m_stack; +}; + +} // namespace detail +} // namespace luaponte + +# define LUAPONTE_CHECK_STACK(L) luaponte::detail::stack_checker_type stack_checker_object(L) + +#else + +# define LUAPONTE_CHECK_STACK(L) do {} while (0) + +#endif + +#endif // LUAPONTE_DETAIL_DEBUG_HPP diff --git a/luaponte/detail/decorate_type.hpp b/luaponte/detail/decorate_type.hpp new file mode 100644 index 0000000..8a09871 --- /dev/null +++ b/luaponte/detail/decorate_type.hpp @@ -0,0 +1,263 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_DECORATE_TYPE_HPP +#define LUAPONTE_DETAIL_DECORATE_TYPE_HPP + +#include +#include + +namespace luaponte { +namespace detail { + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + + template + struct decorated_type + { + static by_value t; + static inline by_value& get() { return /*by_value()*/t; } + }; + + template + by_value decorated_type::t; + + template + struct decorated_type + { + static by_pointer t; + static inline by_pointer& get() { return /*by_pointer()*/t; } + }; + + template + by_pointer decorated_type::t; + + template + struct decorated_type + { + static by_const_pointer t; + static inline by_const_pointer get() { return /*by_const_pointer()*/t; } + }; + + template + by_const_pointer decorated_type::t; + + template + struct decorated_type + { + static by_const_pointer t; + static inline by_const_pointer& get() { return /*by_const_pointer()*/t; } + }; + + template + by_const_pointer decorated_type::t; + + template + struct decorated_type + { + static by_reference t; + static inline by_reference& get() { return /*by_reference()*/t; } + }; + + template + by_reference decorated_type::t; + + template + struct decorated_type + { + static by_const_reference t; + static inline by_const_reference& get() { return /*by_const_reference()*/t; } + }; + + template + by_const_reference decorated_type::t; + +#ifdef BOOST_HAS_RVALUE_REFS + template + struct decorated_type + { + static by_value t; + static inline by_value& get() { return /*by_value()*/t; } + }; + + template + by_value decorated_type::t; +#endif + + #define LUAPONTE_DECORATE_TYPE(t) luaponte::detail::decorated_type::get() + +#else + +#include + + namespace + { + LUAPONTE_ANONYMOUS_FIX char decorated_type_array[64]; + } + + template + struct decorated_type_cref_impl + { +#if defined(BOOST_MSVC) && BOOST_MSVC == 1200 + template + static by_const_reference get(const U&) + { + return by_const_reference(); + } + static T data() { return reinterpret_cast(decorated_type_array); } +#else + + static void(*data())(T) + { return (void(*)(T))0; } + + template + static by_const_reference get(void(*f)(const U&)) + { return by_const_reference(); } +#endif + }; + + template + struct decorated_type_ref_impl + { +#if defined(BOOST_MSVC) && BOOST_MSVC == 1200 + template + static by_reference get(U&) + { + return by_reference(); + } + static T data() { return reinterpret_cast(decorated_type_array); } +#else + static void(*data())(T) + { return (void(*)(T))0; } + + template + static by_reference get(void(*)(U&)) + { return by_reference(); } +#endif + }; + + template + struct decorated_type_cptr_impl + { +#if defined(BOOST_MSVC) && BOOST_MSVC == 1200 + template + static by_const_pointer get(const U*) + { + return by_const_pointer(); + } + static T& data() { return reinterpret_cast(decorated_type_array); } +#else + static void(*data())(T) + { return (void(*)(T))0; } + + template + static by_const_pointer get(void(*)(const U*)) + { return by_const_pointer(); } +#endif + }; + + template + struct decorated_type_ptr_impl + { +#if defined(BOOST_MSVC) && BOOST_MSVC == 1200 + template + static by_pointer get(U*) + { + return by_pointer(); + } + static T& data() { return reinterpret_cast(decorated_type_array); } +#else + static void(*data())(T) + { return (void(*)(T))0; } + + template + static by_pointer get(void(*)(U*)) + { return by_pointer(); } +#endif + }; + + template + struct decorated_type_value_impl + { +#if defined(BOOST_MSVC) && BOOST_MSVC == 1200 + template + static by_value get(U&) + { + return by_value(); + } + static T& data() { return reinterpret_cast(decorated_type_array); } +#else + static void(*data())(T&) + { return (void(*)(T&))0; } + + template + static by_value get(void(*)(U&)) + { return by_value(); } +#endif + }; + + template<> + struct decorated_type_value_impl + { + static by_value get(int) + { + return by_value(); + } + static int data() { return 0; } + }; + + template + struct decorated_type_array_impl + { + template + static by_pointer get(U*) + { + return by_pointer(); + } + + template + static by_pointer get(void(*)(U)) + { return by_pointer(); } + + static T& data() { return reinterpret_cast(decorated_type_array); } + }; + + template + struct decorated_type + : boost::mpl::if_ + , decorated_type_cref_impl + , typename boost::mpl::if_ + , decorated_type_ref_impl + , typename boost::mpl::if_ + , decorated_type_ptr_impl + , typename boost::mpl::if_ + , decorated_type_cptr_impl + , decorated_type_value_impl + >::type + >::type + >::type + >::type + { + }; + +#if defined(BOOST_MSVC) && BOOST_MSVC == 1200 + #define LUAPONTE_DECORATE_TYPE(t) luaponte::detail::decorated_type::get(luaponte::detail::decorated_type::data()) +#else + #define LUAPONTE_DECORATE_TYPE(t) luaponte::detail::decorated_type::get(luaponte::detail::decorated_type::data()) +#endif + +#endif + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_DECORATE_TYPE_HPP diff --git a/luaponte/detail/deduce_signature.hpp b/luaponte/detail/deduce_signature.hpp new file mode 100644 index 0000000..6c5f2fd --- /dev/null +++ b/luaponte/detail/deduce_signature.hpp @@ -0,0 +1,127 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !BOOST_PP_IS_ITERATING + +# ifndef LUAPONTE_DETAIL_DEDUCE_SIGNATURE_HPP +# define LUAPONTE_DETAIL_DEDUCE_SIGNATURE_HPP + +# include + +# if LUAPONTE_MAX_ARITY <= 8 +# include +# else +# include +# endif +# include +# include +# include + +namespace luaponte { +namespace detail { + +namespace mpl = boost::mpl; + +template +mpl::vector1 deduce_signature(R(*)(), ...) +{ + return mpl::vector1(); +} + +template +mpl::vector2 deduce_signature(R(T::*)()) +{ + return mpl::vector2(); +} + +template +mpl::vector2::type&> +deduce_signature(R(T::*)(), Wrapped*) +{ + return mpl::vector2::type&>(); +} + +template +mpl::vector2 deduce_signature(R(T::*)() const) +{ + return mpl::vector2(); +} + +template +mpl::vector2::type const&> +deduce_signature(R(T::*)() const, Wrapped*) +{ + return mpl::vector2::type const&>(); +} + +# define BOOST_PP_ITERATION_PARAMS_1 \ + (3, (1, LUAPONTE_MAX_ARITY, )) +# include BOOST_PP_ITERATE() + +} // namespace detail +} // namespace luaponte + +# endif // LUAPONTE_DETAIL_DEDUCE_SIGNATURE_HPP + +#else // BOOST_PP_IS_ITERATING + +# define N BOOST_PP_ITERATION() +# define NPLUS1 BOOST_PP_INC(N) + +template +BOOST_PP_CAT(mpl::vector,NPLUS1) +deduce_signature(R(*)(BOOST_PP_ENUM_PARAMS(N,A)), ...) +{ + return BOOST_PP_CAT(mpl::vector,NPLUS1)(); +} + +# define NPLUS2 BOOST_PP_INC(NPLUS1) + +template +BOOST_PP_CAT(mpl::vector,NPLUS2) +deduce_signature(R(T::*)(BOOST_PP_ENUM_PARAMS(N,A))) +{ + return BOOST_PP_CAT(mpl::vector,NPLUS2)(); +} + +template +BOOST_PP_CAT(mpl::vector,NPLUS2)< + R, typename most_derived::type&, BOOST_PP_ENUM_PARAMS(N,A) +> +deduce_signature(R(T::*)(BOOST_PP_ENUM_PARAMS(N,A)), Wrapped*) +{ + return BOOST_PP_CAT(mpl::vector,NPLUS2)< + R,typename most_derived::type&,BOOST_PP_ENUM_PARAMS(N,A)>(); +} + +template +BOOST_PP_CAT(mpl::vector,NPLUS2) +deduce_signature(R(T::*)(BOOST_PP_ENUM_PARAMS(N,A)) const) +{ + return BOOST_PP_CAT(mpl::vector,NPLUS2)(); +} + +template +BOOST_PP_CAT(mpl::vector,NPLUS2)< + R, typename most_derived::type const&, BOOST_PP_ENUM_PARAMS(N,A) +> +deduce_signature(R(T::*)(BOOST_PP_ENUM_PARAMS(N,A)) const, Wrapped*) +{ + return BOOST_PP_CAT(mpl::vector,NPLUS2)< + R,typename most_derived::type const&,BOOST_PP_ENUM_PARAMS(N,A)>(); +} + +# undef NPLUS2 +# undef NPLUS1 +# undef N + +#endif // BOOST_PP_IS_ITERATING diff --git a/luaponte/detail/enum_maker.hpp b/luaponte/detail/enum_maker.hpp new file mode 100644 index 0000000..2602d79 --- /dev/null +++ b/luaponte/detail/enum_maker.hpp @@ -0,0 +1,113 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_ENUM_MAKER_HPP +#define LUAPONTE_DETAIL_ENUM_MAKER_HPP + +#include +#include + +#include +#include + +namespace luaponte { + +struct value; + +struct value_vector : public std::vector +{ + // a bug in intel's compiler forces us to declare these constructors explicitly. + value_vector(); + virtual ~value_vector(); + value_vector(const value_vector& v); + value_vector& operator,(const value& rhs); +}; + +struct value +{ +friend class std::vector; + template + value(const char* name, T v) + : name_(name) + , val_(v) + {} + + const char* name_; + int val_; + + value_vector operator,(const value& rhs) const + { + value_vector v; + + v.push_back(*this); + v.push_back(rhs); + + return v; + } + +private: + + value() {} +}; + +inline value_vector::value_vector() + : std::vector() +{ +} + +inline value_vector::~value_vector() {} + +inline value_vector::value_vector(const value_vector& rhs) + : std::vector(rhs) +{ +} + +inline value_vector& value_vector::operator,(const value& rhs) +{ + push_back(rhs); + return *this; +} + +namespace detail { + +template +struct enum_maker +{ + explicit enum_maker(From& from): from_(from) {} + + From& operator[](const value& val) + { + from_.add_static_constant(val.name_, val.val_); + return from_; + } + + From& operator[](const value_vector& values) + { + for (value_vector::const_iterator i = values.begin(); i != values.end(); ++i) + { + from_.add_static_constant(i->name_, i->val_); + } + + return from_; + } + + From& from_; + +private: + void operator=(enum_maker const&); // C4512, assignment operator could not be generated + template void operator,(T const&) const; +}; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_ENUM_MAKER_HPP diff --git a/luaponte/detail/format_signature.hpp b/luaponte/detail/format_signature.hpp new file mode 100644 index 0000000..9519e68 --- /dev/null +++ b/luaponte/detail/format_signature.hpp @@ -0,0 +1,161 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_FORMAT_SIGNATURE_HPP +# define LUAPONTE_DETAIL_FORMAT_SIGNATURE_HPP + +# include +# include +# include + +# include +# include +# include + +namespace luaponte { +namespace adl { + + class object; + class argument; + template + struct table; + +} // namespace adl + +using adl::object; +using adl::argument; +using adl::table; + +namespace detail { + +LUAPONTE_API std::string get_class_name(lua_State* L, type_id const& i); + +template +struct type_to_string +{ + static void get(lua_State* L) + { + lua_pushstring(L, get_class_name(L, typeid(T)).c_str()); + } +}; + +template +struct type_to_string +{ + static void get(lua_State* L) + { + type_to_string::get(L); + lua_pushstring(L, "*"); + lua_concat(L, 2); + } +}; + +template +struct type_to_string +{ + static void get(lua_State* L) + { + type_to_string::get(L); + lua_pushstring(L, "&"); + lua_concat(L, 2); + } +}; + +template +struct type_to_string +{ + static void get(lua_State* L) + { + type_to_string::get(L); + lua_pushstring(L, " const"); + lua_concat(L, 2); + } +}; + +# define LUAPONTE_TYPE_TO_STRING(x) \ + template <> \ + struct type_to_string \ + { \ + static void get(lua_State* L) \ + { \ + lua_pushstring(L, #x); \ + } \ + }; + +# define LUAPONTE_INTEGRAL_TYPE_TO_STRING(x) \ + LUAPONTE_TYPE_TO_STRING(x) \ + LUAPONTE_TYPE_TO_STRING(unsigned x) + +LUAPONTE_INTEGRAL_TYPE_TO_STRING(char) +LUAPONTE_INTEGRAL_TYPE_TO_STRING(short) +LUAPONTE_INTEGRAL_TYPE_TO_STRING(int) +LUAPONTE_INTEGRAL_TYPE_TO_STRING(long) + +LUAPONTE_TYPE_TO_STRING(void) +LUAPONTE_TYPE_TO_STRING(bool) +LUAPONTE_TYPE_TO_STRING(std::string) +LUAPONTE_TYPE_TO_STRING(lua_State) + +LUAPONTE_TYPE_TO_STRING(luaponte::object) +LUAPONTE_TYPE_TO_STRING(luaponte::argument) + +# undef LUAPONTE_INTEGRAL_TYPE_TO_STRING +# undef LUAPONTE_TYPE_TO_STRING + +template +struct type_to_string > +{ + static void get(lua_State* L) + { + lua_pushstring(L, "table"); + } +}; + +template +void format_signature_aux(lua_State*, bool, End, End) +{} + +template +void format_signature_aux(lua_State* L, bool first, Iter, End end) +{ + if (!first) + lua_pushstring(L, ","); + type_to_string::get(L); + format_signature_aux(L, false, typename mpl::next::type(), end); +} + +template +void format_signature(lua_State* L, char const* function, Signature) +{ + typedef typename mpl::begin::type first; + + type_to_string::get(L); + + lua_pushstring(L, " "); + lua_pushstring(L, function); + + lua_pushstring(L, "("); + format_signature_aux( + L + , true + , typename mpl::next::type() + , typename mpl::end::type() + ); + lua_pushstring(L, ")"); + + lua_concat(L, static_cast(mpl::size()) * 2 + 2); +} + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_FORMAT_SIGNATURE_HPP diff --git a/luaponte/detail/garbage_collector.hpp b/luaponte/detail/garbage_collector.hpp new file mode 100644 index 0000000..8e0af37 --- /dev/null +++ b/luaponte/detail/garbage_collector.hpp @@ -0,0 +1,44 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_GARBAGE_COLLECTOR_HPP +#define LUAPONTE_DETAIL_GARBAGE_COLLECTOR_HPP + +#include + +namespace luaponte { +namespace detail { + +// function that is used as __gc metafunction on several objects +template +inline int garbage_collector(lua_State* L) +{ + T* obj = static_cast(lua_touserdata(L, -1)); + obj->~T(); + return 0; +} + +template +struct garbage_collector_s +{ + static int apply(lua_State* L) + { + T* obj = static_cast(lua_touserdata(L, -1)); + obj->~T(); + return 0; + } +}; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_GARBAGE_COLLECTOR_HPP diff --git a/luaponte/detail/has_get_pointer.hpp b/luaponte/detail/has_get_pointer.hpp new file mode 100644 index 0000000..fb1a8d8 --- /dev/null +++ b/luaponte/detail/has_get_pointer.hpp @@ -0,0 +1,41 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_HAS_GET_POINTER_HPP +#define LUAPONTE_DETAIL_HAS_GET_POINTER_HPP + +#include + +#include +#include + +namespace luaponte { +namespace detail { + +template +struct has_get_pointer + : std::false_type {}; + + +template +struct has_get_pointer())) + >::value + >::type> + : std::true_type {}; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_HAS_GET_POINTER_HPP diff --git a/luaponte/detail/inheritance.hpp b/luaponte/detail/inheritance.hpp new file mode 100644 index 0000000..b755e8d --- /dev/null +++ b/luaponte/detail/inheritance.hpp @@ -0,0 +1,178 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_INHERITANCE_HPP +#define LUAPONTE_DETAIL_INHERITANCE_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace luaponte { +namespace detail { + +typedef void*(*cast_function)(void*); +typedef std::size_t class_id; + +class_id const unknown_class = (std::numeric_limits::max)(); + +class class_rep; + +class LUAPONTE_API cast_graph +{ +public: + cast_graph(); + ~cast_graph(); + + // `src` and `p` here describe the *most derived* object. This means that + // for a polymorphic type, the pointer must be cast with + // dynamic_cast before being passed in here, and `src` has to + // match typeid(*p). + std::pair cast( + void* p, class_id src, class_id target + , class_id dynamic_id, void const* dynamic_ptr) const; + void insert(class_id src, class_id target, cast_function cast); + +private: + class impl; + boost::scoped_ptr m_impl; +}; + +// Maps a type_id to a class_id. Note that this actually partitions the +// id-space into two, using one half for "local" ids; ids that are used only as +// keys into the conversion cache. This is needed because we need a unique key +// even for types that hasn't been registered explicitly. +class LUAPONTE_API class_id_map +{ +public: + class_id_map(); + + class_id get(type_id const& type) const; + class_id get_local(type_id const& type); + void put(class_id id, type_id const& type); + +private: + typedef std::map map_type; + map_type m_classes; + class_id m_local_id; + + static class_id const local_id_base; +}; + +inline class_id_map::class_id_map() + : m_local_id(local_id_base) +{} + +inline class_id class_id_map::get(type_id const& type) const +{ + map_type::const_iterator i = m_classes.find(type); + if (i == m_classes.end() || i->second >= local_id_base) + return unknown_class; + return i->second; +} + +inline class_id class_id_map::get_local(type_id const& type) +{ + std::pair result = m_classes.insert( + std::make_pair(type, 0)); + + if (result.second) + result.first->second = m_local_id++; + + assert(m_local_id >= local_id_base); + + return result.first->second; +} + +inline void class_id_map::put(class_id id, type_id const& type) +{ + assert(id < local_id_base); + + std::pair result = m_classes.insert( + std::make_pair(type, 0)); + + assert( + result.second + || result.first->second == id + || result.first->second >= local_id_base + ); + + result.first->second = id; +} + +class class_map +{ +public: + class_rep* get(class_id id) const; + void put(class_id id, class_rep* cls); + +private: + std::vector m_classes; +}; + +inline class_rep* class_map::get(class_id id) const +{ + if (id >= m_classes.size()) + return 0; + return m_classes[id]; +} + +inline void class_map::put(class_id id, class_rep* cls) +{ + if (id >= m_classes.size()) + m_classes.resize(id + 1); + m_classes[id] = cls; +} + +template +struct static_cast_ +{ + static void* execute(void* p) + { + return static_cast(static_cast(p)); + } +}; + +template +struct dynamic_cast_ +{ + static void* execute(void* p) + { + return dynamic_cast(static_cast(p)); + } +}; + +// Thread safe class_id allocation. +LUAPONTE_API class_id allocate_class_id(type_id const& cls); + +template +struct registered_class +{ + static class_id const id; +}; + +template +class_id const registered_class::id = allocate_class_id(typeid(T)); + +template +struct registered_class + : registered_class +{}; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_INHERITANCE_HPP diff --git a/luaponte/detail/instance_holder.hpp b/luaponte/detail/instance_holder.hpp new file mode 100644 index 0000000..d6dca5e --- /dev/null +++ b/luaponte/detail/instance_holder.hpp @@ -0,0 +1,136 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_INSTANCE_HOLDER_HPP +#define LUAPONTE_DETAIL_INSTANCE_HOLDER_HPP + +#include +#include +#include + +#include +#include +#include + +namespace luaponte { +namespace detail { + +class instance_holder +{ +public: + instance_holder(bool pointee_const) + : m_pointee_const(pointee_const) + {} + + virtual ~instance_holder() + {} + + virtual std::pair get( + cast_graph const& casts, class_id target) const = 0; + + virtual void release() = 0; + + bool pointee_const() const + { + return m_pointee_const; + } + +private: + bool m_pointee_const; +}; + +namespace mpl = boost::mpl; + +inline mpl::false_ check_const_pointer(void*) +{ + return mpl::false_(); +} + +inline mpl::true_ check_const_pointer(void const*) +{ + return mpl::true_(); +} + +template +void release_ownership(std::unique_ptr& p) +{ + p.release(); +} + +template +void release_ownership(P const&) +{ + throw std::runtime_error( + "luabind: smart pointer does not allow ownership transfer"); +} + +template +class_id static_class_id(T*) +{ + return registered_class::id; +} + +template +class pointer_holder : public instance_holder +{ +public: + pointer_holder( + P p, class_id dynamic_id, void* dynamic_ptr + ) + : instance_holder(check_const_pointer(false ? get_pointer(p) : 0)) + , p(std::move(p)) + , weak(0) + , dynamic_id(dynamic_id) + , dynamic_ptr(dynamic_ptr) + {} + + std::pair get(cast_graph const& casts, class_id target) const + { + if (target == registered_class

::id) + return std::pair(&this->p, 0); + + void* naked_ptr = const_cast(static_cast( + weak ? weak : get_pointer(p))); + + if (!naked_ptr) + return std::pair((void*)0, 0); + + return casts.cast( + naked_ptr + , static_class_id(false ? get_pointer(p) : 0) + , target + , dynamic_id + , dynamic_ptr + ); + } + + void release() + { + weak = const_cast(static_cast( + get_pointer(p))); + release_ownership(p); + } + +private: + mutable P p; + // weak will hold a possibly stale pointer to the object owned + // by p once p has released it's owership. This is a workaround + // to make adopt() work with virtual function wrapper classes. + void* weak; + class_id dynamic_id; + void* dynamic_ptr; +}; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_INSTANCE_HOLDER_HPP diff --git a/luaponte/detail/link_compatibility.hpp b/luaponte/detail/link_compatibility.hpp new file mode 100644 index 0000000..7cbd07f --- /dev/null +++ b/luaponte/detail/link_compatibility.hpp @@ -0,0 +1,51 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_LINK_COMPATIBILITY_HPP +#define LUAPONTE_DETAIL_LINK_COMPATIBILITY_HPP + +#include + +namespace luaponte { +namespace detail { + +#ifdef LUAPONTE_NOT_THREADSAFE +LUAPONTE_API void not_threadsafe_defined_conflict(); +#else +LUAPONTE_API void not_threadsafe_not_defined_conflict(); +#endif + +#ifdef LUAPONTE_NO_ERROR_CHECKING +LUAPONTE_API void no_error_checking_defined_conflict(); +#else +LUAPONTE_API void no_error_checking_not_defined_conflict(); +#endif + +inline void check_link_compatibility() +{ +#ifdef LUAPONTE_NOT_THREADSAFE + not_threadsafe_defined_conflict(); +#else + not_threadsafe_not_defined_conflict(); +#endif + +#ifdef LUAPONTE_NO_ERROR_CHECKING + no_error_checking_defined_conflict(); +#else + no_error_checking_not_defined_conflict(); +#endif +} + +} // namespace detail +} // namespace luaponte + +#endif diff --git a/luaponte/detail/make_instance.hpp b/luaponte/detail/make_instance.hpp new file mode 100644 index 0000000..cf86577 --- /dev/null +++ b/luaponte/detail/make_instance.hpp @@ -0,0 +1,115 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_MAKE_INSTANCE_HPP +#define LUAPONTE_DETAIL_MAKE_INSTANCE_HPP + +#include +#include +#include + +namespace luaponte { +namespace detail { + +template +std::pair get_dynamic_class_aux( + lua_State* L, T const* p, mpl::true_) +{ + lua_pushliteral(L, "__luabind_class_id_map"); + lua_rawget(L, LUA_REGISTRYINDEX); + + class_id_map& class_ids = *static_cast( + lua_touserdata(L, -1)); + + lua_pop(L, 1); + + return std::make_pair( + class_ids.get_local(typeid(*p)) + , dynamic_cast(const_cast(p)) + ); +} + +template +std::pair get_dynamic_class_aux( + lua_State*, T const* p, mpl::false_) +{ + return std::make_pair(registered_class::id, (void*)p); +} + +template +std::pair get_dynamic_class(lua_State* L, T* p) +{ + return get_dynamic_class_aux(L, p, boost::is_polymorphic()); +} + +template +class_rep* get_pointee_class(class_map const& classes, T*) +{ + return classes.get(registered_class::id); +} + +template +class_rep* get_pointee_class(lua_State* L, P const& p, class_id dynamic_id) +{ + lua_pushliteral(L, "__luabind_class_map"); + lua_rawget(L, LUA_REGISTRYINDEX); + + class_map const& classes = *static_cast( + lua_touserdata(L, -1)); + + lua_pop(L, 1); + + class_rep* cls = classes.get(dynamic_id); + + if (!cls) + cls = get_pointee_class(classes, get_pointer(p)); + + return cls; +} + +// Create an appropriate instance holder for the given pointer like object. +template +void make_instance(lua_State* L, P p) +{ + std::pair dynamic = get_dynamic_class(L, get_pointer(p)); + + class_rep* cls = get_pointee_class(L, p, dynamic.first); + + if (!cls) + { + throw std::runtime_error("Trying to use unregistered class"); + } + + object_rep* instance = push_new_instance(L, cls); + + typedef pointer_holder

holder_type; + + void* storage = instance->allocate(sizeof(holder_type)); + + try + { + new (storage) holder_type(std::move(p), dynamic.first, dynamic.second); + } + catch (...) + { + instance->deallocate(storage); + lua_pop(L, 1); + throw; + } + + instance->set_instance(static_cast(storage)); +} + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_MAKE_INSTANCE_HPP diff --git a/luaponte/detail/most_derived.hpp b/luaponte/detail/most_derived.hpp new file mode 100644 index 0000000..400df4d --- /dev/null +++ b/luaponte/detail/most_derived.hpp @@ -0,0 +1,35 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_MOST_DERIVED_HPP +#define LUAPONTE_DETAIL_MOST_DERIVED_HPP + +#include +#include + +namespace luaponte { +namespace detail { + +template +struct most_derived +{ + typedef typename boost::mpl::if_< + boost::is_base_and_derived + , WrappedClass + , Class + >::type type; +}; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_MOST_DERIVED_HPP diff --git a/luaponte/detail/object_call.hpp b/luaponte/detail/object_call.hpp new file mode 100644 index 0000000..83c9b5c --- /dev/null +++ b/luaponte/detail/object_call.hpp @@ -0,0 +1,41 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !BOOST_PP_IS_ITERATING +# error Do not include object_call.hpp directly! +#endif + +#include +#include +#include + +#define N BOOST_PP_ITERATION() + +template +call_proxy< + Derived + , boost::tuples::tuple< + BOOST_PP_ENUM_BINARY_PARAMS(N, A, const* BOOST_PP_INTERCEPT) + > +> operator()(BOOST_PP_ENUM_BINARY_PARAMS(N, A, const& a)) +{ + typedef boost::tuples::tuple< + BOOST_PP_ENUM_BINARY_PARAMS(N, A, const* BOOST_PP_INTERCEPT) + > arguments; + + return call_proxy( + derived() + , arguments(BOOST_PP_ENUM_PARAMS(N, &a)) + ); +} + +#undef N diff --git a/luaponte/detail/object_rep.hpp b/luaponte/detail/object_rep.hpp new file mode 100644 index 0000000..aa83ca9 --- /dev/null +++ b/luaponte/detail/object_rep.hpp @@ -0,0 +1,121 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_OBJECT_REP_HPP +#define LUAPONTE_DETAIL_OBJECT_REP_HPP + +#include +#include +#include +#include +#include + +namespace luaponte { +namespace detail { + +void finalize(lua_State* L, class_rep* crep); + +// this class is allocated inside lua for each pointer. +// it contains the actual c++ object-pointer. +// it also tells if it is const or not. +class LUAPONTE_API object_rep +{ +public: + object_rep(instance_holder* instance, class_rep* crep); + ~object_rep(); + + const class_rep* crep() const { return m_classrep; } + class_rep* crep() { return m_classrep; } + + void set_instance(instance_holder* instance) { m_instance = instance; } + + void add_dependency(lua_State* L, int index); + void release_dependency_refs(lua_State* L); + + std::pair get_instance(class_id target) const + { + if (m_instance == 0) + return std::pair((void*)0, -1); + return m_instance->get(m_classrep->casts(), target); + } + + bool is_const() const + { + return m_instance && m_instance->pointee_const(); + } + + void release() + { + if (m_instance) + m_instance->release(); + } + + void* allocate(std::size_t size) + { + if (size <= 32) + return &m_instance_buffer; + return std::malloc(size); + } + + void deallocate(void* storage) + { + if (storage == &m_instance_buffer) + return; + std::free(storage); + } + +private: + +object_rep(object_rep const&) +{} + +void operator=(object_rep const&) +{} + + instance_holder* m_instance; + boost::aligned_storage<32> m_instance_buffer; + class_rep* m_classrep; // the class information about this object's type + std::size_t m_dependency_cnt; // counts dependencies +}; + +template +struct delete_s +{ + static void apply(void* ptr) + { + delete static_cast(ptr); + } +}; + +template +struct destruct_only_s +{ + static void apply(void* ptr) + { + // Removes unreferenced formal parameter warning on VC7. + (void)ptr; +#ifndef NDEBUG + int completeness_check[sizeof(T)]; + (void)completeness_check; +#endif + static_cast(ptr)->~T(); + } +}; + +LUAPONTE_API object_rep* get_instance(lua_State* L, int index); +LUAPONTE_API void push_instance_metatable(lua_State* L); +LUAPONTE_API object_rep* push_new_instance(lua_State* L, class_rep* cls); + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_OBJECT_REP_HPP diff --git a/luaponte/detail/open.hpp b/luaponte/detail/open.hpp new file mode 100644 index 0000000..f79857a --- /dev/null +++ b/luaponte/detail/open.hpp @@ -0,0 +1,34 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_OPEN_HPP +#define LUAPONTE_DETAIL_OPEN_HPP + +#include + +namespace luaponte { +namespace detail { + +LUAPONTE_API void add_operator_to_metatable(lua_State* L, int op_index); +LUAPONTE_API int create_cpp_class_metatable(lua_State* L); +LUAPONTE_API int create_cpp_instance_metatable(lua_State* L); +LUAPONTE_API int create_lua_class_metatable(lua_State* L); +LUAPONTE_API int create_lua_instance_metatable(lua_State* L); +LUAPONTE_API int create_lua_function_metatable(lua_State* L); + +} // namespace detail + +LUAPONTE_API void open(lua_State* L); + +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_OPEN_HPP diff --git a/luaponte/detail/operator_id.hpp b/luaponte/detail/operator_id.hpp new file mode 100644 index 0000000..dcc2273 --- /dev/null +++ b/luaponte/detail/operator_id.hpp @@ -0,0 +1,69 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_OPERATOR_ID_HPP +#define LUAPONTE_DETAIL_OPERATOR_ID_HPP + +#include + +namespace luaponte { +namespace detail { + +enum operator_id +{ + op_add = 0, + op_sub, + op_mul, + op_div, + op_pow, + op_lt, + op_le, + op_eq, + op_call, + op_unm, + op_tostring, + op_concat, + op_len, + + number_of_operators +}; + +inline const char* get_operator_name(int i) +{ + static const char* a[number_of_operators] = { + "__add", "__sub", "__mul", "__div", "__pow", + "__lt", "__le", "__eq", "__call", "__unm", + "__tostring", "__concat", "__len" }; + return a[i]; +} + +inline const char* get_operator_symbol(int i) +{ + static const char* a[number_of_operators] = { + "+", "-", "*", "/", "^", "<", + "<=", "==", "()", "- (unary)", + "tostring", "..", "#" }; + return a[i]; +} + +inline bool is_unary(int i) +{ + // the reason why unary minus is not considered a unary operator here is + // that it always is given two parameters, where the second parameter always + // is nil. + return i == op_tostring; +} + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_OPERATOR_ID_HPP diff --git a/luaponte/detail/other.hpp b/luaponte/detail/other.hpp new file mode 100644 index 0000000..3fad876 --- /dev/null +++ b/luaponte/detail/other.hpp @@ -0,0 +1,115 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_OTHER_HPP +#define LUAPONTE_DETAIL_OTHER_HPP + +// header derived from source code found in Boost.Python + +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include +#include + +namespace luaponte { + + template + struct other + { + typedef T type; + }; + +} // namespace luaponte + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace luaponte { +namespace detail { + + template + class unwrap_other + { + public: + typedef T type; + }; + + template + class unwrap_other > + { + public: + typedef T type; + }; + +} // namespace detail +} // namespace luaponte + +# else // no partial specialization + +#include + +namespace luaponte { +namespace detail { + + typedef char (&yes_other_t)[1]; + typedef char (&no_other_t)[2]; + + no_other_t is_other_test(...); + + template + yes_other_t is_other_test(type_< other >); + + template + struct other_unwrapper + { + template + struct apply + { + typedef T type; + }; + }; + + template<> + struct other_unwrapper + { + template + struct apply + { + typedef typename T::type type; + }; + }; + + template + class is_other + { + public: + BOOST_STATIC_CONSTANT( + bool, value = ( + sizeof(detail::is_other_test(type_())) + == sizeof(detail::yes_other_t))); + }; + + template + class unwrap_other + : public detail::other_unwrapper< + is_other::value + >::template apply + {}; + +} // namespace detail +} // namespace luaponte + +#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +#endif // LUAPONTE_DETAIL_OTHER_HPP diff --git a/luaponte/detail/pcall.hpp b/luaponte/detail/pcall.hpp new file mode 100644 index 0000000..71a062e --- /dev/null +++ b/luaponte/detail/pcall.hpp @@ -0,0 +1,29 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_PCALL_HPP +#define LUAPONTE_DETAIL_PCALL_HPP + +#include + +struct lua_State; + +namespace luaponte { +namespace detail { + +LUAPONTE_API int pcall(lua_State *L, int nargs, int nresults); +LUAPONTE_API int resume_impl(lua_State *L, int nargs, int nresults); + +} // namespace detail +} // namespace luaponte + +#endif diff --git a/luaponte/detail/pointee_sizeof.hpp b/luaponte/detail/pointee_sizeof.hpp new file mode 100644 index 0000000..ff891da --- /dev/null +++ b/luaponte/detail/pointee_sizeof.hpp @@ -0,0 +1,42 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_POINTEE_SIZEOF_HPP +#define LUAPONTE_DETAIL_POINTEE_SIZEOF_HPP + +#include + +namespace luaponte { +namespace detail { + +template T& deref_type(T(*)(), int); +template T& deref_type(T*(*)(), long); + +} // namespace detail + +// returns the indirect sizeof U, as in +// sizeof(T*) = sizeof(T) +// sizeof(T&) = sizeof(T) +// sizeof(T) = sizeof(T) +template +struct pointee_sizeof +{ + BOOST_STATIC_CONSTANT(int, value = ( + sizeof(detail::deref_type((T(*)())0), 0L) + )); + + typedef boost::mpl::int_ type; +}; + +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_POINTEE_SIZEOF_HPP diff --git a/luaponte/detail/pointee_typeid.hpp b/luaponte/detail/pointee_typeid.hpp new file mode 100644 index 0000000..a762c5e --- /dev/null +++ b/luaponte/detail/pointee_typeid.hpp @@ -0,0 +1,31 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_POINTEE_TYPEID_HPP +#define LUAPONTE_POINTEE_TYPEID_HPP + +#include +#include + +namespace luaponte { +namespace detail { + +template +type_id pointee_typeid(T*) +{ + return typeid(T); +} + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_POINTEE_TYPEID_HPP diff --git a/luaponte/detail/policy.hpp b/luaponte/detail/policy.hpp new file mode 100644 index 0000000..ef3832b --- /dev/null +++ b/luaponte/detail/policy.hpp @@ -0,0 +1,1326 @@ +// Luaponte library + +// Copyright (c) 2011-2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_POLICY_HPP +#define LUAPONTE_DETAIL_POLICY_HPP + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#if LUA_VERSION_NUM < 502 +# define lua_rawlen lua_objlen +#endif + +namespace luaponte { + namespace detail + { + struct conversion_policy_base {}; + } + + template + struct conversion_policy : detail::conversion_policy_base + { + BOOST_STATIC_CONSTANT(int, index = N); + BOOST_STATIC_CONSTANT(bool, has_arg = HasArg); + }; + + class index_map + { + public: + index_map(const int* m): m_map(m) {} + + int operator[](int index) const + { + return m_map[index]; + } + + private: + const int* m_map; + }; + +// template class functor; + class weak_ref; +} + +namespace luaponte { +namespace detail { + template + struct policy_cons + { + typedef H head; + typedef T tail; + + template + policy_cons > operator,(policy_cons) + { + return policy_cons >(); + } + + template + policy_cons > operator+(policy_cons) + { + return policy_cons >(); + } + + template + policy_cons > operator|(policy_cons) + { + return policy_cons >(); + } + }; + + struct indirection_layer + { + template + indirection_layer(const T&); + }; + + yes_t is_policy_cons_test(const null_type&); + template + yes_t is_policy_cons_test(const policy_cons&); + no_t is_policy_cons_test(...); + + template + struct is_policy_cons + { + static const T& t; + + BOOST_STATIC_CONSTANT(bool, value = + sizeof(is_policy_cons_test(t)) == sizeof(yes_t)); + + typedef boost::mpl::bool_ type; + }; + + template + struct is_string_literal + { + static no_t helper(indirection_layer); + static yes_t helper(const char*); + }; + + template<> + struct is_string_literal + { + static no_t helper(indirection_layer); + }; + + + namespace mpl = boost::mpl; + + template + typename std::enable_if::value, void>::type + make_pointee_instance(lua_State* L, T& x, Clone) + { + if (get_pointer(x)) + { + make_instance(L, std::move(x)); + } + else + { + lua_pushnil(L); + } + } + + template + typename std::enable_if::value, void>::type + make_pointee_instance(lua_State* L, T& x, mpl::true_) + { + std::unique_ptr ptr(new T(x)); + make_instance(L, std::move(ptr)); + } + + template + typename std::enable_if::value, void>::type + make_pointee_instance(lua_State* L, T& x, mpl::false_) + { + make_instance(L, &x); + } + +// ********** pointer converter *********** + + struct pointer_converter + { + typedef pointer_converter type; + typedef mpl::false_ is_native; + + pointer_converter() + : result(0) + {} + + void* result; + + int consumed_args(...) const + { + return 1; + } + + template + void apply(lua_State* L, T* ptr) + { + if (ptr == 0) + { + lua_pushnil(L); + return; + } + + if (luaponte::get_back_reference(L, ptr)) + return; + + make_instance(L, ptr); + } + + template + T* apply(lua_State*, by_pointer, int) + { + return static_cast(result); + } + + template + int match(lua_State* L, by_pointer, int index) + { + if (lua_isnil(L, index)) return 0; + object_rep* obj = get_instance(L, index); + if (obj == 0) return -1; + + if (obj->is_const()) + return -1; + + std::pair s = obj->get_instance(registered_class::id); + result = s.first; + return s.second; + } + + template + void converter_postcall(lua_State*, by_pointer, int) + {} + }; + +// ******* value converter ******* + + struct value_converter + { + typedef value_converter type; + typedef mpl::false_ is_native; + + int consumed_args(...) const + { + return 1; + } + + value_converter() + : result(0) + {} + + void* result; + + template + void apply(lua_State* L, T x) + { + if (luaponte::get_back_reference(L, x)) + return; + + make_pointee_instance(L, x, mpl::true_()); + } + + template + T apply(lua_State*, by_value, int) + { + return *static_cast(result); + } + + template + int match(lua_State* L, by_value, int index) + { + // special case if we get nil in, try to match the holder type + if (lua_isnil(L, index)) + return -1; + + object_rep* obj = get_instance(L, index); + if (obj == 0) return -1; + + std::pair s = obj->get_instance(registered_class::id); + result = s.first; + return s.second; + } + + template + void converter_postcall(lua_State*, T, int) {} + }; + +// ******* const pointer converter ******* + + struct const_pointer_converter + { + typedef const_pointer_converter type; + typedef mpl::false_ is_native; + + int consumed_args(...) const + { + return 1; + } + + const_pointer_converter() + : result(0) + {} + + void* result; + + template + void apply(lua_State* L, const T* ptr) + { + if (ptr == 0) + { + lua_pushnil(L); + return; + } + + if (luaponte::get_back_reference(L, ptr)) + return; + + make_instance(L, ptr); + } + + template + T const* apply(lua_State*, by_const_pointer, int) + { + return static_cast(result); + } + + template + int match(lua_State* L, by_const_pointer, int index) + { + if (lua_isnil(L, index)) return 0; + object_rep* obj = get_instance(L, index); + if (obj == 0) return -1; // if the type is not one of our own registered types, classify it as a non-match + std::pair s = obj->get_instance(registered_class::id); + if (s.second >= 0 && !obj->is_const()) + s.second += 10; + result = s.first; + return s.second; + } + + template + void converter_postcall(lua_State*, T, int) {} + }; + +// ******* reference converter ******* + + struct ref_converter : pointer_converter + { + typedef ref_converter type; + typedef mpl::false_ is_native; + + int consumed_args(...) const + { + return 1; + } + + template + void apply(lua_State* L, T& ref) + { + if (luaponte::get_back_reference(L, ref)) + return; + + make_pointee_instance(L, ref, mpl::false_()); + } + + template + T& apply(lua_State* L, by_reference, int index) + { + assert(!lua_isnil(L, index)); + return *pointer_converter::apply(L, by_pointer(), index); + } + + template + int match(lua_State* L, by_reference, int index) + { + object_rep* obj = get_instance(L, index); + if (obj == 0) return -1; + + if (obj->is_const()) + return -1; + + std::pair s = obj->get_instance(registered_class::id); + result = s.first; + return s.second; + } + + template + void converter_postcall(lua_State*, T, int) {} + }; + +// ******** const reference converter ********* + + struct const_ref_converter + { + typedef const_ref_converter type; + typedef mpl::false_ is_native; + + int consumed_args(...) const + { + return 1; + } + + const_ref_converter() + : result(0) + {} + + void* result; + + template + void apply(lua_State* L, T const& ref) + { + if (luaponte::get_back_reference(L, ref)) + return; + + make_pointee_instance(L, ref, mpl::false_()); + } + + template + T const& apply(lua_State*, by_const_reference, int) + { + return *static_cast(result); + } + + template + int match(lua_State* L, by_const_reference, int index) + { + object_rep* obj = get_instance(L, index); + if (obj == 0) return -1; // if the type is not one of our own registered types, classify it as a non-match + + std::pair s = obj->get_instance(registered_class::id); + if (s.second >= 0 && !obj->is_const()) + s.second += 10; + result = s.first; + return s.second; + } + + template + void converter_postcall(lua_State*, by_const_reference, int) + { + } + }; + + // ****** enum converter ******** + + struct enum_converter + { + typedef enum_converter type; + typedef mpl::true_ is_native; + + int consumed_args(...) const + { + return 1; + } + + void apply(lua_State* L, int val) + { + lua_pushnumber(L, val); + } + + template + T apply(lua_State* L, by_value, int index) + { + return static_cast(static_cast(lua_tonumber(L, index))); + } + + template + static int match(lua_State* L, by_value, int index) + { + if (lua_isnumber(L, index)) return 0; else return -1; + } + + template + T apply(lua_State* L, by_const_reference, int index) + { + return static_cast(static_cast(lua_tonumber(L, index))); + } + + template + static int match(lua_State* L, by_const_reference, int index) + { + if (lua_isnumber(L, index)) return 0; else return -1; + } + + template + void converter_postcall(lua_State*, T, int) {} + }; + + template + struct value_wrapper_converter + { + typedef value_wrapper_converter type; + typedef mpl::true_ is_native; + + int consumed_args(...) const + { + return 1; + } + + template + T apply(lua_State* L, by_const_reference, int index) + { + return T(from_stack(L, index)); + } + + template + T apply(lua_State* L, by_value, int index) + { + return apply(L, by_const_reference(), index); + } + + template + static int match(lua_State* L, by_const_reference, int index) + { + return value_wrapper_traits::check(L, index) + ? (std::numeric_limits::max)() / LUAPONTE_MAX_ARITY + : -1; + } + + template + static int match(lua_State* L, by_value, int index) + { + return match(L, by_const_reference(), index); + } + + void converter_postcall(...) {} + + template + void apply(lua_State* interpreter, T const& value_wrapper) + { + value_wrapper_traits::unwrap(interpreter, value_wrapper); + } + }; + + template + struct default_converter_generator + : mpl::eval_if< + is_value_wrapper_arg + , value_wrapper_converter + , mpl::eval_if< + boost::is_enum::type> + , enum_converter + , mpl::eval_if< + is_nonconst_pointer + , pointer_converter + , mpl::eval_if< + is_const_pointer + , const_pointer_converter + , mpl::eval_if< + is_nonconst_reference + , ref_converter + , mpl::eval_if< + is_const_reference + , const_ref_converter + , value_converter + > + > + > + > + > + > + {}; + +} // namespace detail + +// *********** default_policy ***************** + +template +struct default_converter + : detail::default_converter_generator::type +{}; + +template > +struct native_converter_base +{ + typedef boost::mpl::true_ is_native; + + int consumed_args(...) const + { + return 1; + } + + template + void converter_postcall(lua_State*, U const&, int) + {} + + int match(lua_State* L, detail::by_value, int index) + { + return derived().compute_score(L, index); + } + + int match(lua_State* L, detail::by_value, int index) + { + return derived().compute_score(L, index); + } + + int match(lua_State* L, detail::by_const_reference, int index) + { + return derived().compute_score(L, index); + } + + T apply(lua_State* L, detail::by_value, int index) + { + return derived().from(L, index); + } + + T apply(lua_State* L, detail::by_value, int index) + { + return derived().from(L, index); + } + + T apply(lua_State* L, detail::by_const_reference, int index) + { + return derived().from(L, index); + } + + void apply(lua_State* L, T const& value) + { + derived().to(L, value); + } + + Derived& derived() + { + return static_cast(*this); + } +}; + +namespace detail { + +#ifndef LUAPONTE_NO_EXACT_INTEGER_CONVERSION +template +inline T checked_narrowing_cast(lua_State* L, S const& value) +{ + T result = static_cast(value); + if (static_cast(result) != value) { + lua_pushliteral(L, "value not exactly representable in target type"); + throw error(L); + } + return result; +} +#endif + +template +struct integer_number_converter + : native_converter_base +{ + int compute_score(lua_State* L, int index) + { + return lua_isnumber(L, index) ? 0 : -1; + }; + + T from(lua_State* L, int index) + { +#ifndef LUAPONTE_NO_EXACT_INTEGER_CONVERSION + return checked_narrowing_cast(L, lua_tonumber(L, index)); +#else + return static_cast(lua_tonumber(L, index)); +#endif + } + + void to(lua_State* L, T const& value) + { +#ifndef LUAPONTE_NO_EXACT_INTEGER_CONVERSION + lua_pushnumber(L, checked_narrowing_cast(L, value)); +#else + lua_pushnumber(L, static_cast(value)); +#endif + } +}; + +template +struct floating_point_number_converter + : native_converter_base +{ + int compute_score(lua_State* L, int index) + { + return lua_isnumber(L, index) ? 0 : -1; + }; + + T from(lua_State* L, int index) + { + return static_cast(lua_tonumber(L, index)); + } + + void to(lua_State* L, T const& value) + { + lua_pushnumber(L, static_cast(value)); + } +}; + +} // namespace detail + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::integer_number_converter +{}; + +template <> +struct default_converter + : detail::floating_point_number_converter +{}; + +template <> +struct default_converter + : detail::floating_point_number_converter +{}; + +template <> +struct default_converter + : detail::floating_point_number_converter +{}; + +template <> +struct default_converter + : detail::floating_point_number_converter +{}; + +template <> +struct default_converter + : detail::floating_point_number_converter +{}; + +template <> +struct default_converter + : detail::floating_point_number_converter +{}; + +template <> +struct default_converter + : detail::floating_point_number_converter +{}; + +template <> +struct default_converter + : detail::floating_point_number_converter +{}; + +template <> +struct default_converter + : detail::floating_point_number_converter +{}; + +template <> +struct default_converter + : detail::floating_point_number_converter +{}; + +template <> +struct default_converter + : detail::floating_point_number_converter +{}; + +template <> +struct default_converter + : detail::floating_point_number_converter +{}; + +template <> +struct default_converter + : native_converter_base +{ + static int compute_score(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TBOOLEAN ? 0 : -1; + } + + bool from(lua_State* L, int index) + { + return lua_toboolean(L, index) == 1; + } + + void to(lua_State* L, bool value) + { + lua_pushboolean(L, value); + } +}; + +template <> +struct default_converter + : default_converter +{}; + +template <> +struct default_converter + : default_converter +{}; + +#ifdef BOOST_HAS_RVALUE_REFS +template <> +struct default_converter + : default_converter +{}; +#endif + +template <> +struct default_converter + : native_converter_base +{ + static int compute_score(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TSTRING ? 0 : -1; + } + + std::string from(lua_State* L, int index) + { + return std::string(lua_tostring(L, index), lua_rawlen(L, index)); + } + + void to(lua_State* L, std::string const& value) + { + lua_pushlstring(L, value.data(), value.size()); + } +}; + +template <> +struct default_converter + : default_converter +{}; + +template <> +struct default_converter + : default_converter +{}; + +#ifdef BOOST_HAS_RVALUE_REFS +template <> +struct default_converter + : default_converter +{}; +#endif + +template <> +struct default_converter +{ + typedef boost::mpl::true_ is_native; + + int consumed_args(...) const + { + return 1; + } + + template + static int match(lua_State* L, U, int index) + { + int type = lua_type(L, index); + return (type == LUA_TSTRING || type == LUA_TNIL) ? 0 : -1; + } + + template + char const* apply(lua_State* L, U, int index) + { + return lua_tostring(L, index); + } + + void apply(lua_State* L, char const* str) + { + lua_pushstring(L, str); + } + + template + void converter_postcall(lua_State*, U, int) + {} +}; + +template <> +struct default_converter + : default_converter +{}; + +template <> +struct default_converter + : default_converter +{}; + +template +struct default_converter + : default_converter +{}; + +template +struct default_converter + : default_converter +{}; + +template <> +struct default_converter +{ + int consumed_args(...) const + { + return 0; + } + + template + lua_State* apply(lua_State* L, U, int) + { + return L; + } + + template + static int match(lua_State*, U, int) + { + return 0; + } + + template + void converter_postcall(lua_State*, U, int) {} +}; + +namespace detail { + + struct default_policy : converter_policy_tag + { + BOOST_STATIC_CONSTANT(bool, has_arg = true); + + template + static void precall(lua_State*, T, int) {} + + template + struct apply + { + typedef default_converter type; + }; + }; + + template + struct is_primitive + : default_converter::is_native + {}; + +// ============== new policy system ================= + + template struct find_conversion_policy; + + template + struct find_conversion_impl + { + template + struct apply + { + typedef typename find_conversion_policy::type type; + }; + }; + + template<> + struct find_conversion_impl + { + template + struct apply + { + typedef typename Policies::head head; + typedef typename Policies::tail tail; + + BOOST_STATIC_CONSTANT(bool, found = (N == head::index)); + + typedef typename + boost::mpl::if_c::type + >::type type; + }; + }; + + template + struct find_conversion_impl2 + { + template + struct apply + : find_conversion_impl< + boost::is_base_and_derived::value + >::template apply + { + }; + }; + + template<> + struct find_conversion_impl2 + { + template + struct apply + { + typedef default_policy type; + }; + }; + + template + struct find_conversion_policy : find_conversion_impl2::template apply + { + }; + + template + struct policy_list_postcall + { + typedef typename List::head head; + typedef typename List::tail tail; + + static void apply(lua_State* L, const index_map& i) + { + head::postcall(L, i); + policy_list_postcall::apply(L, i); + } + }; + + template<> + struct policy_list_postcall + { + static void apply(lua_State*, const index_map&) {} + }; + +// ================================================== + +// ************** precall and postcall on policy_cons ********************* + + + template + struct policy_precall + { + typedef typename List::head head; + typedef typename List::tail tail; + + static void apply(lua_State* L, int index) + { + head::precall(L, index); + policy_precall::apply(L, index); + } + }; + + template<> + struct policy_precall + { + static void apply(lua_State*, int) {} + }; + + template + struct policy_postcall + { + typedef typename List::head head; + typedef typename List::tail tail; + + static void apply(lua_State* L, int index) + { + head::postcall(L, index); + policy_postcall::apply(L, index); + } + }; + + template<> + struct policy_postcall + { + static void apply(lua_State*, int) {} + }; + + template + struct has_policy + : mpl::if_< + boost::is_same + , mpl::true_ + , has_policy + >::type + {}; + + template + struct has_policy + : mpl::false_ + {}; + +} // namespace detail +} // namespace luaponte + + +namespace luaponte { namespace +{ +#if defined(__GNUC__) && ( \ + (BOOST_VERSION < 103500) \ + || (BOOST_VERSION < 103900 && (__GNUC__ * 100 + __GNUC_MINOR__ <= 400)) \ + || (__GNUC__ * 100 + __GNUC_MINOR__ < 400)) + static inline boost::arg<0> return_value() + { + return boost::arg<0>(); + } + + static inline boost::arg<0> result() + { + return boost::arg<0>(); + } +# define LUAPONTE_PLACEHOLDER_ARG(N) boost::arg(*)() +#elif defined(BOOST_MSVC) || defined(__MWERKS__) \ + || (BOOST_VERSION >= 103900 && defined(__GNUC__) \ + && (__GNUC__ * 100 + __GNUC_MINOR__ == 400)) + static boost::arg<0> return_value; + static boost::arg<0> result; +# define LUAPONTE_PLACEHOLDER_ARG(N) boost::arg +#else + boost::arg<0> return_value; + boost::arg<0> result; +# define LUAPONTE_PLACEHOLDER_ARG(N) boost::arg +#endif +}} + +#if LUA_VERSION_NUM < 502 +# undef lua_rawlen +#endif + +#endif // LUAPONTE_DETAIL_POLICY_HPP diff --git a/luaponte/detail/primitives.hpp b/luaponte/detail/primitives.hpp new file mode 100644 index 0000000..314be93 --- /dev/null +++ b/luaponte/detail/primitives.hpp @@ -0,0 +1,73 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_PRIMITIVES_HPP +#define LUAPONTE_DETAIL_PRIMITIVES_HPP + +#include +#include + +#include +#include + +namespace luaponte { +namespace detail { + +template +struct identity +{ + typedef T type; +}; + +template +struct type_ {}; + +struct null_type {}; + +struct lua_to_cpp {}; +struct cpp_to_lua {}; + +template struct by_value {}; +template struct by_reference {}; +template struct by_const_reference {}; +template struct by_pointer {}; +template struct by_const_pointer {}; + +struct converter_policy_tag {}; + +struct ltstr +{ + bool operator()(const char* s1, const char* s2) const { return std::strcmp(s1, s2) < 0; } +}; + +template +struct aligned +{ + char storage[N]; +}; + +// returns the offset added to a Derived* when cast to a Base* +// TODO: return ptrdiff +template +int ptr_offset(type_, type_) +{ + aligned obj; + Derived* ptr = reinterpret_cast(&obj); + + return int(static_cast(static_cast(static_cast(ptr))) + - static_cast(static_cast(ptr))); +} + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_PRIMITIVES_HPP diff --git a/luaponte/detail/property.hpp b/luaponte/detail/property.hpp new file mode 100644 index 0000000..0b93c6b --- /dev/null +++ b/luaponte/detail/property.hpp @@ -0,0 +1,42 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_PROPERTY_HPP +#define LUAPONTE_DETAIL_PROPERTY_HPP + +namespace luaponte { +namespace detail { + +template +struct access_member_ptr +{ + access_member_ptr(T Class::* mem_ptr) + : mem_ptr(mem_ptr) + {} + + Result operator()(Class const& x) const + { + return const_cast(x).*mem_ptr; + } + + void operator()(Class& x, T const& value) const + { + x.*mem_ptr = value; + } + + T Class::* mem_ptr; +}; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_PROPERTY_HPP diff --git a/luaponte/detail/ref.hpp b/luaponte/detail/ref.hpp new file mode 100644 index 0000000..d517bcf --- /dev/null +++ b/luaponte/detail/ref.hpp @@ -0,0 +1,98 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_REF_HPP +#define LUAPONTE_DETAIL_REF_HPP + +#include +#include + +#include +#include + +namespace luaponte { +namespace detail { + +struct lua_reference +{ + lua_reference(lua_State* L_ = 0) + : L(L_) + , m_ref(LUA_NOREF) + {} + lua_reference(lua_reference const& r) + : L(r.L) + , m_ref(LUA_NOREF) + { + if (!r.is_valid()) return; + r.get(L); + set(L); + } + ~lua_reference() { reset(); } + + lua_State* state() const { return L; } + + void operator=(lua_reference const& r) + { + // TODO: self assignment problems + reset(); + if (!r.is_valid()) return; + r.get(r.state()); + set(r.state()); + } + + bool is_valid() const + { return m_ref != LUA_NOREF; } + + void set(lua_State* L_) + { + reset(); + L = L_; + m_ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + + void replace(lua_State* L_) + { + lua_rawseti(L_, LUA_REGISTRYINDEX, m_ref); + } + + // L may not be the same pointer as + // was used when creating this reference + // since it may be a thread that shares + // the same globals table. + void get(lua_State* L_) const + { + assert(m_ref != LUA_NOREF); + assert(L_); + lua_rawgeti(L_, LUA_REGISTRYINDEX, m_ref); + } + + void reset() + { + if (L && m_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, m_ref); + m_ref = LUA_NOREF; + } + + void swap(lua_reference& r) + { + assert(r.L == L); + std::swap(r.m_ref, m_ref); + } + +private: + lua_State* L; + int m_ref; +}; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_REF_HPP diff --git a/luaponte/detail/signature_match.hpp b/luaponte/detail/signature_match.hpp new file mode 100644 index 0000000..87bca9c --- /dev/null +++ b/luaponte/detail/signature_match.hpp @@ -0,0 +1,50 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_SIGNATURE_MATCH_HPP +#define LUAPONTE_DETAIL_SIGNATURE_MATCH_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace luaponte { + +namespace adl { + +class argument; + +} // namespace adl + +template +struct constructor +{ + typedef BOOST_PP_CAT( + boost::mpl::vector, BOOST_PP_INC(BOOST_PP_INC(LUAPONTE_MAX_ARITY)))< + void, argument const&, BOOST_PP_ENUM_PARAMS(LUAPONTE_MAX_ARITY, A) + > signature0; + + typedef typename boost::mpl::remove< + signature0, detail::null_type>::type signature; +}; + +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_SIGNATURE_MATCH_HPP diff --git a/luaponte/detail/stack_utils.hpp b/luaponte/detail/stack_utils.hpp new file mode 100644 index 0000000..e256a97 --- /dev/null +++ b/luaponte/detail/stack_utils.hpp @@ -0,0 +1,43 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_STACK_UTILS_HPP +#define LUAPONTE_DETAIL_STACK_UTILS_HPP + +#include + +namespace luaponte { +namespace detail { + +struct stack_pop +{ + stack_pop(lua_State* L, int n) + : m_state(L) + , m_n(n) + { + } + + ~stack_pop() + { + lua_pop(m_state, m_n); + } + +private: + + lua_State* m_state; + int m_n; +}; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_STACK_UTILS_HPP diff --git a/luaponte/detail/typetraits.hpp b/luaponte/detail/typetraits.hpp new file mode 100644 index 0000000..efadaa7 --- /dev/null +++ b/luaponte/detail/typetraits.hpp @@ -0,0 +1,192 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_TYPETRAITS_HPP +#define LUAPONTE_DETAIL_TYPETRAITS_HPP + +#include +#include +#include +#include +#include + +namespace luaponte { +namespace detail { + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + + template + struct is_const_type + { + typedef typename boost::mpl::if_ + , yes_t + , no_t + >::type type; + }; + + template + struct is_const_reference_helper + { + template + struct apply + { + enum + { + value = false + }; + }; + }; + + template + typename is_const_type::type is_const_reference_tester(T&); + no_t is_const_reference_tester(...); + + template<> + struct is_const_reference_helper + { + template + struct apply + { + static T getT(); + + enum + { + value = sizeof(is_const_reference_tester(getT())) == sizeof(yes_t) + }; + }; + }; + + template + struct is_const_reference + : is_const_reference_helper::value>::template apply + { + typedef boost::mpl::bool_ type; + }; + + template + struct is_nonconst_reference + { + enum + { + value = boost::is_reference::value && !is_const_reference::value + }; + typedef boost::mpl::bool_ type; + }; + +#else + + template + struct is_const_reference + { + enum { value = false }; + typedef boost::mpl::bool_ type; + }; + + template + struct is_const_reference + { + enum { value = true }; + typedef boost::mpl::bool_ type; + }; + + template + struct is_nonconst_reference + { + enum { value = false }; + typedef boost::mpl::bool_ type; + }; + + template + struct is_nonconst_reference + { + enum { value = !is_const_reference::value }; + typedef boost::mpl::bool_ type; + }; + +#endif + + template + yes_t is_const_pointer_helper(void(*)(const A*)); + no_t is_const_pointer_helper(...); + + template + struct is_const_pointer + { + enum { value = sizeof(is_const_pointer_helper((void(*)(T))0)) == sizeof(yes_t) }; + typedef boost::mpl::bool_ type; + }; + + template + yes_t is_nonconst_pointer_helper(void(*)(A*)); + no_t is_nonconst_pointer_helper(...); + + template + struct is_nonconst_pointer + { + enum { value = sizeof(is_nonconst_pointer_helper((void(*)(T))0)) == sizeof(yes_t) && !is_const_pointer::value }; + typedef boost::mpl::bool_ type; + }; +/* + template + struct is_constructable_from_helper + { + static yes_t check(const T&); + static no_t check(...); + }; + + template + struct is_constructable_from + { + static From getFrom(); + + enum + { + value = sizeof(is_constructable_from_helper::check(getFrom())) == sizeof(yes_t) + }; + }; + + template + struct is_const_member_function_helper + { + static no_t test(...); + template + static yes_t test(R(T::*)() const); + template + static yes_t test(R(T::*)(A1) const); + template + static yes_t test(R(T::*)(A1,A2) const); + template + static yes_t test(R(T::*)(A1,A2,A3) const); + }; + + template + struct is_const_member_function + { + static U getU(); + + enum + { + value = sizeof(is_const_member_function_helper::test(getU())) == sizeof(yes_t) + }; + }; +*/ + + template + struct max_c + { + enum { value = (v1>v2)?v1:v2 }; + }; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_TYPETRAITS_HPP diff --git a/luaponte/detail/yes_no.hpp b/luaponte/detail/yes_no.hpp new file mode 100644 index 0000000..176d90c --- /dev/null +++ b/luaponte/detail/yes_no.hpp @@ -0,0 +1,25 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DETAIL_YES_NO_HPP +#define LUAPONTE_DETAIL_YES_NO_HPP + +namespace luaponte { +namespace detail { + +typedef char(&yes_t)[1]; +typedef char(&no_t)[2]; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DETAIL_YES_NO_HPP diff --git a/luaponte/discard_result_policy.hpp b/luaponte/discard_result_policy.hpp new file mode 100644 index 0000000..6e5b420 --- /dev/null +++ b/luaponte/discard_result_policy.hpp @@ -0,0 +1,63 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_DISCARD_RESULT_POLICY_HPP +#define LUAPONTE_DISCARD_RESULT_POLICY_HPP + +#include +#include + +namespace luaponte { +namespace detail { + +struct discard_converter +{ + template + void apply(lua_State*, T) {} +}; + +struct discard_result_policy : conversion_policy<0> +{ + static void precall(lua_State*, const index_map&) {} + static void postcall(lua_State*, const index_map&) {} + + struct can_only_convert_from_cpp_to_lua {}; + + template + struct apply + { + typedef typename boost::mpl::if_ + , discard_converter + , can_only_convert_from_cpp_to_lua + >::type type; + }; +}; + +} // namespace detail +} // namespace luaponte + +namespace luaponte { + +detail::policy_cons< + detail::discard_result_policy, detail::null_type> const discard_result = {}; + +namespace detail { + +inline void ignore_unused_discard_result() +{ + (void)discard_result; +} + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_DISCARD_RESULT_POLICY_HPP diff --git a/luaponte/error.hpp b/luaponte/error.hpp new file mode 100644 index 0000000..59dcd46 --- /dev/null +++ b/luaponte/error.hpp @@ -0,0 +1,81 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_ERROR_HPP +#define LUAPONTE_ERROR_HPP + +#include +#include +#include +#include + +struct lua_State; + +namespace luaponte { + +#ifndef LUAPONTE_NO_EXCEPTIONS + +// this exception usually means that the lua function you called +// from C++ failed with an error code. You will have to +// read the error code from the top of the lua stack +// the reason why this exception class doesn't contain +// the message itself is that std::string's copy constructor +// may throw, if the copy constructor of an exception that is +// being thrown throws another exception, terminate will be called +// and the entire application is killed. +class LUAPONTE_API error : public std::exception +{ +public: + explicit error(lua_State* L): m_L(L) {} + lua_State* state() const throw() { return m_L; } + virtual const char* what() const throw() + { + return "lua runtime error"; + } +private: + lua_State* m_L; +}; + +// if an object_cast<>() fails, this is thrown +// it is also thrown if the return value of +// a lua function cannot be converted +class LUAPONTE_API cast_failed : public std::exception +{ +public: + cast_failed(lua_State* L, type_id const& i): m_L(L), m_info(i) {} + lua_State* state() const throw() { return m_L; } + type_id info() const throw() { return m_info; } + virtual const char* what() const throw() { return "unable to make cast"; } +private: + lua_State* m_L; + type_id m_info; +}; + +#else + +typedef void(*error_callback_fun)(lua_State*); +typedef void(*cast_failed_callback_fun)(lua_State*, type_id const&); + +LUAPONTE_API void set_error_callback(error_callback_fun e); +LUAPONTE_API void set_cast_failed_callback(cast_failed_callback_fun c); +LUAPONTE_API error_callback_fun get_error_callback(); +LUAPONTE_API cast_failed_callback_fun get_cast_failed_callback(); + +#endif + +typedef int(*pcall_callback_fun)(lua_State*); +LUAPONTE_API void set_pcall_callback(pcall_callback_fun e); +LUAPONTE_API pcall_callback_fun get_pcall_callback(); + +} // namespace luaponte + +#endif // LUAPONTE_ERROR_HPP diff --git a/luaponte/exception_handler.hpp b/luaponte/exception_handler.hpp new file mode 100644 index 0000000..56104dd --- /dev/null +++ b/luaponte/exception_handler.hpp @@ -0,0 +1,116 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_EXCEPTION_HANDLER_HPP +# define LUAPONTE_EXCEPTION_HANDLER_HPP + +# include +# include +# include +# include + +# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) +# include +# include +# endif + +namespace luaponte { + +# ifndef LUAPONTE_NO_EXCEPTIONS + +namespace detail { + +struct LUAPONTE_API exception_handler_base +{ + exception_handler_base() + : next(0) + {} + + virtual ~exception_handler_base() {} + virtual void handle(lua_State*) const = 0; + + void try_next(lua_State*) const; + + exception_handler_base* next; +}; + +namespace mpl = boost::mpl; + +template +struct exception_handler : exception_handler_base +{ +# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + typedef typename mpl::if_< + boost::is_pointer, E, E const& + >::type argument; +# else + typedef E const& argument; +# endif + + exception_handler(Handler handler) + : handler(handler) + {} + + void handle(lua_State* L) const + { + try + { + try_next(L); + } + catch (argument e) + { + handler(L, e); + } + } + + Handler handler; +}; + +LUAPONTE_API void handle_exception_aux(lua_State* L); +LUAPONTE_API void register_exception_handler(exception_handler_base*); + +} // namespace detail + +# endif + +template +void register_exception_handler(Handler handler, boost::type* = 0) +{ +# ifndef LUAPONTE_NO_EXCEPTIONS + detail::register_exception_handler( + new detail::exception_handler(handler) + ); +# endif +} + +template +boost::optional handle_exceptions(lua_State* L, F fn, boost::type* = 0) +{ +# ifndef LUAPONTE_NO_EXCEPTIONS + try + { + return fn(); + } + catch (...) + { + detail::handle_exception_aux(L); + } + + return boost::optional(); +# else + return fn(); +# endif +} + +} // namespace luaponte + +#endif // LUAPONTE_EXCEPTION_HANDLER_HPP diff --git a/luaponte/from_stack.hpp b/luaponte/from_stack.hpp new file mode 100644 index 0000000..3fe7345 --- /dev/null +++ b/luaponte/from_stack.hpp @@ -0,0 +1,31 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_FROM_STACK_HPP +#define LUAPONTE_FROM_STACK_HPP + +namespace luaponte { + +struct from_stack +{ + from_stack(lua_State* interpreter, int index) + : interpreter(interpreter) + , index(index) + {} + + lua_State* interpreter; + int index; +}; + +} // namespace luaponte + +#endif // LUAPONTE_FROM_STACK_HPP diff --git a/luaponte/function.hpp b/luaponte/function.hpp new file mode 100644 index 0000000..285ac5f --- /dev/null +++ b/luaponte/function.hpp @@ -0,0 +1,69 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_FUNCTION_HPP +#define LUAPONTE_FUNCTION_HPP + +#include +#include +#include + +#include + +namespace luaponte { +namespace detail { + +template +struct function_registration : registration +{ + function_registration(char const* name, F f, Policies const& policies) + : name(name) + , f(f) + , policies(policies) + {} + + void register_(lua_State* L) const + { + object fn = make_function(L, f, deduce_signature(f), policies); + + add_overload( + object(from_stack(L, -1)) + , name + , fn + ); + } + + char const* name; + F f; + Policies policies; +}; + +LUAPONTE_API bool is_luabind_function(lua_State* L, int index); + +} // namespace detail + +template +scope def(char const* name, F f, Policies const& policies) +{ + return scope(std::unique_ptr( + new detail::function_registration(name, f, policies))); +} + +template +scope def(char const* name, F f) +{ + return def(name, f, detail::null_type()); +} + +} // namespace luaponte + +#endif // LUAPONTE_FUNCTION_HPP diff --git a/luaponte/get_main_thread.hpp b/luaponte/get_main_thread.hpp new file mode 100644 index 0000000..f5a6234 --- /dev/null +++ b/luaponte/get_main_thread.hpp @@ -0,0 +1,24 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_GET_MAIN_THREAD_HPP +#define LUAPONTE_GET_MAIN_THREAD_HPP + +#include + +namespace luaponte { + +LUAPONTE_API lua_State* get_main_thread(lua_State* L); + +} // namespace luaponte + +#endif // LUAPONTE_GET_MAIN_THREAD_HPP diff --git a/luaponte/get_pointer.hpp b/luaponte/get_pointer.hpp new file mode 100644 index 0000000..c6ca960 --- /dev/null +++ b/luaponte/get_pointer.hpp @@ -0,0 +1,41 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_GET_POINTER_HPP +#define LUAPONTE_GET_POINTER_HPP + +// +// We need these overloads in the luabind namespace. +// + +#include +#include + +namespace luaponte { + +using boost::get_pointer; + +template +T* get_pointer(std::shared_ptr const& ptr) +{ + return ptr.get(); +} + +template +T* get_pointer(std::unique_ptr const& ptr) +{ + return ptr.get(); +} + +} // namespace luaponte + +#endif // LUAPONTE_GET_POINTER_HPP diff --git a/luaponte/handle.hpp b/luaponte/handle.hpp new file mode 100644 index 0000000..1da1a3b --- /dev/null +++ b/luaponte/handle.hpp @@ -0,0 +1,133 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_HANDLE_HPP +#define LUAPONTE_HANDLE_HPP + +#include +#include + +namespace luaponte { + +// A reference to a Lua value. Represents an entry in the +// registry table. +class handle +{ +public: + handle(); + handle(lua_State* interpreter, int stack_index); + handle(lua_State* main, lua_State* interpreter, int stack_index); + handle(handle const& other); + ~handle() noexcept; + + handle& operator=(handle const& other); + void swap(handle& other); + + void push(lua_State* interpreter) const; + + lua_State* interpreter() const; + + void replace(lua_State* interpreter, int stack_index); + +private: + lua_State* m_interpreter; + int m_index; +}; + +inline handle::handle() + : m_interpreter(0) + , m_index(LUA_NOREF) +{} + +inline handle::handle(handle const& other) + : m_interpreter(other.m_interpreter) + , m_index(LUA_NOREF) +{ + if (m_interpreter == 0) return; + lua_rawgeti(m_interpreter, LUA_REGISTRYINDEX, other.m_index); + m_index = luaL_ref(m_interpreter, LUA_REGISTRYINDEX); +} + +inline handle::handle(lua_State* interpreter, int stack_index) + : m_interpreter(interpreter) + , m_index(LUA_NOREF) +{ + lua_pushvalue(interpreter, stack_index); + m_index = luaL_ref(interpreter, LUA_REGISTRYINDEX); +} + +inline handle::handle(lua_State* main, lua_State* interpreter, int stack_index) + : m_interpreter(main) + , m_index(LUA_NOREF) +{ + lua_pushvalue(interpreter, stack_index); + m_index = luaL_ref(interpreter, LUA_REGISTRYINDEX); +} + +inline handle::~handle() noexcept +{ + if (m_interpreter && m_index != LUA_NOREF) + luaL_unref(m_interpreter, LUA_REGISTRYINDEX, m_index); +} + +inline handle& handle::operator=(handle const& other) +{ + handle(other).swap(*this); + return *this; +} + +inline void handle::swap(handle& other) +{ + std::swap(m_interpreter, other.m_interpreter); + std::swap(m_index, other.m_index); +} + +inline void handle::push(lua_State* interpreter) const +{ + lua_rawgeti(interpreter, LUA_REGISTRYINDEX, m_index); +} + +inline lua_State* handle::interpreter() const +{ + return m_interpreter; +} + +inline void handle::replace(lua_State* interpreter, int stack_index) +{ + lua_pushvalue(interpreter, stack_index); + lua_rawseti(interpreter, LUA_REGISTRYINDEX, m_index); +} + +template<> +struct value_wrapper_traits +{ + typedef boost::mpl::true_ is_specialized; + + static lua_State* interpreter(handle const& value) + { + return value.interpreter(); + } + + static void unwrap(lua_State* interpreter, handle const& value) + { + value.push(interpreter); + } + + static bool check(...) + { + return true; + } +}; + +} // namespace luaponte + +#endif // LUAPONTE_HANDLE_HPP diff --git a/luaponte/iterator_policy.hpp b/luaponte/iterator_policy.hpp new file mode 100644 index 0000000..5e6fceb --- /dev/null +++ b/luaponte/iterator_policy.hpp @@ -0,0 +1,123 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_ITERATOR_POLICY_HPP +#define LUAPONTE_ITERATOR_POLICY_HPP + +#include +#include +#include + +namespace luaponte { +namespace detail { + +template +struct iterator +{ + static int next(lua_State* L) + { + iterator* self = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + + if (self->first != self->last) + { + convert_to_lua(L, *self->first); + ++self->first; + } + else + { + lua_pushnil(L); + } + + return 1; + } + + static int destroy(lua_State* L) + { + iterator* self = static_cast(lua_touserdata(L, 1)); + self->~iterator(); + return 0; + } + + iterator(Iterator first, Iterator last) + : first(first) + , last(last) + {} + + Iterator first; + Iterator last; +}; + +template +int make_range(lua_State* L, Iterator first, Iterator last) +{ + void* storage = lua_newuserdata(L, sizeof(iterator)); + lua_newtable(L); + lua_pushcclosure(L, iterator::destroy, 0); + lua_setfield(L, -2, "__gc"); + lua_setmetatable(L, -2); + lua_pushcclosure(L, iterator::next, 1); + new (storage) iterator(first, last); + return 1; +} + +template +int make_range(lua_State* L, Container& container) +{ + return make_range(L, container.begin(), container.end()); +} + +struct iterator_converter +{ + typedef iterator_converter type; + + template + void apply(lua_State* L, Container& container) + { + make_range(L, container); + } + + template + void apply(lua_State* L, Container const& container) + { + make_range(L, container); + } +}; + +struct iterator_policy : conversion_policy<0> +{ + static void precall(lua_State*, index_map const&) + {} + + static void postcall(lua_State*, index_map const&) + {} + + template + struct apply + { + typedef iterator_converter type; + }; +}; + +} // namespace detail +} // namespace luaponte + +namespace luaponte { +namespace { + +LUAPONTE_ANONYMOUS_FIX detail::policy_cons< + detail::iterator_policy, detail::null_type> return_stl_iterator; + +} // namespace +} // namespace luaponte + +#endif // LUAPONTE_ITERATOR_POLICY_HPP diff --git a/luaponte/lua_include.hpp b/luaponte/lua_include.hpp new file mode 100644 index 0000000..acb4ac7 --- /dev/null +++ b/luaponte/lua_include.hpp @@ -0,0 +1,28 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUA_INCLUDE_HPP +#define LUA_INCLUDE_HPP + +#ifndef LUAPONTE_CPLUSPLUS_LUA +extern "C" +{ +#endif + +#include "lua.h" +#include "lauxlib.h" + +#ifndef LUAPONTE_CPLUSPLUS_LUA +} +#endif + +#endif // LUA_INCLUDE_HPP diff --git a/luaponte/luaponte.hpp b/luaponte/luaponte.hpp new file mode 100644 index 0000000..3b7fe8a --- /dev/null +++ b/luaponte/luaponte.hpp @@ -0,0 +1,21 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_LUAPONTE_HPP +#define LUAPONTE_LUAPONTE_HPP + +#include +#include +#include +#include + +#endif // LUAPONTE_LUAPONTE_HPP diff --git a/luaponte/make_function.hpp b/luaponte/make_function.hpp new file mode 100644 index 0000000..9629afd --- /dev/null +++ b/luaponte/make_function.hpp @@ -0,0 +1,128 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_MAKE_FUNCTION_HPP +# define LUAPONTE_MAKE_FUNCTION_HPP + +# include +# include +# include +# include +# include + +namespace luaponte { +namespace detail { + +# ifndef LUAPONTE_NO_EXCEPTIONS +LUAPONTE_API void handle_exception_aux(lua_State* L); +# endif + +// MSVC complains about member being sensitive to alignment (C4121) +// when F is a pointer to member of a class with virtual bases. +# ifdef BOOST_MSVC +# pragma pack(push) +# pragma pack(16) +# endif + +template +struct function_object_impl : function_object +{ + function_object_impl(F f, Policies const& policies) + : function_object(&entry_point) + , f(f) + , policies(policies) + {} + + int call(lua_State* L, invoke_context& ctx) const + { + return invoke(L, *this, ctx, f, Signature(), policies); + } + + void format_signature(lua_State* L, char const* function) const + { + detail::format_signature(L, function, Signature()); + } + + static int entry_point(lua_State* L) + { + function_object_impl const* impl = + *(function_object_impl const**)lua_touserdata(L, lua_upvalueindex(1)); + + invoke_context ctx; + + int results = 0; + +# ifndef LUAPONTE_NO_EXCEPTIONS + bool exception_caught = false; + + try + { + results = invoke( + L, *impl, ctx, impl->f, Signature(), impl->policies); + } + catch (...) + { + exception_caught = true; + handle_exception_aux(L); + } + + if (exception_caught) + lua_error(L); +# else + results = invoke(L, *impl, ctx, impl->f, Signature(), impl->policies); +# endif + + if (!ctx) + { + ctx.format_error(L, impl); + lua_error(L); + } + + return results; + } + + F f; + Policies policies; +}; + +# ifdef BOOST_MSVC +# pragma pack(pop) +# endif + +LUAPONTE_API object make_function_aux( + lua_State* L, function_object* impl +); + +LUAPONTE_API void add_overload(object const&, char const*, object const&); + +} // namespace detail + +template +object make_function(lua_State* L, F f, Signature, Policies) +{ + return detail::make_function_aux( + L + , new detail::function_object_impl( + f, Policies() + ) + ); +} + +template +object make_function(lua_State* L, F f) +{ + return make_function(L, detail::deduce_signature(f), detail::null_type()); +} + +} // namespace luaponte + +#endif // LUAPONTE_MAKE_FUNCTION_HPP diff --git a/luaponte/nil.hpp b/luaponte/nil.hpp new file mode 100644 index 0000000..c4316a1 --- /dev/null +++ b/luaponte/nil.hpp @@ -0,0 +1,30 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_NIL_HPP +#define LUAPONTE_NIL_HPP + +#include + +namespace luaponte { +namespace detail { + +struct nil_type {}; + +} // namespace detail + +// defined in class.cpp +extern LUAPONTE_API detail::nil_type nil; + +} // namespace luaponte + +#endif diff --git a/luaponte/no_dependency.hpp b/luaponte/no_dependency.hpp new file mode 100644 index 0000000..1525519 --- /dev/null +++ b/luaponte/no_dependency.hpp @@ -0,0 +1,47 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_NO_DEPENDENCY_HPP +#define LUAPONTE_NO_DEPENDENCY_HPP + +#include + +namespace luaponte { +namespace detail { + +struct no_dependency_policy +{ + static void precall(lua_State*, index_map const&) + {} + + static void postcall(lua_State*, index_map const&) + {} +}; + +typedef policy_cons + no_dependency_node; + +} // namespace detail + +detail::no_dependency_node const no_dependency = {}; + +namespace detail { + +inline void ignore_unused_no_dependency() +{ + (void)no_dependency; +} + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_NO_DEPENDENCY_HPP diff --git a/luaponte/object.hpp b/luaponte/object.hpp new file mode 100644 index 0000000..90ac297 --- /dev/null +++ b/luaponte/object.hpp @@ -0,0 +1,1408 @@ +// Luaponte library + +// Copyright (c) 2011-2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_OBJECT_HPP +#define LUAPONTE_OBJECT_HPP + +#include // detail::push() +#include // detail::push() +#include // value_wrapper_traits specializations +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include // REFACTOR +#include + +#include // iterator + +#include +#include + +#if LUA_VERSION_NUM < 502 +# define lua_compare(L, index1, index2, fn) fn(L, index1, index2) +# define LUA_OPEQ lua_equal +# define LUA_OPLT lua_lessthan +# define lua_rawlen lua_objlen +# define lua_pushglobaltable(L) lua_pushvalue(L, LUA_GLOBALSINDEX) +#endif + +namespace luaponte { +namespace detail { + + namespace mpl = boost::mpl; + + template + void push_aux(lua_State* interpreter, T& value, ConverterGenerator*) + { + typedef typename boost::mpl::if_< + boost::is_reference_wrapper + , BOOST_DEDUCED_TYPENAME boost::unwrap_reference::type& + , T + >::type unwrapped_type; + + typename mpl::apply_wrap2< + ConverterGenerator,unwrapped_type,cpp_to_lua + >::type cv; + + cv.apply( + interpreter + , boost::implicit_cast< + BOOST_DEDUCED_TYPENAME boost::unwrap_reference::type& + >(value) + ); + } + + template + void push(lua_State* interpreter, T& value, Policies const&) + { + typedef typename find_conversion_policy< + 0 + , Policies + >::type converter_policy; + + push_aux(interpreter, value, (converter_policy*)0); + } + + template + void push(lua_State* interpreter, T& value) + { + push(interpreter, value, null_type()); + } + +} // namespace detail + +namespace adl +{ + namespace mpl = boost::mpl; + + template + class object_interface; + + namespace is_object_interface_aux + { + typedef char (&yes)[1]; + typedef char (&no)[2]; + + template + yes check(object_interface*); + no check(void*); + + template + struct impl + { + BOOST_STATIC_CONSTANT(bool, value = + sizeof(is_object_interface_aux::check((T*)0)) == sizeof(yes) + ); + + typedef mpl::bool_ type; + }; + + } // namespace detail + + template + struct is_object_interface + : is_object_interface_aux::impl::type + {}; + + template + struct enable_binary +# ifndef BOOST_NO_SFINAE + : boost::enable_if< + mpl::or_< + is_object_interface + , is_object_interface + > + , R + > + {}; +# else + { + typedef R type; + }; +# endif + + template + int binary_interpreter(lua_State*& L, T const& lhs, U const& rhs + , boost::mpl::true_, boost::mpl::true_) + { + L = value_wrapper_traits::interpreter(lhs); + lua_State* L2 = value_wrapper_traits::interpreter(rhs); + + // you are comparing objects with different interpreters + // that's not allowed. + assert(L == L2 || L == 0 || L2 == 0); + + // if the two objects we compare have different interpreters + // then they + + if (L != L2) return -1; + if (L == 0) return 1; + return 0; + } + + template + int binary_interpreter(lua_State*& L, T const& x, U const& + , boost::mpl::true_, boost::mpl::false_) + { + L = value_wrapper_traits::interpreter(x); + return 0; + } + + template + int binary_interpreter(lua_State*& L, T const&, U const& x, boost::mpl::false_, boost::mpl::true_) + { + L = value_wrapper_traits::interpreter(x); + return 0; + } + + template + int binary_interpreter(lua_State*& L, T const& x, U const& y) + { + return binary_interpreter( + L + , x + , y + , is_value_wrapper() + , is_value_wrapper() + ); + } + +#define LUAPONTE_BINARY_OP_DEF(op, fn) \ + template \ + typename enable_binary::type \ + operator op(LHS const& lhs, RHS const& rhs) \ + { \ + lua_State* L = 0; \ + switch (binary_interpreter(L, lhs, rhs)) \ + { \ + case 1: \ + return true; \ + case -1: \ + return false; \ + } \ +\ + assert(L); \ +\ + detail::stack_pop pop1(L, 1); \ + detail::push(L, lhs); \ + detail::stack_pop pop2(L, 1); \ + detail::push(L, rhs); \ +\ + return lua_compare(L, -1, -2, fn) != 0; \ + } + +LUAPONTE_BINARY_OP_DEF(==, LUA_OPEQ) +LUAPONTE_BINARY_OP_DEF(<, LUA_OPLT) + + template + std::ostream& operator<<(std::ostream& os + , object_interface const& v) + { + using namespace luaponte; + lua_State* interpreter = value_wrapper_traits::interpreter( + static_cast(v)); + detail::stack_pop pop(interpreter, 1); + value_wrapper_traits::unwrap(interpreter + , static_cast(v)); + char const* p = lua_tostring(interpreter, -1); + std::size_t len = lua_rawlen(interpreter, -1); + std::copy(p, p + len, std::ostream_iterator(os)); + return os; + } + +#undef LUAPONTE_BINARY_OP_DEF + + template + typename enable_binary::type + operator>(LHS const& lhs, RHS const& rhs) + { + return !(lhs < rhs || lhs == rhs); + } + + template + typename enable_binary::type + operator<=(LHS const& lhs, RHS const& rhs) + { + return lhs < rhs || lhs == rhs; + } + + template + typename enable_binary::type + operator>=(LHS const& lhs, RHS const& rhs) + { + return !(lhs < rhs); + } + + template + typename enable_binary::type + operator!=(LHS const& lhs, RHS const& rhs) + { + return !(lhs == rhs); + } + + template + struct call_proxy; + + template + class index_proxy; + + class object; + + template + class object_interface + { + struct safe_bool_type {}; + public: + ~object_interface() {} + + call_proxy > operator()(); + + template + call_proxy< + Derived + , boost::tuples::tuple + > operator()(A0 const& a0) + { + typedef boost::tuples::tuple arguments; + + return call_proxy( + derived() + , arguments(&a0) + ); + } + + template + call_proxy< + Derived + , boost::tuples::tuple + > operator()(A0 const& a0, A1 const& a1) + { + typedef boost::tuples::tuple arguments; + + return call_proxy( + derived() + , arguments(&a0, &a1) + ); + } + + // The rest of the overloads are PP-generated. + #define BOOST_PP_ITERATION_PARAMS_1 (3, \ + (3, LUAPONTE_MAX_ARITY, )) + #include BOOST_PP_ITERATE() + + operator safe_bool_type*() const + { + lua_State* L = value_wrapper_traits::interpreter(derived()); + + if (!L) + return 0; + + value_wrapper_traits::unwrap(L, derived()); + detail::stack_pop pop(L, 1); + + return lua_toboolean(L, -1) == 1 ? (safe_bool_type*)1 : 0; + } + + private: + Derived& derived() + { + return *static_cast(this); + } + + Derived const& derived() const + { + return *static_cast(this); + } + }; + +#ifdef LUAPONTE_USE_VALUE_WRAPPER_TAG + struct iterator_proxy_tag; +#endif + + template + class iterator_proxy + : public object_interface > + { + public: +#ifdef LUAPONTE_USE_VALUE_WRAPPER_TAG + typedef iterator_proxy_tag value_wrapper_tag; +#endif + + iterator_proxy(lua_State* interpreter, handle const& table, handle const& key) + : m_interpreter(interpreter) + , m_table_index(lua_gettop(interpreter) + 1) + , m_key_index(m_table_index + 1) + { + table.push(m_interpreter); + key.push(m_interpreter); + } + + iterator_proxy(iterator_proxy const& other) + : m_interpreter(other.m_interpreter) + , m_table_index(other.m_table_index) + , m_key_index(other.m_key_index) + { + other.m_interpreter = 0; + } + + ~iterator_proxy() + { + if (m_interpreter) + lua_pop(m_interpreter, 2); + } + + // this will set the value to nil + iterator_proxy & operator=(luaponte::detail::nil_type) + { + lua_pushvalue(m_interpreter, m_key_index); + lua_pushnil(m_interpreter); + AccessPolicy::set(m_interpreter, m_table_index); + return *this; + } + + template + iterator_proxy& operator=(T const& value) + { + lua_pushvalue(m_interpreter, m_key_index); + detail::push(m_interpreter, value); + AccessPolicy::set(m_interpreter, m_table_index); + return *this; + } + + template + index_proxy > operator[](Key const& key) + { + return index_proxy >( + *this, m_interpreter, key + ); + } + + // This is non-const to prevent conversion on lvalues. + operator object(); + + lua_State* interpreter() const + { + return m_interpreter; + } + + // TODO: Why is it non-const? + void push(lua_State* interpreter) + { + assert(interpreter == m_interpreter); + lua_pushvalue(m_interpreter, m_key_index); + AccessPolicy::get(m_interpreter, m_table_index); + } + + private: + mutable lua_State* m_interpreter; + int m_table_index; + int m_key_index; + }; + +} // namespace adl + +namespace detail { + struct basic_access + { + static void set(lua_State* interpreter, int table) + { + lua_settable(interpreter, table); + } + + static void get(lua_State* interpreter, int table) + { + lua_gettable(interpreter, table); + } + }; + + struct raw_access + { + static void set(lua_State* interpreter, int table) + { + lua_rawset(interpreter, table); + } + + static void get(lua_State* interpreter, int table) + { + lua_rawget(interpreter, table); + } + }; + + template + class basic_iterator + : public boost::iterator_facade< + basic_iterator + , adl::iterator_proxy + , boost::single_pass_traversal_tag + , adl::iterator_proxy + > + { + public: + basic_iterator() + : m_interpreter(0) + {} + + template + explicit basic_iterator(ValueWrapper const& value_wrapper) + : m_interpreter( + value_wrapper_traits::interpreter(value_wrapper) + ) + { + detail::stack_pop pop(m_interpreter, 1); + value_wrapper_traits::unwrap(m_interpreter, value_wrapper); + + lua_pushnil(m_interpreter); + if (lua_next(m_interpreter, -2) != 0) + { + detail::stack_pop pop(m_interpreter, 2); + handle(m_interpreter, -2).swap(m_key); + } + else + { + m_interpreter = 0; + return; + } + + handle(m_interpreter, -1).swap(m_table); + } + + adl::object key() const; + + private: + friend class boost::iterator_core_access; + + void increment() + { + m_table.push(m_interpreter); + m_key.push(m_interpreter); + + detail::stack_pop pop(m_interpreter, 1); + + if (lua_next(m_interpreter, -2) != 0) + { + m_key.replace(m_interpreter, -2); + lua_pop(m_interpreter, 2); + } + else + { + m_interpreter = 0; + handle().swap(m_table); + handle().swap(m_key); + } + } + + bool equal(basic_iterator const& other) const + { + if (m_interpreter == 0 && other.m_interpreter == 0) + return true; + + if (m_interpreter != other.m_interpreter) + return false; + + detail::stack_pop pop(m_interpreter, 2); + m_key.push(m_interpreter); + other.m_key.push(m_interpreter); + return lua_compare(m_interpreter, -2, -1, LUA_OPEQ) != 0; + } + + adl::iterator_proxy dereference() const + { + return adl::iterator_proxy(m_interpreter, m_table, m_key); + } + + lua_State* m_interpreter; + handle m_table; + handle m_key; + }; + +// Needed because of some strange ADL issues. + +#define LUAPONTE_OPERATOR_ADL_WKND(op) \ + inline bool operator op( \ + basic_iterator const& x \ + , basic_iterator const& y) \ + { \ + return boost::operator op(x, y); \ + } \ + \ + inline bool operator op( \ + basic_iterator const& x \ + , basic_iterator const& y) \ + { \ + return boost::operator op(x, y); \ + } + + LUAPONTE_OPERATOR_ADL_WKND(==) + LUAPONTE_OPERATOR_ADL_WKND(!=) + +#undef LUAPONTE_OPERATOR_ADL_WKND + +} // namespace detail + +namespace adl +{ + +#ifdef LUAPONTE_USE_VALUE_WRAPPER_TAG + struct index_proxy_tag; +#endif + + template + class index_proxy + : public object_interface > + { + public: +#ifdef LUAPONTE_USE_VALUE_WRAPPER_TAG + typedef index_proxy_tag value_wrapper_tag; +#endif + + typedef index_proxy this_type; + + template + index_proxy(Next const& next, lua_State* interpreter, Key const& key) + : m_interpreter(interpreter) + , m_key_index(lua_gettop(interpreter) + 1) + , m_next(next) + { + detail::push(m_interpreter, key); + } + + index_proxy(index_proxy const& other) + : m_interpreter(other.m_interpreter) + , m_key_index(other.m_key_index) + , m_next(other.m_next) + { + other.m_interpreter = 0; + } + + ~index_proxy() + { + if (m_interpreter) + lua_pop(m_interpreter, 1); + } + + // This is non-const to prevent conversion on lvalues. + operator object(); + + // this will set the value to nil + this_type& operator=(luaponte::detail::nil_type) + { + value_wrapper_traits::unwrap(m_interpreter, m_next); + detail::stack_pop pop(m_interpreter, 1); + + lua_pushvalue(m_interpreter, m_key_index); + lua_pushnil(m_interpreter); + lua_settable(m_interpreter, -3); + return *this; + } + + template + this_type& operator=(T const& value) + { + value_wrapper_traits::unwrap(m_interpreter, m_next); + detail::stack_pop pop(m_interpreter, 1); + + lua_pushvalue(m_interpreter, m_key_index); + detail::push(m_interpreter, value); + lua_settable(m_interpreter, -3); + return *this; + } + + this_type& operator=(this_type const& value) + { + value_wrapper_traits::unwrap(m_interpreter, m_next); + detail::stack_pop pop(m_interpreter, 1); + + lua_pushvalue(m_interpreter, m_key_index); + detail::push(m_interpreter, value); + lua_settable(m_interpreter, -3); + return *this; + } + + template + index_proxy operator[](T const& key) + { + return index_proxy(*this, m_interpreter, key); + } + + void push(lua_State* interpreter); + + lua_State* interpreter() const + { + return m_interpreter; + } + + private: + struct hidden_type {}; + +// this_type& operator=(index_proxy const&); + + mutable lua_State* m_interpreter; + int m_key_index; + + Next const& m_next; + }; + +} // namespace adl + +typedef detail::basic_iterator iterator; +typedef detail::basic_iterator raw_iterator; + +#ifndef LUAPONTE_USE_VALUE_WRAPPER_TAG +template +struct value_wrapper_traits > +#else +template<> +struct value_wrapper_traits +#endif +{ + typedef boost::mpl::true_ is_specialized; + + template + static lua_State* interpreter(adl::index_proxy const& proxy) + { + return proxy.interpreter(); + } + + template + static void unwrap(lua_State* interpreter, adl::index_proxy const& proxy) + { + const_cast&>(proxy).push(interpreter); + } +}; + +#ifndef LUAPONTE_USE_VALUE_WRAPPER_TAG +template +struct value_wrapper_traits > +#else +template<> +struct value_wrapper_traits +#endif +{ + typedef boost::mpl::true_ is_specialized; + + template + static lua_State* interpreter(Proxy const& p) + { + return p.interpreter(); + } + + template + static void unwrap(lua_State* interpreter, Proxy const& p) + { + // TODO: Why const_cast? + const_cast(p).push(interpreter); + } +}; + +namespace adl +{ + + // An object holds a reference to a Lua value residing + // in the registry. + class object : public object_interface + { + public: + object() + {} + + explicit object(handle const& other) + : m_handle(other) + {} + + explicit object(from_stack const& stack_reference) + : m_handle(stack_reference.interpreter, stack_reference.index) + { + } + + template + object(lua_State* interpreter, T const& value) + { + detail::push(interpreter, value); + detail::stack_pop pop(interpreter, 1); + handle(interpreter, -1).swap(m_handle); + } + + template + object(lua_State* interpreter, T const& value, Policies const&) + { + detail::push(interpreter, value, Policies()); + detail::stack_pop pop(interpreter, 1); + handle(interpreter, -1).swap(m_handle); + } + + void push(lua_State* interpreter) const; + lua_State* interpreter() const; + bool is_valid() const; + + template + index_proxy operator[](T const& key) const + { + return index_proxy( + *this, m_handle.interpreter(), key + ); + } + + void swap(object& other) + { + m_handle.swap(other.m_handle); + } + + private: + handle m_handle; + }; + + inline void object::push(lua_State* interpreter) const + { + m_handle.push(interpreter); + } + + inline lua_State* object::interpreter() const + { + return m_handle.interpreter(); + } + + inline bool object::is_valid() const + { + return m_handle.interpreter() != 0; + } + + class argument : public object_interface + { + public: + argument(from_stack const& stack_reference) + : m_interpreter(stack_reference.interpreter) + , m_index(stack_reference.index) + { + if (m_index < 0) + m_index = lua_gettop(m_interpreter) - m_index + 1; + } + + template + index_proxy operator[](T const& key) const + { + return index_proxy(*this, m_interpreter, key); + } + + void push(lua_State* L) const + { + lua_pushvalue(L, m_index); + } + + lua_State* interpreter() const + { + return m_interpreter; + } + + private: + lua_State* m_interpreter; + int m_index; + }; + +} // namespace adl + +using adl::object; +using adl::argument; + +#ifndef LUAPONTE_USE_VALUE_WRAPPER_TAG +template +struct value_wrapper_traits > +#else +template<> +struct value_wrapper_traits +#endif +{ + typedef boost::mpl::true_ is_specialized; + + template + static lua_State* interpreter(adl::call_proxy const& proxy) + { + return value_wrapper_traits::interpreter(*proxy.value_wrapper); + } + + template + static void unwrap(lua_State*, adl::call_proxy const& proxy) + { + object result = const_cast&>(proxy); + result.push(result.interpreter()); + } +}; + +template<> +struct value_wrapper_traits +{ + typedef boost::mpl::true_ is_specialized; + + static lua_State* interpreter(object const& value) + { + return value.interpreter(); + } + + static void unwrap(lua_State* interpreter, object const& value) + { + value.push(interpreter); + } + + static bool check(...) + { + return true; + } +}; + +template<> +struct value_wrapper_traits +{ + typedef boost::mpl::true_ is_specialized; + + static lua_State* interpreter(argument const& value) + { + return value.interpreter(); + } + + static void unwrap(lua_State* interpreter, argument const& value) + { + value.push(interpreter); + } + + static bool check(...) + { + return true; + } +}; + +template +inline void adl::index_proxy::push(lua_State* interpreter) +{ + assert(interpreter == m_interpreter); + + value_wrapper_traits::unwrap(m_interpreter, m_next); + + lua_pushvalue(m_interpreter, m_key_index); + lua_gettable(m_interpreter, -2); + lua_remove(m_interpreter, -2); +} + +template +inline adl::index_proxy::operator object() +{ + detail::stack_pop pop(m_interpreter, 1); + push(m_interpreter); + return object(from_stack(m_interpreter, -1)); +} + +template +adl::iterator_proxy::operator object() +{ + lua_pushvalue(m_interpreter, m_key_index); + AccessPolicy::get(m_interpreter, m_table_index); + detail::stack_pop pop(m_interpreter, 1); + return object(from_stack(m_interpreter, -1)); +} + +template +object detail::basic_iterator::key() const +{ + return object(m_key); +} + +namespace detail { + + template< + class T + , class ValueWrapper + , class Policies + , class ErrorPolicy + , class ReturnType + > + ReturnType object_cast_aux( + ValueWrapper const& value_wrapper + , T* + , Policies* + , ErrorPolicy* + , ReturnType* + ) + { + lua_State* interpreter = value_wrapper_traits::interpreter( + value_wrapper + ); + +#ifndef LUAPONTE_NO_ERROR_CHECKING + if (!interpreter) + return ErrorPolicy::handle_error(interpreter, typeid(void)); +#endif + + value_wrapper_traits::unwrap(interpreter, value_wrapper); + + detail::stack_pop pop(interpreter, 1); + + typedef typename detail::find_conversion_policy< + 0 + , Policies + >::type converter_generator; + + typename mpl::apply_wrap2::type cv; + + if (cv.match(interpreter, LUAPONTE_DECORATE_TYPE(T), -1) < 0) + { + return ErrorPolicy::handle_error(interpreter, typeid(T)); + } + + return cv.apply(interpreter, LUAPONTE_DECORATE_TYPE(T), -1); + } + +# ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable:4702) // unreachable code +# endif + + template + struct throw_error_policy + { + static T handle_error(lua_State* interpreter, type_id const& type_info) + { +#ifndef LUAPONTE_NO_EXCEPTIONS + throw cast_failed(interpreter, type_info); +#else + cast_failed_callback_fun e = get_cast_failed_callback(); + if (e) e(interpreter, type_info); + + assert(0 && "object_cast failed. If you want to handle this error use " + "luaponte::set_error_callback()"); + std::terminate(); + return *(typename boost::remove_reference::type*)0; +#endif + } + }; + +# ifdef BOOST_MSVC +# pragma warning(pop) +# endif + + template + struct nothrow_error_policy + { + static boost::optional handle_error(lua_State*, type_id const&) + { + return boost::optional(); + } + }; + +} // namespace detail + +template +T object_cast(ValueWrapper const& value_wrapper) +{ + return detail::object_cast_aux( + value_wrapper + , (T*)0 + , (detail::null_type*)0 + , (detail::throw_error_policy*)0 + , (T*)0 + ); +} + +template +T object_cast(ValueWrapper const& value_wrapper, Policies const&) +{ + return detail::object_cast_aux( + value_wrapper + , (T*)0 + , (Policies*)0 + , (detail::throw_error_policy*)0 + , (T*)0 + ); +} + +template +boost::optional object_cast_nothrow(ValueWrapper const& value_wrapper) +{ + return detail::object_cast_aux( + value_wrapper + , (T*)0 + , (detail::null_type*)0 + , (detail::nothrow_error_policy*)0 + , (boost::optional*)0 + ); +} + +template +boost::optional object_cast_nothrow(ValueWrapper const& value_wrapper, Policies const&) +{ + return detail::object_cast_aux( + value_wrapper + , (T*)0 + , (Policies*)0 + , (detail::nothrow_error_policy*)0 + , (boost::optional*)0 + ); +} + +namespace detail { + + template + struct push_args_from_tuple + { + template + inline static void apply(lua_State* L, const boost::tuples::cons& x, const Policies& p) + { + convert_to_lua_p(L, *x.get_head(), p); + push_args_from_tuple::apply(L, x.get_tail(), p); + } + + template + inline static void apply(lua_State* L, const boost::tuples::cons& x) + { + convert_to_lua(L, *x.get_head()); + push_args_from_tuple::apply(L, x.get_tail()); + } + + template + inline static void apply(lua_State*, const boost::tuples::null_type&, const Policies&) {} + + inline static void apply(lua_State*, const boost::tuples::null_type&) {} + }; + +} // namespace detail + +namespace adl +{ + + template + struct call_proxy + { + call_proxy(ValueWrapper& value_wrapper, Arguments arguments) + : value_wrapper(&value_wrapper) + , arguments(arguments) + {} + + call_proxy(call_proxy const& other) + : value_wrapper(other.value_wrapper) + , arguments(other.arguments) + { + other.value_wrapper = 0; + } + + ~call_proxy() + { + if (value_wrapper) + call((detail::null_type*)0); + } + + operator object() + { + return call((detail::null_type*)0); + } + + template + object operator[](Policies const&) + { + return call((Policies*)0); + } + + template + object call(Policies*) + { + lua_State* interpreter = value_wrapper_traits::interpreter( + *value_wrapper + ); + + value_wrapper_traits::unwrap( + interpreter + , *value_wrapper + ); + + value_wrapper = 0; + + detail::push_args_from_tuple<1>::apply(interpreter, arguments, Policies()); + + if (detail::pcall(interpreter, boost::tuples::length::value, 1)) + { +#ifndef LUAPONTE_NO_EXCEPTIONS + throw luaponte::error(interpreter); +#else + error_callback_fun e = get_error_callback(); + if (e) e(interpreter); + + assert(0 && "the lua function threw an error and exceptions are disabled." + "if you want to handle this error use luaponte::set_error_callback()"); + std::terminate(); +#endif + } + + detail::stack_pop pop(interpreter, 1); + return object(from_stack(interpreter, -1)); + } + + mutable ValueWrapper* value_wrapper; + Arguments arguments; + }; + + template + call_proxy > + object_interface::operator()() + { + return call_proxy >( + derived() + , boost::tuples::tuple<>() + ); + } + + // Simple value_wrapper adaptor with the sole purpose of helping with + // overload resolution. Use this as a function parameter type instead + // of "object" or "argument" to restrict the parameter to Lua tables. + template + struct table : Base + { + table(from_stack const& stack_reference) + : Base(stack_reference) + {} + }; + +} // namespace adl + +using adl::table; + +template +struct value_wrapper_traits > + : value_wrapper_traits +{ + static bool check(lua_State* L, int idx) + { + return value_wrapper_traits::check(L, idx) && + lua_istable(L, idx); + } +}; + +inline object newtable(lua_State* interpreter) +{ + lua_newtable(interpreter); + detail::stack_pop pop(interpreter, 1); + return object(from_stack(interpreter, -1)); +} + +// this could be optimized by returning a proxy +inline object globals(lua_State* interpreter) +{ + lua_pushglobaltable(interpreter); + detail::stack_pop pop(interpreter, 1); + return object(from_stack(interpreter, -1)); +} + +// this could be optimized by returning a proxy +inline object registry(lua_State* interpreter) +{ + lua_pushvalue(interpreter, LUA_REGISTRYINDEX); + detail::stack_pop pop(interpreter, 1); + return object(from_stack(interpreter, -1)); +} + +template +inline object gettable(ValueWrapper const& table, K const& key) +{ + lua_State* interpreter = value_wrapper_traits::interpreter( + table + ); + + value_wrapper_traits::unwrap(interpreter, table); + detail::stack_pop pop(interpreter, 2); + detail::push(interpreter, key); + lua_gettable(interpreter, -2); + return object(from_stack(interpreter, -1)); +} + +template +inline void settable(ValueWrapper const& table, K const& key, T const& value) +{ + lua_State* interpreter = value_wrapper_traits::interpreter( + table + ); + + // TODO: Exception safe? + + value_wrapper_traits::unwrap(interpreter, table); + detail::stack_pop pop(interpreter, 1); + detail::push(interpreter, key); + detail::push(interpreter, value); + lua_settable(interpreter, -3); +} + +template +inline object rawget(ValueWrapper const& table, K const& key) +{ + lua_State* interpreter = value_wrapper_traits::interpreter( + table + ); + + value_wrapper_traits::unwrap(interpreter, table); + detail::stack_pop pop(interpreter, 2); + detail::push(interpreter, key); + lua_rawget(interpreter, -2); + return object(from_stack(interpreter, -1)); +} + +template +inline void rawset(ValueWrapper const& table, K const& key, T const& value) +{ + lua_State* interpreter = value_wrapper_traits::interpreter( + table + ); + + // TODO: Exception safe? + + value_wrapper_traits::unwrap(interpreter, table); + detail::stack_pop pop(interpreter, 1); + detail::push(interpreter, key); + detail::push(interpreter, value); + lua_rawset(interpreter, -3); +} + +template +inline int type(ValueWrapper const& value) +{ + lua_State* interpreter = value_wrapper_traits::interpreter( + value + ); + + value_wrapper_traits::unwrap(interpreter, value); + detail::stack_pop pop(interpreter, 1); + return lua_type(interpreter, -1); +} + +template +inline object getmetatable(ValueWrapper const& obj) +{ + lua_State* interpreter = value_wrapper_traits::interpreter( + obj + ); + + value_wrapper_traits::unwrap(interpreter, obj); + detail::stack_pop pop(interpreter, 2); + lua_getmetatable(interpreter, -1); + return object(from_stack(interpreter, -1)); +} + +template +inline void setmetatable( + ValueWrapper1 const& obj, ValueWrapper2 const& metatable) +{ + lua_State* interpreter = value_wrapper_traits::interpreter( + obj + ); + + value_wrapper_traits::unwrap(interpreter, obj); + detail::stack_pop pop(interpreter, 1); + value_wrapper_traits::unwrap(interpreter, metatable); + lua_setmetatable(interpreter, -2); +} + +template +inline lua_CFunction tocfunction(ValueWrapper const& value) +{ + lua_State* interpreter = value_wrapper_traits::interpreter( + value + ); + + value_wrapper_traits::unwrap(interpreter, value); + detail::stack_pop pop(interpreter, 1); + return lua_tocfunction(interpreter, -1); +} + +template +inline T* touserdata(ValueWrapper const& value) +{ + lua_State* interpreter = value_wrapper_traits::interpreter( + value + ); + + value_wrapper_traits::unwrap(interpreter, value); + detail::stack_pop pop(interpreter, 1); + return static_cast(lua_touserdata(interpreter, -1)); +} + +template +inline object getupvalue(ValueWrapper const& value, int index) +{ + lua_State* interpreter = value_wrapper_traits::interpreter( + value + ); + + value_wrapper_traits::unwrap(interpreter, value); + detail::stack_pop pop(interpreter, 2); + lua_getupvalue(interpreter, -1, index); + return object(from_stack(interpreter, -1)); +} + +template +inline void setupvalue( + ValueWrapper1 const& function, int index, ValueWrapper2 const& value) +{ + lua_State* interpreter = value_wrapper_traits::interpreter( + function + ); + + value_wrapper_traits::unwrap(interpreter, function); + detail::stack_pop pop(interpreter, 1); + value_wrapper_traits::unwrap(interpreter, value); + lua_setupvalue(interpreter, -2, index); +} + +template +object property(GetValueWrapper const& get) +{ + lua_State* interpreter = value_wrapper_traits::interpreter( + get + ); + + value_wrapper_traits::unwrap(interpreter, get); + lua_pushnil(interpreter); + + lua_pushcclosure(interpreter, &detail::property_tag, 2); + detail::stack_pop pop(interpreter, 1); + + return object(from_stack(interpreter, -1)); +} + +template +object property(GetValueWrapper const& get, SetValueWrapper const& set) +{ + lua_State* interpreter = value_wrapper_traits::interpreter( + get + ); + + value_wrapper_traits::unwrap(interpreter, get); + value_wrapper_traits::unwrap(interpreter, set); + + lua_pushcclosure(interpreter, &detail::property_tag, 2); + detail::stack_pop pop(interpreter, 1); + + return object(from_stack(interpreter, -1)); + +} + +} // namespace luaponte + +#if LUA_VERSION_NUM < 502 +# undef lua_compare +# undef LUA_OPEQ +# undef LUA_OPLT +# undef lua_rawlen +# undef lua_pushglobaltable +#endif + +#endif // LUAPONTE_OBJECT_HPP diff --git a/luaponte/open.hpp b/luaponte/open.hpp new file mode 100644 index 0000000..c0056e8 --- /dev/null +++ b/luaponte/open.hpp @@ -0,0 +1,24 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_OPEN_HPP +#define LUAPONTE_OPEN_HPP + +#include + +namespace luaponte { + +LUAPONTE_API void open(lua_State* L); + +} // namespace luaponte + +#endif // LUAPONTE_OPEN_HPP diff --git a/luaponte/operator.hpp b/luaponte/operator.hpp new file mode 100644 index 0000000..fac687b --- /dev/null +++ b/luaponte/operator.hpp @@ -0,0 +1,345 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_OPERATOR_HPP +#define LUAPONTE_OPERATOR_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__GNUC__) && __GNUC__ < 3 +# define LUAPONTE_NO_STRINGSTREAM +#else +# if defined(BOOST_NO_STRINGSTREAM) +# define LUAPONTE_NO_STRINGSTREAM +# endif +#endif + +#ifdef LUAPONTE_NO_STRINGSTREAM +#include +#else +#include +#endif + +namespace luaponte { +namespace detail { + + template struct unwrap_parameter_type; + template struct operator_ {}; + + struct operator_void_return {}; + +#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + template + inline T const& operator,(T const& x, operator_void_return) + { + return x; + } +#endif + +}} // namespace luaponte + +namespace luaponte { namespace operators { + + #define BOOST_PP_ITERATION_PARAMS_1 (3, \ + (0, LUAPONTE_MAX_ARITY, )) + #include BOOST_PP_ITERATE() + +}} // namespace luaponte::operators + +#include + +namespace luaponte { + + template + struct self_base + { + operators::call_operator0 operator()() const + { + return 0; + } + +#define BOOST_PP_LOCAL_MACRO(n) \ + template \ + BOOST_PP_CAT(operators::call_operator, n)< \ + Derived \ + BOOST_PP_ENUM_TRAILING_PARAMS(n, A) \ + >\ + operator()( \ + BOOST_PP_ENUM_BINARY_PARAMS(n, A, const& BOOST_PP_INTERCEPT) \ + ) const \ + { \ + return 0; \ + } + +#define BOOST_PP_LOCAL_LIMITS (1, LUAPONTE_MAX_ARITY) +#include BOOST_PP_LOCAL_ITERATE() + + }; + + struct self_type : self_base + { + }; + + struct const_self_type : self_base + { + }; + +namespace detail { + + template + struct unwrap_parameter_type + { + typedef typename boost::mpl::eval_if< + boost::is_same + , boost::mpl::identity + , boost::mpl::eval_if< + boost::is_same + , boost::mpl::identity + , unwrap_other + > + >::type type; + }; + + template + struct binary_operator + : operator_ > + { + binary_operator(int) {} + + template + struct apply + { + typedef typename unwrap_parameter_type::type arg0; + typedef typename unwrap_parameter_type::type arg1; + + static void execute(lua_State* L, arg0 _0, arg1 _1) + { + Derived::template apply::execute( + L, _0, _1); + } + }; + + static char const* name() + { + return Derived::name(); + } + }; + + template + struct unary_operator + : operator_ > + { + unary_operator(int) {} + + template + struct apply + { + typedef typename unwrap_parameter_type::type arg0; + + static void execute(lua_State* L, arg0 _0) + { + Derived::template apply::execute(L, _0); + } + }; + + static char const* name() + { + return Derived::name(); + } + }; + + template + inline void operator_result(lua_State* L, operator_void_return, Policies*) + { + } + + namespace mpl = boost::mpl; + + template + inline void operator_result(lua_State* L, T const& x, Policies*) + { + typedef typename find_conversion_policy< + 0 + , Policies + >::type cv_policy; + + typename mpl::apply_wrap2::type cv; + + cv.apply(L, x); + } + +}} // namespace detail::luabind + +namespace luaponte { + +#define LUAPONTE_BINARY_OPERATOR(name_, op) \ + namespace operators { \ +\ + struct name_ \ + { \ + template \ + struct apply \ + { \ + static void execute(lua_State* L, T0 _0, T1 _1) \ + { \ + detail::operator_result(L, _0 op _1, (Policies*)0); \ + } \ + }; \ +\ + static char const* name() \ + { \ + return "__" # name_; \ + } \ + }; \ +\ + } \ + \ + template \ + detail::binary_operator< \ + operators::name_ \ + , U \ + , T \ + > \ + inline operator op(self_base, T const&) \ + { \ + return 0; \ + } \ + \ + template \ + detail::binary_operator< \ + operators::name_ \ + , T \ + , U \ + > \ + inline operator op(T const&, self_base) \ + { \ + return 0; \ + } \ + \ + detail::binary_operator< \ + operators::name_ \ + , self_type \ + , self_type \ + > \ + inline operator op(self_type, self_type) \ + { \ + return 0; \ + } \ + \ + detail::binary_operator< \ + operators::name_ \ + , self_type \ + , const_self_type \ + > \ + inline operator op(self_type, const_self_type) \ + { \ + return 0; \ + } \ + \ + detail::binary_operator< \ + operators::name_ \ + , const_self_type \ + , self_type \ + > \ + inline operator op(const_self_type, self_type) \ + { \ + return 0; \ + } \ + \ + detail::binary_operator< \ + operators::name_ \ + , const_self_type \ + , const_self_type \ + > \ + inline operator op(const_self_type, const_self_type) \ + { \ + return 0; \ + } + + LUAPONTE_BINARY_OPERATOR(add, +) + LUAPONTE_BINARY_OPERATOR(sub, -) + LUAPONTE_BINARY_OPERATOR(mul, *) + LUAPONTE_BINARY_OPERATOR(div, /) + LUAPONTE_BINARY_OPERATOR(pow, ^) + LUAPONTE_BINARY_OPERATOR(lt, <) + LUAPONTE_BINARY_OPERATOR(le, <=) + LUAPONTE_BINARY_OPERATOR(eq, ==) + +#undef LUAPONTE_UNARY_OPERATOR + +#define LUAPONTE_UNARY_OPERATOR(name_, op, fn) \ + namespace operators { \ +\ + struct name_ \ + { \ + template \ + struct apply \ + { \ + static void execute(lua_State* L, T x) \ + { \ + detail::operator_result(L, op(x), (Policies*)0); \ + } \ + }; \ +\ + static char const* name() \ + { \ + return "__" # name_; \ + } \ + }; \ +\ + } \ + \ + template \ + detail::unary_operator< \ + operators::name_ \ + , T \ + > \ + inline fn(self_base) \ + { \ + return 0; \ + } + + template + std::string tostring_operator(T const& x) + { +#ifdef LUAPONTE_NO_STRINGSTREAM + std::strstream s; + s << x << std::ends; +#else + std::stringstream s; + s << x; +#endif + return s.str(); + } + + LUAPONTE_UNARY_OPERATOR(tostring, tostring_operator, tostring) + LUAPONTE_UNARY_OPERATOR(unm, -, operator-) + +#undef LUAPONTE_BINARY_OPERATOR + + namespace { + + LUAPONTE_ANONYMOUS_FIX self_type const self = self_type(); + LUAPONTE_ANONYMOUS_FIX const_self_type const const_self = const_self_type(); + + } // namespace unnamed + +} // namespace luaponte + +#endif // LUAPONTE_OPERATOR_HPP diff --git a/luaponte/out_value_policy.hpp b/luaponte/out_value_policy.hpp new file mode 100644 index 0000000..c57ad5b --- /dev/null +++ b/luaponte/out_value_policy.hpp @@ -0,0 +1,319 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_OUT_VALUE_POLICY_HPP +#define LUAPONTE_OUT_VALUE_POLICY_HPP + +#include +#include +#include + +namespace luaponte { +namespace detail { + +template +struct char_array +{ + char storage[N]; +}; + +#if defined(__GNUC__) && ( __GNUC__ == 3 && __GNUC_MINOR__ == 1 ) + +template +char_array indirect_sizeof_test(by_reference); + +template +char_array indirect_sizeof_test(by_const_reference); + +template +char_array indirect_sizeof_test(by_pointer); + +template +char_array indirect_sizeof_test(by_const_pointer); + +template +char_array indirect_sizeof_test(by_value); + +#else + +template +char_array::type)> indirect_sizeof_test(by_reference); + +template +char_array::type)> indirect_sizeof_test(by_const_reference); + +template +char_array::type)> indirect_sizeof_test(by_pointer); + +template +char_array::type)> indirect_sizeof_test(by_const_pointer); + +template +char_array::type)> indirect_sizeof_test(by_value); + +#endif + +template +struct indirect_sizeof +{ + BOOST_STATIC_CONSTANT(int, value = sizeof(indirect_sizeof_test(LUAPONTE_DECORATE_TYPE(T)))); +}; + +namespace mpl = boost::mpl; + +template +struct out_value_converter +{ + int consumed_args(...) const + { + return 1; + } + + template + T& apply(lua_State* L, by_reference, int index) + { + typedef typename find_conversion_policy<1, Policies>::type converter_policy; + typename mpl::apply_wrap2::type converter; +#if defined(__GNUC__) && __GNUC__ >= 4 + T* storage = reinterpret_cast(m_storage); + new (storage) T(converter.apply(L, LUAPONTE_DECORATE_TYPE(T), index)); + return *storage; +#else + new (m_storage) T(converter.apply(L, LUAPONTE_DECORATE_TYPE(T), index)); + return *reinterpret_cast(m_storage); +#endif + } + + template + static int match(lua_State* L, by_reference, int index) + { + typedef typename find_conversion_policy<1, Policies>::type converter_policy; + typedef typename mpl::apply_wrap2::type converter; + return converter::match(L, LUAPONTE_DECORATE_TYPE(T), index); + } + + template + void converter_postcall(lua_State* L, by_reference, int) + { + typedef typename find_conversion_policy<2, Policies>::type converter_policy; + typename mpl::apply_wrap2::type converter; +#if defined(__GNUC__) && __GNUC__ >= 4 + T* storage = reinterpret_cast(m_storage); + converter.apply(L, *storage); + storage->~T(); +#else + converter.apply(L, *reinterpret_cast(m_storage)); + reinterpret_cast(m_storage)->~T(); +#endif + } + + template + T* apply(lua_State* L, by_pointer, int index) + { + typedef typename find_conversion_policy<1, Policies>::type converter_policy; + typename mpl::apply_wrap2::type converter; +#if defined(__GNUC__) && __GNUC__ >= 4 + T* storage = reinterpret_cast(m_storage); + new (storage) T(converter.apply(L, LUAPONTE_DECORATE_TYPE(T), index)); + return storage; +#else + new (m_storage) T(converter.apply(L, LUAPONTE_DECORATE_TYPE(T), index)); + return reinterpret_cast(m_storage); +#endif + } + + template + static int match(lua_State* L, by_pointer, int index) + { + typedef typename find_conversion_policy<1, Policies>::type converter_policy; + typedef typename mpl::apply_wrap2::type converter; + return converter::match(L, LUAPONTE_DECORATE_TYPE(T), index); + } + + template + void converter_postcall(lua_State* L, by_pointer, int) + { + typedef typename find_conversion_policy<2, Policies>::type converter_policy; + typename mpl::apply_wrap2::type converter; +#if defined(__GNUC__) && __GNUC__ >= 4 + T* storage = reinterpret_cast(m_storage); + converter.apply(L, *storage); + storage->~T(); +#else + converter.apply(L, *reinterpret_cast(m_storage)); + reinterpret_cast(m_storage)->~T(); +#endif + } + + char m_storage[Size]; +}; + +template +struct out_value_policy : conversion_policy +{ + static void precall(lua_State*, const index_map&) {} + static void postcall(lua_State*, const index_map&) {} + + struct only_accepts_nonconst_references_or_pointers {}; + struct can_only_convert_from_lua_to_cpp {}; + + template + struct apply + { + typedef typename boost::mpl::if_ + , typename boost::mpl::if_, is_nonconst_pointer > + , out_value_converter::value, Policies> + , only_accepts_nonconst_references_or_pointers + >::type + , can_only_convert_from_lua_to_cpp + >::type type; + }; +}; + +template +struct pure_out_value_converter +{ + int consumed_args(...) const + { + return 0; + } + + template + T& apply(lua_State*, by_reference, int) + { +#if defined(__GNUC__) && __GNUC__ >= 4 + T* storage = reinterpret_cast(m_storage); + new (storage) T(); + return *storage; +#else + new (m_storage) T(); + return *reinterpret_cast(m_storage); +#endif + } + + template + static int match(lua_State*, by_reference, int) + { + return 0; + } + + template + void converter_postcall(lua_State* L, by_reference, int) + { + typedef typename find_conversion_policy<1, Policies>::type converter_policy; + typename mpl::apply_wrap2::type converter; +#if defined(__GNUC__) && __GNUC__ >= 4 + T* storage = reinterpret_cast(m_storage); + converter.apply(L, *storage); + storage->~T(); +#else + converter.apply(L, *reinterpret_cast(m_storage)); + reinterpret_cast(m_storage)->~T(); +#endif + } + + template + T* apply(lua_State*, by_pointer, int) + { +#if defined(__GNUC__) && __GNUC__ >= 4 + T* storage = reinterpret_cast(m_storage); + new (storage) T(); + return storage; +#else + new (m_storage) T(); + return reinterpret_cast(m_storage); +#endif + } + + template + static int match(lua_State*, by_pointer, int) + { + return 0; + } + + template + void converter_postcall(lua_State* L, by_pointer, int) + { + typedef typename find_conversion_policy<1, Policies>::type converter_policy; + typename mpl::apply_wrap2::type converter; +#if defined(__GNUC__) && __GNUC__ >= 4 + T* storage = reinterpret_cast(m_storage); + converter.apply(L, *storage); + storage->~T(); +#else + converter.apply(L, *reinterpret_cast(m_storage)); + reinterpret_cast(m_storage)->~T(); +#endif + } + + + char m_storage[Size]; +}; + +template +struct pure_out_value_policy : conversion_policy +{ + static void precall(lua_State*, const index_map&) {} + static void postcall(lua_State*, const index_map&) {} + + struct only_accepts_nonconst_references_or_pointers {}; + struct can_only_convert_from_lua_to_cpp {}; + + template + struct apply + { + typedef typename boost::mpl::if_ + , typename boost::mpl::if_, is_nonconst_pointer > + , pure_out_value_converter::value, Policies> + , only_accepts_nonconst_references_or_pointers + >::type + , can_only_convert_from_lua_to_cpp + >::type type; + }; +}; + +} // namespace detail +} // namespace luaponte + +namespace luaponte { + +template +detail::policy_cons, detail::null_type> +out_value(LUAPONTE_PLACEHOLDER_ARG(N)) +{ + return detail::policy_cons, detail::null_type>(); +} + +template +detail::policy_cons, detail::null_type> +out_value(LUAPONTE_PLACEHOLDER_ARG(N), const Policies&) +{ + return detail::policy_cons, detail::null_type>(); +} + +template +detail::policy_cons, detail::null_type> +pure_out_value(LUAPONTE_PLACEHOLDER_ARG(N)) +{ + return detail::policy_cons, detail::null_type>(); +} + +template +detail::policy_cons, detail::null_type> +pure_out_value(LUAPONTE_PLACEHOLDER_ARG(N), const Policies&) +{ + return detail::policy_cons, detail::null_type>(); +} + +} // namespace luaponte + +#endif // LUAPONTE_OUT_VALUE_POLICY_HPP diff --git a/luaponte/prefix.hpp b/luaponte/prefix.hpp new file mode 100644 index 0000000..142be0f --- /dev/null +++ b/luaponte/prefix.hpp @@ -0,0 +1,20 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_PREFIX_HPP +#define LUAPONTE_PREFIX_HPP + +#ifdef LUAPONTE_PREFIX_INCLUDE +# include LUAPONTE_PREFIX_INCLUDE +#endif + +#endif // LUAPONTE_PREFIX_HPP diff --git a/luaponte/raw_policy.hpp b/luaponte/raw_policy.hpp new file mode 100644 index 0000000..8c06558 --- /dev/null +++ b/luaponte/raw_policy.hpp @@ -0,0 +1,72 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_RAW_POLICY_HPP +#define LUAPONTE_RAW_POLICY_HPP + +#include +#include + +namespace luaponte { +namespace detail { + +struct raw_converter +{ + int consumed_args(...) const + { + return 0; + } + + lua_State* apply(lua_State* L, by_pointer, int) + { + return L; + } + + static int match(...) + { + return 0; + } + + void converter_postcall(lua_State*, by_pointer, int) {} +}; + +template +struct raw_policy : conversion_policy +{ + static void precall(lua_State*, const index_map&) {} + static void postcall(lua_State*, const index_map&) {} + + template + struct apply + { + typedef raw_converter type; + }; +}; + +} // namespace detail + +template +detail::policy_cons< + detail::raw_policy + , detail::null_type +> +inline raw(LUAPONTE_PLACEHOLDER_ARG(N)) +{ + return detail::policy_cons< + detail::raw_policy + , detail::null_type + >(); +} + +} // namespace luaponte + +#endif // LUAPONTE_RAW_POLICY_HPP diff --git a/luaponte/return_reference_to_policy.hpp b/luaponte/return_reference_to_policy.hpp new file mode 100644 index 0000000..98a7dc7 --- /dev/null +++ b/luaponte/return_reference_to_policy.hpp @@ -0,0 +1,63 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_RETURN_REFERENCE_TO_POLICY_HPP +#define LUAPONTE_RETURN_REFERENCE_TO_POLICY_HPP + +namespace luaponte { +namespace detail { + +template +struct return_reference_to_converter; + +template<> +struct return_reference_to_converter +{ + template + void apply(lua_State* L, const T&) + { + lua_pushnil(L); + } +}; + +template +struct return_reference_to_policy : conversion_policy<0> +{ + static void precall(lua_State*, const index_map&) {} + static void postcall(lua_State* L, const index_map& indices) + { + int result_index = indices[0]; + int ref_to_index = indices[N]; + + lua_pushvalue(L, ref_to_index); + lua_replace(L, result_index); + } + + template + struct apply + { + typedef return_reference_to_converter type; + }; +}; + +} // namespace detail + +template +detail::policy_cons, detail::null_type> +return_reference_to(LUAPONTE_PLACEHOLDER_ARG(N)) +{ + return detail::policy_cons, detail::null_type>(); +} + +} // namespace luaponte + +#endif // LUAPONTE_RETURN_REFERENCE_TO_POLICY_HPP diff --git a/luaponte/scope.hpp b/luaponte/scope.hpp new file mode 100644 index 0000000..cefd9a9 --- /dev/null +++ b/luaponte/scope.hpp @@ -0,0 +1,94 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_NEW_SCOPE_HPP +#define LUAPONTE_NEW_SCOPE_HPP + +#include +#include +#include +#include +#include + +namespace luaponte { + +struct scope; + +namespace detail { + +struct LUAPONTE_API registration +{ + registration(); + virtual ~registration(); + +protected: + virtual void register_(lua_State*) const = 0; + +private: + friend struct ::luaponte::scope; + registration* m_next; +}; + +} // namespace detail + +struct LUAPONTE_API scope +{ + scope(); + explicit scope(std::unique_ptr reg); + scope(scope const& other_); + ~scope(); + + scope& operator=(scope const& other_); + + scope& operator,(scope s); + + void register_(lua_State* L) const; + +private: + detail::registration* m_chain; +}; + +class LUAPONTE_API namespace_ : public scope +{ +public: + explicit namespace_(char const* name); + namespace_& operator[](scope s); + +private: + struct registration_; + registration_* m_registration; +}; + +class LUAPONTE_API module_ +{ +public: + module_(object const& table); + module_(lua_State* L, char const* name); + void operator[](scope s); + +private: + object m_table; +}; + +inline module_ module(object const& table) +{ + return module_(table); +} + +inline module_ module(lua_State* L, char const* name = 0) +{ + return module_(L, name); +} + +} // namespace luaponte + +#endif // LUAPONTE_NEW_SCOPE_HPP diff --git a/luaponte/shared_ptr_converter.hpp b/luaponte/shared_ptr_converter.hpp new file mode 100644 index 0000000..11d4d4a --- /dev/null +++ b/luaponte/shared_ptr_converter.hpp @@ -0,0 +1,98 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_SHARED_PTR_CONVERTER_HPP +#define LUAPONTE_SHARED_PTR_CONVERTER_HPP + +#include +#include +#include + +#include + +namespace luaponte { + +namespace detail { + + struct shared_ptr_deleter + { + shared_ptr_deleter(lua_State* L, int index) + : life_support(get_main_thread(L), L, index) + {} + + void operator()(void const*) + { + handle().swap(life_support); + } + + handle life_support; + }; + +} // namespace detail + +template +struct default_converter > + : default_converter +{ + typedef boost::mpl::false_ is_native; + + template + int match(lua_State* L, U, int index) + { + return default_converter::match( + L, LUAPONTE_DECORATE_TYPE(T*), index); + } + + template + std::shared_ptr apply(lua_State* L, U, int index) + { + T* raw_ptr = default_converter::apply( + L, LUAPONTE_DECORATE_TYPE(T*), index); + if (!raw_ptr) + return std::shared_ptr(); + return std::shared_ptr( + raw_ptr, detail::shared_ptr_deleter(L, index)); + } + + void apply(lua_State* L, std::shared_ptr const& p) + { + if (detail::shared_ptr_deleter* d = + std::get_deleter(p)) + { + d->life_support.push(L); + } + else + { + detail::value_converter().apply(L, p); + } + } + + template + void converter_postcall(lua_State*, U const&, int) + {} +}; + +template +struct default_converter const&> + : default_converter > +{}; + +#ifdef BOOST_HAS_RVALUE_REFS +template +struct default_converter&&> + : default_converter > +{}; +#endif + +} // namespace luaponte + +#endif // LUAPONTE_SHARED_PTR_CONVERTER_HPP diff --git a/luaponte/tag_function.hpp b/luaponte/tag_function.hpp new file mode 100644 index 0000000..08ee374 --- /dev/null +++ b/luaponte/tag_function.hpp @@ -0,0 +1,92 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !BOOST_PP_IS_ITERATING + +# ifndef LUAPONTE_TAG_FUNCTION_HPP +# define LUAPONTE_TAG_FUNCTION_HPP + +# if LUAPONTE_MAX_ARITY <= 8 +# include +# else +# include +# endif +# include +# include +# include +# include + +namespace luaponte { +namespace detail { + +template +struct tagged_function +{ + tagged_function(F f) + : f(f) + {} + + F f; +}; + +template +Signature deduce_signature(tagged_function const&, ...) +{ + return Signature(); +} + +template +int invoke( + lua_State* L, function_object const& self, invoke_context& ctx + , tagged_function const& tagged + , Signature, Policies const& policies) +{ + return invoke(L, self, ctx, tagged.f, Signature(), policies); +} + +template +struct signature_from_function; + +# define BOOST_PP_ITERATION_PARAMS_1 \ + (3, (0, LUAPONTE_MAX_ARITY, )) +# include BOOST_PP_ITERATE() + +} // namespace detail + +template +detail::tagged_function< + typename detail::signature_from_function::type + , F +> +tag_function(F f) +{ + return f; +} + +} // namespace luaponte + +# endif // LUAPONTE_TAG_FUNCTION_HPP + +#else // BOOST_PP_IS_ITERATING + +# define N BOOST_PP_ITERATION() +# define NPLUS1 BOOST_PP_INC(N) + +template +struct signature_from_function +{ + typedef BOOST_PP_CAT(mpl::vector, NPLUS1)< + R BOOST_PP_ENUM_TRAILING_PARAMS(N, A) + > type; +}; + +#endif // BOOST_PP_IS_ITERATING diff --git a/luaponte/typeid.hpp b/luaponte/typeid.hpp new file mode 100644 index 0000000..2cfe266 --- /dev/null +++ b/luaponte/typeid.hpp @@ -0,0 +1,89 @@ +// Luaponte library + +// Copyright (c) 2011-2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_TYPEID_HPP +# define LUAPONTE_TYPEID_HPP + +# include +# include +# include +# include +# include + +// boost/units/detail/utility.hpp +# if defined(__GLIBCXX__) || defined(__GLIBCPP__) +# define LUAPONTE_USE_DEMANGLING +# include +# endif // __GNUC__ + +namespace luaponte { + +# ifdef BOOST_MSVC +# pragma warning(push) +// std::type_info::before() returns int, rather than bool. +// At least on MSVC7.1, this is true for the comparison +// operators as well. +# pragma warning(disable:4800) +# endif + +class type_id + : public boost::less_than_comparable +{ +public: + type_id() + : id(&typeid(detail::null_type)) + {} + + type_id(std::type_info const& id) + : id(&id) + {} + + bool operator!=(type_id const& other) const + { + return std::strcmp(id->name(), other.id->name()) != 0; + } + + bool operator==(type_id const& other) const + { + return std::strcmp(id->name(), other.id->name()) == 0; + } + + bool operator<(type_id const& other) const + { + return std::strcmp(id->name(), other.id->name()) < 0; + } + + std::string name() const + { +# ifdef LUAPONTE_USE_DEMANGLING + int status; + char* buf = abi::__cxa_demangle(id->name(), 0, 0, &status); + if (buf != 0) { + std::string name(buf); + std::free(buf); + return name; + } +# endif + return id->name(); + } + +private: + std::type_info const* id; +}; + +# ifdef BOOST_MSVC +# pragma warning(pop) +# endif + +} // namespace luaponte + +#endif // LUAPONTE_TYPEID_HPP diff --git a/luaponte/value_wrapper.hpp b/luaponte/value_wrapper.hpp new file mode 100644 index 0000000..347ae3b --- /dev/null +++ b/luaponte/value_wrapper.hpp @@ -0,0 +1,155 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_VALUE_WRAPPER_HPP +#define LUAPONTE_VALUE_WRAPPER_HPP + +#include +#include +#include + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +# define LUAPONTE_USE_VALUE_WRAPPER_TAG +#else +#endif + +#ifdef LUAPONTE_USE_VALUE_WRAPPER_TAG +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +namespace luaponte { + +// +// Concept ``ValueWrapper`` +// + +#ifdef LUAPONTE_USE_VALUE_WRAPPER_TAG +template +struct value_wrapper_traits; + +namespace detail { + + BOOST_MPL_HAS_XXX_TRAIT_DEF(value_wrapper_tag); + + struct unspecialized_value_wrapper_traits + { + typedef boost::mpl::false_ is_specialized; + }; + + template + struct value_wrapper_traits_aux + { + typedef value_wrapper_traits type; + }; + +} // namespace detail +#endif + +template +struct value_wrapper_traits +#ifdef LUAPONTE_USE_VALUE_WRAPPER_TAG + : boost::mpl::eval_if< + boost::mpl::and_< + boost::mpl::not_< + boost::mpl::or_< + boost::is_reference + , boost::is_pointer + , boost::is_array + > + > + , detail::has_value_wrapper_tag + > + , detail::value_wrapper_traits_aux + , boost::mpl::identity + >::type +{}; +#else +{ + typedef boost::mpl::false_ is_specialized; +}; +#endif + +template +struct is_value_wrapper + : boost::mpl::aux::msvc_eti_base< + typename value_wrapper_traits::is_specialized + >::type +{}; + +} // namespace luaponte + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +# include +# include + +namespace luaponte { + +template +struct is_value_wrapper_arg + : is_value_wrapper< + typename boost::remove_const< + typename boost::remove_reference::type + >::type + > +{}; + +} // namespace luaponte + +#else + +# include +# include + +namespace luaponte { +namespace detail { + + template + typename is_value_wrapper::type is_value_wrapper_arg_check(T const*); + + yes_t to_yesno(boost::mpl::true_); + no_t to_yesno(boost::mpl::false_); + + template + struct is_value_wrapper_arg_aux + { + static typename boost::add_reference::type x; + + BOOST_STATIC_CONSTANT(bool, value = + sizeof(to_yesno(is_value_wrapper_arg_check(&x))) + == sizeof(yes_t) + ); + + typedef boost::mpl::bool_ type; + }; + +} // namespace detail + +template +struct is_value_wrapper_arg + : detail::is_value_wrapper_arg_aux::type +{ +}; + +} // namespace luaponte + +#endif + +#endif // LUAPONTE_VALUE_WRAPPER_HPP diff --git a/luaponte/version.hpp b/luaponte/version.hpp new file mode 100644 index 0000000..8be0381 --- /dev/null +++ b/luaponte/version.hpp @@ -0,0 +1,24 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_VERSION_HPP +#define LUAPONTE_VERSION_HPP + +#define LUAPONTE_VERSION 100 + +// Each component uses two digits, so: +// +// major = LUAPONTE_VERSION / 10000 +// minor = LUAPONTE_VERSION / 100 % 100 +// patch = LUAPONTE_VERSION % 100 + +#endif // LUAPONTE_VERSION_HPP diff --git a/luaponte/weak_ref.hpp b/luaponte/weak_ref.hpp new file mode 100644 index 0000000..d6c3b08 --- /dev/null +++ b/luaponte/weak_ref.hpp @@ -0,0 +1,48 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_WEAK_REF_HPP +#define LUAPONTE_WEAK_REF_HPP + +#include + +struct lua_State; + +namespace luaponte { + +class LUAPONTE_API weak_ref +{ +public: + weak_ref(); + weak_ref(lua_State* main, lua_State* L, int index); + weak_ref(weak_ref const&); + ~weak_ref(); + + weak_ref& operator=(weak_ref const&); + + void swap(weak_ref&); + + // returns a unique id that no + // other weak ref will return + int id() const; + + lua_State* state() const; + void get(lua_State* L) const; + +private: + struct impl; + impl* m_impl; +}; + +} // namespace luaponte + +#endif // LUAPONTE_WEAK_REF_HPP diff --git a/luaponte/wrapper_base.hpp b/luaponte/wrapper_base.hpp new file mode 100644 index 0000000..d0fd727 --- /dev/null +++ b/luaponte/wrapper_base.hpp @@ -0,0 +1,183 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !BOOST_PP_IS_ITERATING + +#ifndef LUAPONTE_WRAPPER_BASE_HPP +#define LUAPONTE_WRAPPER_BASE_HPP + +#include +#include +#include +#include + +#include +#include + +#include + +namespace luaponte { +namespace detail { + +struct wrap_access; + +// implements the selection between dynamic dispatch +// or default implementation calls from within a virtual +// function wrapper. The input is the self reference on +// the top of the stack. Output is the function to call +// on the top of the stack (the input self reference will +// be popped) +LUAPONTE_API void do_call_member_selection(lua_State* L, char const* name); + +} // namespace detail + +struct wrapped_self_t: weak_ref +{ + detail::lua_reference m_strong_ref; +}; + +struct wrap_base +{ + friend struct detail::wrap_access; + wrap_base() {} + +#define BOOST_PP_ITERATION_PARAMS_1 (4, (0, LUAPONTE_MAX_ARITY, , 1)) +#include BOOST_PP_ITERATE() + +private: + wrapped_self_t m_self; +}; + +#define BOOST_PP_ITERATION_PARAMS_1 (4, (0, LUAPONTE_MAX_ARITY, , 2)) +#include BOOST_PP_ITERATE() + +namespace detail { + +struct wrap_access +{ + static wrapped_self_t const& ref(wrap_base const& b) + { + return b.m_self; + } + + static wrapped_self_t& ref(wrap_base& b) + { + return b.m_self; + } +}; + +} // namespace detail +} // namespace luaponte + +#endif // LUAPONTE_WRAPPER_BASE_HPP + +#else +#if BOOST_PP_ITERATION_FLAGS() == 1 + +#define LUAPONTE_TUPLE_PARAMS(z, n, data) const A##n * +#define LUAPONTE_OPERATOR_PARAMS(z, n, data) const A##n & a##n + +template + typename boost::mpl::if_ + , luaponte::detail::proxy_member_void_caller > + , luaponte::detail::proxy_member_caller > >::type + call(char const* name BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUAPONTE_OPERATOR_PARAMS, _), detail::type_* = 0) const + { + typedef boost::tuples::tuple tuple_t; +#if BOOST_PP_ITERATION() == 0 + tuple_t args; +#else + tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a)); +#endif + + typedef typename boost::mpl::if_ + , luaponte::detail::proxy_member_void_caller > + , luaponte::detail::proxy_member_caller > >::type proxy_type; + + // this will be cleaned up by the proxy object + // once the call has been made + + // TODO: what happens if this virtual function is + // dispatched from a lua thread where the state + // pointer is different? + + // get the function + lua_State* L = m_self.state(); + m_self.get(L); + assert(!lua_isnil(L, -1)); + detail::do_call_member_selection(L, name); + + if (lua_isnil(L, -1)) + { + lua_pop(L, 1); + throw std::runtime_error("Attempt to call nonexistent function"); + } + + // push the self reference as the first parameter + m_self.get(L); + + // now the function and self objects + // are on the stack. These will both + // be popped by pcall + return proxy_type(L, args); + } + +#undef LUAPONTE_CALL_MEMBER_NAME +#undef LUAPONTE_OPERATOR_PARAMS +#undef LUAPONTE_TUPLE_PARAMS + +#else // free call_member forwardarding functions + +#define N BOOST_PP_ITERATION() + +#define LUAPONTE_TUPLE_PARAMS(z, n, data) const A##n * +#define LUAPONTE_OPERATOR_PARAMS(z, n, data) const A##n & a##n + +template< + class R + BOOST_PP_ENUM_TRAILING_PARAMS(N, class A) +> +typename boost::mpl::if_< + boost::is_void + , detail::proxy_member_void_caller< + boost::tuples::tuple< + BOOST_PP_ENUM(N, LUAPONTE_TUPLE_PARAMS, _) + > + > + , detail::proxy_member_caller< + R + , boost::tuples::tuple< + BOOST_PP_ENUM(N, LUAPONTE_TUPLE_PARAMS, _) + > + > +>::type +call_member( + wrap_base const* self + , char const* fn + BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, A, &a) + , detail::type_* = 0 +) +{ + return self->call( + fn + BOOST_PP_ENUM_TRAILING_PARAMS(N, a) + , (detail::type_*)0 + ); +} + +#undef LUAPONTE_OPERATOR_PARAMS +#undef LUAPONTE_TUPLE_PARAMS + +#undef N + +#endif +#endif diff --git a/luaponte/yield_policy.hpp b/luaponte/yield_policy.hpp new file mode 100644 index 0000000..f2b231c --- /dev/null +++ b/luaponte/yield_policy.hpp @@ -0,0 +1,46 @@ +// Luaponte library + +// Copyright (c) 2012 Peter Colberg + +// Luaponte is based on Luabind, a library, inspired by and similar to +// Boost.Python, that helps you create bindings between C++ and Lua, +// Copyright (c) 2003-2010 Daniel Wallin and Arvid Norberg. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LUAPONTE_YIELD_POLICY_HPP +#define LUAPONTE_YIELD_POLICY_HPP + +#include +#include + +namespace luaponte { +namespace detail { + +struct yield_policy +{ + static void precall(lua_State*, const index_map&) {} + static void postcall(lua_State*, const index_map&) {} +}; + +} // namespace detail +} // namespace luaponte + +namespace luaponte { + +detail::policy_cons const yield = {}; + +namespace detail { + +inline void ignore_unused_yield() +{ + (void)yield; +} + +} // namespace detail +} // luaponte + +#endif // LUAPONTE_YIELD_POLICY_HPP + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fbf1e23..98a882d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ if(WIN32) include_directories(../external/glm/) include_directories(../external/lua/include) - include_directories(../external/luabind/include) + include_directories(../external/luaponte/include) include_directories(../external/cpptest/include) include_directories(../external/glfw/include) include_directories(../external/glew/include) @@ -12,7 +12,7 @@ if(WIN32) include_directories(../external/devil/include) include_directories(../external/boost/include) else(WIN32) - link_libraries(glfw GLEW IL assimp pthread cpptest lua luabind GL) + link_libraries(glfw GLEW IL assimp pthread cpptest lua luaponte GL) endif(WIN32) #compiler flags @@ -20,22 +20,21 @@ if(WIN32) SET(CMAKE_CXX_FLAGS_DEBUG "/MTd /W3") SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG /FORCE:MULTIPLE") else(WIN32) - add_definitions(-ggdb -std=c++0x -Wall -lpthread) + add_definitions(-ggdb -std=c++11 -Wall -lpthread -fpermissive) endif(WIN32) #add include directories for compiler +include_directories(/usr/include/lua/5.2/) include_directories(../BambooEngine/include/) include_directories(../include/) +include_directories(../) include_directories(../include/tinyxml/) include_directories(../test/) #define headers, not for compile time, only for QtCreator file(GLOB H_BAMBOO "../BambooEngine/include/*.h") file(GLOB H_BAMBOO_RN "../BambooEngine/include/RenderNodes/*.h") -file(GLOB H_BAMBOO_SO "../BambooEngine/include/SceneObjects/*.h") file(GLOB H_BAMBOO_SSN "../BambooEngine/include/SemanticSceneNodes/*.h") -file(GLOB H_BAMBOO_RSN "../BambooEngine/include/RenderingSceneNodes/*.h") -file(GLOB H_BAMBOO_STO "../BambooEngine/include/StateObjects/*.h") file(GLOB H_BAMBOO_DNT "../BambooEngine/include/DeferredNodeTranslator/*.h") file(GLOB H_GAMELOGIC "../include/Gamelogic/*.h") file(GLOB H_GAMELOGIC_OBJ "../include/Gamelogic/Objects/*.h") @@ -59,9 +58,7 @@ file(GLOB HEADERS "../include/*.h" #define sources file(GLOB S_BAMBOO "../BambooEngine/src/*.cpp") file(GLOB S_BAMBOO_RN "../BambooEngine/src/RenderNodes/*.cpp") -file(GLOB S_BAMBOO_SO "../BambooEngine/src/SceneObjects/*.cpp") file(GLOB S_BAMBOO_SSN "../BambooEngine/src/SemanticSceneNodes/*.cpp") -file(GLOB S_BAMBOO_RSN "../BambooEngine/src/RenderingSceneNodes/*.cpp") file(GLOB S_BAMBOO_STO "../BambooEngine/src/StateObjects/*.cpp") file(GLOB S_BAMBOO_DNT "../BambooEngine/src/DeferredNodeTranslator/*.cpp") file(GLOB S_GAMELOGIC "../src/Gamelogic/*.cpp") @@ -89,7 +86,7 @@ if(WIN32) SOURCE_GROUP("Header Files\\DummyGame" FILES ${H_DUMMYGAME}) SOURCE_GROUP("Header Files\\BambooEngine" FILES ${H_BAMBOO}) SOURCE_GROUP("Header Files\\BambooEngine\\RenderNodes" FILES ${H_BAMBOO_RN}) - SOURCE_GROUP("Header Files\\BambooEngine\\SceneObjects" FILES ${H_BAMBOO_SO}) + SOURCE_GROUP("Header Files\\BambooEngine\\SemanticSceneNodes" FILES ${H_BAMBOO_SO}) SOURCE_GROUP("Header Files\\BambooEngine\\SemanticSceneNodes" FILES ${H_BAMBOO_SSN}) SOURCE_GROUP("Header Files\\BambooEngine\\RenderingSceneNodes" FILES ${H_BAMBOO_RSN}) SOURCE_GROUP("Header Files\\BambooEngine\\StateObjects" FILES ${H_BAMBOO_STO}) @@ -101,7 +98,7 @@ if(WIN32) SOURCE_GROUP("Source Files\\DummyGame" FILES ${S_DUMMYGAME}) SOURCE_GROUP("Source Files\\BambooEngine" FILES ${S_BAMBOO}) SOURCE_GROUP("Source Files\\BambooEngine\\RenderNodes" FILES ${S_BAMBOO_RN}) - SOURCE_GROUP("Source Files\\BambooEngine\\SceneObjects" FILES ${S_BAMBOO_SO}) + SOURCE_GROUP("Source Files\\BambooEngine\\SemanticSceneNodes" FILES ${S_BAMBOO_SO}) SOURCE_GROUP("Source Files\\BambooEngine\\SemanticSceneNodes" FILES ${S_BAMBOO_SSN}) SOURCE_GROUP("Source Files\\BambooEngine\\RenderingSceneNodes" FILES ${S_BAMBOO_RSN}) SOURCE_GROUP("Source Files\\BambooEngine\\StateObjects" FILES ${S_BAMBOO_STO}) @@ -127,6 +124,6 @@ if(WIN32) target_link_libraries(project-cube ../../Project-Cube/external/glew/lib/glew32) target_link_libraries(project-cube ../../Project-Cube/external/glfw/lib-msvc100/debug/GLFW) target_link_libraries(project-cube ../../Project-Cube/external/lua/msvc-10.0-x86/lua.debug) - target_link_libraries(project-cube ../../Project-Cube/external/luabind/msvc-10.0-x86/luabind.debug) + target_link_libraries(project-cube ../../Project-Cube/external/luaponte/msvc-10.0-x86/luaponte.debug) endif(WIN32) diff --git a/src/DummyGame/SampleObject.cpp b/src/DummyGame/SampleObject.cpp index ca8ee73..9b8023a 100644 --- a/src/DummyGame/SampleObject.cpp +++ b/src/DummyGame/SampleObject.cpp @@ -1,5 +1,5 @@ #include "DummyGame/SampleObject.h" -#include "SemanticSceneNodes\Light_SemSceneNode.h" +#include "SemanticSceneNodes/Light_SemSceneNode.h" glm::mat4 SampleObject::GetTransformation() { diff --git a/src/EventManager.cpp b/src/EventManager.cpp index befa1f9..9963959 100644 --- a/src/EventManager.cpp +++ b/src/EventManager.cpp @@ -78,17 +78,17 @@ void EventManager::Test() lua_State *myLuaState = lua_open(); // Connect LuaBind to this lua state - luabind::open(myLuaState); + luaponte::open(myLuaState); - luabind::module(myLuaState) + luaponte::module(myLuaState) [ - luabind::class_("EventManager") + luaponte::class_("EventManager") .def("CreateEvent2", &EventManager::CreateEvent2), - luabind::class_("IEvent"), - luabind::class_("InputEvent"), - luabind::class_("InputMouse") - //luabind::def("eventmanager", this) + luaponte::class_("IEvent"), + luaponte::class_("InputEvent"), + luaponte::class_("InputMouse") + //luaponte::def("eventmanager", this) ]; luaL_openlibs(myLuaState); @@ -100,7 +100,7 @@ void EventManager::Test() "end\n" ); - luabind::globals(myLuaState)["eventmanager2"] = this; + luaponte::globals(myLuaState)["eventmanager2"] = this; // Define a lua function that we can call luaL_dostring( @@ -115,11 +115,11 @@ void EventManager::Test() try { - int a = luabind::call_function(myLuaState, "test2", ""); + int a = luaponte::call_function(myLuaState, "test2", ""); std::cout << a << std::endl; } - catch (luabind::error &e) + catch (luaponte::error &e) { std::cerr << lua_tostring(myLuaState, -1) << std::endl; } @@ -275,13 +275,13 @@ lua_State * EventManager::RegisterLua() lua_State *pLuaState = LuaManager::GetInstance()->GetLuaState(); /*assert (pLuaState != NULL); - luabind::module(pLuaState) + luaponte::module(pLuaState) [ - luabind::class_("EventManager") + luaponte::class_("EventManager") .def("QueueEvent", &EventManager::QueueEvent) ]; - luabind::globals(pLuaState)["eventmanager"] = this; + luaponte::globals(pLuaState)["eventmanager"] = this; */ return pLuaState; } diff --git a/src/Events.cpp b/src/Events.cpp index b01d27a..aa00c6a 100644 --- a/src/Events.cpp +++ b/src/Events.cpp @@ -53,10 +53,10 @@ void InputKeyEvent::RegisterLua() { lua_State *pLuaState = LuaManager::GetInstance()->GetLuaState(); - /*luabind::module(pLuaState) + /*luaponte::module(pLuaState) [ - luabind::class_("IEvent"), - luabind::class_ >("InputKeyEvent") + luaponte::class_("IEvent"), + luaponte::class_ >("InputKeyEvent") .def("Create", &InputKeyEvent::Create) .def("GetKey", &InputKeyEvent::GetKey) .def("GetEvent", &InputKeyEvent::GetEvent) @@ -101,10 +101,10 @@ void InputMouseButtonEvent::RegisterLua() { lua_State *pLuaState = LuaManager::GetInstance()->GetLuaState(); - /*luabind::module(pLuaState) + /*luaponte::module(pLuaState) [ - //luabind::class_("IEvent"), - luabind::class_ >("InputMouseButtonEvent") + //luaponte::class_("IEvent"), + luaponte::class_ >("InputMouseButtonEvent") .def("Create", &InputMouseButtonEvent::Create) .def("GetMouseButton", &InputMouseButtonEvent::GetMouseButton) ];*/ @@ -142,10 +142,10 @@ void InputMouseMoveEvent::RegisterLua() { lua_State *pLuaState = LuaManager::GetInstance()->GetLuaState(); - /*luabind::module(pLuaState) + /*luaponte::module(pLuaState) [ - //luabind::class_("IEvent"), - luabind::class_ >("InputMouseMoveEvent") + //luaponte::class_("IEvent"), + luaponte::class_ >("InputMouseMoveEvent") .def("Create", &InputMouseMoveEvent::Create) .def("GetX", &InputMouseMoveEvent::GetX) .def("GetY", &InputMouseMoveEvent::GetY) @@ -183,10 +183,10 @@ void CameraMovementEvent::RegisterLua() { lua_State *pLuaState = LuaManager::GetInstance()->GetLuaState(); - /*luabind::module(pLuaState) + /*luaponte::module(pLuaState) [ - //luabind::class_("IEvent"), - luabind::class_ >("CameraMovementEvent") + //luaponte::class_("IEvent"), + luaponte::class_ >("CameraMovementEvent") .def("Create", &CameraMovementEvent::Create) .def("GetMovementType", &CameraMovementEvent::GetMovementType) .def("GetValue", &CameraMovementEvent::GetValue) diff --git a/src/Gamelogic/Level.cpp b/src/Gamelogic/Level.cpp index d63f0a7..70b2908 100644 --- a/src/Gamelogic/Level.cpp +++ b/src/Gamelogic/Level.cpp @@ -1,7 +1,7 @@ #include "Gamelogic/Level.h" -#include "SemanticSceneNodes\Camera_SemSceneNode.h" -#include "SemanticSceneNodes\Cube_SemSceneNode.h" -#include "Gamelogic\Objects\Object.h" +#include "SemanticSceneNodes/Camera_SemSceneNode.h" +#include "SemanticSceneNodes/Cube_SemSceneNode.h" +#include "Gamelogic/Objects/Object.h" #include using namespace std; @@ -670,4 +670,4 @@ void Level::itlInitSemanticSceneNode() { m_spCamera = Bamboo::PerspectiveCamera::Create(45.0f, 1.33f, 0.01f, 100.0f, glm::vec3(-0.2f, 0.2f, 0.0f), 90.0f, -50.0f); m_spSemanticScene = Camera_SemSceneNode::Create(m_spCamera); -} \ No newline at end of file +} diff --git a/src/Gamelogic/Objects/LightObject.cpp b/src/Gamelogic/Objects/LightObject.cpp index 422a36b..468ff81 100644 --- a/src/Gamelogic/Objects/LightObject.cpp +++ b/src/Gamelogic/Objects/LightObject.cpp @@ -1,4 +1,4 @@ -#include "Gamelogic\Objects\LightObject.h" +#include "Gamelogic/Objects/LightObject.h" LightObject::LightObject(std::string sName) { @@ -59,4 +59,4 @@ void LightObject::SetNearplane(const float fNearplane) void LightObject::SetFarplane(const float fFarplane) { m_spLightSceneNode->SetFarplane(fFarplane); -} \ No newline at end of file +} diff --git a/src/Gamelogic/Objects/Object.cpp b/src/Gamelogic/Objects/Object.cpp index fefdca6..4e6b958 100644 --- a/src/Gamelogic/Objects/Object.cpp +++ b/src/Gamelogic/Objects/Object.cpp @@ -1,4 +1,4 @@ -#include "Gamelogic\Objects\Object.h" +#include "Gamelogic/Objects/Object.h" Object::Object(std::string sName, std::string sFilename) { @@ -48,4 +48,4 @@ void Object::ActivateEnvironmentMapping() void Object::DeactivateEnvironmentMapping() { m_spObjectSceneNode->DeactivateEnvironmentMapping(); -} \ No newline at end of file +} diff --git a/src/LuaManager.cpp b/src/LuaManager.cpp index 7d56ff1..c5267ae 100644 --- a/src/LuaManager.cpp +++ b/src/LuaManager.cpp @@ -31,7 +31,7 @@ void LuaManager::InitLua() luaL_openlibs(m_pLuaState); - luabind::open(m_pLuaState); + luaponte::open(m_pLuaState); ExecuteFile("lua/functions.lua"); @@ -47,10 +47,10 @@ void LuaManager::RegisterClasses() { Logger::debug() << "Registering classes to LUA" << Logger::endl; // Register Grid class - luabind::module(m_pLuaState) + luaponte::module(m_pLuaState) [ - luabind::class_("Grid") - .def(luabind::constructor<>()) + luaponte::class_("Grid") + .def(luaponte::constructor<>()) .def("AddDoor", (bool(Grid::*)(int, int))&Grid::AddDoor) .def("ClearGrid", &Grid::ClearGrid) .def("GetDoorPositions", &Grid::GetDoorPositions) @@ -63,10 +63,10 @@ void LuaManager::RegisterClasses() ]; // Register Cube class - luabind::module(m_pLuaState) + luaponte::module(m_pLuaState) [ - luabind::class_("Cube") - .def(luabind::constructor<>()) + luaponte::class_("Cube") + .def(luaponte::constructor<>()) .def("GetCubeID", &Cube::GetCubeID) .def("GetCubePosition", &Cube::GetCubePosition) .def("GetTransfomation", &Cube::GetTransformation) @@ -90,10 +90,10 @@ void LuaManager::RegisterClasses() ]; // Register Level class - luabind::module(m_pLuaState) + luaponte::module(m_pLuaState) [ - luabind::class_("Level") - .def(luabind::constructor<>()) + luaponte::class_("Level") + .def(luaponte::constructor<>()) .def("GetLevelID", &Level::GetLevelID) .def("GetLevelName", &Level::GetLevelName) .def("GetNumCubes", &Level::GetNumCubes) @@ -112,10 +112,10 @@ void LuaManager::RegisterClasses() ]; // Register Object class - luabind::module(m_pLuaState) + luaponte::module(m_pLuaState) [ - luabind::class_("Object") - .def(luabind::constructor()) + luaponte::class_("Object") + .def(luaponte::constructor()) .def("Translate", &Object::Translate) .def("Scale", &Object::Scale) .def("ActivateEnvironmentMapping", &Object::ActivateEnvironmentMapping) @@ -124,10 +124,10 @@ void LuaManager::RegisterClasses() ]; // Register Lightobject class - luabind::module(m_pLuaState) + luaponte::module(m_pLuaState) [ - luabind::class_("Light") - .def(luabind::constructor()) + luaponte::class_("Light") + .def(luaponte::constructor()) .def("GetObjectType", &LightObject::GetObjectType) .def("GetName", &LightObject::GetName) .def("SetPosition", &LightObject::SetPosition) @@ -144,11 +144,16 @@ void LuaManager::ExecuteFile(std::string sFile) Logger::debug() << "Executing LUA file: "<< sFile << Logger::endl; try { - luaL_dofile(m_pLuaState, sFile.c_str()); + { + std::ifstream sTest(sFile.c_str()); + assert (sTest.is_open()); + } + + luaL_dofile(m_pLuaState, sFile.data()); } catch(std::exception e) { Logger::error() << e.what() << Logger::endl; lua_tostring(m_pLuaState, -1); } -} \ No newline at end of file +} diff --git a/src/MainApp.cpp b/src/MainApp.cpp index 4aba47d..465d446 100644 --- a/src/MainApp.cpp +++ b/src/MainApp.cpp @@ -21,6 +21,7 @@ MainApp * MainApp::s_pInstance = NULL; std::shared_ptr g_spSphere; +std::shared_ptr g_spTreppe; MainApp::MainApp() { @@ -125,22 +126,25 @@ void MainApp::StartGraphic_Test2() GetEventManager()->RegisterEventListener(this, CameraMovementEvent::EventType()); // load level - LuaManager::GetInstance()->ExecuteFile("lua/test.lua"); + // LuaManager::GetInstance()->ExecuteFile("lua/test.lua"); - Level level = LuaManager::GetInstance()->CallLuaFunction("GetLevel"); + // Level level = LuaManager::GetInstance()->CallLuaFunction("GetLevel"); // create scene nodes - std::shared_ptr spTreppe = LoadedModel_SemSceneNode::Create("models/bunte-treppe3.dae"); + std::shared_ptr spTreppe = LoadedModel_SemSceneNode::Create("models/bunte-treppe3.dae"); spTreppe->SetTransformMatrix(glm::scale(glm::mat4(), glm::vec3(0.01, 0.01, 0.01))); std::shared_ptr spSphere = LoadedModel_SemSceneNode::Create("models/pool_sphere.dae"); spSphere->SetTransformMatrix(glm::scale(glm::mat4(), glm::vec3(0.01, 0.01, 0.01))); spSphere->SetTransformMatrix(glm::translate(spSphere->GetTransformMatrix(), glm::vec3(0.0, 2.0, 0.0))); + //spTreppe->ActivateEnvironmentMapping(); spSphere->ActivateEnvironmentMapping(); g_spSphere = spSphere; - std::shared_ptr spCube = Cube_SemSceneNode::Create(level.GetCubeByPosition(0,0,0)); + g_spTreppe = spTreppe; + + //std::shared_ptr spCube = Cube_SemSceneNode::Create(level.GetCubeByPosition(0,0,0)); //spCube->SetTransformMatrix(glm::scale(glm::mat4(), glm::vec3(0.01, 0.01, 0.01))); std::shared_ptr spTestLight1 = Light_SemSceneNode::Create(glm::vec3(-0.2f, 0.10f, 0.14f), glm::vec3(1.0f, -0.4f, -1.0f), 50.0f, glm::vec3(1.0, 1.0, 1.0), 0.1, 50.0f); @@ -151,7 +155,7 @@ void MainApp::StartGraphic_Test2() // link scene graph spCamera->AddChild(spTreppe); spCamera->AddChild(spSphere); - spCamera->AddChild(spCube); + //spCamera->AddChild(spCube); spCamera->AddChild(spTestLight1); spCamera->AddChild(spTestLight2); @@ -166,76 +170,6 @@ void MainApp::StartGraphic_Test2() m_pGraphic->AddRenderLoop(spWindow, spCamera, spDeferredTranslator); } -void MainApp::StartGraphic_Test() -{ -#ifdef something - // create glfw window - std::shared_ptr spWindow = Bamboo::GlfwWindow::Create(1024, 768, "Test"); - // set input event listener - spWindow->SetInputEventListener(m_spInputEventListener); - - // create camera - m_spCamera = Bamboo::PerspectiveCamera::Create(90.0f, 1.0f, 0.01f, 100.0f, glm::vec3(-0.2f, 0.2f, 0.0f), 90.0f, -50.0f); - - // create scene - std::shared_ptr spScene = Bamboo::Scene::Create(); - - // create objects - - std::shared_ptr spTestLight1 = Bamboo::SO_SpotLight::Create(glm::vec3(-0.2f, 0.10f, 0.14f), glm::vec3(1.0f, -0.4f, -1.0f), 45.0f, glm::vec3(1.0f, 1.0f, 1.0f)); - //std::shared_ptr spTestLight2 = Bamboo::SO_SpotLight::Create(glm::vec3(0.0f, 0.25f, -0.09f), glm::vec3(0.0f, -2.0f, 1.0f), 5.0f, glm::vec3(1.0f, 1.0f, 1.0f)); - std::shared_ptr spTestLight3 = Bamboo::SO_SpotLight::Create(glm::vec3(-0.2f, 0.2f, -0.14f), glm::vec3(1.0f, -1.1f, 0.62f), 45.0f, glm::vec3(1.0f, 1.0f, 1.0f)); - std::shared_ptr spTestLight4 = Bamboo::SO_SpotLight::Create(glm::vec3(0.0f, 0.3f, 0.0f), glm::vec3(0.2f, -1.0f, 0.0f), 45.0f, glm::vec3(1.0f, 1.0f, 1.0f)); - std::shared_ptr spTestLight5 = Bamboo::SO_SpotLight::Create(glm::vec3(-0.2f, 0.20f, 0.16f), glm::vec3(1.0f, -0.9f, -1.0f), 45.0f, glm::vec3(0.5f, 0.5f, 0.5f)); - std::shared_ptr spTestLight6 = Bamboo::SO_SpotLight::Create(glm::vec3(-0.2f, 0.20f, 0.18f), glm::vec3(1.0f, -0.9f, -1.0f), 45.0f, glm::vec3(0.5f, 0.5f, 0.5f)); - - //spLight->SetTransformMatrix(glm::translate(0.0f, 1.0f, 0.0f)); - - - std::shared_ptr spTreppe = Bamboo::SO_LoadedModel::Create("models/bunte-treppe3.dae"); - std::shared_ptr spSphere = Bamboo::SO_LoadedModel::Create("models/pool_sphere.dae"); - // std::shared_ptr spTable = Bamboo::SO_LoadedModel::Create("models/table.dae"); - spTreppe->SetTransformMatrix(glm::scale(glm::mat4(), glm::vec3(0.01, 0.01, 0.01))); - spSphere->SetTransformMatrix(glm::scale(glm::mat4(), glm::vec3(0.01, 0.01, 0.01))); - //spTable->SetTransformMatrix(glm::scale(glm::mat4(), glm::vec3(0.01, 0.01, 0.01)) * glm::translate(glm::mat4(), glm::vec3(0.0f, -0.9f, 0.0f))); - - g_spTreppe = spTreppe; - - // load level - LuaManager::GetInstance()->ExecuteFile("lua/test.lua"); - - Level level = LuaManager::GetInstance()->CallLuaFunction("GetLevel"); - - // add doors - /* level.GetCubeByPosition(0,0,0)->GetGrid(3).AddDoor(5,2); - level.GetCubeByPosition(0,0,0)->GetGrid(3).AddDoor(5,9); - level.GetCubeByPosition(0,0,0)->GetGrid(3).AddDoor(3,3);*/ - - std::shared_ptr spCube = Bamboo::SO_Cube::Create(level.GetCubeByPosition(0,0,0)); - - // add objects to scene - spScene->AttachObject(spCube); - spScene->AttachObject(spTreppe); - spScene->AttachObject(spSphere); - - // add light to scene - spScene->AttachObject(spTestLight1); - // spScene->AttachObject(spTestLight5); - // spScene->AttachObject(spTestLight6); - //spScene->AttachObject(spTestLight2); - spScene->AttachObject(spTestLight3); - //spScene->AttachObject(spTestLight4); - - - // add render loop - GetGraphic()->AddRenderLoop(spWindow, m_spCamera, spScene); - - // register itself as listener for camera events - GetEventManager()->RegisterEventListener(this, CameraMovementEvent::EventType()); - -#endif -} - void MainApp::Run() { // init game logic, graphics, do main loop, all this nasty stuff. @@ -254,9 +188,17 @@ void MainApp::Run() i++; //g_spSphere->SetTransformMatrix(glm::translate(g_spSphere->GetTransformMatrix(), glm::vec3(cos(i / 400.0) / 100.0, sin(i / 400.0) / 400.0, sin(i / 400.0) / 100.0))); + //g_spTreppe->SetTransformMatrix(glm::rotate(g_spTreppe->GetTransformMatrix(), 0.04f, glm::vec3(1.0, 1.0, 0.0))); + + if (i == 2000) + g_spSphere->DeactivateEnvironmentMapping(); + if (i==3000) + g_spSphere->ActivateEnvironmentMapping(); GetGraphic()->Render(); } + + } Bamboo * MainApp::GetGraphic() @@ -277,11 +219,6 @@ DummyGame * MainApp::GetGame() return m_pGame; } -void MainApp::ItlCreateSceneGraphs() -{ - -} - void MainApp::InputEventListener::ItlHandleKeyboardEvent(int iKeyIdentifier, int iNewKeyState) { InputKeyEvent::TKey eKey = InputKeyEvent::KEY_UNKNOWN;