aboutsummaryrefslogtreecommitdiff
path: root/lldb/examples/synthetic/unordered_multi.py
blob: ad25e1d4509def663d632b0ca097236d0f46f8a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import lldb

_map_capping_size = 255


class libcxx_hash_table_SynthProvider:
    def __init__(self, valobj, dict):
        self.valobj = valobj
        self.num_elements = None
        self.next_element = None
        self.bucket_count = None

    def update(self):
        logger = lldb.formatters.Logger.Logger()
        self.num_elements = None
        self.next_element = None
        self.bucket_count = None
        try:
            # unordered_map is made up of a hash_map, which has 4 pieces in it:
            #   bucket list :
            #      array of buckets
            #   p1 (pair):
            #      first - pointer to first loaded element
            #   p2 (pair):
            #      first - number of elements
            #      second - hash function
            #   p3 (pair):
            #      first - max_load_factor
            #      second - equality operator function
            #
            # For display, we actually don't need to go inside the buckets, since 'p1' has a way to iterate over all
            # the elements directly.
            #
            # We will calculate other values about the map because they will be useful for the summary.
            #
            table = self.valobj.GetChildMemberWithName("__table_")

            bl_ptr = table.GetChildMemberWithName(
                "__bucket_list_"
            ).GetChildMemberWithName("__ptr_")
            self.bucket_array_ptr = bl_ptr.GetChildMemberWithName(
                "__first_"
            ).GetValueAsUnsigned(0)
            self.bucket_count = (
                bl_ptr.GetChildMemberWithName("__second_")
                .GetChildMemberWithName("__data_")
                .GetChildMemberWithName("__first_")
                .GetValueAsUnsigned(0)
            )
            logger >> "Bucket count = %r" % self.bucket_count

            self.begin_ptr = (
                table.GetChildMemberWithName("__p1_")
                .GetChildMemberWithName("__first_")
                .GetChildMemberWithName("__next_")
            )

            self.num_elements = (
                table.GetChildMemberWithName("__p2_")
                .GetChildMemberWithName("__first_")
                .GetValueAsUnsigned(0)
            )
            self.max_load_factor = (
                table.GetChildMemberWithName("__p3_")
                .GetChildMemberWithName("__first_")
                .GetValueAsUnsigned(0)
            )
            logger >> "Num elements = %r" % self.num_elements

            # save the pointers as we get them
            #   -- don't access this first element if num_element==0!
            self.elements_cache = []
            if self.num_elements:
                self.next_element = self.begin_ptr
            else:
                self.next_element = None
        except Exception as e:
            logger >> "Caught exception: %r" % e
            pass

    def num_children(self):
        global _map_capping_size
        num_elements = self.num_elements
        if num_elements is not None:
            if num_elements > _map_capping_size:
                num_elements = _map_capping_size
        return num_elements

    def has_children(self):
        return True

    def get_child_index(self, name):
        logger = lldb.formatters.Logger.Logger()
        try:
            return int(name.lstrip("[").rstrip("]"))
        except:
            return -1

    def get_child_at_index(self, index):
        logger = lldb.formatters.Logger.Logger()
        logger >> "Retrieving child " + str(index)
        if index < 0:
            return None
        if index >= self.num_children():
            return None

        # extend
        logger >> " : cache size starts with %d elements" % len(self.elements_cache)
        while index >= len(self.elements_cache):
            # if we hit the end before we get the index, give up:
            if not self.next_element:
                logger >> " : hit end of list"
                return None

            node = self.next_element.Dereference()

            value = node.GetChildMemberWithName("__value_")
            hash_value = node.GetChildMemberWithName("__hash_").GetValueAsUnsigned()
            self.elements_cache.append((value, hash_value))

            self.next_element = node.GetChildMemberWithName("__next_")
            if not self.next_element.GetValueAsUnsigned(0):
                self.next_element = None

        # hit the index! so we have the value
        logger >> " : cache size ends with %d elements" % len(self.elements_cache)
        value, hash_value = self.elements_cache[index]
        return self.valobj.CreateValueFromData(
            "[%d] <hash %d>" % (index, hash_value), value.GetData(), value.GetType()
        )


def __lldb_init_module(debugger, dict):
    debugger.HandleCommand(
        'type synthetic add -l unordered_multi.libcxx_hash_table_SynthProvider -x "^(std::__1::)unordered_(multi)?(map|set)<.+> >$" -w libcxx'
    )