This commit is contained in:
Huoji's
2023-10-03 04:07:50 +08:00
parent f08e0b90fa
commit 8f3005e9b2
50 changed files with 11966 additions and 107 deletions

View File

@@ -0,0 +1,62 @@
// https://github.com/vinniefalco/LuaBridge
//
// Copyright 2020, Dmitry Tarakanov
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <array>
namespace luabridge {
template<class T, std::size_t s>
struct Stack<std::array<T, s>>
{
static void push(lua_State* L, std::array<T, s> const& array)
{
lua_createtable(L, static_cast<int>(s), 0);
for (std::size_t i = 0; i < s; ++i)
{
lua_pushinteger(L, static_cast<lua_Integer>(i + 1));
Stack<T>::push(L, array[i]);
lua_settable(L, -3);
}
}
static std::array<T, s> get(lua_State* L, int index)
{
if (!lua_istable(L, index))
{
luaL_error(L, "#%d argument must be table", index);
}
std::size_t const tableSize = static_cast<std::size_t>(get_length(L, index));
if (tableSize != s)
{
luaL_error(L, "array size must be %d ", s);
}
std::array<T, s> array;
int const absindex = lua_absindex(L, index);
lua_pushnil(L);
int arrayIndex = 0;
while (lua_next(L, absindex) != 0)
{
array[arrayIndex] = Stack<T>::get(L, -1);
lua_pop(L, 1);
++arrayIndex;
}
return array;
}
static bool isInstance(lua_State* L, int index)
{
return lua_istable(L, index) && get_length(L, index) == s;
}
};
} // namespace luabridge

View File

@@ -0,0 +1,51 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2020, Dmitry Tarakanov
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <list>
namespace luabridge {
template<class T>
struct Stack<std::list<T>>
{
static void push(lua_State* L, std::list<T> const& list)
{
lua_createtable(L, static_cast<int>(list.size()), 0);
typename std::list<T>::const_iterator item = list.begin();
for (std::size_t i = 1; i <= list.size(); ++i)
{
lua_pushinteger(L, static_cast<lua_Integer>(i));
Stack<T>::push(L, *item);
lua_settable(L, -3);
++item;
}
}
static std::list<T> get(lua_State* L, int index)
{
if (!lua_istable(L, index))
{
luaL_error(L, "#%d argument must be a table", index);
}
std::list<T> list;
int const absindex = lua_absindex(L, index);
lua_pushnil(L);
while (lua_next(L, absindex) != 0)
{
list.push_back(Stack<T>::get(L, -1));
lua_pop(L, 1);
}
return list;
}
static bool isInstance(lua_State* L, int index) { return lua_istable(L, index); }
};
} // namespace luabridge

View File

@@ -0,0 +1,34 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2020, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2007, Nathan Reed
// SPDX-License-Identifier: MIT
#pragma once
// All #include dependencies are listed here
// instead of in the individual header files.
//
#define LUABRIDGE_MAJOR_VERSION 2
#define LUABRIDGE_MINOR_VERSION 7
#define LUABRIDGE_VERSION 207
#ifndef LUA_VERSION_NUM
#error "Lua headers must be included prior to LuaBridge ones"
#endif
#include <LuaBridge/detail/CFunctions.h>
#include <LuaBridge/detail/ClassInfo.h>
#include <LuaBridge/detail/Constructor.h>
#include <LuaBridge/detail/FuncTraits.h>
#include <LuaBridge/detail/Iterator.h>
#include <LuaBridge/detail/LuaException.h>
#include <LuaBridge/detail/LuaHelpers.h>
#include <LuaBridge/detail/LuaRef.h>
#include <LuaBridge/detail/Namespace.h>
#include <LuaBridge/detail/Security.h>
#include <LuaBridge/detail/Stack.h>
#include <LuaBridge/detail/TypeList.h>
#include <LuaBridge/detail/TypeTraits.h>
#include <LuaBridge/detail/Userdata.h>

View File

@@ -0,0 +1,52 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2018, Dmitry Tarakanov
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <LuaBridge/detail/dump.h>
#include <map>
namespace luabridge {
template<class K, class V>
struct Stack<std::map<K, V>>
{
typedef std::map<K, V> Map;
static void push(lua_State* L, const Map& map)
{
lua_createtable(L, 0, static_cast<int>(map.size()));
typedef typename Map::const_iterator ConstIter;
for (ConstIter i = map.begin(); i != map.end(); ++i)
{
Stack<K>::push(L, i->first);
Stack<V>::push(L, i->second);
lua_settable(L, -3);
}
}
static Map get(lua_State* L, int index)
{
if (!lua_istable(L, index))
{
luaL_error(L, "#%d argument must be a table", index);
}
Map map;
int const absindex = lua_absindex(L, index);
lua_pushnil(L);
while (lua_next(L, absindex) != 0)
{
map.emplace(Stack<K>::get(L, -2), Stack<V>::get(L, -1));
lua_pop(L, 1);
}
return map;
}
static bool isInstance(lua_State* L, int index) { return lua_istable(L, index); }
};
} // namespace luabridge

View File

@@ -0,0 +1,46 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2021, Stefan Frings
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <optional>
namespace luabridge {
template<class T>
struct Stack<std::optional<T>>
{
static void push(lua_State* L, std::optional<T> const& optional)
{
if (optional)
{
Stack<T>::push(L, *optional);
}
else
{
lua_pushnil(L);
}
}
static std::optional<T> get(lua_State* L, int index)
{
if (lua_isnil(L, index))
{
lua_pop(L, 1);
return std::nullopt;
}
return Stack<T>::get(L, index);
}
static bool isInstance(lua_State* L, int index)
{
return lua_isnil(L, index) || Stack<T>::isInstance(L, index);
}
};
} // namespace luabridge

View File

@@ -0,0 +1,77 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2022, Stefan Frings
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <cassert>
#include <utility>
namespace luabridge {
template<class T1, class T2>
struct Stack<std::pair<T1, T2>>
{
static void push(lua_State* L, std::pair<T1, T2> const& pair)
{
lua_createtable(L, 2, 0);
lua_pushinteger(L, static_cast<lua_Integer>(1));
Stack<T1>::push(L, pair.first);
lua_settable(L, -3);
lua_pushinteger(L, static_cast<lua_Integer>(2));
Stack<T2>::push(L, pair.second);
lua_settable(L, -3);
}
static std::pair<T1, T2> get(lua_State* L, int index)
{
if (!lua_istable(L, index))
{
luaL_error(L, "#%d argument must be a table", index);
}
std::size_t const tableSize = static_cast<std::size_t>(get_length(L, index));
if (tableSize != 2)
{
luaL_error(L, "pair size must be 2");
}
std::pair<T1, T2> pair;
int const absindex = lua_absindex(L, index);
lua_pushnil(L);
{
int const next = lua_next(L, absindex);
assert(next != 0);
pair.first = Stack<T1>::get(L, -1);
lua_pop(L, 1);
}
{
int const next = lua_next(L, absindex);
assert(next != 0);
pair.second = Stack<T2>::get(L, -1);
lua_pop(L, 1);
}
{
int const next = lua_next(L, absindex);
assert(next == 0);
}
return pair;
}
static bool isInstance(lua_State* L, int index)
{
return lua_istable(L, index) && get_length(L, index) == 2;
}
};
} // namespace luabridge

View File

@@ -0,0 +1,317 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2004-11 by Raw Material Software Ltd.
// SPDX-License-Identifier: MIT
//==============================================================================
/*
This is a derivative work used by permission from part of
JUCE, available at http://www.rawaterialsoftware.com
License: The MIT License (http://www.opensource.org/licenses/mit-license.php)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
This file incorporates work covered by the following copyright and
permission notice:
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
*/
//==============================================================================
#pragma once
#include <cassert>
#include <utility>
namespace luabridge {
//==============================================================================
/**
Adds reference-counting to an object.
To add reference-counting to a class, derive it from this class, and
use the RefCountedObjectPtr class to point to it.
e.g. @code
class MyClass : public RefCountedObjectType
{
void foo();
// This is a neat way of declaring a typedef for a pointer class,
// rather than typing out the full templated name each time..
typedef RefCountedObjectPtr<MyClass> Ptr;
};
MyClass::Ptr p = new MyClass();
MyClass::Ptr p2 = p;
p = 0;
p2->foo();
@endcode
Once a new RefCountedObjectType has been assigned to a pointer, be
careful not to delete the object manually.
*/
template<class CounterType>
class RefCountedObjectType
{
public:
//==============================================================================
/** Increments the object's reference count.
This is done automatically by the smart pointer, but is public just
in case it's needed for nefarious purposes.
*/
void incReferenceCount() const { ++refCount; }
/** Decreases the object's reference count.
If the count gets to zero, the object will be deleted.
*/
void decReferenceCount() const
{
assert(getReferenceCount() > 0);
if (--refCount == 0)
delete this;
}
/** Returns the object's current reference count.
* @returns The reference count.
*/
int getReferenceCount() const { return static_cast<int>(refCount); }
protected:
//==============================================================================
/** Creates the reference-counted object (with an initial ref count of zero). */
RefCountedObjectType() : refCount() {}
/** Destructor. */
virtual ~RefCountedObjectType()
{
// it's dangerous to delete an object that's still referenced by something else!
assert(getReferenceCount() == 0);
}
private:
//==============================================================================
CounterType mutable refCount;
};
//==============================================================================
/** Non thread-safe reference counted object.
This creates a RefCountedObjectType that uses a non-atomic integer
as the counter.
*/
typedef RefCountedObjectType<int> RefCountedObject;
//==============================================================================
/**
A smart-pointer class which points to a reference-counted object.
The template parameter specifies the class of the object you want to point
to - the easiest way to make a class reference-countable is to simply make
it inherit from RefCountedObjectType, but if you need to, you could roll
your own reference-countable class by implementing a pair of methods called
incReferenceCount() and decReferenceCount().
When using this class, you'll probably want to create a typedef to
abbreviate the full templated name - e.g.
@code
typedef RefCountedObjectPtr <MyClass> MyClassPtr;
@endcode
*/
template<class ReferenceCountedObjectClass>
class RefCountedObjectPtr
{
public:
/** The class being referenced by this pointer. */
typedef ReferenceCountedObjectClass ReferencedType;
//==============================================================================
/** Creates a pointer to a null object. */
RefCountedObjectPtr() : referencedObject(nullptr) {}
/** Creates a pointer to an object.
This will increment the object's reference-count if it is non-null.
@param refCountedObject A reference counted object to own.
*/
RefCountedObjectPtr(ReferenceCountedObjectClass* const refCountedObject)
: referencedObject(refCountedObject)
{
if (refCountedObject != nullptr)
refCountedObject->incReferenceCount();
}
/** Copies another pointer.
This will increment the object's reference-count (if it is non-null).
@param other Another pointer.
*/
RefCountedObjectPtr(const RefCountedObjectPtr& other) : referencedObject(other.referencedObject)
{
if (referencedObject != nullptr)
referencedObject->incReferenceCount();
}
/**
Takes-over the object from another pointer.
@param other Another pointer.
*/
RefCountedObjectPtr(RefCountedObjectPtr&& other) : referencedObject(other.referencedObject)
{
other.referencedObject = nullptr;
}
/** Copies another pointer.
This will increment the object's reference-count (if it is non-null).
@param other Another pointer.
*/
template<class DerivedClass>
RefCountedObjectPtr(const RefCountedObjectPtr<DerivedClass>& other)
: referencedObject(static_cast<ReferenceCountedObjectClass*>(other.getObject()))
{
if (referencedObject != nullptr)
referencedObject->incReferenceCount();
}
/** Changes this pointer to point at a different object.
The reference count of the old object is decremented, and it might be
deleted if it hits zero. The new object's count is incremented.
@param other A pointer to assign from.
@returns This pointer.
*/
RefCountedObjectPtr& operator=(const RefCountedObjectPtr& other)
{
return operator=(other.referencedObject);
}
/** Changes this pointer to point at a different object.
The reference count of the old object is decremented, and it might be
deleted if it hits zero. The new object's count is incremented.
@param other A pointer to assign from.
@returns This pointer.
*/
template<class DerivedClass>
RefCountedObjectPtr& operator=(const RefCountedObjectPtr<DerivedClass>& other)
{
return operator=(static_cast<ReferenceCountedObjectClass*>(other.getObject()));
}
/**
Takes-over the object from another pointer.
@param other A pointer to assign from.
@returns This pointer.
*/
RefCountedObjectPtr& operator=(RefCountedObjectPtr&& other)
{
std::swap(referencedObject, other.referencedObject);
return *this;
}
/** Changes this pointer to point at a different object.
The reference count of the old object is decremented, and it might be
deleted if it hits zero. The new object's count is incremented.
@param newObject A reference counted object to own.
@returns This pointer.
*/
RefCountedObjectPtr& operator=(ReferenceCountedObjectClass* const newObject)
{
if (referencedObject != newObject)
{
if (newObject != nullptr)
newObject->incReferenceCount();
ReferenceCountedObjectClass* const oldObject = referencedObject;
referencedObject = newObject;
if (oldObject != nullptr)
oldObject->decReferenceCount();
}
return *this;
}
/** Destructor.
This will decrement the object's reference-count, and may delete it if it
gets to zero.
*/
~RefCountedObjectPtr()
{
if (referencedObject != nullptr)
referencedObject->decReferenceCount();
}
/** Returns the object that this pointer references.
The returned pointer may be null.
@returns The pointee.
*/
operator ReferenceCountedObjectClass*() const { return referencedObject; }
/** Returns the object that this pointer references.
The returned pointer may be null.
@returns The pointee.
*/
ReferenceCountedObjectClass* operator->() const { return referencedObject; }
/** Returns the object that this pointer references.
The returned pointer may be null.
@returns The pointee.
*/
ReferenceCountedObjectClass* getObject() const { return referencedObject; }
private:
//==============================================================================
ReferenceCountedObjectClass* referencedObject;
};
//==============================================================================
// forward declaration
template<class T>
struct ContainerTraits;
template<class T>
struct ContainerTraits<RefCountedObjectPtr<T>>
{
typedef T Type;
static T* get(RefCountedObjectPtr<T> const& c) { return c.getObject(); }
};
//==============================================================================
} // namespace luabridge

