name contained types properly in treebuilder v2

Types within containers were previously named TODO. This sorts it out so
they're named as their most resolved type. The current implementation
skips Typedef names.
This commit is contained in:
Jake Hillion 2023-08-24 05:42:12 -07:00 committed by Jake Hillion
parent 1459433a50
commit d009f02ecb
21 changed files with 134 additions and 72 deletions

View File

@ -218,6 +218,24 @@ void genDecls(const TypeGraph& typeGraph, std::string& code) {
}
}
void genNames(const TypeGraph& typeGraph, std::string& code) {
code += R"(
template <typename T>
struct NameProvider {};
)";
for (const Type& t : typeGraph.finalTypes) {
if (dynamic_cast<const Typedef*>(&t))
continue;
code += "template <> struct NameProvider<";
code += t.name();
code += "> { static constexpr std::array<std::string_view, 1> names = {\"";
code += t.inputName();
code += "\"}; };\n";
}
}
/*
* Generates a declaration for a given fully-qualified type.
*
@ -1136,6 +1154,8 @@ void CodeGen::generate(
genDecls(typeGraph, code);
genDefs(typeGraph, code);
genStaticAsserts(typeGraph, code);
if (config_.features[Feature::TreeBuilderV2])
genNames(typeGraph, code);
if (config_.features[Feature::TypedDataSegment]) {
addStandardTypeHandlers(typeGraph, config_.features, code);

View File

@ -86,7 +86,7 @@ class {
} // namespace
// alignas(0) is ignored according to docs so can be default
template <unsigned int N, unsigned int align = 0>
template <unsigned int N, unsigned int align = 0, int32_t Id = 0>
struct alignas(align) DummySizedOperator {
char c[N];
};
@ -96,15 +96,14 @@ struct alignas(align) DummySizedOperator {
// even though an empty class and a class with a single character have size one,
// there is some empty class optimization that changes the static size of the
// container if an empty class is passed.
template <int32_t Id>
struct DummySizedOperator<0, 0, Id> {};
// DummySizedOperator<0,0> also collapses to this
template <>
struct DummySizedOperator<0> {};
template <template <typename, size_t, size_t> typename DerivedT,
template <template <typename, size_t, size_t, int32_t> typename DerivedT,
typename T,
size_t N,
size_t Align>
size_t Align,
int32_t Id>
struct DummyAllocatorBase {
using value_type = T;
T* allocate(std::size_t n) {
@ -115,18 +114,19 @@ struct DummyAllocatorBase {
template <typename U>
struct rebind {
using other = DerivedT<U, N, Align>;
using other = DerivedT<U, N, Align, Id>;
};
};
template <typename T, size_t N, size_t Align = 0>
template <typename T, size_t N, size_t Align = 0, int32_t Id = 0>
struct alignas(Align) DummyAllocator
: DummyAllocatorBase<DummyAllocator, T, N, Align> {
: DummyAllocatorBase<DummyAllocator, T, N, Align, Id> {
char c[N];
};
template <typename T>
struct DummyAllocator<T, 0> : DummyAllocatorBase<DummyAllocator, T, 0, 0> {};
template <typename T, int32_t Id>
struct DummyAllocator<T, 0, 0, Id>
: DummyAllocatorBase<DummyAllocator, T, 0, 0, Id> {};
template <typename Type, size_t ExpectedSize, size_t ActualSize = 0>
struct validate_size {

View File

@ -140,14 +140,14 @@ void Printer::visit(const Pointer& p) {
}
void Printer::visit(const Dummy& d) {
prefix();
prefix(&d);
out_ << "Dummy ";
out_ << "[" << d.inputName() << "] ";
out_ << "(size: " << d.size() << align_str(d.align()) << ")" << std::endl;
}
void Printer::visit(const DummyAllocator& d) {
prefix();
prefix(&d);
out_ << "DummyAllocator ";
out_ << "[" << d.inputName() << "] ";
out_ << "(size: " << d.size() << align_str(d.align()) << ")" << std::endl;

View File

@ -73,6 +73,10 @@ void TopoSorter::visit(Class& c) {
}
}
void TopoSorter::visit(Primitive& p) {
sortedTypes_.push_back(p);
}
namespace {
/*
* C++17 allows the std::vector, std::list and std::forward_list containers to

View File

@ -46,6 +46,7 @@ class TopoSorter : public RecursiveVisitor {
void visit(Enum& e) override;
void visit(Typedef& td) override;
void visit(Pointer& p) override;
void visit(Primitive& p) override;
private:
std::unordered_set<Type*> visited_;

View File

@ -72,11 +72,19 @@ void TypeIdentifier::visit(Container& c) {
bool replaced = false;
for (const auto& info : passThroughTypes_) {
if (std::regex_search(paramClass->fqName(), info.matcher)) {
// Create dummy containers
auto& dummy =
typeGraph_.makeType<Container>(info, param.type().size());
dummy.templateParams = paramClass->templateParams;
c.templateParams[i] = dummy;
// Create dummy containers. Use a map so previously deduplicated nodes
// remain deduplicated.
Container* dummy;
if (auto it = passThroughTypeDummys_.find(paramClass->id());
it != passThroughTypeDummys_.end()) {
dummy = &it->second.get();
} else {
dummy = &typeGraph_.makeType<Container>(info, param.type().size());
dummy->templateParams = paramClass->templateParams;
passThroughTypeDummys_.insert(it,
{paramClass->id(), std::ref(*dummy)});
}
c.templateParams[i] = *dummy;
replaced = true;
}
}

View File

@ -15,6 +15,8 @@
*/
#pragma once
#include <functional>
#include <unordered_map>
#include <vector>
#include "NodeTracker.h"
@ -54,6 +56,9 @@ class TypeIdentifier : public RecursiveVisitor {
NodeTracker& tracker_;
TypeGraph& typeGraph_;
const std::vector<ContainerInfo>& passThroughTypes_;
std::unordered_map<NodeId, std::reference_wrapper<Container>>
passThroughTypeDummys_;
};
} // namespace oi::detail::type_graph

