diff --git a/oi/CodeGen.cpp b/oi/CodeGen.cpp index 19f8de5..161d8f6 100644 --- a/oi/CodeGen.cpp +++ b/oi/CodeGen.cpp @@ -188,6 +188,22 @@ void genDecls(const TypeGraph& typeGraph, std::string& code) { } } +namespace { + +size_t calculateExclusiveSize(const Type& t) { + if (const auto* c = dynamic_cast(&t)) { + return std::accumulate(c->members.cbegin(), c->members.cend(), 0, + [](size_t a, const auto& m) { + if (m.name.starts_with(AddPadding::MemberPrefix)) + return a + m.type().size(); + return a; + }); + } + return t.size(); +} + +} // namespace + void genNames(const TypeGraph& typeGraph, std::string& code) { code += R"( template @@ -206,6 +222,26 @@ struct NameProvider {}; } } +void genExclusiveSizes(const TypeGraph& typeGraph, std::string& code) { + code += R"( +template +struct ExclusiveSizeProvider { + static constexpr size_t size = sizeof(T); +}; +)"; + + for (const Type& t : typeGraph.finalTypes) { + size_t exclusiveSize = calculateExclusiveSize(t); + if (exclusiveSize != t.size()) { + code += "template <> struct ExclusiveSizeProvider<"; + code += t.name(); + code += "> { static constexpr size_t size = "; + code += std::to_string(exclusiveSize); + code += "; };\n"; + } + } +} + /* * Generates a declaration for a given fully-qualified type. * @@ -714,22 +750,6 @@ void CodeGen::genClassStaticType(const Class& c, std::string& code) { } } -namespace { - -size_t calculateExclusiveSize(const Type& t) { - if (const auto* c = dynamic_cast(&t)) { - return std::accumulate(c->members.cbegin(), c->members.cend(), 0, - [](size_t a, const auto& m) { - if (m.name.starts_with(AddPadding::MemberPrefix)) - return a + m.type().size(); - return a; - }); - } - return t.size(); -} - -} // namespace - void CodeGen::genClassTreeBuilderInstructions(const Class& c, std::string& code) { code += " private:\n"; @@ -1047,7 +1067,7 @@ template constexpr inst::Field make_field(std::string_view name) { return inst::Field{ sizeof(T), - sizeof(T), // TODO: this is incorrect for excl size + ExclusiveSizeProvider::size, name, NameProvider::names, TypeHandler::fields, @@ -1245,8 +1265,10 @@ void CodeGen::generate( genDecls(typeGraph, code); genDefs(typeGraph, code); genStaticAsserts(typeGraph, code); - if (config_.features[Feature::TreeBuilderV2]) + if (config_.features[Feature::TreeBuilderV2]) { genNames(typeGraph, code); + genExclusiveSizes(typeGraph, code); + } if (config_.features[Feature::TypedDataSegment]) { addStandardTypeHandlers(typeGraph, config_.features, code); diff --git a/test/integration/std_vector.toml b/test/integration/std_vector.toml index 473e8a4..d466891 100644 --- a/test/integration/std_vector.toml +++ b/test/integration/std_vector.toml @@ -1,4 +1,13 @@ includes = ["vector"] + +definitions = ''' + struct SimpleStruct { + int a; + char b; + long long c; + }; +''' + [cases] [cases.int_empty] param_types = ["const std::vector&"] @@ -14,6 +23,15 @@ includes = ["vector"] {"staticSize":4, "exclusiveSize":4}, {"staticSize":4, "exclusiveSize":4} ]}]''' + [cases.struct_some] + param_types = ["const std::vector&"] + setup = "return {{{}, {}, {}}};" + expect_json = '[{"staticSize":24, "dynamicSize":48, "length":3, "capacity":3, "elementStaticSize":16}]' + expect_json_v2 = '''[{"staticSize":24, "exclusiveSize":24, "length":3, "capacity":3, "members":[ + {"staticSize":16, "exclusiveSize":3}, + {"staticSize":16, "exclusiveSize":3}, + {"staticSize":16, "exclusiveSize":3} + ]}]''' [cases.bool_empty] skip = true # https://github.com/facebookexperimental/object-introspection/issues/14 param_types = ["const std::vector&"] diff --git a/test/integration/std_vector_del_allocator.toml b/test/integration/std_vector_del_allocator.toml index 335f010..8fb5e92 100644 --- a/test/integration/std_vector_del_allocator.toml +++ b/test/integration/std_vector_del_allocator.toml @@ -27,7 +27,6 @@ includes = ["vector"] [cases] [cases.a] - oil_skip = "oil gets the exclusive size of vector subfields wrong" # https://github.com/facebookexperimental/object-introspection/issues/301 param_types = ["const Foo&"] setup = ''' Foo foo;