View File

@@ -0,0 +1,226 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2021, Stefan Frings
// Copyright 2019, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2007, Nathan Reed
// SPDX-License-Identifier: MIT
#pragma once
#include <cassert>
#include <unordered_map>
#include <utility>
namespace luabridge {
namespace detail {
//==============================================================================
/**
Support for our RefCountedPtr.
*/
struct RefCountedPtrBase
{
// Declaration of container for the refcounts
typedef std::unordered_map<const void*, int> RefCountsType;
protected:
RefCountsType& getRefCounts() const
{
static RefCountsType refcounts;
return refcounts;
}
};
} // namespace detail
//==============================================================================
/**
A reference counted smart pointer.
The api is compatible with boost::RefCountedPtr and std::RefCountedPtr, in the
sense that it implements a strict subset of the functionality.
This implementation uses a hash table to look up the reference count
associated with a particular pointer.
@tparam T The class type.
@todo Decompose RefCountedPtr using a policy. At a minimum, the underlying
reference count should be policy based (to support atomic operations)
and the delete behavior should be policy based (to support custom
disposal methods).
@todo Provide an intrusive version of RefCountedPtr.
*/
template<class T>
class RefCountedPtr : private detail::RefCountedPtrBase
{
public:
template<typename Other>
struct rebind
{
typedef RefCountedPtr<Other> other;
};
/** Construct as nullptr or from existing pointer to T.
@param p The optional, existing pointer to assign from.
*/
RefCountedPtr(T* const p = nullptr) : m_p(p)
{
if (m_p)
{
++getRefCounts()[m_p];
}
}
/** Construct from another RefCountedPtr.
@param rhs The RefCountedPtr to assign from.
*/
RefCountedPtr(RefCountedPtr<T> const& rhs) : RefCountedPtr(rhs.get()) {}
/** Construct from a RefCountedPtr of a different type.
@invariant A pointer to U must be convertible to a pointer to T.
@tparam U The other object type.
@param rhs The RefCountedPtr to assign from.
*/
template<typename U>
RefCountedPtr(RefCountedPtr<U> const& rhs) : RefCountedPtr(rhs.get())
{
}
/** Release the object.
If there are no more references then the object is deleted.
*/
~RefCountedPtr() { reset(); }
/** Assign from another RefCountedPtr.
@param rhs The RefCountedPtr to assign from.
@returns A reference to the RefCountedPtr.
*/
RefCountedPtr<T>& operator=(RefCountedPtr<T> const& rhs)
{
// NOTE Self assignment is handled gracefully
*this = rhs.get();
return *this;
}
/** Assign from another RefCountedPtr of a different type.
@note A pointer to U must be convertible to a pointer to T.
@tparam U The other object type.
@param rhs The other RefCountedPtr to assign from.
@returns A reference to the RefCountedPtr.
*/
template<typename U>
RefCountedPtr<T>& operator=(RefCountedPtr<U> const& rhs)
{
// NOTE Self assignment is handled gracefully
*this = rhs.get();
return *this;
}
RefCountedPtr<T>& operator=(T* const p)
{
if (p != m_p)
{
RefCountedPtr<T> tmp(p);
std::swap(m_p, tmp.m_p);
}
return *this;
}
/** Retrieve the raw pointer.
@returns A pointer to the object.
*/
T* get() const { return m_p; }
/** Retrieve the raw pointer by conversion.
@returns A pointer to the object.
*/
operator T*() const { return m_p; }
/** Retrieve the raw pointer.
@returns A pointer to the object.
*/
T* operator*() const { return m_p; }
/** Retrieve the raw pointer.
@returns A pointer to the object.
*/
T* operator->() const { return m_p; }
/** Determine the number of references.
@note This is not thread-safe.
@returns The number of active references.
*/
RefCountsType::mapped_type use_count() const
{
if (!m_p)
{
return 0;
}
const auto itCounter = getRefCounts().find(m_p);
assert(itCounter != getRefCounts().end());
assert(itCounter->second > 0);
return itCounter->second;
}
/** Release the pointer.
The reference count is decremented. If the reference count reaches
zero, the object is deleted.
*/
void reset()
{
if (m_p)
{
const auto itCounter = getRefCounts().find(m_p);
assert(itCounter != getRefCounts().end());
assert(itCounter->second > 0);
if (--itCounter->second == 0)
{
delete m_p;
getRefCounts().erase(itCounter);
}
m_p = nullptr;
}
}
private:
T* m_p;
};
//==============================================================================
// forward declaration
template<class T>
struct ContainerTraits;
template<class T>
struct ContainerTraits<RefCountedPtr<T>>
{
typedef T Type;
static T* get(RefCountedPtr<T> const& c) { return c.get(); }
};
} // namespace luabridge

View File

@@ -0,0 +1,51 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2019, Dmitry Tarakanov
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <unordered_map>
namespace luabridge {
template<class K, class V>
struct Stack<std::unordered_map<K, V>>
{
typedef std::unordered_map<K, V> Map;
static void push(lua_State* L, const Map& map)
{
lua_createtable(L, 0, static_cast<int>(map.size()));
typedef typename Map::const_iterator ConstIter;
for (ConstIter i = map.begin(); i != map.end(); ++i)
{
Stack<K>::push(L, i->first);
Stack<V>::push(L, i->second);
lua_settable(L, -3);
}
}
static Map get(lua_State* L, int index)
{
if (!lua_istable(L, index))
{
luaL_error(L, "#%d argument must be a table", index);
}
Map map;
int const absindex = lua_absindex(L, index);
lua_pushnil(L);
while (lua_next(L, absindex) != 0)
{
map.emplace(Stack<K>::get(L, -2), Stack<V>::get(L, -1));
lua_pop(L, 1);
}
return map;
}
static bool isInstance(lua_State* L, int index) { return lua_istable(L, index); }
};
} // namespace luabridge

View File

@@ -0,0 +1,50 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2018, Dmitry Tarakanov
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <vector>
namespace luabridge {
template<class T>
struct Stack<std::vector<T>>
{
static void push(lua_State* L, std::vector<T> const& vector)
{
lua_createtable(L, static_cast<int>(vector.size()), 0);
for (std::size_t i = 0; i < vector.size(); ++i)
{
lua_pushinteger(L, static_cast<lua_Integer>(i + 1));
Stack<T>::push(L, vector[i]);
lua_settable(L, -3);
}
}
static std::vector<T> get(lua_State* L, int index)
{
if (!lua_istable(L, index))
{
luaL_error(L, "#%d argument must be a table", index);
}
std::vector<T> vector;
vector.reserve(static_cast<std::size_t>(get_length(L, index)));
int const absindex = lua_absindex(L, index);
lua_pushnil(L);
while (lua_next(L, absindex) != 0)
{
vector.push_back(Stack<T>::get(L, -1));
lua_pop(L, 1);
}
return vector;
}
static bool isInstance(lua_State* L, int index) { return lua_istable(L, index); }
};
} // namespace luabridge

View File

