Skip to content

Commit d0ce0c6

Browse files
committed
Initial version of overload resolution logic
Only works for overloads with the same number of parameters
1 parent 0ce4777 commit d0ce0c6

File tree

5 files changed

+183
-1
lines changed

5 files changed

+183
-1
lines changed

Client/mods/deathmatch/logic/luadefs/CLuaDefs.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,23 @@ class CLuaDefs
7474
return CLuaFunctionParser<false, T>()(L, m_pScriptDebugging);
7575
}
7676

77+
template <auto T, auto U>
78+
static inline int ArgumentParserWarn(lua_State* L)
79+
{
80+
return CLuaFunctionParser<false, CLuaOverloadParser<T, U>::Call>()(L, m_pScriptDebugging);
81+
}
82+
7783
// New style: hard error on usage mistakes
7884
template <auto T>
7985
static inline int ArgumentParser(lua_State* L)
8086
{
8187
return CLuaFunctionParser<true, T>()(L, m_pScriptDebugging);
8288
}
89+
90+
// Overload variant
91+
template <auto T, auto U>
92+
static inline int ArgumentParser(lua_State* L)
93+
{
94+
return CLuaFunctionParser<true, CLuaOverloadParser<T, U>::Call>()(L, m_pScriptDebugging);
95+
}
8396
};

Server/mods/deathmatch/logic/luadefs/CLuaDefs.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,23 @@ class CLuaDefs
9595
return CLuaFunctionParser<false, T>()(L, m_pScriptDebugging);
9696
}
9797

98+
template <auto T, auto U>
99+
static inline int ArgumentParserWarn(lua_State* L)
100+
{
101+
return CLuaFunctionParser<false, CLuaOverloadParser<T, U>::Call>()(L, m_pScriptDebugging);
102+
}
103+
98104
// New style: hard error on usage mistakes
99105
template <auto T>
100106
static inline int ArgumentParser(lua_State* L)
101107
{
102108
return CLuaFunctionParser<true, T>()(L, m_pScriptDebugging);
103109
}
110+
111+
// Overload variant
112+
template <auto T, auto U>
113+
static inline int ArgumentParser(lua_State* L)
114+
{
115+
return CLuaFunctionParser<true, CLuaOverloadParser<T, U>::Call>()(L, m_pScriptDebugging);
116+
}
104117
};

Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <optional>
1212
#include <variant>
1313
#include <SharedUtil.Template.h>
14+
#include "lua/CLuaOverloadParser.h"
1415
#include "lua/CLuaFunctionParseHelpers.h"
1516
#include "lua/CLuaStackChecker.h"
1617
#include "lua/LuaBasic.h"
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*****************************************************************************
2+
*
3+
* PROJECT: Multi Theft Auto
4+
* LICENSE: See LICENSE in the top level directory
5+
*
6+
* Multi Theft Auto is available from http://www.multitheftauto.com/
7+
*
8+
*****************************************************************************/
9+
#pragma once
10+
11+
#include <SharedUtil.Template.h>
12+
#include <type_traits>
13+
#include <variant>
14+
15+
template <auto*, auto*>
16+
struct CLuaOverloadParser
17+
{
18+
};
19+
20+
template <typename Ret, typename Ret2, typename... Args, typename... Args2, auto (*Func)(Args...)->Ret, auto (*Func2)(Args2...)->Ret2>
21+
struct CLuaOverloadParser<Func, Func2>
22+
{
23+
private:
24+
enum class ChosenFunction
25+
{
26+
FUNCA,
27+
FUNCB,
28+
COMMON,
29+
FAIL
30+
};
31+
32+
template <std::size_t N, typename... Ts, typename... Us>
33+
static ChosenFunction MakeAllChoice(std::variant<Ts...> var, Us... us)
34+
{
35+
ChosenFunction result = MakeChoice<0>(var);
36+
if constexpr (sizeof...(Us) == 0)
37+
return result;
38+
else
39+
{
40+
ChosenFunction rest = MakeAllChoice<N + 1>(us...);
41+
// If types match for overload X, use overload X
42+
if (result == rest)
43+
return result;
44+
// If types don't match, check if this variable matches
45+
// both. If so, use the other type
46+
else if (result == ChosenFunction::COMMON)
47+
return rest;
48+
// If the rest matches both overloads, use the current one
49+
else if (rest == ChosenFunction::COMMON)
50+
return result;
51+
// result != rest && result != 0 && rest != 0
52+
// Type error
53+
return ChosenFunction::FAIL;
54+
}
55+
}
56+
57+
// Chose an overload that the Nth paramter matches
58+
template <std::size_t N, typename... T>
59+
static ChosenFunction MakeChoice(std::variant<T...> var)
60+
{
61+
return std::visit(
62+
[](auto&& f) {
63+
using ft = decltype(f);
64+
if constexpr (!std::is_convertible_v<ft, nth_element_t<N, Args...>>)
65+
return ChosenFunction::FUNCB; // if it cannot match A, B it is
66+
if constexpr (!std::is_convertible_v<ft, nth_element_t<N, Args2...>>)
67+
return ChosenFunction::FUNCA; // if it cannot match A, B it is
68+
return ChosenFunction::COMMON; // Both match
69+
},
70+
var);
71+
}
72+
73+
public:
74+
typename common_variant<Ret, Ret2>::type
75+
static Call(typename common_variant<Args, Args2>::type... args)
76+
{
77+
ChosenFunction choice = MakeAllChoice<0>(args...);
78+
if (choice == ChosenFunction::FUNCA)
79+
return Func(std::get<Args>(args)...);
80+
else if (choice == ChosenFunction::FUNCB)
81+
return Func2(std::get<Args2>(args)...);
82+
else if (choice == ChosenFunction::FAIL)
83+
{
84+
// User provided incorrect arguments
85+
throw std::invalid_argument("Overload resolution failed.");
86+
}
87+
// If this exception is thrown, there is a bug in the overload, as they are not unique
88+
throw std::invalid_argument("MTA:SA Bug. Please file an issue with the parameters used for calling.");
89+
}
90+
};

