Implement Container V2 for folly::small_vector

This commit is contained in:
Thierry Treyer 2023-09-07 13:12:54 -07:00 committed by Thierry Treyer
parent 465303cb99
commit 331c47705c
2 changed files with 79 additions and 7 deletions

View File

@ -1,28 +1,27 @@
includes = ["folly/small_vector.h", "vector"]
[cases]
[cases.int_default_empty]
oil_skip = 'not implemented for treebuilder v2' # https://github.com/facebookexperimental/object-introspection/issues/321
param_types = ["const folly::small_vector<int>&"]
setup = "return {};"
expect_json = '[{"staticSize":16, "dynamicSize":0, "exclusiveSize":16, "length":0, "capacity":2, "elementStaticSize":4}]'
expect_json_v2 = '[{"staticSize":16, "exclusiveSize":16, "length":0, "capacity":2}]'
[cases.int_default_inlined]
oil_skip = 'not implemented for treebuilder v2' # https://github.com/facebookexperimental/object-introspection/issues/321
param_types = ["const folly::small_vector<int>&"]
setup = "return {{1,2}};"
expect_json = '[{"staticSize":16, "dynamicSize":0, "exclusiveSize":16, "length":2, "capacity":2, "elementStaticSize":4}]'
expect_json_v2 = '[{"staticSize":16, "exclusiveSize":8, "length":2, "capacity":2}]'
[cases.int_default_overflow]
oil_skip = 'not implemented for treebuilder v2' # https://github.com/facebookexperimental/object-introspection/issues/321
param_types = ["const folly::small_vector<int>&"]
setup = "return {{1,2,3,4}};"
expect_json = '[{"staticSize":16, "dynamicSize":24, "exclusiveSize":40, "length":4, "capacity":6, "elementStaticSize":4}]'
expect_json_v2 = '[{"staticSize":16, "exclusiveSize":24, "length":4, "capacity":6}]'
[cases.vector_3_empty]
oil_skip = 'not implemented for treebuilder v2' # https://github.com/facebookexperimental/object-introspection/issues/321
param_types = ["const folly::small_vector<std::vector<int>, 3>&"]
setup = "return {};"
expect_json = '[{"staticSize":80, "dynamicSize":0, "exclusiveSize":80, "length":0, "capacity":3, "elementStaticSize":24}]'
expect_json_v2 = '[{"staticSize":80, "exclusiveSize":80, "length":0, "capacity":3}]'
[cases.vector_3_inlined]
oil_skip = 'not implemented for treebuilder v2' # https://github.com/facebookexperimental/object-introspection/issues/321
param_types = ["const folly::small_vector<std::vector<int>, 3>&"]
setup = "return {{ {1,2,3}, {4}, {5,6} }};"
expect_json = '''[
@ -31,8 +30,13 @@ includes = ["folly/small_vector.h", "vector"]
{"staticSize":24, "dynamicSize":4, "exclusiveSize":28, "length":1, "capacity":1, "elementStaticSize":4},
{"staticSize":24, "dynamicSize":8, "exclusiveSize":32, "length":2, "capacity":2, "elementStaticSize":4}
]}]'''
expect_json_v2 = '''[
{"staticSize":80, "length":3, "exclusiveSize":8, "capacity":3, "members":[
{"staticSize":24, "exclusiveSize":24, "length":3, "capacity":3},
{"staticSize":24, "exclusiveSize":24, "length":1, "capacity":1},
{"staticSize":24, "exclusiveSize":24, "length":2, "capacity":2}
]}]'''
[cases.vector_3_overflow]
oil_skip = 'not implemented for treebuilder v2' # https://github.com/facebookexperimental/object-introspection/issues/321
param_types = ["const folly::small_vector<std::vector<int>, 3>&"]
setup = "return {{ {1,2,3}, {4}, {5,6}, {7} }};"
expect_json = '''[
@ -42,9 +46,16 @@ includes = ["folly/small_vector.h", "vector"]
{"staticSize":24, "dynamicSize":8, "exclusiveSize":32, "length":2, "capacity":2, "elementStaticSize":4},
{"staticSize":24, "dynamicSize":4, "exclusiveSize":28, "length":1, "capacity":1, "elementStaticSize":4}
]}]'''
expect_json_v2 = '''[
{"staticSize":80, "exclusiveSize":104, "length":4, "capacity":5, "members":[
{"staticSize":24, "exclusiveSize":24, "length":3, "capacity":3},
{"staticSize":24, "exclusiveSize":24, "length":1, "capacity":1},
{"staticSize":24, "exclusiveSize":24, "length":2, "capacity":2},
{"staticSize":24, "exclusiveSize":24, "length":1, "capacity":1}
]}]'''
[cases.int_always_heap]
oil_skip = 'not implemented for treebuilder v2' # https://github.com/facebookexperimental/object-introspection/issues/321
param_types = ["const folly::small_vector<int, 0>&"]
setup = "return {{1}};"
expect_json = '[{"staticSize":16, "dynamicSize":4, "exclusiveSize":20, "length":1, "capacity":1, "elementStaticSize":4}]'
expect_json_v2 = '[{"staticSize":16, "exclusiveSize":16, "length":1, "capacity":1}]'

View File

@ -41,6 +41,7 @@ void getSizeType(const %1%<V, N, P> &container, size_t& returnArg)
}
}
"""
handler = """
template <typename DB, typename T0, std::size_t N0, typename T1>
struct TypeHandler<DB, %1%<T0, N0, T1>> {
@ -67,3 +68,63 @@ struct TypeHandler<DB, %1%<T0, N0, T1>> {
}
};
"""
traversal_func = """
// If `container.data()` pointer is within the container struct,
// then the container's storage is inlined and doesn't uses the heap.
// TODO: Is there an API to get this information?
bool uses_intern_storage =
(uintptr_t)&container <= (uintptr_t)container.data() &&
(uintptr_t)container.data() < ((uintptr_t)&container + sizeof(container));
auto tail = returnArg
.write((uintptr_t)uses_intern_storage)
.write(container.capacity())
.write(container.size());
for (auto &&it: container) {
tail = tail.delegate([&it](typename TypeHandler<DB, T0>::type ret) {
return OIInternal::getSizeType<DB>(it, ret);
});
}
return tail.finish();
"""
[[codegen.processor]]
type = "types::st::VarInt<DB>"
func = """
// Using the container's pointer to temporarily store the uses_intern_storage boolean.
// TODO: Is there another way to pass a value across processors?
el.pointer = std::get<ParsedData::VarInt>(d.val).value;
"""
[[codegen.processor]]
type = "types::st::VarInt<DB>"
func = """
el.container_stats.emplace(result::Element::ContainerStats {
.capacity = std::get<ParsedData::VarInt>(d.val).value,
});
"""
[[codegen.processor]]
type = "types::st::List<DB, typename TypeHandler<DB, T0>::type>"
func = """
// Reading the `uses_intern_storage` boolean that was stored in `pointer` by the processor above.
bool uses_intern_storage = std::exchange(el.pointer.value(), (uintptr_t)0);
auto list = std::get<ParsedData::List>(d.val);
el.container_stats->length = list.length;
if (uses_intern_storage) {
// The storage is inlined, so don't double count for items using the intern storage.
el.exclusive_size -= list.length * sizeof(T0);
} else {
// The storage is heap allocated, so add any unused capacity.
el.exclusive_size += (el.container_stats->capacity - el.container_stats->length) * sizeof(T0);
}
static constexpr auto childField = make_field<DB, T0>("[]");
for (size_t i = 0; i < list.length; i++)
ins.emplace(childField);
"""