@@ -0,0 +1,470 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2019, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Config.h>
#include <LuaBridge/detail/FuncTraits.h>
#include <string>
namespace luabridge {
namespace detail {
// We use a structure so we can define everything in the header.
//
struct CFunc
{
static void addGetter(lua_State* L, const char* name, int tableIndex)
{
assert(lua_istable(L, tableIndex));
assert(lua_iscfunction(L, -1)); // Stack: getter
lua_rawgetp(L, tableIndex, getPropgetKey()); // Stack: getter, propget table (pg)
lua_pushvalue(L, -2); // Stack: getter, pg, getter
rawsetfield(L, -2, name); // Stack: getter, pg
lua_pop(L, 2); // Stack: -
}
static void addSetter(lua_State* L, const char* name, int tableIndex)
{
assert(lua_istable(L, tableIndex));
assert(lua_iscfunction(L, -1)); // Stack: setter
lua_rawgetp(L, tableIndex, getPropsetKey()); // Stack: setter, propset table (ps)
lua_pushvalue(L, -2); // Stack: setter, ps, setter
rawsetfield(L, -2, name); // Stack: setter, ps
lua_pop(L, 2); // Stack: -
}
//----------------------------------------------------------------------------
/**
__index metamethod for a namespace or class static and non-static members.
Retrieves functions from metatables and properties from propget tables.
Looks through the class hierarchy if inheritance is present.
*/
static int indexMetaMethod(lua_State* L)
{
assert(lua_istable(L, 1) ||
lua_isuserdata(L, 1)); // Stack (further not shown): table | userdata, name
lua_getmetatable(L, 1); // Stack: class/const table (mt)
assert(lua_istable(L, -1));
for (;;)
{
lua_pushvalue(L, 2); // Stack: mt, field name
lua_rawget(L, -2); // Stack: mt, field | nil
if (lua_iscfunction(L, -1)) // Stack: mt, field
{
lua_remove(L, -2); // Stack: field
return 1;
}
assert(lua_isnil(L, -1)); // Stack: mt, nil
lua_pop(L, 1); // Stack: mt
lua_rawgetp(L, -1, getPropgetKey()); // Stack: mt, propget table (pg)
assert(lua_istable(L, -1));
lua_pushvalue(L, 2); // Stack: mt, pg, field name
lua_rawget(L, -2); // Stack: mt, pg, getter | nil
lua_remove(L, -2); // Stack: mt, getter | nil
if (lua_iscfunction(L, -1)) // Stack: mt, getter
{
lua_remove(L, -2); // Stack: getter
lua_pushvalue(L, 1); // Stack: getter, table | userdata
lua_call(L, 1, 1); // Stack: value
return 1;
}
assert(lua_isnil(L, -1)); // Stack: mt, nil
lua_pop(L, 1); // Stack: mt
// It may mean that the field may be in const table and it's constness violation.
// Don't check that, just return nil
// Repeat the lookup in the parent metafield,
// or return nil if the field doesn't exist.
lua_rawgetp(L, -1, getParentKey()); // Stack: mt, parent mt | nil
if (lua_isnil(L, -1)) // Stack: mt, nil
{
lua_remove(L, -2); // Stack: nil
return 1;
}
// Removethe metatable and repeat the search in the parent one.
assert(lua_istable(L, -1)); // Stack: mt, parent mt
lua_remove(L, -2); // Stack: parent mt
}
// no return
}
//----------------------------------------------------------------------------
/**
__newindex metamethod for namespace or class static members.
Retrieves properties from propset tables.
*/
static int newindexStaticMetaMethod(lua_State* L) { return newindexMetaMethod(L, false); }
//----------------------------------------------------------------------------
/**
__newindex metamethod for non-static members.
Retrieves properties from propset tables.
*/
static int newindexObjectMetaMethod(lua_State* L) { return newindexMetaMethod(L, true); }
static int newindexMetaMethod(lua_State* L, bool pushSelf)
{
assert(
lua_istable(L, 1) ||
lua_isuserdata(L, 1)); // Stack (further not shown): table | userdata, name, new value
lua_getmetatable(L, 1); // Stack: metatable (mt)
assert(lua_istable(L, -1));
for (;;)
{
lua_rawgetp(L, -1, getPropsetKey()); // Stack: mt, propset table (ps) | nil
if (lua_isnil(L, -1)) // Stack: mt, nil
{
lua_pop(L, 2); // Stack: -
return luaL_error(L, "No member named '%s'", lua_tostring(L, 2));
}
assert(lua_istable(L, -1));
lua_pushvalue(L, 2); // Stack: mt, ps, field name
lua_rawget(L, -2); // Stack: mt, ps, setter | nil
lua_remove(L, -2); // Stack: mt, setter | nil
if (lua_iscfunction(L, -1)) // Stack: mt, setter
{
lua_remove(L, -2); // Stack: setter
if (pushSelf)
{
lua_pushvalue(L, 1); // Stack: setter, table | userdata
}
lua_pushvalue(L, 3); // Stack: setter, table | userdata, new value
lua_call(L, pushSelf ? 2 : 1, 0); // Stack: -
return 0;
}
assert(lua_isnil(L, -1)); // Stack: mt, nil
lua_pop(L, 1); // Stack: mt
lua_rawgetp(L, -1, getParentKey()); // Stack: mt, parent mt | nil
if (lua_isnil(L, -1)) // Stack: mt, nil
{
lua_pop(L, 1); // Stack: -
return luaL_error(L, "No writable member '%s'", lua_tostring(L, 2));
}
assert(lua_istable(L, -1)); // Stack: mt, parent mt
lua_remove(L, -2); // Stack: parent mt
// Repeat the search in the parent
}
// no return
}
//----------------------------------------------------------------------------
/**
lua_CFunction to report an error writing to a read-only value.
The name of the variable is in the first upvalue.
*/
static int readOnlyError(lua_State* L)
{
std::string s;
s = s + "'" + lua_tostring(L, lua_upvalueindex(1)) + "' is read-only";
return luaL_error(L, s.c_str());
}
//----------------------------------------------------------------------------
/**
lua_CFunction to get a variable.
This is used for global variables or class static data members.
The pointer to the data is in the first upvalue.
*/
template<class T>
static int getVariable(lua_State* L)
{
assert(lua_islightuserdata(L, lua_upvalueindex(1)));
T const* ptr = static_cast<T const*>(lua_touserdata(L, lua_upvalueindex(1)));
assert(ptr != 0);
Stack<T>::push(L, *ptr);
return 1;
}
//----------------------------------------------------------------------------
/**
lua_CFunction to set a variable.
This is used for global variables or class static data members.
The pointer to the data is in the first upvalue.
*/
template<class T>
static int setVariable(lua_State* L)
{
assert(lua_islightuserdata(L, lua_upvalueindex(1)));
T* ptr = static_cast<T*>(lua_touserdata(L, lua_upvalueindex(1)));
assert(ptr != 0);
*ptr = Stack<T>::get(L, 1);
return 0;
}
//----------------------------------------------------------------------------
/**
lua_CFunction to call a function with a return value.
This is used for global functions, global properties, class static methods,
and class static properties.
The function pointer (lightuserdata) in the first upvalue.
*/
template<class FnPtr>
struct Call
{
typedef typename FuncTraits<FnPtr>::Params Params;
typedef typename FuncTraits<FnPtr>::ReturnType ReturnType;
static int f(lua_State* L)
{
assert(lua_islightuserdata(L, lua_upvalueindex(1)));
FnPtr fnptr = reinterpret_cast<FnPtr>(lua_touserdata(L, lua_upvalueindex(1)));
assert(fnptr != 0);
return Invoke<ReturnType, Params, 1>::run(L, fnptr);
}
};
//----------------------------------------------------------------------------
/**
lua_CFunction to call a class member function with a return value.
The member function pointer is in the first upvalue.
The class userdata object is at the top of the Lua stack.
*/
template<class MemFnPtr>
struct CallMember
{
typedef typename FuncTraits<MemFnPtr>::ClassType T;
typedef typename FuncTraits<MemFnPtr>::Params Params;
typedef typename FuncTraits<MemFnPtr>::ReturnType ReturnType;
static int f(lua_State* L)
{
assert(isfulluserdata(L, lua_upvalueindex(1)));
T* const t = Userdata::get<T>(L, 1, false);
MemFnPtr const& fnptr =
*static_cast<MemFnPtr const*>(lua_touserdata(L, lua_upvalueindex(1)));
assert(fnptr != 0);
return Invoke<ReturnType, Params, 2>::run(L, t, fnptr);
}
};
template<class MemFnPtr>
struct CallConstMember
{
typedef typename FuncTraits<MemFnPtr>::ClassType T;
typedef typename FuncTraits<MemFnPtr>::Params Params;
typedef typename FuncTraits<MemFnPtr>::ReturnType ReturnType;
static int f(lua_State* L)
{
assert(isfulluserdata(L, lua_upvalueindex(1)));
T const* const t = Userdata::get<T>(L, 1, true);
MemFnPtr const& fnptr =
*static_cast<MemFnPtr const*>(lua_touserdata(L, lua_upvalueindex(1)));
assert(fnptr != 0);
return Invoke<ReturnType, Params, 2>::run(L, t, fnptr);
}
};
//--------------------------------------------------------------------------
/**
lua_CFunction to call a class member lua_CFunction.
The member function pointer is in the first upvalue.
The object userdata ('this') value is at top ot the Lua stack.
*/
template<class T>
struct CallMemberCFunction
{
static int f(lua_State* L)
{
assert(isfulluserdata(L, lua_upvalueindex(1)));
typedef int (T::*MFP)(lua_State * L);
T* const t = Userdata::get<T>(L, 1, false);
MFP const& fnptr = *static_cast<MFP const*>(lua_touserdata(L, lua_upvalueindex(1)));
assert(fnptr != 0);
return (t->*fnptr)(L);
}
};
template<class T>
struct CallConstMemberCFunction
{
static int f(lua_State* L)
{
assert(isfulluserdata(L, lua_upvalueindex(1)));
typedef int (T::*MFP)(lua_State * L);
T const* const t = Userdata::get<T>(L, 1, true);
MFP const& fnptr = *static_cast<MFP const*>(lua_touserdata(L, lua_upvalueindex(1)));
assert(fnptr != 0);
return (t->*fnptr)(L);
}
};
//--------------------------------------------------------------------------
/**
lua_CFunction to call on a object.
The proxy function pointer (lightuserdata) is in the first upvalue.
The class userdata object is at the top of the Lua stack.
*/
template<class FnPtr>
struct CallProxyFunction
{
using Params = typename FuncTraits<FnPtr>::Params;
using ReturnType = typename FuncTraits<FnPtr>::ReturnType;
static int f(lua_State* L)
{
assert(lua_islightuserdata(L, lua_upvalueindex(1)));
auto fnptr = reinterpret_cast<FnPtr>(lua_touserdata(L, lua_upvalueindex(1)));
assert(fnptr != 0);
return Invoke<ReturnType, Params, 1>::run(L, fnptr);
}
};
template<class Functor>
struct CallProxyFunctor
{
using Params = typename FuncTraits<Functor>::Params;
using ReturnType = typename FuncTraits<Functor>::ReturnType;
static int f(lua_State* L)
{
assert(isfulluserdata(L, lua_upvalueindex(1)));
Functor& fn = *static_cast<Functor*>(lua_touserdata(L, lua_upvalueindex(1)));
return Invoke<ReturnType, Params, 1>::run(L, fn);
}
};
//--------------------------------------------------------------------------
// SFINAE Helpers
template<class MemFnPtr, bool isConst>
struct CallMemberFunctionHelper
{
static void add(lua_State* L, char const* name, MemFnPtr mf)
{
new (lua_newuserdata(L, sizeof(MemFnPtr))) MemFnPtr(mf);
lua_pushcclosure(L, &CallConstMember<MemFnPtr>::f, 1);
lua_pushvalue(L, -1);
rawsetfield(L, -5, name); // const table
rawsetfield(L, -3, name); // class table
}
};
template<class MemFnPtr>
struct CallMemberFunctionHelper<MemFnPtr, false>
{
static void add(lua_State* L, char const* name, MemFnPtr mf)
{
new (lua_newuserdata(L, sizeof(MemFnPtr))) MemFnPtr(mf);
lua_pushcclosure(L, &CallMember<MemFnPtr>::f, 1);
rawsetfield(L, -3, name); // class table
}
};
//--------------------------------------------------------------------------
/**
__gc metamethod for a class.
*/
template<class C>
static int gcMetaMethod(lua_State* L)
{
Userdata* const ud = Userdata::getExact<C>(L, 1);
ud->~Userdata();
return 0;
}
/**
__gc metamethod for an arbitrary class.
*/
template<class T>
static int gcMetaMethodAny(lua_State* L)
{
assert(isfulluserdata(L, 1));
T* t = static_cast<T*>(lua_touserdata(L, 1));
t->~T();
return 0;
}
//--------------------------------------------------------------------------
/**
lua_CFunction to get a class data member.
The pointer-to-member is in the first upvalue.
The class userdata object is at the top of the Lua stack.
*/
template<class C, typename T>
static int getProperty(lua_State* L)
{
C* const c = Userdata::get<C>(L, 1, true);
T C::** mp = static_cast<T C::**>(lua_touserdata(L, lua_upvalueindex(1)));
try
{
Stack<T&>::push(L, c->**mp);
}
catch (const std::exception& e)
{
luaL_error(L, e.what());
}
return 1;
}
//--------------------------------------------------------------------------
/**
lua_CFunction to set a class data member.
The pointer-to-member is in the first upvalue.
The class userdata object is at the top of the Lua stack.
*/
template<class C, typename T>
static int setProperty(lua_State* L)
{
C* const c = Userdata::get<C>(L, 1, false);
T C::** mp = static_cast<T C::**>(lua_touserdata(L, lua_upvalueindex(1)));
try
{
c->** mp = Stack<T>::get(L, 2);
}
catch (const std::exception& e)
{
luaL_error(L, e.what());
}
return 0;
}
};
} // namespace detail
} // namespace luabridge

