From 4c047b5f915d453b8036a46db35ed7e3489e5d8f Mon Sep 17 00:00:00 2001 From: Jake Hillion Date: Mon, 15 Jan 2024 16:23:10 +0000 Subject: [PATCH] tbv2: add is_primitive to output C++ has a concept of Primitive which holds in the type graph. However we don't currently expose this information to the end user. Expose this from the OIL iterator to allow future features like primitive rollups. This affects containers like maps which have a fake `[]` element with no type. They use this to group together the key/value in a map and to account for any per element storage overhead. Currently the decision is to make the fake `[]` element a primitive if all of its children are primitives. This allows for more effective primitive rollups if that is implemented. This implementation detail may be changed in future. Test Plan: - CI - Updated simple tests. --- include/oi/exporters/Json.h | 5 +++-- include/oi/exporters/inst.h | 16 ++++++++----- include/oi/result/Element.h | 1 + oi/CodeGen.cpp | 6 ++++- oi/FuncGen.cpp | 11 +++------ oi/IntrospectionResult.cpp | 1 + test/integration/simple.toml | 31 ++++++++++++++++++++++---- types/f14_fast_map.toml | 1 + types/f14_node_map.toml | 1 + types/f14_value_map.toml | 1 + types/f14_vector_map.toml | 1 + types/map_seq_type.toml | 1 + types/multi_map_type.toml | 1 + types/std_map_type.toml | 1 + types/std_unordered_map_type.toml | 1 + types/std_unordered_multimap_type.toml | 1 + 16 files changed, 60 insertions(+), 20 deletions(-) diff --git a/include/oi/exporters/Json.h b/include/oi/exporters/Json.h index dd88ade..3dd37f4 100644 --- a/include/oi/exporters/Json.h +++ b/include/oi/exporters/Json.h @@ -98,8 +98,8 @@ inline void Json::printStringField(std::string_view name, inline void Json::printBoolField(std::string_view name, bool value, std::string_view indent) { - out_ << tab() << '"' << name << "\":" << space() << value << ',' << endl() - << indent; + out_ << tab() << '"' << name << "\":" << space() << (value ? "true" : "false") + << ',' << endl() << indent; } inline void Json::printUnsignedField(std::string_view name, uint64_t value, @@ -159,6 +159,7 @@ inline void Json::printFields(const result::Element& el, } if (el.is_set_stats.has_value()) printUnsignedField("is_set", el.is_set_stats->is_set, indent); + printBoolField("is_primitive", el.is_primitive, indent); } template diff --git a/include/oi/exporters/inst.h b/include/oi/exporters/inst.h index 8397cd6..5484376 100644 --- a/include/oi/exporters/inst.h +++ b/include/oi/exporters/inst.h @@ -58,19 +58,22 @@ struct Field { std::string_view name_, const std::array& type_names_, const std::array& fields_, - const std::array& processors_); + const std::array& processors_, + bool is_primitive_); template constexpr Field(size_t static_size_, std::string_view name_, const std::array& type_names_, const std::array& fields_, - const std::array& processors_) + const std::array& processors_, + bool is_primitive_) : Field(static_size_, static_size_, name_, type_names_, fields_, - processors_) { + processors_, + is_primitive_) { } constexpr Field(const Field&) = default; // no idea why this is needed @@ -80,6 +83,7 @@ struct Field { std::span type_names; std::span fields; std::span processors; + bool is_primitive; }; template @@ -88,13 +92,15 @@ constexpr Field::Field(size_t static_size_, std::string_view name_, const std::array& type_names_, const std::array& fields_, - const std::array& processors_) + const std::array& processors_, + bool is_primitive_) : static_size(static_size_), exclusive_size(exclusive_size_), name(name_), type_names(type_names_), fields(fields_), - processors(processors_) { + processors(processors_), + is_primitive(is_primitive_) { } } // namespace oi::exporters::inst diff --git a/include/oi/result/Element.h b/include/oi/result/Element.h index 1eea86b..c971236 100644 --- a/include/oi/result/Element.h +++ b/include/oi/result/Element.h @@ -52,6 +52,7 @@ struct Element { std::nullopt}; std::optional container_stats; std::optional is_set_stats; + bool is_primitive; }; } // namespace oi::result diff --git a/oi/CodeGen.cpp b/oi/CodeGen.cpp index 84fb9b4..cb5bf54 100644 --- a/oi/CodeGen.cpp +++ b/oi/CodeGen.cpp @@ -798,12 +798,15 @@ void CodeGen::genClassTreeBuilderInstructions(const Class& c, if (m.name.starts_with(AddPadding::MemberPrefix)) continue; std::string fullName = c.name() + "::" + m.name; + bool isPrimitive = dynamic_cast(&m.type()); code += " inst::Field{sizeof(" + fullName + "), " + std::to_string(calculateExclusiveSize(m.type())) + ",\"" + m.inputName + "\", member_" + std::to_string(index) + "_type_names, TypeHandler::fields, TypeHandler::processors},\n"; + ")>::processors, "; + code += isPrimitive ? "true" : "false"; + code += "},\n"; } code += " };\n"; code += @@ -1074,6 +1077,7 @@ constexpr inst::Field make_field(std::string_view name) { NameProvider::names, TypeHandler::fields, TypeHandler::processors, + std::is_fundamental_v }; } )"; diff --git a/oi/FuncGen.cpp b/oi/FuncGen.cpp index 97d2707..5ac3abf 100644 --- a/oi/FuncGen.cpp +++ b/oi/FuncGen.cpp @@ -399,7 +399,8 @@ const std::array::fields, " "OIInternal::TypeHandler::processors};\n"; + "OIInternal::__ROOT_TYPE__>::processors, " + "std::is_fundamental_v};\n"; code += "} // namespace\n"; code += "extern const exporters::inst::Inst __attribute__((used, retain)) " @@ -640,13 +641,7 @@ void FuncGen::DefineBasicTypeHandlers(std::string& code, FeatureSet features) { } static void process_pointer_content(result::Element& el, std::function stack_ins, ParsedData d) { static constexpr std::array names{"TODO"}; - static constexpr auto childField = inst::Field{ - sizeof(T), - "*", - names, - TypeHandler::fields, - TypeHandler::processors, - }; + static constexpr auto childField = make_field("*"); const ParsedData::Sum& sum = std::get(d.val); diff --git a/oi/IntrospectionResult.cpp b/oi/IntrospectionResult.cpp index bc59f5e..5310001 100644 --- a/oi/IntrospectionResult.cpp +++ b/oi/IntrospectionResult.cpp @@ -78,6 +78,7 @@ IntrospectionResult::const_iterator::operator++() { .exclusive_size = ty.exclusive_size, .container_stats = std::nullopt, .is_set_stats = std::nullopt, + .is_primitive = ty.is_primitive, }; for (const auto& [dy, handler] : ty.processors) { diff --git a/test/integration/simple.toml b/test/integration/simple.toml index 0945f70..4557319 100644 --- a/test/integration/simple.toml +++ b/test/integration/simple.toml @@ -24,12 +24,21 @@ definitions = ''' "staticSize":16, "dynamicSize":0, "exclusiveSize": 3, - "size": 16, "members":[ {"name":"a", "staticSize":4, "dynamicSize":0, "exclusiveSize": 4, "size": 4}, {"name":"b", "staticSize":1, "dynamicSize":0, "exclusiveSize": 1, "size": 1}, {"name":"c", "staticSize":8, "dynamicSize":0, "exclusiveSize": 8, "size": 8} ]}]''' + expect_json_v2 = '''[{ + "staticSize":16, + "exclusiveSize": 3, + "size": 16, + "is_primitive": false, + "members":[ + {"name":"a", "staticSize":4, "exclusiveSize": 4, "size": 4, "is_primitive": true}, + {"name":"b", "staticSize":1, "exclusiveSize": 1, "size": 1, "is_primitive": true}, + {"name":"c", "staticSize":8, "exclusiveSize": 8, "size": 8, "is_primitive": true} + ]}]''' [cases.class] param_types = ["const SimpleClass&"] setup = "return {};" @@ -37,18 +46,32 @@ definitions = ''' "staticSize":16, "dynamicSize":0, "exclusiveSize": 3, - "size": 16, "members":[ {"name":"a", "staticSize":4, "dynamicSize":0, "exclusiveSize": 4, "size": 4}, {"name":"b", "staticSize":1, "dynamicSize":0, "exclusiveSize": 1, "size": 1}, {"name":"c", "staticSize":8, "dynamicSize":0, "exclusiveSize": 8, "size": 8} ]}]''' + expect_json_v2 = '''[{ + "staticSize":16, + "exclusiveSize": 3, + "size": 16, + "is_primitive": false, + "members":[ + {"name":"a", "staticSize":4, "exclusiveSize": 4, "size": 4, "is_primitive": true}, + {"name":"b", "staticSize":1, "exclusiveSize": 1, "size": 1, "is_primitive": true}, + {"name":"c", "staticSize":8, "exclusiveSize": 8, "size": 8, "is_primitive": true} + ]}]''' [cases.union] param_types = ["const SimpleUnion&"] setup = "return {};" expect_json = '''[{ "staticSize":8, "dynamicSize":0, - "exclusiveSize":8, - "size":8 + "exclusiveSize":8 + }]''' + expect_json_v2 = '''[{ + "staticSize":8, + "exclusiveSize":8, + "size":8, + "is_primitive":false }]''' diff --git a/types/f14_fast_map.toml b/types/f14_fast_map.toml index 06c6f72..69a5173 100644 --- a/types/f14_fast_map.toml +++ b/types/f14_fast_map.toml @@ -95,6 +95,7 @@ static constexpr inst::Field element{ std::array{}, element_fields, std::array{}, + element_fields[0].is_primitive && element_fields[1].is_primitive, }; for (size_t i = 0; i < list.length; i++) diff --git a/types/f14_node_map.toml b/types/f14_node_map.toml index de1dcda..cc89f06 100644 --- a/types/f14_node_map.toml +++ b/types/f14_node_map.toml @@ -95,6 +95,7 @@ static constexpr inst::Field element{ std::array{}, element_fields, std::array{}, + element_fields[0].is_primitive && element_fields[1].is_primitive, }; for (size_t i = 0; i < list.length; i++) diff --git a/types/f14_value_map.toml b/types/f14_value_map.toml index c09bbf0..aa6aa59 100644 --- a/types/f14_value_map.toml +++ b/types/f14_value_map.toml @@ -95,6 +95,7 @@ static constexpr inst::Field element{ std::array{}, element_fields, std::array{}, + element_fields[0].is_primitive && element_fields[1].is_primitive, }; for (size_t i = 0; i < list.length; i++) diff --git a/types/f14_vector_map.toml b/types/f14_vector_map.toml index a673bbd..f640dcc 100644 --- a/types/f14_vector_map.toml +++ b/types/f14_vector_map.toml @@ -95,6 +95,7 @@ static constexpr inst::Field element{ std::array{}, element_fields, std::array{}, + element_fields[0].is_primitive && element_fields[1].is_primitive, }; for (size_t i = 0; i < list.length; i++) diff --git a/types/map_seq_type.toml b/types/map_seq_type.toml index a09efff..f4281eb 100644 --- a/types/map_seq_type.toml +++ b/types/map_seq_type.toml @@ -91,6 +91,7 @@ static constexpr auto entry = inst::Field { std::array{}, entryFields, processors, + entryFields[0].is_primitive && entryFields[1].is_primitive, }; auto list = std::get(d.val); diff --git a/types/multi_map_type.toml b/types/multi_map_type.toml index a5d628f..e313417 100644 --- a/types/multi_map_type.toml +++ b/types/multi_map_type.toml @@ -118,6 +118,7 @@ static constexpr auto element = inst::Field { std::array{}, elementFields, std::array{}, + elementFields[0].is_primitive && elementFields[1].is_primitive, }; auto list = std::get(d.val); diff --git a/types/std_map_type.toml b/types/std_map_type.toml index ee652ec..b972b70 100644 --- a/types/std_map_type.toml +++ b/types/std_map_type.toml @@ -135,6 +135,7 @@ static constexpr inst::Field element{ std::array{}, element_fields, processors, + element_fields[0].is_primitive && element_fields[1].is_primitive, }; auto list = std::get(d.val); diff --git a/types/std_unordered_map_type.toml b/types/std_unordered_map_type.toml index 5b2402f..108731e 100644 --- a/types/std_unordered_map_type.toml +++ b/types/std_unordered_map_type.toml @@ -135,6 +135,7 @@ static constexpr auto element = inst::Field{ std::array{}, element_fields, processors, + element_fields[0].is_primitive && element_fields[1].is_primitive, }; for (size_t i = 0; i < list.length; i++) diff --git a/types/std_unordered_multimap_type.toml b/types/std_unordered_multimap_type.toml index a6f7671..8452154 100644 --- a/types/std_unordered_multimap_type.toml +++ b/types/std_unordered_multimap_type.toml @@ -121,6 +121,7 @@ static constexpr auto element = inst::Field{ std::array{}, element_fields, std::array{}, + element_fields[0].is_primitive && element_fields[1].is_primitive, }; for (size_t i = 0; i < list.length; i++)