Add simple type -> type name string compile time reflection stuff

This is needed for passing types to the LuaJIT ffi.
This commit is contained in:
Thomas Goyne 2014-07-17 19:54:05 -07:00
parent 77ecff1cba
commit cf252fa91a
5 changed files with 115 additions and 1 deletions
build
libaegisub/include/libaegisub
tests/tests

View file

@ -108,6 +108,7 @@
<ClInclude Include="$(SrcDir)include\libaegisub\spellchecker.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\split.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\thesaurus.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\type_name.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\util.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\util_osx.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\vfr.h" />

View file

@ -80,6 +80,9 @@
<ClInclude Include="$(SrcDir)include\libaegisub\thesaurus.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)include\libaegisub\type_name.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)include\libaegisub\util.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -373,4 +376,4 @@
<Filter>Header Files</Filter>
</None>
</ItemGroup>
</Project>
</Project>

View file

@ -71,6 +71,9 @@
<ClCompile Include="$(SrcDir)tests\thesaurus.cpp">
<Filter>Tests</Filter>
</ClCompile>
<ClCompile Include="$(SrcDir)tests\type_name.cpp">
<Filter>Tests</Filter>
</ClCompile>
<ClCompile Include="$(SrcDir)tests\util.cpp">
<Filter>Tests</Filter>
</ClCompile>

View file

@ -0,0 +1,73 @@
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// Aegisub Project http://www.aegisub.org/
#include <string>
namespace agi {
// Get the name of a type as a string in C syntax
// Currently supports primitives, pointers, references, const, and function pointers
template<typename T> struct type_name;
#define AGI_TYPE_NAME_PRIMITIVE(type) \
template<> struct type_name<type> { static const char *name() { return #type; }}
AGI_TYPE_NAME_PRIMITIVE(bool);
AGI_TYPE_NAME_PRIMITIVE(char);
AGI_TYPE_NAME_PRIMITIVE(double);
AGI_TYPE_NAME_PRIMITIVE(float);
AGI_TYPE_NAME_PRIMITIVE(int);
AGI_TYPE_NAME_PRIMITIVE(void);
#undef AGI_TYPE_NAME_PRIMITIVE
#define AGI_TYPE_NAME_MODIFIER(pre, type) \
template<typename T> \
struct type_name<T type> { \
static std::string name() { \
return std::string(type_name<T>::name()) + pre #type; \
} \
}
AGI_TYPE_NAME_MODIFIER("", *);
AGI_TYPE_NAME_MODIFIER("", &);
AGI_TYPE_NAME_MODIFIER(" ", const);
#undef AGI_TYPE_NAME_MODIFIER
template<typename First>
std::string function_args(bool is_first) {
return std::string(is_first ? "" : ", ") + type_name<First>::name() + ")";
}
template<typename First, typename Second, typename... Rest>
std::string function_args(bool is_first) {
return std::string(is_first ? "" : ", ") + type_name<First>::name() + function_args<Second, Rest...>(false);
}
template<typename Return, typename... Args>
struct type_name<Return (*)(Args...)> {
static std::string name() {
return std::string(type_name<Return>::name()) + " (*)(" + function_args<Args...>(true);
}
};
template<typename Return>
struct type_name<Return (*)()> {
static std::string name() {
return std::string(type_name<Return>::name()) + " (*)()";
}
};
}

34
tests/tests/type_name.cpp Normal file
View file

@ -0,0 +1,34 @@
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// Aegisub Project http://www.aegisub.org/
#include <main.h>
#include <util.h>
#include <libaegisub/type_name.h>
TEST(lagi_type_name, type_name) {
EXPECT_STREQ("bool", agi::type_name<bool>::name());
EXPECT_EQ("char const", agi::type_name<char const>::name());
EXPECT_EQ("void*", agi::type_name<void *>::name());
EXPECT_EQ("float const*", agi::type_name<float const*>::name());
EXPECT_EQ("int const&", agi::type_name<int const&>::name());
EXPECT_EQ("double&", agi::type_name<double &>::name());
EXPECT_EQ("void (*)()", agi::type_name<void (*)()>::name());
EXPECT_EQ("int (*)(bool)", agi::type_name<int (*)(bool)>::name());
EXPECT_EQ("char const* (*)(int, bool, int)", agi::type_name<char const*(*)(int, bool, int)>::name());
EXPECT_EQ("char* (*)(int, int, void (*)())", agi::type_name<char *(*)(int, int, void (*)())>::name());
}