View File

@@ -0,0 +1,140 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2020, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
namespace luabridge {
namespace detail {
/**
* A unique key for a type name in a metatable.
*/
inline const void* getTypeKey()
{
#ifdef _NDEBUG
static char value;
return &value;
#else
return reinterpret_cast<void*>(0x71);
#endif
}
/**
* The key of a const table in another metatable.
*/
inline const void* getConstKey()
{
#ifdef _NDEBUG
static char value;
return &value;
#else
return reinterpret_cast<void*>(0xc07);
#endif
}
/**
* The key of a class table in another metatable.
*/
inline const void* getClassKey()
{
#ifdef _NDEBUG
static char value;
return &value;
#else
return reinterpret_cast<void*>(0xc1a);
#endif
}
/**
* The key of a propget table in another metatable.
*/
inline const void* getPropgetKey()
{
#ifdef _NDEBUG
static char value;
return &value;
#else
return reinterpret_cast<void*>(0x6e7);
#endif
}
/**
* The key of a propset table in another metatable.
*/
inline const void* getPropsetKey()
{
#ifdef _NDEBUG
static char value;
return &value;
#else
return reinterpret_cast<void*>(0x5e7);
#endif
}
/**
* The key of a static table in another metatable.
*/
inline const void* getStaticKey()
{
#ifdef _NDEBUG
static char value;
return &value;
#else
return reinterpret_cast<void*>(0x57a);
#endif
}
/**
* The key of a parent table in another metatable.
*/
inline const void* getParentKey()
{
#ifdef _NDEBUG
static char value;
return &value;
#else
return reinterpret_cast<void*>(0xdad);
#endif
}
/**
Get the key for the static table in the Lua registry.
The static table holds the static data members, static properties, and
static member functions for a class.
*/
template<class T>
void const* getStaticRegistryKey()
{
static char value;
return &value;
}
/** Get the key for the class table in the Lua registry.
The class table holds the data members, properties, and member functions
of a class. Read-only data and properties, and const member functions are
also placed here (to save a lookup in the const table).
*/
template<class T>
void const* getClassRegistryKey()
{
static char value;
return &value;
}
/** Get the key for the const table in the Lua registry.
The const table holds read-only data members and properties, and const
member functions of a class.
*/
template<class T>
void const* getConstRegistryKey()
{
static char value;
return &value;
}
} // namespace detail
} // namespace luabridge

View File

@@ -0,0 +1,7 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2020, Dmitry Tarakanov
// SPDX-License-Identifier: MIT
#pragma once
// Empty file

View File

@@ -0,0 +1,225 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2007, Nathan Reed
// SPDX-License-Identifier: MIT
#pragma once
namespace luabridge {
namespace detail {
/*
* Constructor generators. These templates allow you to call operator new and
* pass the contents of a type/value list to the Constructor. Like the
* function pointer containers, these are only defined up to 8 parameters.
*/
/** Constructor generators.
These templates call operator new with the contents of a type/value
list passed to the Constructor with up to 8 parameters. Two versions
of call() are provided. One performs a regular new, the other performs
a placement new.
*/
template<class T, typename List>
struct Constructor
{
};
template<class T>
struct Constructor<T, None>
{
static T* call(TypeListValues<None> const&) { return new T; }
static T* call(void* mem, TypeListValues<None> const&) { return new (mem) T; }
};
template<class T, class P1>
struct Constructor<T, TypeList<P1>>
{
static T* call(const TypeListValues<TypeList<P1>>& tvl) { return new T(tvl.hd); }
static T* call(void* mem, const TypeListValues<TypeList<P1>>& tvl)
{
return new (mem) T(tvl.hd);
}
};
template<class T, class P1, class P2>
struct Constructor<T, TypeList<P1, TypeList<P2>>>
{
static T* call(const TypeListValues<TypeList<P1, TypeList<P2>>>& tvl)
{
return new T(tvl.hd, tvl.tl.hd);
}
static T* call(void* mem, const TypeListValues<TypeList<P1, TypeList<P2>>>& tvl)
{
return new (mem) T(tvl.hd, tvl.tl.hd);
}
};
template<class T, class P1, class P2, class P3>
struct Constructor<T, TypeList<P1, TypeList<P2, TypeList<P3>>>>
{
static T* call(const TypeListValues<TypeList<P1, TypeList<P2, TypeList<P3>>>>& tvl)
{
return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd);
}
static T* call(void* mem, const TypeListValues<TypeList<P1, TypeList<P2, TypeList<P3>>>>& tvl)
{
return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd);
}
};
template<class T, class P1, class P2, class P3, class P4>
struct Constructor<T, TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4>>>>>
{
static T*
call(const TypeListValues<TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4>>>>>& tvl)
{
return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd);
}
static T*
call(void* mem,
const TypeListValues<TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4>>>>>& tvl)
{
return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd);
}
};
template<class T, class P1, class P2, class P3, class P4, class P5>
struct Constructor<T, TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5>>>>>>
{
static T*
call(const TypeListValues<TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5>>>>>>&
tvl)
{
return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd);
}
static T*
call(void* mem,
const TypeListValues<TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5>>>>>>&
tvl)
{
return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd);
}
};
template<class T, class P1, class P2, class P3, class P4, class P5, class P6>
struct Constructor<
T,
TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6>>>>>>>
{
static T*
call(const TypeListValues<
TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6>>>>>>>& tvl)
{
return new T(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd);
}
static T*
call(void* mem,
const TypeListValues<
TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6>>>>>>>&
tvl)
{
return new (mem) T(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd);
}
};
template<class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7>
struct Constructor<
T,
TypeList<P1,
TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6, TypeList<P7>>>>>>>>
{
static T*
call(const TypeListValues<TypeList<
P1,
TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6, TypeList<P7>>>>>>>>&
tvl)
{
return new T(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.hd);
}
static T*
call(void* mem,
const TypeListValues<TypeList<
P1,
TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6, TypeList<P7>>>>>>>>&
tvl)
{
return new (mem) T(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.hd);
}
};
template<class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
struct Constructor<
T,
TypeList<
P1,
TypeList<
P2,
TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6, TypeList<P7, TypeList<P8>>>>>>>>>
{
static T*
call(const TypeListValues<TypeList<
P1,
TypeList<
P2,
TypeList<P3,
TypeList<P4, TypeList<P5, TypeList<P6, TypeList<P7, TypeList<P8>>>>>>>>>&
tvl)
{
return new T(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.tl.hd);
}
static T*
call(void* mem,
const TypeListValues<TypeList<
P1,
TypeList<
P2,
TypeList<P3,
TypeList<P4, TypeList<P5, TypeList<P6, TypeList<P7, TypeList<P8>>>>>>>>>&
tvl)
{
return new (mem) T(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.tl.hd);
}
};
} // namespace detail
} // namespace luabridge

View File

@@ -0,0 +1,435 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2020, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Config.h>
#include <LuaBridge/detail/TypeList.h>
#include <functional>
namespace luabridge {
namespace detail {
/**
Since the throw specification is part of a function signature, the FuncTraits
family of templates needs to be specialized for both types. The
LUABRIDGE_THROWSPEC macro controls whether we use the 'throw ()' form, or
'noexcept' (if C++11 is available) to distinguish the functions.
*/
#if defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__clang__) || defined(__GNUC__) || \
(defined(_MSC_VER) && (_MSC_VER >= 1700))
// Do not define LUABRIDGE_THROWSPEC since the Xcode and gcc compilers do not
// distinguish the throw specification in the function signature.
#define LUABRIDGE_THROWSPEC
#else
// Visual Studio 10 and earlier pay too much mind to useless throw () spec.
//
#define LUABRIDGE_THROWSPEC throw()
#endif
//==============================================================================
/**
* Traits class for unrolling the type list values into function arguments.
*/
template<class ReturnType, size_t NUM_PARAMS>
struct Caller;
template<class ReturnType>
struct Caller<ReturnType, 0>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>&)
{
return fn();
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>&)
{
return (obj->*fn)();
}
};
template<class ReturnType>
struct Caller<ReturnType, 1>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 2>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd, tvl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd, tvl.tl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 3>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 4>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 5>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 6>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 7>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 8>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.tl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 9>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.tl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd,
tvl.tl.hd,
tvl.tl.tl.hd,
tvl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.tl.hd,
tvl.tl.tl.tl.tl.tl.tl.tl.tl.hd);
}
};
template<class ReturnType, class Fn, class Params>
ReturnType doCall(Fn& fn, TypeListValues<Params>& tvl)
{
return Caller<ReturnType, TypeListSize<Params>::value>::f(fn, tvl);
}
template<class ReturnType, class T, class MemFn, class Params>
ReturnType doCall(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return Caller<ReturnType, TypeListSize<Params>::value>::f(obj, fn, tvl);
}
//==============================================================================
/**
Traits for function pointers.
There are three types of functions: global, non-const member, and const
member. These templates determine the type of function, which class type it
belongs to if it is a class member, the const-ness if it is a member
function, and the type information for the return value and argument list.
Expansions are provided for functions with up to 8 parameters. This can be
manually extended, or expanded to an arbitrary amount using C++11 features.
*/
template<class MemFn, class D = MemFn>
struct FuncTraits
{
};
/* Ordinary function pointers. */
template<class R, class... ParamList>
struct FuncTraits<R (*)(ParamList...)>
{
static bool const isMemberFunction = false;
using DeclType = R (*)(ParamList...);
using ReturnType = R;
using Params = typename MakeTypeList<ParamList...>::Result;
static R call(const DeclType& fp, TypeListValues<Params>& tvl) { return doCall<R>(fp, tvl); }
};
/* Windows: WINAPI (a.k.a. __stdcall) function pointers. */
#ifdef _M_IX86 // Windows 32bit only
template<class R, class... ParamList>
struct FuncTraits<R(__stdcall*)(ParamList...)>
{
static bool const isMemberFunction = false;
using DeclType = R(__stdcall*)(ParamList...);
using ReturnType = R;
using Params = typename MakeTypeList<ParamList...>::Result;
static R call(const DeclType& fp, TypeListValues<Params>& tvl) { return doCall<R>(fp, tvl); }
};
#endif // _M_IX86
/* Non-const member function pointers. */
template<class T, class R, class... ParamList>
struct FuncTraits<R (T::*)(ParamList...)>
{
static bool const isMemberFunction = true;
static bool const isConstMemberFunction = false;
using DeclType = R (T::*)(ParamList...);
using ClassType = T;
using ReturnType = R;
using Params = typename MakeTypeList<ParamList...>::Result;
static R call(ClassType* obj, const DeclType& fp, TypeListValues<Params>& tvl)
{
return doCall<R>(obj, fp, tvl);
}
};
/* Const member function pointers. */
template<class T, class R, class... ParamList>
struct FuncTraits<R (T::*)(ParamList...) const>
{
static bool const isMemberFunction = true;
static bool const isConstMemberFunction = true;
using DeclType = R (T::*)(ParamList...) const;
using ClassType = T;
using ReturnType = R;
using Params = typename MakeTypeList<ParamList...>::Result;
static R call(const ClassType* obj, const DeclType& fp, TypeListValues<Params>& tvl)
{
return doCall<R>(obj, fp, tvl);
}
};
/* std::function */
template<class R, class... ParamList>
struct FuncTraits<std::function<R(ParamList...)>>
{
static bool const isMemberFunction = false;
static bool const isConstMemberFunction = false;
using DeclType = std::function<R(ParamList...)>;
using ReturnType = R;
using Params = typename MakeTypeList<ParamList...>::Result;
static ReturnType call(DeclType& fn, TypeListValues<Params>& tvl)
{
return doCall<ReturnType>(fn, tvl);
}
};
template<class ReturnType, class Params, int startParam>
struct Invoke
{
template<class Fn>
static int run(lua_State* L, Fn& fn)
{
try
{
ArgList<Params, startParam> args(L);
Stack<ReturnType>::push(L, FuncTraits<Fn>::call(fn, args));
return 1;
}
catch (const std::exception& e)
{
return luaL_error(L, e.what());
}
}
template<class T, class MemFn>
static int run(lua_State* L, T* object, const MemFn& fn)
{
try
{
ArgList<Params, startParam> args(L);
Stack<ReturnType>::push(L, FuncTraits<MemFn>::call(object, fn, args));
return 1;
}
catch (const std::exception& e)
{
return luaL_error(L, e.what());
}
}
};
template<class Params, int startParam>
struct Invoke<void, Params, startParam>
{
template<class Fn>
static int run(lua_State* L, Fn& fn)
{
try
{
ArgList<Params, startParam> args(L);
FuncTraits<Fn>::call(fn, args);
return 0;
}
catch (const std::exception& e)
{
return luaL_error(L, e.what());
}
}
template<class T, class MemFn>
static int run(lua_State* L, T* object, const MemFn& fn)
{
try
{
ArgList<Params, startParam> args(L);
FuncTraits<MemFn>::call(object, fn, args);
return 0;
}
catch (const std::exception& e)
{
return luaL_error(L, e.what());
}
}
};
} // namespace detail
} // namespace luabridge

