import re
class StdListSynthProvider:

    def __init__(self, valobj, dict):
        self.valobj = valobj
        self.update()

    def num_children(self):
        next_val = self.next.GetValueAsUnsigned(0)
        prev_val = self.prev.GetValueAsUnsigned(0)
        # After a std::list has been initialized, both next and prev will be non-NULL
        if next_val == 0 or prev_val == 0:
        	return 0
        if next_val == self.node_address:
        	return 0
        if next_val == prev_val:
        	return 1
        size = 2
        current = self.next
        while current.GetChildMemberWithName('_M_next').GetValueAsUnsigned(0) != self.node_address:
        	size = size + 1
        	current = current.GetChildMemberWithName('_M_next')
        return (size - 1)

    def get_child_index(self,name):
        return int(name.lstrip('[').rstrip(']'))

    def get_child_at_index(self,index):
        if index >= self.num_children():
            return None;
        offset = index
        current = self.next
        while offset > 0:
            current = current.GetChildMemberWithName('_M_next')
            offset = offset - 1
        return current.CreateChildAtOffset('['+str(index)+']',2*current.GetType().GetByteSize(),self.data_type)

    def extract_type_name(self,name):
        self.type_name = name[16:]
        index = 2
        count_of_template = 1
        while index < len(self.type_name):
            if self.type_name[index] == '<':
                count_of_template = count_of_template + 1
            elif self.type_name[index] == '>':
                count_of_template = count_of_template - 1
            elif self.type_name[index] == ',' and count_of_template == 1:
                self.type_name = self.type_name[:index]
                break
            index = index + 1
        self.type_name_nospaces = self.type_name.replace(", ", ",")

    def update(self):
        impl = self.valobj.GetChildMemberWithName('_M_impl')
        node = impl.GetChildMemberWithName('_M_node')
        self.extract_type_name(impl.GetType().GetName())
        self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0)
        self.next = node.GetChildMemberWithName('_M_next')
        self.prev = node.GetChildMemberWithName('_M_prev')
        self.data_type = node.GetTarget().FindFirstType(self.type_name)
        # tries to fight against a difference in formatting type names between gcc and clang
        if self.data_type.IsValid() == False:
            self.data_type = node.GetTarget().FindFirstType(self.type_name_nospaces)
        self.data_size = self.data_type.GetByteSize()
