reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    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
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')