View File

@@ -0,0 +1,150 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2018, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/LuaRef.h>
#include <utility>
namespace luabridge {
/** Allows table iteration.
*/
class Iterator
{
lua_State* m_L;
LuaRef m_table;
LuaRef m_key;
LuaRef m_value;
void next()
{
m_table.push();
m_key.push();
if (lua_next(m_L, -2))
{
m_value.pop();
m_key.pop();
}
else
{
m_key = Nil();
m_value = Nil();
}
lua_pop(m_L, 1);
}
public:
explicit Iterator(const LuaRef& table, bool isEnd = false)
: m_L(table.state())
, m_table(table)
, m_key(table.state()) // m_key is nil
, m_value(table.state()) // m_value is nil
{
if (!isEnd)
{
next(); // get the first (key, value) pair from table
}
}
/// Return an associated Lua state.
///
/// @returns A Lua state.
///
lua_State* state() const { return m_L; }
/// Dereference the iterator.
///
/// @returns A key-value pair for a current table entry.
///
std::pair<LuaRef, LuaRef> operator*() const { return std::make_pair(m_key, m_value); }
/// Return the value referred by the iterator.
///
/// @returns A value for the current table entry.
///
LuaRef operator->() const { return m_value; }
/// Compare two iterators.
///
/// @param rhs Another iterator.
/// @returns True if iterators point to the same entry of the same table,
/// false otherwise.
///
bool operator!=(const Iterator& rhs) const
{
assert(m_L == rhs.m_L);
return !m_table.rawequal(rhs.m_table) || !m_key.rawequal(rhs.m_key);
}
/// Move the iterator to the next table entry.
///
/// @returns This iterator.
///
Iterator& operator++()
{
if (isNil())
{
// if the iterator reaches the end, do nothing
return *this;
}
else
{
next();
return *this;
}
}
/// Check if the iterator points after the last table entry.
///
/// @returns True if there are no more table entries to iterate,
/// false otherwise.
///
bool isNil() const { return m_key.isNil(); }
/// Return the key for the current table entry.
///
/// @returns A reference to the entry key.
///
LuaRef key() const { return m_key; }
/// Return the key for the current table entry.
///
/// @returns A reference to the entry value.
///
LuaRef value() const { return m_value; }
private:
// Don't use postfix increment, it is less efficient
Iterator operator++(int);
};
namespace detail {
class Range
{
Iterator m_begin;
Iterator m_end;
public:
Range(const Iterator& begin, const Iterator& end) : m_begin(begin), m_end(end) {}
const Iterator& begin() const { return m_begin; }
const Iterator& end() const { return m_end; }
};
} // namespace detail
/// Return a range for the Lua table reference.
///
/// @returns A range suitable for range-based for statement.
///
inline detail::Range pairs(const LuaRef& table)
{
return detail::Range(Iterator(table, false), Iterator(table, true));
}
} // namespace luabridge

View File

@@ -0,0 +1,104 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2008, Nigel Atkinson <suprapilot+LuaCode@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <exception>
#include <string>
namespace luabridge {
class LuaException : public std::exception
{
private:
lua_State* m_L;
std::string m_what;
public:
//----------------------------------------------------------------------------
/**
Construct a LuaException after a lua_pcall().
*/
LuaException(lua_State* L, int /*code*/) : m_L(L) { whatFromStack(); }
//----------------------------------------------------------------------------
LuaException(lua_State* L, char const*, char const*, long) : m_L(L) { whatFromStack(); }
//----------------------------------------------------------------------------
~LuaException() throw() {}
//----------------------------------------------------------------------------
char const* what() const throw() { return m_what.c_str(); }
//============================================================================
/**
Throw an exception.
This centralizes all the exceptions thrown, so that we can set
breakpoints before the stack is unwound, or otherwise customize the
behavior.
*/
template<class Exception>
static void Throw(Exception e)
{
throw e;
}
//----------------------------------------------------------------------------
/**
Wrapper for lua_pcall that throws.
*/
static void pcall(lua_State* L, int nargs = 0, int nresults = 0, int msgh = 0)
{
int code = lua_pcall(L, nargs, nresults, msgh);
if (code != LUABRIDGE_LUA_OK)
Throw(LuaException(L, code));
}
//----------------------------------------------------------------------------
/**
Initializes error handling. Subsequent Lua errors are translated to C++ exceptions.
*/
static void enableExceptions(lua_State* L) { lua_atpanic(L, throwAtPanic); }
/** Retrieve the lua_State associated with the exception.
@returns A Lua state.
*/
lua_State* state() const { return m_L; }
protected:
void whatFromStack()
{
if (lua_gettop(m_L) > 0)
{
char const* s = lua_tostring(m_L, -1);
m_what = s ? s : "";
}
else
{
// stack is empty
m_what = "missing error";
}
}
private:
static int throwAtPanic(lua_State* L) { throw LuaException(L, -1); }
};
//----------------------------------------------------------------------------
/**
Initializes error handling. Subsequent Lua errors are translated to C++ exceptions.
*/
static void enableExceptions(lua_State* L)
{
LuaException::enableExceptions(L);
}
} // namespace luabridge

View File

@@ -0,0 +1,126 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2007, Nathan Reed
// SPDX-License-Identifier: MIT
#pragma once
#include <cassert>
namespace luabridge {
// These are for Lua versions prior to 5.2.0.
//
#if LUA_VERSION_NUM < 502
inline int lua_absindex(lua_State* L, int idx)
{
if (idx > LUA_REGISTRYINDEX && idx < 0)
return lua_gettop(L) + idx + 1;
else
return idx;
}
inline void lua_rawgetp(lua_State* L, int idx, void const* p)
{
idx = lua_absindex(L, idx);
lua_pushlightuserdata(L, const_cast<void*>(p));
lua_rawget(L, idx);
}
inline void lua_rawsetp(lua_State* L, int idx, void const* p)
{
idx = lua_absindex(L, idx);
lua_pushlightuserdata(L, const_cast<void*>(p));
// put key behind value
lua_insert(L, -2);
lua_rawset(L, idx);
}
#define LUA_OPEQ 1
#define LUA_OPLT 2
#define LUA_OPLE 3
inline int lua_compare(lua_State* L, int idx1, int idx2, int op)
{
switch (op)
{
case LUA_OPEQ:
return lua_equal(L, idx1, idx2);
break;
case LUA_OPLT:
return lua_lessthan(L, idx1, idx2);
break;
case LUA_OPLE:
return lua_equal(L, idx1, idx2) || lua_lessthan(L, idx1, idx2);
break;
default:
return 0;
};
}
inline int get_length(lua_State* L, int idx)
{
return int(lua_objlen(L, idx));
}
#else
inline int get_length(lua_State* L, int idx)
{
lua_len(L, idx);
int len = int(luaL_checknumber(L, -1));
lua_pop(L, 1);
return len;
}
#endif
#ifndef LUA_OK
#define LUABRIDGE_LUA_OK 0
#else
#define LUABRIDGE_LUA_OK LUA_OK
#endif
/** Get a table value, bypassing metamethods.
*/
inline void rawgetfield(lua_State* L, int index, char const* key)
{
assert(lua_istable(L, index));
index = lua_absindex(L, index);
lua_pushstring(L, key);
lua_rawget(L, index);
}
/** Set a table value, bypassing metamethods.
*/
inline void rawsetfield(lua_State* L, int index, char const* key)
{
assert(lua_istable(L, index));
index = lua_absindex(L, index);
lua_pushstring(L, key);
lua_insert(L, -2);
lua_rawset(L, index);
}
/** Returns true if the value is a full userdata (not light).
*/
inline bool isfulluserdata(lua_State* L, int index)
{
return lua_isuserdata(L, index) && !lua_islightuserdata(L, index);
}
/** Test lua_State objects for global equality.
This can determine if two different lua_State objects really point
to the same global state, such as when using coroutines.
@note This is used for assertions.
*/
inline bool equalstates(lua_State* L1, lua_State* L2)
{
return lua_topointer(L1, LUA_REGISTRYINDEX) == lua_topointer(L2, LUA_REGISTRYINDEX);
}
} // namespace luabridge

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
namespace luabridge {
//------------------------------------------------------------------------------
/**
security options.
*/
class Security
{
public:
static bool hideMetatables() { return getSettings().hideMetatables; }
static void setHideMetatables(bool shouldHide) { getSettings().hideMetatables = shouldHide; }
private:
struct Settings
{
Settings() : hideMetatables(true) {}
bool hideMetatables;
};
static Settings& getSettings()
{
static Settings settings;
return settings;
}
};
//------------------------------------------------------------------------------
/**
Set a global value in the lua_State.
@note This works on any type specialized by `Stack`, including `LuaRef` and
its table proxies.
*/
template<class T>
inline void setGlobal(lua_State* L, T t, char const* name)
{
push(L, t);
lua_setglobal(L, name);
}
//------------------------------------------------------------------------------
/**
Change whether or not metatables are hidden (on by default).
*/
inline void setHideMetatables(bool shouldHide)
{
Security::setHideMetatables(shouldHide);
}
} // namespace luabridge

View File