View File

@ -629,15 +629,16 @@ class Pointer : public Type {
*/
class Dummy : public Type {
public:
explicit Dummy(size_t size, uint64_t align, std::string inputName)
explicit Dummy(NodeId id, size_t size, uint64_t align, std::string inputName)
: size_(size),
align_(align),
id_(id),
name_(std::string{"DummySizedOperator<"} + std::to_string(size) + ", " +
std::to_string(align) + ">"),
std::to_string(align) + ", " + std::to_string(id_) + ">"),
inputName_(std::move(inputName)) {
}
static inline constexpr bool has_node_id = false;
static inline constexpr bool has_node_id = true;
DECLARE_ACCEPT
@ -658,12 +659,13 @@ class Dummy : public Type {
}
virtual NodeId id() const override {
return -1;
return id_;
}
private:
size_t size_;
uint64_t align_;
NodeId id_ = -1;
std::string name_;
std::string inputName_;
@ -677,18 +679,17 @@ class Dummy : public Type {
*/
class DummyAllocator : public Type {
public:
explicit DummyAllocator(Type& type,
size_t size,
uint64_t align,
std::string inputName)
explicit DummyAllocator(
NodeId id, Type& type, size_t size, uint64_t align, std::string inputName)
: type_(type),
size_(size),
align_(align),
id_(id),
inputName_(std::move(inputName)) {
regenerateName();
}
static inline constexpr bool has_node_id = false;
static inline constexpr bool has_node_id = true;
DECLARE_ACCEPT
@ -698,7 +699,8 @@ class DummyAllocator : public Type {
void regenerateName() {
name_ = std::string{"DummyAllocator<"} + type_.name() + ", " +
std::to_string(size_) + ", " + std::to_string(align_) + ">";
std::to_string(size_) + ", " + std::to_string(align_) + ", " +
std::to_string(id_) + ">";
}
virtual std::string_view inputName() const override {
@ -714,7 +716,7 @@ class DummyAllocator : public Type {
}
virtual NodeId id() const override {
return -1;
return id_;
}
Type& allocType() const {
@ -725,6 +727,7 @@ class DummyAllocator : public Type {
Type& type_;
size_t size_;
uint64_t align_;
NodeId id_ = -1;
std::string name_;
std::string inputName_;

View File

@ -295,14 +295,14 @@ Type& TypeGraphParser::parseType(std::string_view& input, size_t rootIndent) {
// Format: "Dummy (size: 4)"
auto size = parseNumericAttribute(line, nodeTypeName, "size: ");
std::string inputName{*tryParseInputName(line)};
type = &typeGraph_.makeType<Dummy>(size, 0, inputName);
type = &typeGraph_.makeType<Dummy>(id, size, 0, inputName);
} else if (nodeTypeName == "DummyAllocator") {
// Format: "DummyAllocator (size: 8)"
auto size = parseNumericAttribute(line, nodeTypeName, "size: ");
std::string inputName{*tryParseInputName(line)};
auto& typeToAlloc = parseType(input, indent + 2);
type =
&typeGraph_.makeType<DummyAllocator>(typeToAlloc, size, 0, inputName);
type = &typeGraph_.makeType<DummyAllocator>(id, typeToAlloc, size, 0,
inputName);
} else {
throw TypeGraphParserError{"Unsupported node type: " +
std::string{nodeTypeName}};

View File

@ -59,11 +59,11 @@ TEST(CodeGenTest, TransformContainerAllocator) {
Function: deallocate
)",
R"(
[0] Container: std::vector<int32_t, DummyAllocator<int32_t, 8, 0>> (size: 24)
[0] Container: std::vector<int32_t, DummyAllocator<int32_t, 8, 0, 2>> (size: 24)
Param
Primitive: int32_t
Param
DummyAllocator [MyAlloc] (size: 8)
[2] DummyAllocator [MyAlloc] (size: 8)
Primitive: int32_t
)");
}
@ -92,13 +92,13 @@ TEST(CodeGenTest, TransformContainerAllocatorParamInParent) {
Function: deallocate
)",
R"(
[0] Container: std::map<int32_t, int32_t, DummyAllocator<std::pair<int32_t const, int32_t>, 0, 0>> (size: 24)
[0] Container: std::map<int32_t, int32_t, DummyAllocator<std::pair<int32_t const, int32_t>, 0, 0, 4>> (size: 24)
Param
Primitive: int32_t
Param
Primitive: int32_t
Param
DummyAllocator [MyAlloc<std::pair<const int, int>>] (size: 0)
[4] DummyAllocator [MyAlloc<std::pair<const int, int>>] (size: 0)
[3] Container: std::pair<int32_t const, int32_t> (size: 8)
Param
Primitive: int32_t

View File

@ -365,12 +365,12 @@ TEST(NameGenTest, Pointer) {
}
TEST(NameGenTest, Dummy) {
auto dummy = Dummy{12, 34, "InputName"};
auto dummy = Dummy{0, 12, 34, "InputName"};
NameGen nameGen;
nameGen.generateNames({dummy});
EXPECT_EQ(dummy.name(), "DummySizedOperator<12, 34>");
EXPECT_EQ(dummy.name(), "DummySizedOperator<12, 34, 0>");
EXPECT_EQ(dummy.inputName(), "InputName");
}
@ -382,7 +382,7 @@ TEST(NameGenTest, DummyAllocator) {
mycontainer.templateParams.push_back(myparam1);
mycontainer.templateParams.push_back(myparam2);
auto myalloc = DummyAllocator{mycontainer, 12, 34, "BigAllocator"};
auto myalloc = DummyAllocator{2, mycontainer, 12, 34, "BigAllocator"};
NameGen nameGen;
nameGen.generateNames({myalloc});
@ -391,7 +391,7 @@ TEST(NameGenTest, DummyAllocator) {
EXPECT_EQ(myparam2.name(), "MyParam_1");
EXPECT_EQ(mycontainer.name(), "std::vector<MyParam_0, MyParam_1>");
EXPECT_EQ(myalloc.name(),
"DummyAllocator<std::vector<MyParam_0, MyParam_1>, 12, 34>");
"DummyAllocator<std::vector<MyParam_0, MyParam_1>, 12, 34, 2>");
EXPECT_EQ(myparam1.inputName(), "MyParam");
EXPECT_EQ(myparam2.inputName(), "MyParam");

View File

@ -98,6 +98,7 @@ TEST(TopoSorterTest, TemplateParamValue) {
myclass.templateParams.push_back(TemplateParam{myint, "123"});
test({myclass}, R"(
int32_t
MyClass
)");
}

View File

@ -23,7 +23,7 @@ TEST(TypeIdentifierTest, StubbedParam) {
Param
Primitive: int32_t
Param
Dummy [MyParam] (size: 4)
[2] Dummy [MyParam] (size: 4)
Param
Primitive: int32_t
)");
@ -48,7 +48,7 @@ TEST(TypeIdentifierTest, Allocator) {
Param
Primitive: int32_t
Param
DummyAllocator [MyAlloc] (size: 8)
[2] DummyAllocator [MyAlloc] (size: 8)
Primitive: int32_t
Param
Primitive: int32_t
@ -74,7 +74,7 @@ TEST(TypeIdentifierTest, AllocatorSize1) {
Param
Primitive: int32_t
Param
DummyAllocator [MyAlloc] (size: 0)
[2] DummyAllocator [MyAlloc] (size: 0)
Primitive: int32_t
Param
Primitive: int32_t
@ -107,6 +107,36 @@ TEST(TypeIdentifierTest, PassThroughTypes) {
)");
}
TEST(TypeIdentifierTest, PassThroughSameType) {
std::vector<ContainerInfo> passThroughTypes;
passThroughTypes.emplace_back("std::allocator", DUMMY_TYPE, "memory");
test(TypeIdentifier::createPass(passThroughTypes), R"(
[0] Container: std::vector (size: 24)
Param
Primitive: int32_t
Param
[1] Class: std::allocator (size: 1)
Param
Primitive: int32_t
Function: allocate
Function: deallocate
Param
[1]
)",
R"(
[0] Container: std::vector (size: 24)
Param
Primitive: int32_t
Param
[2] Container: std::allocator (size: 1)
Param
Primitive: int32_t
Param
[2]
)");
}
TEST(TypeIdentifierTest, ContainerNotReplaced) {
test(TypeIdentifier::createPass({}), R"(
[0] Container: std::vector (size: 24)
@ -134,7 +164,7 @@ TEST(TypeIdentifierTest, DummyNotReplaced) {
Param
Primitive: int32_t
Param
Dummy [InputName] (size: 22)
[1] Dummy [InputName] (size: 22)
)");
}
@ -144,7 +174,7 @@ TEST(TypeIdentifierTest, DummyAllocatorNotReplaced) {
Param
Primitive: int32_t
Param
DummyAllocator [InputName] (size: 22)
[1] DummyAllocator [InputName] (size: 22)
Primitive: int32_t
)");
}

View File

@ -65,11 +65,10 @@ traversal_func = """
[[codegen.processor]]
type = "types::st::List<DB, typename TypeHandler<DB, T0>::type>"
func = """
static constexpr std::array<std::string_view, 1> names{"TODO"};
static constexpr inst::Field childField{
sizeof(T0),
"[]",
names,
NameProvider<T0>::names,
TypeHandler<DB, T0>::fields,
TypeHandler<DB, T0>::processors,
};

View File

@ -102,29 +102,28 @@ type = '''types::st::List<DB, types::st::Pair<DB,
func = '''
using element_type = std::pair<T0, T1>;
static constexpr std::array<std::string_view, 1> names{"TODO"};
static constexpr std::array<inst::Field, 2> entryFields{
inst::Field{
sizeof(T0),
"key",
names,
NameProvider<T0>::names,
TypeHandler<DB, T0>::fields,
TypeHandler<DB, T0>::processors,
},
inst::Field{
sizeof(T1),
"value",
names,
NameProvider<T1>::names,
TypeHandler<DB, T1>::fields,
TypeHandler<DB, T1>::processors,
},
};
static constexpr auto entryField = inst::Field {
sizeof(element_type),
sizeof(element_type) - sizeof(T0) - sizeof(T1),
"[]",
names,
std::array<std::string_view, 0>{},
entryFields,
std::array<inst::ProcessorInst, 0>{},
};

View File

@ -135,20 +135,18 @@ static constexpr size_t element_size = sizeof(OI__tree_node);
static_assert(false && "No known element_size for sets. See types/multi_map_type.toml");
#endif
static constexpr std::array<std::string_view, 1> names{"TODO"};
static constexpr std::array<inst::Field, 2> element_fields{
inst::Field {
sizeof(T0),
"key",
names,
NameProvider<T0>::names,
TypeHandler<DB, T0>::fields,
TypeHandler<DB, T0>::processors,
},
inst::Field {
sizeof(T1),
"value",
names,
NameProvider<T1>::names,
TypeHandler<DB, T1>::fields,
TypeHandler<DB, T1>::processors,
},
@ -157,7 +155,7 @@ static constexpr auto element = inst::Field {
element_size,
element_size - sizeof(T0) - sizeof(T1),
"[]",
names,
std::array<std::string_view, 0>{},
element_fields,
std::array<inst::ProcessorInst, 0>{},
};

View File

@ -128,11 +128,10 @@ static constexpr size_t element_size = sizeof(OI__tree_node);
static_assert(false && "No known element_size for multisets. See types/multi_set_type.toml");
#endif
static constexpr std::array<std::string_view, 1> names{"TODO"};
static constexpr auto childField = inst::Field{
sizeof(T0),
"[]",
names,
NameProvider<T0>::names,
TypeHandler<DB, T0>::fields,
TypeHandler<DB, T0>::processors,
};

View File

@ -58,18 +58,17 @@ traversal_func = """
[[codegen.processor]]
type = "types::st::Pair<DB, typename TypeHandler<DB, T0>::type, typename TypeHandler<DB, T1>::type>"
func = """
static constexpr std::array<std::string_view, 1> names{"TODO"};
static constexpr auto firstField = inst::Field{
sizeof(T0),
"first",
names,
NameProvider<T0>::names,
TypeHandler<DB, T0>::fields,
TypeHandler<DB, T0>::processors,
};
static constexpr auto secondField = inst::Field{
sizeof(T1),
"second",
names,
NameProvider<T1>::names,
TypeHandler<DB, T1>::fields,
TypeHandler<DB, T1>::processors,
};

View File

@ -95,11 +95,10 @@ el.container_stats.emplace(result::Element::ContainerStats{ .capacity = std::get
[[codegen.processor]]
type = "types::st::List<DB, typename TypeHandler<DB, T0>::type>"
func = """
static constexpr std::array<std::string_view, 1> names{"TODO"};
static constexpr auto childField = inst::Field{
sizeof(T0),
"[]",
names,
NameProvider<T0>::names,
TypeHandler<DB, T0>::fields,
TypeHandler<DB, T0>::processors,
};

View File

@ -132,11 +132,10 @@ static constexpr size_t element_size = sizeof(OI__tree_node);
static_assert(false && "No known element_size for sets. See types/set_type.toml");
#endif
static constexpr std::array<std::string_view, 1> names{"TODO"};
static constexpr auto childField = inst::Field{
sizeof(T0),
"[]",
names,
NameProvider<T0>::names,
TypeHandler<DB, T0>::fields,
TypeHandler<DB, T0>::processors,
};

View File

@ -143,20 +143,18 @@ static constexpr size_t element_size = sizeof(OI__tree_node);
static_assert(false && "No known element_size for sets. See types/std_map_type.toml");
#endif
static constexpr std::array<std::string_view, 1> names{"TODO"};
static constexpr std::array<inst::Field, 2> element_fields{
inst::Field {
sizeof(T0),
"key",
names,
NameProvider<T0>::names,
TypeHandler<DB, T0>::fields,
TypeHandler<DB, T0>::processors,
},
inst::Field {
sizeof(T1),
"value",
names,
NameProvider<T1>::names,
TypeHandler<DB, T1>::fields,
TypeHandler<DB, T1>::processors,
},
@ -165,7 +163,7 @@ static constexpr auto element = inst::Field {
element_size,
element_size - sizeof(T0) - sizeof(T1),
"[]",
names,
std::array<std::string_view, 0>{},
element_fields,
std::array<inst::ProcessorInst, 0>{},
};