Shared/sdk/SharedUtil.Template.h

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,69 @@ struct nth_element_impl<0, T, Ts...>
7878
};
7979

8080
template <std::size_t I, typename... Ts>
81-
using nth_element = typename nth_element_impl<I, Ts...>::type;
81+
using nth_element_t = typename nth_element_impl<I, Ts...>::type;
82+
83+
84+
// common_variant
85+
// common_variant builds a single variant from types or variants
86+
// bool, bool -> variant<bool>
87+
// int, bool -> variant<int, bool>
88+
// variant<int, bool>, bool -> variant<int, bool>
89+
// variant<int, bool>, float -> variant<int, bool, float>
90+
// variant<int, bool>, variant<bool, float> -> variant<int, bool, float>
91+
// variant<int, bool>, variant<bool, float, double> -> variant<int, bool, float, double>
92+
93+
// Two different types
94+
// int, bool -> variant<int, bool>
95+
template <typename T, typename U>
96+
struct common_variant
97+
{
98+
using type = std::variant<T, U>;
99+
};
100+
101+
// Identical types
102+
// int, int -> variant<int>
103+
template <typename T>
104+
struct common_variant<T, T>
105+
{
106+
using type = std::variant<T>;
107+
};
108+
109+
// Type + Variant which starts with the Type
110+
// int, variant<int> -> variant<int>
111+
template <typename T, typename... Ts>
112+
struct common_variant<T, std::variant<T, Ts...>>
113+
{
114+
using type = std::variant<T, Ts...>;
115+
};
116+
117+
// Variant + Empty = Variant
118+
template <typename... Ts>
119+
struct common_variant<std::variant<Ts...>, std::variant<>>
120+
{
121+
using type = std::variant<Ts...>;
122+
};
123+
// Empty + Variant = Variant
124+
template <typename... Ts>
125+
struct common_variant<std::variant<>, std::variant<Ts...>>
126+
{
127+
using type = std::variant<Ts...>;
128+
};
129+
130+
template <typename T, typename... Ts>
131+
struct common_variant<T, std::variant<Ts...>>
132+
{
133+
using type = std::conditional_t<std::is_convertible_v<T, std::variant<Ts...>>, std::variant<Ts...>, std::variant<T, Ts...>>;
134+
};
135+
136+
template <typename T, typename... Ts>
137+
struct common_variant<std::variant<Ts...>, T>
138+
{
139+
using type = typename common_variant<T, std::variant<Ts...>>::type;
140+
};
141+
142+
template <typename T, typename... Ts, typename... Us>
143+
struct common_variant<std::variant<T, Ts...>, std::variant<Us...>>
144+
{
145+
using type = typename common_variant<std::variant<Ts...>, typename common_variant<T, std::variant<Us...>>::type>::type;
146+
};

0 commit comments

Comments
 (0)