@@ -0,0 +1,535 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2019, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2007, Nathan Reed
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/LuaHelpers.h>
#include <LuaBridge/detail/Userdata.h>
#include <string>
#ifdef LUABRIDGE_CXX17
#include <string_view>
#endif
namespace luabridge {
/// Lua stack traits for C++ types.
///
/// @tparam T A C++ type.
///
template<class T>
struct Stack;
template<>
struct Stack<void>
{
static void push(lua_State*) {}
};
//------------------------------------------------------------------------------
/**
Receive the lua_State* as an argument.
*/
template<>
struct Stack<lua_State*>
{
static lua_State* get(lua_State* L, int) { return L; }
};
//------------------------------------------------------------------------------
/**
Stack specialization for a lua_CFunction.
*/
template<>
struct Stack<lua_CFunction>
{
static void push(lua_State* L, lua_CFunction f) { lua_pushcfunction(L, f); }
static lua_CFunction get(lua_State* L, int index) { return lua_tocfunction(L, index); }
static bool isInstance(lua_State* L, int index) { return lua_iscfunction(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `int`.
*/
template<>
struct Stack<int>
{
static void push(lua_State* L, int value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static int get(lua_State* L, int index)
{
return static_cast<int>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index)
{
if (lua_type(L, index) != LUA_TNUMBER)
{
return false;
}
#if LUA_VERSION_NUM <= 501
return true;
#else
int isNumber;
lua_tointegerx(L, index, &isNumber);
return isNumber;
#endif
}
};
//------------------------------------------------------------------------------
/**
Stack specialization for `unsigned int`.
*/
template<>
struct Stack<unsigned int>
{
static void push(lua_State* L, unsigned int value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned int get(lua_State* L, int index)
{
return static_cast<unsigned int>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `unsigned char`.
*/
template<>
struct Stack<unsigned char>
{
static void push(lua_State* L, unsigned char value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned char get(lua_State* L, int index)
{
return static_cast<unsigned char>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `short`.
*/
template<>
struct Stack<short>
{
static void push(lua_State* L, short value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static short get(lua_State* L, int index)
{
return static_cast<short>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `unsigned short`.
*/
template<>
struct Stack<unsigned short>
{
static void push(lua_State* L, unsigned short value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned short get(lua_State* L, int index)
{
return static_cast<unsigned short>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `long`.
*/
template<>
struct Stack<long>
{
static void push(lua_State* L, long value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static long get(lua_State* L, int index)
{
return static_cast<long>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `unsigned long`.
*/
template<>
struct Stack<unsigned long>
{
static void push(lua_State* L, unsigned long value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned long get(lua_State* L, int index)
{
return static_cast<unsigned long>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
* Stack specialization for `long long`.
*/
template<>
struct Stack<long long>
{
static void push(lua_State* L, long long value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static long long get(lua_State* L, int index)
{
return static_cast<long long>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
* Stack specialization for `unsigned long long`.
*/
template<>
struct Stack<unsigned long long>
{
static void push(lua_State* L, unsigned long long value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned long long get(lua_State* L, int index)
{
return static_cast<unsigned long long>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `float`.
*/
template<>
struct Stack<float>
{
static void push(lua_State* L, float value)
{
lua_pushnumber(L, static_cast<lua_Number>(value));
}
static float get(lua_State* L, int index)
{
return static_cast<float>(luaL_checknumber(L, index));
}
static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TNUMBER; }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `double`.
*/
template<>
struct Stack<double>
{
static void push(lua_State* L, double value)
{
lua_pushnumber(L, static_cast<lua_Number>(value));
}
static double get(lua_State* L, int index)
{
return static_cast<double>(luaL_checknumber(L, index));
}
static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TNUMBER; }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `bool`.
*/
template<>
struct Stack<bool>
{
static void push(lua_State* L, bool value) { lua_pushboolean(L, value ? 1 : 0); }
static bool get(lua_State* L, int index) { return lua_toboolean(L, index) ? true : false; }
static bool isInstance(lua_State* L, int index) { return lua_isboolean(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `char`.
*/
template<>
struct Stack<char>
{
static void push(lua_State* L, char value) { lua_pushlstring(L, &value, 1); }
static char get(lua_State* L, int index) { return luaL_checkstring(L, index)[0]; }
static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TSTRING; }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `const char*`.
*/
template<>
struct Stack<char const*>
{
static void push(lua_State* L, char const* str)
{
if (str != 0)
lua_pushstring(L, str);
else
lua_pushnil(L);
}
static char const* get(lua_State* L, int index)
{
return lua_isnil(L, index) ? 0 : luaL_checkstring(L, index);
}
static bool isInstance(lua_State* L, int index)
{
return lua_isnil(L, index) || lua_type(L, index) == LUA_TSTRING;
}
};
//------------------------------------------------------------------------------
/**
Stack specialization for `std::string`.
*/
template<>
struct Stack<std::string>
{
static void push(lua_State* L, std::string const& str)
{
lua_pushlstring(L, str.data(), str.size());
}
static std::string get(lua_State* L, int index)
{
size_t len;
if (lua_type(L, index) == LUA_TSTRING)
{
const char* str = lua_tolstring(L, index, &len);
return std::string(str, len);
}
// Lua reference manual:
// If the value is a number, then lua_tolstring also changes the actual value in the stack
// to a string. (This change confuses lua_next when lua_tolstring is applied to keys during
// a table traversal.)
lua_pushvalue(L, index);
const char* str = lua_tolstring(L, -1, &len);
std::string string(str, len);
lua_pop(L, 1); // Pop the temporary string
return string;
}
static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TSTRING; }
};
#ifdef LUABRIDGE_CXX17
//------------------------------------------------------------------------------
/**
Stack specialization for `std::string`.
*/
template<>
struct Stack<std::string_view>
{
static void push(lua_State* L, std::string_view str)
{
lua_pushlstring(L, str.data(), str.size());
}
static std::string_view get(lua_State* L, int index)
{
size_t len;
if (lua_type(L, index) == LUA_TSTRING)
{
const char* str = lua_tolstring(L, index, &len);
return std::string_view(str, len);
}
return {};
}
static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TSTRING; }
};
#endif // LUABRIDGE_CXX17
namespace detail {
template<class T>
struct StackOpSelector<T&, false>
{
typedef T ReturnType;
static void push(lua_State* L, T& value) { Stack<T>::push(L, value); }
static ReturnType get(lua_State* L, int index) { return Stack<T>::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Stack<T>::isInstance(L, index); }
};
template<class T>
struct StackOpSelector<const T&, false>
{
typedef T ReturnType;
static void push(lua_State* L, const T& value) { Stack<T>::push(L, value); }
static ReturnType get(lua_State* L, int index) { return Stack<T>::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Stack<T>::isInstance(L, index); }
};
template<class T>
struct StackOpSelector<T*, false>
{
typedef T ReturnType;
static void push(lua_State* L, T* value) { Stack<T>::push(L, *value); }
static ReturnType get(lua_State* L, int index) { return Stack<T>::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Stack<T>::isInstance(L, index); }
};
template<class T>
struct StackOpSelector<const T*, false>
{
typedef T ReturnType;
static void push(lua_State* L, const T* value) { Stack<T>::push(L, *value); }
static ReturnType get(lua_State* L, int index) { return Stack<T>::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Stack<T>::isInstance(L, index); }
};
} // namespace detail
template<class T>
struct Stack<T&>
{
typedef detail::StackOpSelector<T&, detail::IsUserdata<T>::value> Helper;
typedef typename Helper::ReturnType ReturnType;
static void push(lua_State* L, T& value) { Helper::push(L, value); }
static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); }
};
template<class T>
struct Stack<const T&>
{
typedef detail::StackOpSelector<const T&, detail::IsUserdata<T>::value> Helper;
typedef typename Helper::ReturnType ReturnType;
static void push(lua_State* L, const T& value) { Helper::push(L, value); }
static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); }
};
template<class T>
struct Stack<T*>
{
typedef detail::StackOpSelector<T*, detail::IsUserdata<T>::value> Helper;
typedef typename Helper::ReturnType ReturnType;
static void push(lua_State* L, T* value) { Helper::push(L, value); }
static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); }
};
template<class T>
struct Stack<const T*>
{
typedef detail::StackOpSelector<const T*, detail::IsUserdata<T>::value> Helper;
typedef typename Helper::ReturnType ReturnType;
static void push(lua_State* L, const T* value) { Helper::push(L, value); }
static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); }
};
//------------------------------------------------------------------------------
/**
* Push an object onto the Lua stack.
*/
template<class T>
void push(lua_State* L, T t)
{
Stack<T>::push(L, t);
}
//------------------------------------------------------------------------------
/**
* Get an object from the Lua stack.
*/
template<class T>
T get(lua_State* L, int index)
{
return Stack<T>::get(L, index);
}
//------------------------------------------------------------------------------
/**
* Check whether an object on the Lua stack is of type T.
*/
template<class T>
bool isInstance(lua_State* L, int index)
{
return Stack<T>::isInstance(L, index);
}
} // namespace luabridge

View File

@@ -0,0 +1,183 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2007, Nathan Reed
// SPDX-License-Identifier: MIT
//==============================================================================
/*
This file incorporates work covered by the following copyright and
permission notice:
The Loki Library
Copyright (c) 2001 by Andrei Alexandrescu
This code accompanies the book:
Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
Patterns Applied". Copyright (c) 2001. Addison-Wesley.
Permission to use, copy, modify, distribute and sell this software for any
purpose is hereby granted without fee, provided that the above copyright
notice appear in all copies and that both that copyright notice and this
permission notice appear in supporting documentation.
The author or Addison-Welsey Longman make no representations about the
suitability of this software for any purpose. It is provided "as is"
without express or implied warranty.
*/
//==============================================================================
#pragma once
#include <LuaBridge/detail/Config.h>
#include <LuaBridge/detail/Stack.h>
#include <string>
#include <typeinfo>
namespace luabridge {
namespace detail {
/**
None type means void parameters or return value.
*/
typedef void None;
template<typename Head, typename Tail = None>
struct TypeList
{
typedef Tail TailType;
};
template<class List>
struct TypeListSize
{
static const size_t value = TypeListSize<typename List::TailType>::value + 1;
};
template<>
struct TypeListSize<None>
{
static const size_t value = 0;
};
template<class... Params>
struct MakeTypeList;
template<class Param, class... Params>
struct MakeTypeList<Param, Params...>
{
using Result = TypeList<Param, typename MakeTypeList<Params...>::Result>;
};
template<>
struct MakeTypeList<>
{
using Result = None;
};
/**
A TypeList with actual values.
*/
template<typename List>
struct TypeListValues
{
static std::string const tostring(bool) { return ""; }
};
/**
TypeListValues recursive template definition.
*/
template<typename Head, typename Tail>
struct TypeListValues<TypeList<Head, Tail>>
{
Head hd;
TypeListValues<Tail> tl;
TypeListValues(Head hd_, TypeListValues<Tail> const& tl_) : hd(hd_), tl(tl_) {}
static std::string tostring(bool comma = false)
{
std::string s;
if (comma)
s = ", ";
s = s + typeid(Head).name();
return s + TypeListValues<Tail>::tostring(true);
}
};
// Specializations of type/value list for head types that are references and
// const-references. We need to handle these specially since we can't count
// on the referenced object hanging around for the lifetime of the list.
template<typename Head, typename Tail>
struct TypeListValues<TypeList<Head&, Tail>>
{
Head hd;
TypeListValues<Tail> tl;
TypeListValues(Head& hd_, TypeListValues<Tail> const& tl_) : hd(hd_), tl(tl_) {}
static std::string const tostring(bool comma = false)
{
std::string s;
if (comma)
s = ", ";
s = s + typeid(Head).name() + "&";
return s + TypeListValues<Tail>::tostring(true);
}
};
template<typename Head, typename Tail>
struct TypeListValues<TypeList<Head const&, Tail>>
{
Head hd;
TypeListValues<Tail> tl;
TypeListValues(Head const& hd_, const TypeListValues<Tail>& tl_) : hd(hd_), tl(tl_) {}
static std::string const tostring(bool comma = false)
{
std::string s;
if (comma)
s = ", ";
s = s + typeid(Head).name() + " const&";
return s + TypeListValues<Tail>::tostring(true);
}
};
//==============================================================================
/**
Subclass of a TypeListValues constructable from the Lua stack.
*/
template<typename List, int Start = 1>
struct ArgList
{
};
template<int Start>
struct ArgList<None, Start> : public TypeListValues<None>
{
ArgList(lua_State*) {}
};
template<typename Head, typename Tail, int Start>
struct ArgList<TypeList<Head, Tail>, Start> : public TypeListValues<TypeList<Head, Tail>>
{
ArgList(lua_State* L)
: TypeListValues<TypeList<Head, Tail>>(Stack<Head>::get(L, Start),
ArgList<Tail, Start + 1>(L))
{
}
};
} // namespace detail
} // namespace luabridge

View File

@@ -0,0 +1,112 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2019, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Config.h>
#include <string>
namespace luabridge {
//------------------------------------------------------------------------------
/**
Container traits.
Unspecialized ContainerTraits has the isNotContainer typedef for SFINAE.
All user defined containers must supply an appropriate specialization for
ContinerTraits (without the typedef isNotContainer). The containers that
come with LuaBridge also come with the appropriate ContainerTraits
specialization. See the corresponding declaration for details.
A specialization of ContainerTraits for some generic type ContainerType
looks like this:
template <class T>
struct ContainerTraits <ContainerType <T>>
{
typedef typename T Type;
static T* get (ContainerType <T> const& c)
{
return c.get (); // Implementation-dependent on ContainerType
}
};
*/
template<class T>
struct ContainerTraits
{
typedef bool isNotContainer;
typedef T Type;
};
namespace detail {
//------------------------------------------------------------------------------
/**
Type traits.
Specializations return information about a type.
*/
struct TypeTraits
{
/** Determine if type T is a container.
To be considered a container, there must be a specialization of
ContainerTraits with the required fields.
*/
template<typename T>
class isContainer
{
private:
typedef char yes[1]; // sizeof (yes) == 1
typedef char no[2]; // sizeof (no) == 2
template<typename C>
static no& test(typename C::isNotContainer*);
template<typename>
static yes& test(...);
public:
static const bool value = sizeof(test<ContainerTraits<T>>(0)) == sizeof(yes);
};
/** Determine if T is const qualified.
*/
/** @{ */
template<class T>
struct isConst
{
static bool const value = false;
};
template<class T>
struct isConst<T const>
{
static bool const value = true;
};
/** @} */
/** Remove the const qualifier from T.
*/
/** @{ */
template<class T>
struct removeConst
{
typedef T Type;
};
template<class T>
struct removeConst<T const>
{
typedef T Type;
};
/**@}*/
};
} // namespace detail
} // namespace luabridge

View File

@@ -0,0 +1,769 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2019, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/ClassInfo.h>
#include <LuaBridge/detail/TypeTraits.h>
#include <cassert>
#include <stdexcept>
namespace luabridge {
namespace detail {
//==============================================================================
/**
Return the identity pointer for our lightuserdata tokens.
Because of Lua's dynamic typing and our improvised system of imposing C++
class structure, there is the possibility that executing scripts may
knowingly or unknowingly cause invalid data to get passed to the C functions
created by LuaBridge. In particular, our security model addresses the
following:
1. Scripts cannot create a userdata (ignoring the debug lib).
2. Scripts cannot create a lightuserdata (ignoring the debug lib).
3. Scripts cannot set the metatable on a userdata.
*/
/**
Interface to a class pointer retrievable from a userdata.
*/
class Userdata
{
protected:
void* m_p; // subclasses must set this
Userdata() : m_p(0) {}
//--------------------------------------------------------------------------
/**
Get an untyped pointer to the contained class.
*/
void* getPointer() { return m_p; }
private:
//--------------------------------------------------------------------------
/**
Validate and retrieve a Userdata on the stack.
The Userdata must exactly match the corresponding class table or
const table, or else a Lua error is raised. This is used for the
__gc metamethod.
*/
static Userdata* getExactClass(lua_State* L, int index, void const* /*classKey*/)
{
return static_cast<Userdata*>(lua_touserdata(L, lua_absindex(L, index)));
}
//--------------------------------------------------------------------------
/**
Validate and retrieve a Userdata on the stack.
The Userdata must be derived from or the same as the given base class,
identified by the key. If canBeConst is false, generates an error if
the resulting Userdata represents to a const object. We do the type check
first so that the error message is informative.
*/
static Userdata* getClass(lua_State* L,
int index,
void const* registryConstKey,
void const* registryClassKey,
bool canBeConst)
{
index = lua_absindex(L, index);
lua_getmetatable(L, index); // Stack: object metatable (ot) | nil
if (!lua_istable(L, -1))
{
lua_rawgetp(
L, LUA_REGISTRYINDEX, registryClassKey); // Stack: registry metatable (rt) | nil
return throwBadArg(L, index);
}
lua_rawgetp(L, -1, getConstKey()); // Stack: ot | nil, const table (co) | nil
assert(lua_istable(L, -1) || lua_isnil(L, -1));
// If const table is NOT present, object is const. Use non-const registry table
// if object cannot be const, so constness validation is done automatically.
// E.g. nonConstFn (constObj)
// -> canBeConst = false, isConst = true
// -> 'Class' registry table, 'const Class' object table
// -> 'expected Class, got const Class'
bool isConst = lua_isnil(L, -1); // Stack: ot | nil, nil, rt
if (isConst && canBeConst)
{
lua_rawgetp(L, LUA_REGISTRYINDEX, registryConstKey); // Stack: ot, nil, rt
}
else
{
lua_rawgetp(L, LUA_REGISTRYINDEX, registryClassKey); // Stack: ot, co, rt
}
lua_insert(L, -3); // Stack: rt, ot, co | nil
lua_pop(L, 1); // Stack: rt, ot
for (;;)
{
if (lua_rawequal(L, -1, -2)) // Stack: rt, ot
{
lua_pop(L, 2); // Stack: -
return static_cast<Userdata*>(lua_touserdata(L, index));
}
// Replace current metatable with it's base class.
lua_rawgetp(L, -1, getParentKey()); // Stack: rt, ot, parent ot (pot) | nil
if (lua_isnil(L, -1)) // Stack: rt, ot, nil
{
// Drop the object metatable because it may be some parent metatable
lua_pop(L, 2); // Stack: rt
return throwBadArg(L, index);
}
lua_remove(L, -2); // Stack: rt, pot
}
// no return
}
static bool isInstance(lua_State* L, int index, void const* registryClassKey)
{
index = lua_absindex(L, index);
int result = lua_getmetatable(L, index); // Stack: object metatable (ot) | nothing
if (result == 0)
{
return false; // Nothing was pushed on the stack
}
if (!lua_istable(L, -1))
{
lua_pop(L, 1); // Stack: -
return false;
}
lua_rawgetp(L, LUA_REGISTRYINDEX, registryClassKey); // Stack: ot, rt
lua_insert(L, -2); // Stack: rt, ot
for (;;)
{
if (lua_rawequal(L, -1, -2)) // Stack: rt, ot
{
lua_pop(L, 2); // Stack: -
return true;
}
// Replace current metatable with it's base class.
lua_rawgetp(L, -1, getParentKey()); // Stack: rt, ot, parent ot (pot) | nil
if (lua_isnil(L, -1)) // Stack: rt, ot, nil
{
lua_pop(L, 3); // Stack: -
return false;
}
lua_remove(L, -2); // Stack: rt, pot
}
}
static Userdata* throwBadArg(lua_State* L, int index)
{
assert(lua_istable(L, -1) || lua_isnil(L, -1)); // Stack: rt | nil
const char* expected = 0;
if (lua_isnil(L, -1)) // Stack: nil
{
expected = "unregistered class";
}
else
{
lua_rawgetp(L, -1, getTypeKey()); // Stack: rt, registry type
expected = lua_tostring(L, -1);
}
const char* got = 0;
if (lua_isuserdata(L, index))
{
lua_getmetatable(L, index); // Stack: ..., ot | nil
if (lua_istable(L, -1)) // Stack: ..., ot
{
lua_rawgetp(L, -1, getTypeKey()); // Stack: ..., ot, object type | nil
if (lua_isstring(L, -1))
{
got = lua_tostring(L, -1);
}
}
}
if (!got)
{
got = lua_typename(L, lua_type(L, index));
}
luaL_argerror(L, index, lua_pushfstring(L, "%s expected, got %s", expected, got));
return 0;
}
public:
virtual ~Userdata() {}
//--------------------------------------------------------------------------
/**
Returns the Userdata* if the class on the Lua stack matches.
If the class does not match, a Lua error is raised.
@tparam T A registered user class.
@param L A Lua state.
@param index The index of an item on the Lua stack.
@returns A userdata pointer if the class matches.
*/
template<class T>
static Userdata* getExact(lua_State* L, int index)
{
return getExactClass(L, index, detail::getClassRegistryKey<T>());
}
//--------------------------------------------------------------------------
/**
Get a pointer to the class from the Lua stack.
If the object is not the class or a subclass, or it violates the
const-ness, a Lua error is raised.
@tparam T A registered user class.
@param L A Lua state.
@param index The index of an item on the Lua stack.
@param canBeConst TBD
@returns A pointer if the class and constness match.
*/
template<class T>
static T* get(lua_State* L, int index, bool canBeConst)
{
if (lua_isnil(L, index))
return 0;
return static_cast<T*>(getClass(L,
index,
detail::getConstRegistryKey<T>(),
detail::getClassRegistryKey<T>(),
canBeConst)
->getPointer());
}
template<class T>
static bool isInstance(lua_State* L, int index)
{
return isInstance(L, index, detail::getClassRegistryKey<T>());
}
};
//----------------------------------------------------------------------------
/**
Wraps a class object stored in a Lua userdata.
The lifetime of the object is managed by Lua. The object is constructed
inside the userdata using placement new.
*/
template<class T>
class UserdataValue : public Userdata
{
private:
UserdataValue(UserdataValue<T> const&);
UserdataValue<T> operator=(UserdataValue<T> const&);
char m_storage[sizeof(T)];
private:
/**
Used for placement construction.
*/
UserdataValue() { m_p = 0; }
~UserdataValue()
{
if (getPointer() != 0)
{
getObject()->~T();
}
}
public:
/**
Push a T via placement new.
The caller is responsible for calling placement new using the
returned uninitialized storage.
@param L A Lua state.
@returns An object referring to the newly created userdata value.
*/
static UserdataValue<T>* place(lua_State* const L)
{
UserdataValue<T>* const ud =
new (lua_newuserdata(L, sizeof(UserdataValue<T>))) UserdataValue<T>();
lua_rawgetp(L, LUA_REGISTRYINDEX, detail::getClassRegistryKey<T>());
if (!lua_istable(L, -1))
{
throw std::logic_error("The class is not registered in LuaBridge");
}
lua_setmetatable(L, -2);
return ud;
}
/**
Push T via copy construction from U.
@tparam U A container type.
@param L A Lua state.
@param u A container object reference.
*/
template<class U>
static inline void push(lua_State* const L, U const& u)
{
UserdataValue<T>* ud = place(L);
new (ud->getObject()) U(u);
ud->commit();
}
/**
Confirm object construction.
*/
void commit() { m_p = getObject(); }
T* getObject()
{
// If this fails to compile it means you forgot to provide
// a Container specialization for your container!
//
return reinterpret_cast<T*>(&m_storage[0]);
}
};
//----------------------------------------------------------------------------
/**
Wraps a pointer to a class object inside a Lua userdata.
The lifetime of the object is managed by C++.
*/
class UserdataPtr : public Userdata
{
private:
UserdataPtr(UserdataPtr const&);
UserdataPtr operator=(UserdataPtr const&);
private:
/** Push a pointer to object using metatable key.
*/
static void push(lua_State* L, const void* p, void const* const key)
{
new (lua_newuserdata(L, sizeof(UserdataPtr))) UserdataPtr(const_cast<void*>(p));
lua_rawgetp(L, LUA_REGISTRYINDEX, key);
if (!lua_istable(L, -1))
{
lua_pop(L, 1); // possibly: a nil
throw std::logic_error("The class is not registered in LuaBridge");
}
lua_setmetatable(L, -2);
}
explicit UserdataPtr(void* const p)
{
m_p = p;
// Can't construct with a null pointer!
//
assert(m_p != 0);
}
public:
/** Push non-const pointer to object.
@tparam T A user registered class.
@param L A Lua state.
@param p A pointer to the user class instance.
*/
template<class T>
static void push(lua_State* const L, T* const p)
{
if (p)
push(L, p, getClassRegistryKey<T>());
else
lua_pushnil(L);
}
/** Push const pointer to object.
@tparam T A user registered class.
@param L A Lua state.
@param p A pointer to the user class instance.
*/
template<class T>
static void push(lua_State* const L, T const* const p)
{
if (p)
push(L, p, getConstRegistryKey<T>());
else
lua_pushnil(L);
}
};
//============================================================================
/**
Wraps a container that references a class object.
The template argument C is the container type, ContainerTraits must be
specialized on C or else a compile error will result.
*/
template<class C>
class UserdataShared : public Userdata
{
private:
UserdataShared(UserdataShared<C> const&);
UserdataShared<C>& operator=(UserdataShared<C> const&);
typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
C m_c;
private:
~UserdataShared() {}
public:
/**
Construct from a container to the class or a derived class.
@tparam U A container type.
@param u A container object reference.
*/
template<class U>
explicit UserdataShared(U const& u) : m_c(u)
{
m_p = const_cast<void*>(reinterpret_cast<void const*>((ContainerTraits<C>::get(m_c))));
}
/**
Construct from a pointer to the class or a derived class.
@tparam U A container type.
@param u A container object pointer.
*/
template<class U>
explicit UserdataShared(U* u) : m_c(u)
{
m_p = const_cast<void*>(reinterpret_cast<void const*>((ContainerTraits<C>::get(m_c))));
}
};
//----------------------------------------------------------------------------
//
// SFINAE helpers.
//
// non-const objects
template<class C, bool makeObjectConst>
struct UserdataSharedHelper
{
typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
static void push(lua_State* L, C const& c)
{
if (ContainerTraits<C>::get(c) != 0)
{
new (lua_newuserdata(L, sizeof(UserdataShared<C>))) UserdataShared<C>(c);
lua_rawgetp(L, LUA_REGISTRYINDEX, getClassRegistryKey<T>());
// If this goes off it means the class T is unregistered!
assert(lua_istable(L, -1));
lua_setmetatable(L, -2);
}
else
{
lua_pushnil(L);
}
}
static void push(lua_State* L, T* const t)
{
if (t)
{
new (lua_newuserdata(L, sizeof(UserdataShared<C>))) UserdataShared<C>(t);
lua_rawgetp(L, LUA_REGISTRYINDEX, getClassRegistryKey<T>());
// If this goes off it means the class T is unregistered!
assert(lua_istable(L, -1));
lua_setmetatable(L, -2);
}
else
{
lua_pushnil(L);
}
}
};
// const objects
template<class C>
struct UserdataSharedHelper<C, true>
{
typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
static void push(lua_State* L, C const& c)
{
if (ContainerTraits<C>::get(c) != 0)
{
new (lua_newuserdata(L, sizeof(UserdataShared<C>))) UserdataShared<C>(c);
lua_rawgetp(L, LUA_REGISTRYINDEX, getConstRegistryKey<T>());
// If this goes off it means the class T is unregistered!
assert(lua_istable(L, -1));
lua_setmetatable(L, -2);
}
else
{
lua_pushnil(L);
}
}
static void push(lua_State* L, T* const t)
{
if (t)
{
new (lua_newuserdata(L, sizeof(UserdataShared<C>))) UserdataShared<C>(t);
lua_rawgetp(L, LUA_REGISTRYINDEX, getConstRegistryKey<T>());
// If this goes off it means the class T is unregistered!
assert(lua_istable(L, -1));
lua_setmetatable(L, -2);
}
else
{
lua_pushnil(L);
}
}
};
/**
Pass by container.
The container controls the object lifetime. Typically this will be a
lifetime shared by C++ and Lua using a reference count. Because of type
erasure, containers like std::shared_ptr will not work. Containers must
either be of the intrusive variety, or in the style of the RefCountedPtr
type provided by LuaBridge (that uses a global hash table).
*/
template<class C, bool byContainer>
struct StackHelper
{
static void push(lua_State* L, C const& c)
{
UserdataSharedHelper<C, TypeTraits::isConst<typename ContainerTraits<C>::Type>::value>::
push(L, c);
}
typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
static C get(lua_State* L, int index) { return Userdata::get<T>(L, index, true); }
};
/**
Pass by value.
Lifetime is managed by Lua. A C++ function which accesses a pointer or
reference to an object outside the activation record in which it was
retrieved may result in undefined behavior if Lua garbage collected it.
*/
template<class T>
struct StackHelper<T, false>
{
static inline void push(lua_State* L, T const& t) { UserdataValue<T>::push(L, t); }
static inline T const& get(lua_State* L, int index)
{
return *Userdata::get<T>(L, index, true);
}
};
//------------------------------------------------------------------------------
/**
Lua stack conversions for pointers and references to class objects.
Lifetime is managed by C++. Lua code which remembers a reference to the
value may result in undefined behavior if C++ destroys the object. The
handling of the const and volatile qualifiers happens in UserdataPtr.
*/
template<class C, bool byContainer>
struct RefStackHelper
{
typedef C return_type;
static inline void push(lua_State* L, C const& t)
{
UserdataSharedHelper<C, TypeTraits::isConst<typename ContainerTraits<C>::Type>::value>::
push(L, t);
}
typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
static return_type get(lua_State* L, int index) { return Userdata::get<T>(L, index, true); }
};
template<class T>
struct RefStackHelper<T, false>
{
typedef T& return_type;
static void push(lua_State* L, T const& t) { UserdataPtr::push(L, &t); }
static return_type get(lua_State* L, int index)
{
T* t = Userdata::get<T>(L, index, true);
if (!t)
luaL_error(L, "nil passed to reference");
return *t;
}
};
/**
* Voider class template. Used to force a compiler to instantiate
* an otherwise probably unused template parameter type T.
* See the C++20 std::void_t <> for details.
*/
template<class T>
struct Void
{
typedef void Type;
};
/**
* Trait class that selects whether to return a user registered
* class object by value or by reference.
*/
template<class T, class Enabler = void>
struct UserdataGetter
{
typedef T* ReturnType;
static ReturnType get(lua_State* L, int index) { return Userdata::get<T>(L, index, false); }
};
template<class T>
struct UserdataGetter<T, typename Void<T (*)()>::Type>
{
typedef T ReturnType;
static ReturnType get(lua_State* L, int index)
{
return StackHelper<T, TypeTraits::isContainer<T>::value>::get(L, index);
}
};
} // namespace detail
//==============================================================================
/**
Lua stack conversions for class objects passed by value.
*/
template<class T>
struct Stack
{
typedef void IsUserdata;
typedef detail::UserdataGetter<T> Getter;
typedef typename Getter::ReturnType ReturnType;
static void push(lua_State* L, T const& value)
{
using namespace detail;
StackHelper<T, TypeTraits::isContainer<T>::value>::push(L, value);
}
static ReturnType get(lua_State* L, int index) { return Getter::get(L, index); }
static bool isInstance(lua_State* L, int index)
{
return detail::Userdata::isInstance<T>(L, index);
}
};
namespace detail {
/**
* Trait class indicating whether the parameter type must be
* a user registered class. The trait checks the existence of
* member type Stack::IsUserdata specialization for detection.
*/
template<class T, class Enable = void>
struct IsUserdata
{
static const bool value = false;
};
template<class T>
struct IsUserdata<T, typename Void<typename Stack<T>::IsUserdata>::Type>
{
static const bool value = true;
};
/**
* Trait class that selects a specific push/get implementation.
*/
template<class T, bool isUserdata>
struct StackOpSelector;
// pointer
template<class T>
struct StackOpSelector<T*, true>
{
typedef T* ReturnType;
static void push(lua_State* L, T* value) { UserdataPtr::push(L, value); }
static T* get(lua_State* L, int index) { return Userdata::get<T>(L, index, false); }
static bool isInstance(lua_State* L, int index) { return Userdata::isInstance<T>(L, index); }
};
// pointer to const
template<class T>
struct StackOpSelector<const T*, true>
{
typedef const T* ReturnType;
static void push(lua_State* L, const T* value) { UserdataPtr::push(L, value); }
static const T* get(lua_State* L, int index) { return Userdata::get<T>(L, index, true); }
static bool isInstance(lua_State* L, int index) { return Userdata::isInstance<T>(L, index); }
};
// reference
template<class T>
struct StackOpSelector<T&, true>
{
typedef RefStackHelper<T, TypeTraits::isContainer<T>::value> Helper;
typedef typename Helper::return_type ReturnType;
static void push(lua_State* L, T& value) { UserdataPtr::push(L, &value); }
static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Userdata::isInstance<T>(L, index); }
};
// reference to const
template<class T>
struct StackOpSelector<const T&, true>
{
typedef RefStackHelper<T, TypeTraits::isContainer<T>::value> Helper;
typedef typename Helper::return_type ReturnType;
static void push(lua_State* L, const T& value) { Helper::push(L, value); }
static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Userdata::isInstance<T>(L, index); }
};
} // namespace detail
} // namespace luabridge

View File

@@ -0,0 +1,125 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2019, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2007, Nathan Reed
// SPDX-License-Identifier: MIT
#pragma once
#include "LuaBridge/detail/ClassInfo.h"
#include <iostream>
#include <string>
namespace luabridge {
namespace debug {
inline void putIndent(std::ostream& stream, unsigned level)
{
for (unsigned i = 0; i < level; ++i)
{
stream << " ";
}
}
inline void
dumpTable(lua_State* L, int index, std::ostream& stream, unsigned level, unsigned maxDepth);
inline void
dumpValue(lua_State* L, int index, std::ostream& stream, unsigned maxDepth = 1, unsigned level = 0)
{
const int type = lua_type(L, index);
switch (type)
{
case LUA_TNIL:
stream << "nil";
break;
case LUA_TBOOLEAN:
stream << (lua_toboolean(L, index) ? "true" : "false");
break;
case LUA_TNUMBER:
stream << lua_tonumber(L, index);
break;
case LUA_TSTRING:
stream << '"' << lua_tostring(L, index) << '"';
break;
case LUA_TFUNCTION:
if (lua_iscfunction(L, index))
{
stream << "cfunction@" << lua_topointer(L, index);
}
else
{
stream << "function@" << lua_topointer(L, index);
}
break;
case LUA_TTHREAD:
stream << "thread@" << lua_tothread(L, index);
break;
case LUA_TLIGHTUSERDATA:
stream << "lightuserdata@" << lua_touserdata(L, index);
break;
case LUA_TTABLE:
dumpTable(L, index, stream, level, maxDepth);
break;
case LUA_TUSERDATA:
stream << "userdata@" << lua_touserdata(L, index);
break;
default:
stream << lua_typename(L, type);
;
break;
}
}
inline void
dumpTable(lua_State* L, int index, std::ostream& stream, unsigned level, unsigned maxDepth)
{
stream << "table@" << lua_topointer(L, index);
if (level > maxDepth)
{
return;
}
index = lua_absindex(L, index);
stream << " {";
lua_pushnil(L); // Initial key
while (lua_next(L, index))
{
stream << "\n";
putIndent(stream, level + 1);
dumpValue(L, -2, stream, maxDepth, level + 1); // Key
stream << ": ";
dumpValue(L, -1, stream, maxDepth, level + 1); // Value
lua_pop(L, 1); // Value
}
stream << "\n";
putIndent(stream, level);
stream << "}";
}
inline void dumpState(lua_State* L, std::ostream& stream = std::cerr, unsigned maxDepth = 1)
{
int top = lua_gettop(L);
for (int i = 1; i <= top; ++i)
{
stream << "stack #" << i << ": ";
dumpValue(L, i, stream, maxDepth, 0);
stream << "\n";
}
}
} // namespace debug
} // namespace luabridge