1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 08:47:17 +01:00
SqMod/module/Sqrat/sqratOverloadMethods.h

292 lines
9.1 KiB
C
Raw Normal View History

//
// SqratOverloadMethods: Overload Methods
//
//
// Copyright (c) 2009 Brandon Jones
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
#pragma once
#include <squirrelex.h>
#include "sqratTypes.h"
#include "sqratUtil.h"
#include "sqratGlobalMethods.h"
#include "sqratMemberMethods.h"
namespace Sqrat {
/// @cond DEV
//
// Overload name generator
//
class SqOverloadName {
public:
static void Get(const SQChar* name, int args, string & out) {
SQChar buf[16] = {'_', 'o'};
unsigned l = I32ToA(args, &buf[2]);
out.append(buf, l+2);
out.push_back('_');
out.append(name);
}
static string Get(const SQChar* name, int args) {
string out;
out.reserve(15);
Get(name, args, out);
return out;
}
};
//
// Don't include the overloaded call forwarder into the templated class
// to avoid duplicating code that doesn't need to be specialized.
//
inline SQInteger OverloadExecutionForwarder(HSQUIRRELVM vm) {
const SQInteger top = sq_gettop(vm);
// Get the argument count
const int argCount = static_cast<int>(top - 2);
// Subtract environment and base name in free variable^
const SQChar* funcName;
SQInteger funcNameSize;
// Get the un-mangled function name (free variable)
sq_getstringandsize(vm, -1, &funcName, &funcNameSize);
// Generate the overload mangled name
string overloadName;
overloadName.reserve(static_cast< size_t >(funcNameSize)+5);
SqOverloadName::Get(funcName, argCount, overloadName);
// Pop the un-mangled closure name from the stack so we can replace it later
sq_poptop(vm); // `funcName` becomes invalid after this
// Push the overload mangled name on the stack
sq_pushstring(vm, overloadName.c_str(), static_cast<SQInteger>(overloadName.size()));
// Lookup the proper overload and get it on the stack
#if !defined (SCRAT_NO_ERROR_CHECKING)
if (SQ_FAILED(sq_get(vm, 1))) {
sq_settop(vm, top); // keep the stack size intact
return sq_throwerror(vm, _SC("wrong number of parameters"));
}
#else
sq_get(vm, 1);
#endif
SQFUNCTION f = nullptr;
// Get the native closure pointer that we must invoke
SQRESULT res = sq_getnativeclosurepointer(vm, -1, &f);
if (SQ_FAILED(res)) {
return res;
// Make sure a native closure pointer is available
} else if (!f) {
return sq_throwerror(vm, _SC("unable to acquire the proper overload closure"));
}
// Attempt to get the free variable containing the native closure pointer on the stack
sq_getonefreevariable(vm, 0);
// This is simply a hack to implement a direct call and gain some performance
// Since both closures expect a free variable we simply replace the free variable
// containing closure name with the free variable containing the closure pointer
sq_settop(vm, top); // keep the stack size intact before invoking the overload
// Perform a direct call and return the result back to the caller
return f(vm);
}
//
// Don't include the overloaded call forwarder into the templated class
// to avoid duplicating code that doesn't need to be specialized.
//
inline SQInteger OverloadConstructionForwarder(HSQUIRRELVM vm) {
const SQInteger top = sq_gettop(vm);
// Get the argument count
const int argCount = static_cast<int>(top - 2);
// Subtract environment and base name in free variable^
const SQChar* funcName;
SQInteger funcNameSize;
// Get the un-mangled function name (free variable)
sq_getstringandsize(vm, -1, &funcName, &funcNameSize);
// Generate the overload mangled name
string overloadName;
overloadName.reserve(static_cast< size_t >(funcNameSize)+5);
SqOverloadName::Get(funcName, argCount, overloadName);
// Push the overload mangled name on the stack
sq_pushstring(vm, overloadName.c_str(), static_cast<SQInteger>(overloadName.size()));
// Lookup the proper overload and get it on the stack
#if !defined (SCRAT_NO_ERROR_CHECKING)
if (SQ_FAILED(sq_get(vm, 1))) {
sq_settop(vm, top); // keep the stack size intact
return sq_throwerrorf(vm, _SC("wrong number of parameters. no such constructor overload: `%s`"), overloadName.data());
}
#else
sq_get(vm, 1);
#endif
SQFUNCTION f = nullptr;
// Get the native closure pointer that we must invoke
SQRESULT res = sq_getnativeclosurepointer(vm, -1, &f);
if (SQ_FAILED(res)) {
return res;
// Make sure a native closure pointer is available
} else if (!f) {
return sq_throwerror(vm, _SC("unable to acquire the proper overload closure"));
}
// Restore the stack size by removing the overload closure object
sq_poptop(vm);
// Pop the un-mangled closure name from the stack
// The constructor doesn't expect any free variables
//sq_poptop(vm); // `funcName` becomes invalid after this
// Perform a direct call and store the result
SQRESULT r = f(vm);
// Keep the stack size intact before leaving
sq_settop(vm, top);
// Return the result back to the caller
return r;
}
//
// Squirrel Overload Functions
//
template <class R>
class SqOverload {
public:
static SQInteger Func(HSQUIRRELVM vm) {
return OverloadExecutionForwarder(vm);
}
};
//
// void return specialization
//
template <>
class SqOverload<void> {
public:
static SQInteger Func(HSQUIRRELVM vm) {
return OverloadExecutionForwarder(vm);
}
};
// Global Overloaded Function Resolver
template <class R,class... A> SQFUNCTION SqGlobalOverloadedFunc(R (* /*method*/)(A...)) {
return SqGlobal<R>::template GetProxy<2, true, A...>();
}
// Global Overloaded Function Resolver
template <class R,class... A> SQFUNCTION SqGlobalOverloadedFunc(R& (* /*method*/)(A...)) {
return SqGlobal<R&>::template GetProxy<2, true, A...>();
}
// Member Global Overloaded Function Resolver
template <class R,class T,class... A> SQFUNCTION SqMemberGlobalOverloadedFunc(R (* /*method*/)(T, A...)) {
return SqGlobal<R>::template GetProxy<1, true, T, A...>();
}
// Member Global Overloaded Function Resolver
template <class R,class T,class... A> SQFUNCTION SqMemberGlobalOverloadedFunc(R& (* /*method*/)(T, A...)) {
return SqGlobal<R&>::template GetProxy<1, true, T, A...>();
}
// Member Overloaded Function Resolver
template <class C, class R,class... A> SQFUNCTION SqMemberOverloadedFunc(R (C::* /*method*/)(A...)) {
return SqMember<C,R>::template GetProxy<true, A...>();
}
// Member Overloaded Function Resolver
template <class C, class R,class... A> SQFUNCTION SqMemberOverloadedFunc(R (C::* /*method*/)(A...) const) {
return SqMember<C,R>::template GetProxyC<true, A...>();
}
// Member Overloaded Function Resolver
template <class C, class R,class... A> SQFUNCTION SqMemberOverloadedFunc(R& (C::* /*method*/)(A...)) {
return SqMember<C,R&>::template GetProxy<true, A...>();
}
// Member Overloaded Function Resolver
template <class C, class R,class... A> SQFUNCTION SqMemberOverloadedFunc(R& (C::* /*method*/)(A...) const) {
return SqMember<C,R&>::template GetProxyC<true, A...>();
}
//
// Overload handler resolver
//
template <class R>
inline SQFUNCTION SqOverloadFunc(R (* /*method*/)) {
return &SqOverload<R>::Func;
}
template <class R, class... A>
inline SQFUNCTION SqOverloadFunc(R (* /*method*/)(A...)) {
return &SqOverload<R>::Func;
}
template <class C, class R>
inline SQFUNCTION SqOverloadFunc(R (C::* /*method*/)) {
return &SqOverload<R>::Func;
}
template <class C, class R>
inline SQFUNCTION SqOverloadFunc(R (C::* /*method*/)() const ) {
return &SqOverload<R>::Func;
}
template <class C, class R, class... A>
inline SQFUNCTION SqOverloadFunc(R (C::* /*method*/)(A...) ) {
return &SqOverload<R>::Func;
}
template <class C, class R, class... A>
inline SQFUNCTION SqOverloadFunc(R (C::* /*method*/)(A...) const ) {
return &SqOverload<R>::Func;
}
//
// Query argument count
//
template <class R, class... Args>
inline int SqGetArgCount(R (* /*method*/)(Args...)) {
return sizeof...(Args);
}
//
// Query member function argument count
//
template <class C, class R, class... Args>
inline int SqGetArgCount(R (C::* /*method*/)(Args...)) {
return sizeof...(Args);
}
//
// Query const member function argument count
//
template <class C, class R, class... Args>
inline int SqGetArgCount(R (C::* /*method*/)(Args...) const) {
return sizeof...(Args);
}
/// @endcond
}