This is an archive of the discontinued LLVM Phabricator instance.

[formatters] Add a libstdcpp formatter for for unordered_map, unordered_set, unordered_multimap, unordered_multiset
ClosedPublic

Authored by danilashtefan on Nov 12 2021, 5:17 AM.

Details

Summary

This diff adds a data formatter and tests for libstdcpp's unordered_map, unordered_set, unordered_multimap, unordered_multiset

Diff Detail

Event Timeline

danilashtefan requested review of this revision.Nov 12 2021, 5:17 AM
danilashtefan created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptNov 12 2021, 5:17 AM
danilashtefan retitled this revision from next to Draft diff for unordered_map libstdcpp formatter.Nov 12 2021, 5:18 AM
danilashtefan retitled this revision from Draft diff for unordered_map libstdcpp formatter to [formatters] Draft diff for unordered_map libstdcpp formatter.Nov 12 2021, 5:19 AM

Small cosmetic change

danilashtefan added a comment.EditedNov 12 2021, 6:08 AM

Hi Walter :) This is the Draft PR for the unordered_map/set data formatter. Currently it works well in case both key and values are of the same primitive data types (except string).

Unfortunately, the following problems are encountered:

  1. When key and value are of different types value is detected wrong (some garbage). I will leave the separate comment with the details
  1. Currently I print the unordered_map in the following form [key] = [value]. However, the right from would be: [index] = (first = key, second = value). I am struggling through finding the way to do so
  1. Whether key and/or value are of the string type, formatter cannot read the data. Is the string formatter issue.

Many thanks for your help in advance

danilashtefan added inline comments.Nov 12 2021, 6:12 AM
lldb/examples/synthetic/gnu_libstdcpp.py
77

I assume that the cause of the first issue (different key value type) is located here. self.next.GetType().GetByteSize() + self.data_size does not work in this case. Key is read, however value - not. It means that we cannot always add self.data_size.

I tried to manually figure out on the unordered_map<char, int> case what can I add instead of self.data_size (which is 1 in this case), but got no success

wallace requested changes to this revision.Nov 12 2021, 9:54 AM

When you do your tests, don't care too much about std::string yet, as it has its own issues, but instead create a non-standard size type like

struct Foo {
  int a;
  int b;
  int c;
};

...
 std::unordered_map<int, Foo> u;
lldb/examples/synthetic/gnu_libstdcpp.py
16–24

you can simplify this

18

you are already passing stl_deref_flags when you declare this formatter in C++, so you shouldn't get a Reference type here

21

GetTemplateArgumentType(0) will give you the key, and GetTemplateArgumentType(1) should give you the value type. The idea is that in this place you get both key_type and value_type, so that you don't need to figure them out later

44

remove if not used

55

this looks weird. you are already doing a while loop in get_child_at_index that is taking you to the node you want, but you do again another loop. You have to use current instead. My suggestion is to remove this function and make everything happen in get_child_at_index with one single loop

71

why do you do this? that means that you are traversing backwards. Just move an 'index' number of times. The unordered map is unordered by definition

77

do what i mentioned above regarding fetching the key and value types. I imagine that the internal allocator is using a pair<key, value>, which means that the memory layout will be:

key
value [with an offset of key size]
77

here you are returning a child of type self.data_type, which is the key type. And we don't want that. We want to do the same thing that the map formatter does for getting the pair<key, value> and returning it: https://github.com/llvm-mirror/lldb/blob/master/examples/synthetic/gnu_libstdcpp.py#L366
Notice how data type in that case is gotten here https://github.com/llvm-mirror/lldb/blob/master/examples/synthetic/gnu_libstdcpp.py#L367 and is actually the pair. And then they pair is returned here https://github.com/llvm-mirror/lldb/blob/master/examples/synthetic/gnu_libstdcpp.py#L425

that means that you don't need to individually find the key and the value, you only need to find the pair and return the pair

Btw, if raw print an unordered_map, I get this:

(std::unordered_map<int, double, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<const int, double> > >)

that means that the fifth template argument contains the pair. I've confirmed that also libcxx works the same way

This revision now requires changes to proceed.Nov 12 2021, 9:54 AM
danilashtefan marked 8 inline comments as done.Nov 13 2021, 7:09 AM

All the changes are done and tests pass

danilashtefan retitled this revision from [formatters] Draft diff for unordered_map libstdcpp formatter to [formatters] Add a libstdcpp formatter for for unordered_map, unordered_set, unordered_multimap, unordered_multiset.Nov 13 2021, 7:20 AM
danilashtefan edited the summary of this revision. (Show Details)

Hi Walter,

Thank you for the hints. Everything works now, including the string case. There was a small difficulty with set case, but then I figured out that for set case I need to take not the 5th, but 4th template argument. I will be waiting for your comments. After this I will unify the tests across platforms. Thank you!

Cosmetic change

Some naming corrections

wallace requested changes to this revision.Nov 17 2021, 8:13 AM

just some minor changes.
Could you unify these tests with libcxx?

lldb/examples/synthetic/gnu_libstdcpp.py
10

add a few empty lines before this to avoid confusing that comment with this specific formatter. Besides that, rename this to StdUnorderedMapLikeSynthProvider and add a comment similar to

"""
 This formatter can be applied to all
 unordered map-like structures (unordered_map, unordered_multimap, unordered_set, unordered_multiset)
"""
25

an exception is too much. Normally we just fail silently, as it obvious to the user when the formatter fails and investigation is needed. Just return "map" if "set" is not present in the type name.

29

this comment

  1. type of std::pair<key, value> is the first template
  2. argument type of the 4th template argument to std::map and
  3. 3rd template argument for std::set. That's why
  4. we need to know kind of the object

should be here

32

if we used something that is not a map or set, this data type will be a dummy object that won't fail but won't do anything useful

46

you see? we fail silently by default

83

remove this comment, as this information is easily available to the user

86

this one is fine

lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/main.cpp
5 ↗(On Diff #387084)

also remove this, you barely save a few characters by not typing std::string

7–13 ↗(On Diff #387084)

avoid using these defines, they just obscure the code when reading

This revision now requires changes to proceed.Nov 17 2021, 8:13 AM
danilashtefan marked 9 inline comments as done.

All the above-mentioned is changed. Thank you!

wallace requested changes to this revision.Nov 17 2021, 12:58 PM
wallace added inline comments.
lldb/examples/synthetic/gnu_libstdcpp.py
110–115
This revision now requires changes to proceed.Nov 17 2021, 12:58 PM
wallace accepted this revision.Nov 17 2021, 1:07 PM

good job!

This revision is now accepted and ready to land.Nov 17 2021, 1:07 PM