mirror of
https://github.com/JakeHillion/object-introspection.git
synced 2024-11-09 21:24:14 +00:00
TypeGraph: Replace allocators with DummyAllocator
When we were previously removing allocators, we were only able to work with containers whose allocators appeared as their last template parameter. Now we can replace allocators in the middle of a parameter list. This fixes tests for folly::sorted_vector_set.
This commit is contained in:
parent
e1bc5c7b5e
commit
784b900218
@ -155,3 +155,30 @@ struct alignas(align) DummySizedOperator {
|
|||||||
// DummySizedOperator<0,0> also collapses to this
|
// DummySizedOperator<0,0> also collapses to this
|
||||||
template <>
|
template <>
|
||||||
struct DummySizedOperator<0> {};
|
struct DummySizedOperator<0> {};
|
||||||
|
|
||||||
|
template <template <typename, size_t, size_t> typename DerivedT,
|
||||||
|
typename T,
|
||||||
|
size_t N,
|
||||||
|
size_t Align>
|
||||||
|
struct DummyAllocatorBase {
|
||||||
|
using value_type = T;
|
||||||
|
T* allocate(std::size_t n) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void deallocate(T* p, std::size_t n) noexcept {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
struct rebind {
|
||||||
|
using other = DerivedT<U, N, Align>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, size_t N, size_t Align = 0>
|
||||||
|
struct alignas(Align) DummyAllocator
|
||||||
|
: DummyAllocatorBase<DummyAllocator, T, N, Align> {
|
||||||
|
char c[N];
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct DummyAllocator<T, 0> : DummyAllocatorBase<DummyAllocator, T, 0, 0> {};
|
||||||
|
@ -115,8 +115,9 @@ void Printer::visit(const Dummy& d) {
|
|||||||
|
|
||||||
void Printer::visit(const DummyAllocator& d) {
|
void Printer::visit(const DummyAllocator& d) {
|
||||||
prefix();
|
prefix();
|
||||||
out_ << "DummyAllocatorTODO (size: " << d.size() << align_str(d.align())
|
out_ << "DummyAllocator (size: " << d.size() << align_str(d.align()) << ")"
|
||||||
<< ")" << std::endl;
|
<< std::endl;
|
||||||
|
print(d.allocType());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Printer::prefix(const Type* type) {
|
bool Printer::prefix(const Type* type) {
|
||||||
|
@ -57,47 +57,48 @@ bool isAllocator(Type* t) {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void TypeIdentifier::visit(Container& c) {
|
void TypeIdentifier::visit(Container& c) {
|
||||||
// TODO will containers exist at this point?
|
|
||||||
// maybe don't need this function
|
|
||||||
|
|
||||||
// auto *c = make_type<Container>(containerInfo);
|
|
||||||
|
|
||||||
const auto& stubParams = c.containerInfo_.stubTemplateParams;
|
const auto& stubParams = c.containerInfo_.stubTemplateParams;
|
||||||
// TODO these two arrays could be looped over in sync for better performance
|
// TODO these two arrays could be looped over in sync for better performance
|
||||||
for (size_t i = 0; i < c.templateParams.size(); i++) {
|
for (size_t i = 0; i < c.templateParams.size(); i++) {
|
||||||
|
const auto& param = c.templateParams[i];
|
||||||
|
if (dynamic_cast<Dummy*>(param.type) ||
|
||||||
|
dynamic_cast<DummyAllocator*>(param.type)) {
|
||||||
|
// In case the TypeIdentifier pass is run multiple times, we don't want to
|
||||||
|
// replace dummies again as the context of the original replacement has
|
||||||
|
// been lost.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (std::find(stubParams.begin(), stubParams.end(), i) !=
|
if (std::find(stubParams.begin(), stubParams.end(), i) !=
|
||||||
stubParams.end()) {
|
stubParams.end()) {
|
||||||
const auto& param = c.templateParams[i];
|
size_t size = param.type->size();
|
||||||
if (isAllocator(param.type)) {
|
if (size == 1) {
|
||||||
// auto *allocator = dynamic_cast<Class*>(param.type); // TODO
|
// Hack: when we get a reported size of 1 for these parameters, it
|
||||||
// please don't do this... auto &typeToAllocate =
|
// turns out that a size of 0 is actually expected.
|
||||||
// *allocator->templateParams.at(0).type; auto *dummy =
|
size = 0;
|
||||||
// make_type<DummyAllocator>(typeToAllocate, param.type->size(),
|
}
|
||||||
// param.type->align()); c.templateParams[i] = dummy;
|
|
||||||
|
|
||||||
// TODO allocators are tricky... just remove them entirely for now
|
if (isAllocator(param.type)) {
|
||||||
// The problem is a std::map<int, int> requires an allocator of type
|
auto* allocator =
|
||||||
// std::allocator<std::pair<const int, int>>, but we do not record
|
dynamic_cast<Class*>(param.type); // TODO please don't do this...
|
||||||
// constness of types.
|
Type* typeToAllocate;
|
||||||
if (i != c.templateParams.size() - 1) {
|
if (!allocator->templateParams.empty()) {
|
||||||
throw std::runtime_error("Unsupported allocator parameter");
|
typeToAllocate = allocator->templateParams.at(0).type;
|
||||||
|
} else {
|
||||||
|
// We've encountered some bad DWARF. Let's guess that the type to
|
||||||
|
// allocate is the first parameter of the container.
|
||||||
|
typeToAllocate = c.templateParams[0].type;
|
||||||
}
|
}
|
||||||
c.templateParams.erase(c.templateParams.begin() + i,
|
auto* dummy = typeGraph_.make_type<DummyAllocator>(
|
||||||
c.templateParams.end());
|
*typeToAllocate, size, param.type->align());
|
||||||
|
c.templateParams[i] = dummy;
|
||||||
} else {
|
} else {
|
||||||
size_t size = param.type->size();
|
|
||||||
if (size == 1) { // TODO this is a hack
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
auto* dummy = typeGraph_.make_type<Dummy>(size, param.type->align());
|
auto* dummy = typeGraph_.make_type<Dummy>(size, param.type->align());
|
||||||
c.templateParams[i] = dummy;
|
c.templateParams[i] = dummy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO replace current node with "c" (if we want to transform classes into
|
|
||||||
// containers here)
|
|
||||||
|
|
||||||
for (const auto& param : c.templateParams) {
|
for (const auto& param : c.templateParams) {
|
||||||
visit(*param.type);
|
visit(*param.type);
|
||||||
}
|
}
|
||||||
|
@ -410,10 +410,8 @@ class DummyAllocator : public Type {
|
|||||||
DECLARE_ACCEPT
|
DECLARE_ACCEPT
|
||||||
|
|
||||||
virtual std::string name() const override {
|
virtual std::string name() const override {
|
||||||
return "std::allocator<" + type_.name() + ">";
|
return "DummyAllocator<" + type_.name() + ", " + std::to_string(size_) +
|
||||||
// TODO custom sized allocators:
|
", " + std::to_string(align_) + ">";
|
||||||
// return "DummyAllocator<" + type_.name() + ", " + std::to_string(size_)
|
|
||||||
// + "," + std::to_string(align_) + ">";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t size() const override {
|
virtual size_t size() const override {
|
||||||
|
@ -242,6 +242,15 @@ TEST(NameGenTest, Pointer) {
|
|||||||
EXPECT_EQ(mypointer->name(), "std::vector<MyParam_0, MyParam_1>*");
|
EXPECT_EQ(mypointer->name(), "std::vector<MyParam_0, MyParam_1>*");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(NameGenTest, Dummy) {
|
||||||
|
auto dummy = std::make_unique<Dummy>(12, 34);
|
||||||
|
|
||||||
|
NameGen nameGen;
|
||||||
|
nameGen.generateNames({*dummy});
|
||||||
|
|
||||||
|
EXPECT_EQ(dummy->name(), "DummySizedOperator<12, 34>");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(NameGenTest, DummyAllocator) {
|
TEST(NameGenTest, DummyAllocator) {
|
||||||
auto myparam1 = std::make_unique<Class>(Class::Kind::Struct, "MyParam", 13);
|
auto myparam1 = std::make_unique<Class>(Class::Kind::Struct, "MyParam", 13);
|
||||||
auto myparam2 = std::make_unique<Class>(Class::Kind::Struct, "MyParam", 13);
|
auto myparam2 = std::make_unique<Class>(Class::Kind::Struct, "MyParam", 13);
|
||||||
@ -250,7 +259,7 @@ TEST(NameGenTest, DummyAllocator) {
|
|||||||
mycontainer.templateParams.push_back(myparam1.get());
|
mycontainer.templateParams.push_back(myparam1.get());
|
||||||
mycontainer.templateParams.push_back(myparam2.get());
|
mycontainer.templateParams.push_back(myparam2.get());
|
||||||
|
|
||||||
auto myalloc = std::make_unique<DummyAllocator>(mycontainer, 0, 0);
|
auto myalloc = std::make_unique<DummyAllocator>(mycontainer, 12, 34);
|
||||||
|
|
||||||
NameGen nameGen;
|
NameGen nameGen;
|
||||||
nameGen.generateNames({*myalloc});
|
nameGen.generateNames({*myalloc});
|
||||||
@ -259,7 +268,7 @@ TEST(NameGenTest, DummyAllocator) {
|
|||||||
EXPECT_EQ(myparam2->name(), "MyParam_1");
|
EXPECT_EQ(myparam2->name(), "MyParam_1");
|
||||||
EXPECT_EQ(mycontainer.name(), "std::vector<MyParam_0, MyParam_1>");
|
EXPECT_EQ(mycontainer.name(), "std::vector<MyParam_0, MyParam_1>");
|
||||||
EXPECT_EQ(myalloc->name(),
|
EXPECT_EQ(myalloc->name(),
|
||||||
"std::allocator<std::vector<MyParam_0, MyParam_1>>");
|
"DummyAllocator<std::vector<MyParam_0, MyParam_1>, 12, 34>");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(NameGenTest, Cycle) {
|
TEST(NameGenTest, Cycle) {
|
||||||
|
@ -1,7 +1,109 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "oi/type_graph/Printer.h"
|
||||||
#include "oi/type_graph/TypeIdentifier.h"
|
#include "oi/type_graph/TypeIdentifier.h"
|
||||||
|
#include "oi/type_graph/Types.h"
|
||||||
|
#include "test/type_graph_utils.h"
|
||||||
|
|
||||||
using namespace type_graph;
|
using namespace type_graph;
|
||||||
|
|
||||||
// TODO tests!!!
|
TEST(TypeIdentifierTest, StubbedParam) {
|
||||||
|
auto myint = Primitive{Primitive::Kind::Int32};
|
||||||
|
|
||||||
|
auto myparam = Class{Class::Kind::Struct, "MyParam", 4};
|
||||||
|
myparam.members.push_back(Member{&myint, "a", 0});
|
||||||
|
|
||||||
|
auto container = getVector();
|
||||||
|
container.templateParams.push_back(TemplateParam{&myint});
|
||||||
|
container.templateParams.push_back(TemplateParam{&myparam});
|
||||||
|
container.templateParams.push_back(TemplateParam{&myint});
|
||||||
|
|
||||||
|
test(TypeIdentifier::createPass(), {container}, R"(
|
||||||
|
[0] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
Param
|
||||||
|
[1] Struct: MyParam (size: 4)
|
||||||
|
Member: a (offset: 0)
|
||||||
|
Primitive: int32_t
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)",
|
||||||
|
R"(
|
||||||
|
[0] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
Param
|
||||||
|
Dummy (size: 4)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TypeIdentifierTest, Allocator) {
|
||||||
|
auto myint = Primitive{Primitive::Kind::Int32};
|
||||||
|
|
||||||
|
auto myalloc = Class{Class::Kind::Struct, "MyAlloc", 8};
|
||||||
|
myalloc.templateParams.push_back(TemplateParam{&myint});
|
||||||
|
myalloc.functions.push_back(Function{"allocate"});
|
||||||
|
myalloc.functions.push_back(Function{"deallocate"});
|
||||||
|
|
||||||
|
auto container = getVector();
|
||||||
|
container.templateParams.push_back(TemplateParam{&myint});
|
||||||
|
container.templateParams.push_back(TemplateParam{&myalloc});
|
||||||
|
container.templateParams.push_back(TemplateParam{&myint});
|
||||||
|
|
||||||
|
test(TypeIdentifier::createPass(), {container}, R"(
|
||||||
|
[0] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
Param
|
||||||
|
[1] Struct: MyAlloc (size: 8)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
Function: allocate
|
||||||
|
Function: deallocate
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)",
|
||||||
|
R"(
|
||||||
|
[0] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
Param
|
||||||
|
DummyAllocator (size: 8)
|
||||||
|
Primitive: int32_t
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TypeIdentifierTest, AllocatorNoParam) {
|
||||||
|
auto myint = Primitive{Primitive::Kind::Int32};
|
||||||
|
|
||||||
|
auto myalloc = Class{Class::Kind::Struct, "MyAlloc", 8};
|
||||||
|
myalloc.functions.push_back(Function{"allocate"});
|
||||||
|
myalloc.functions.push_back(Function{"deallocate"});
|
||||||
|
|
||||||
|
auto container = getVector();
|
||||||
|
container.templateParams.push_back(TemplateParam{&myint});
|
||||||
|
container.templateParams.push_back(TemplateParam{&myalloc});
|
||||||
|
|
||||||
|
test(TypeIdentifier::createPass(), {container}, R"(
|
||||||
|
[0] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
Param
|
||||||
|
[1] Struct: MyAlloc (size: 8)
|
||||||
|
Function: allocate
|
||||||
|
Function: deallocate
|
||||||
|
)",
|
||||||
|
R"(
|
||||||
|
[0] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
Param
|
||||||
|
DummyAllocator (size: 8)
|
||||||
|
Primitive: int32_t
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
@ -12,13 +12,13 @@ replaceTemplateParamIndex = []
|
|||||||
|
|
||||||
[codegen]
|
[codegen]
|
||||||
decl = """
|
decl = """
|
||||||
template<typename T>
|
template<typename T, typename Traits, typename Allocator>
|
||||||
void getSizeType(const %1%<T> &container, size_t& returnArg);
|
void getSizeType(const %1%<T, Traits, Allocator> &container, size_t& returnArg);
|
||||||
"""
|
"""
|
||||||
|
|
||||||
func = """
|
func = """
|
||||||
template<typename T>
|
template<typename T, typename Traits, typename Allocator>
|
||||||
void getSizeType(const %1%<T> &container, size_t& returnArg)
|
void getSizeType(const %1%<T, Traits, Allocator> &container, size_t& returnArg)
|
||||||
{
|
{
|
||||||
SAVE_SIZE(sizeof(%1%<T>));
|
SAVE_SIZE(sizeof(%1%<T>));
|
||||||
|
|
||||||
|
@ -12,13 +12,13 @@ allocatorIndex = 1
|
|||||||
|
|
||||||
[codegen]
|
[codegen]
|
||||||
decl = """
|
decl = """
|
||||||
template<typename T>
|
template<typename T, typename Allocator>
|
||||||
void getSizeType(const %1%<T> &container, size_t& returnArg);
|
void getSizeType(const %1%<T, Allocator> &container, size_t& returnArg);
|
||||||
"""
|
"""
|
||||||
|
|
||||||
func = """
|
func = """
|
||||||
template<typename T>
|
template<typename T, typename Allocator>
|
||||||
void getSizeType(const %1%<T> &container, size_t& returnArg)
|
void getSizeType(const %1%<T, Allocator> &container, size_t& returnArg)
|
||||||
{
|
{
|
||||||
SAVE_SIZE(sizeof(%1%<T>));
|
SAVE_SIZE(sizeof(%1%<T>));
|
||||||
|
|
||||||
|
@ -12,13 +12,13 @@ replaceTemplateParamIndex = []
|
|||||||
|
|
||||||
[codegen]
|
[codegen]
|
||||||
decl = """
|
decl = """
|
||||||
template<typename T>
|
template<typename T, typename Traits, typename Allocator>
|
||||||
void getSizeType(const %1%<T> &container, size_t& returnArg);
|
void getSizeType(const %1%<T, Traits, Allocator> &container, size_t& returnArg);
|
||||||
"""
|
"""
|
||||||
|
|
||||||
func = """
|
func = """
|
||||||
template<typename T>
|
template<typename T, typename Traits, typename Allocator>
|
||||||
void getSizeType(const %1%<T> &container, size_t& returnArg)
|
void getSizeType(const %1%<T, Traits, Allocator> &container, size_t& returnArg)
|
||||||
{
|
{
|
||||||
SAVE_SIZE(sizeof(%1%<T>));
|
SAVE_SIZE(sizeof(%1%<T>));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user