import lldb
import lldb.formatters.Logger

# libcxx STL formatters for LLDB
# These formatters are based upon the implementation of libc++ that
# ships with current releases of OS X - They will not work for other implementations
# of the standard C++ library - and they are bound to use the libc++-specific namespace

# the std::string summary is just an example for your convenience
# the actual summary that LLDB uses is C++ code inside the debugger's own core

# this could probably be made more efficient but since it only reads a handful of bytes at a time
# we probably don't need to worry too much about this for the time being
def make_string(F,L):
	strval = ''
	G = F.GetData().uint8
	for X in range(L):
		V = G[X]
		if V == 0:
			break
		strval = strval + chr(V % 256)
	return '"' + strval + '"'

# if we ever care about big-endian, these two functions might need to change
def is_short_string(value):
	return True if (value & 1) == 0 else False
def extract_short_size(value):
	return ((value >> 1) % 256)

# some of the members of libc++ std::string are anonymous or have internal names that convey
# no external significance - we access them by index since this saves a name lookup that would add
# no information for readers of the code, but when possible try to use meaningful variable names
def stdstring_SummaryProvider(valobj,dict):
	logger = lldb.formatters.Logger.Logger()
	r = valobj.GetChildAtIndex(0)
	B = r.GetChildAtIndex(0)
	first = B.GetChildAtIndex(0)
	D = first.GetChildAtIndex(0)
	l = D.GetChildAtIndex(0)
	s = D.GetChildAtIndex(1)
	D20 = s.GetChildAtIndex(0)
	size_mode = D20.GetChildAtIndex(0).GetValueAsUnsigned(0)
	if is_short_string(size_mode):
		size = extract_short_size(size_mode)
		return make_string(s.GetChildAtIndex(1),size)
	else:
		data_ptr = l.GetChildAtIndex(2)
		size_vo = l.GetChildAtIndex(1)
		size = size_vo.GetValueAsUnsigned(0)+1 # the NULL terminator must be accounted for
		if size <= 1 or size == None: # should never be the case
			return '""'
		try:
			data = data_ptr.GetPointeeData(0,size)
		except:
			return '""'
		error = lldb.SBError()
		strval = data.GetString(error,0)
		if error.Fail():
			return '<error:' + error.GetCString() + '>'
		else:
			return '"' + strval + '"'

class stdvector_SynthProvider:

	def __init__(self, valobj, dict):
		logger = lldb.formatters.Logger.Logger()
		self.valobj = valobj;

	def num_children(self):
		logger = lldb.formatters.Logger.Logger()
		try:
			start_val = self.start.GetValueAsUnsigned(0)
			finish_val = self.finish.GetValueAsUnsigned(0)
			# Before a vector has been constructed, it will contain bad values
			# so we really need to be careful about the length we return since
			# uninitialized data can cause us to return a huge number. We need
			# to also check for any of the start, finish or end of storage values
			# being zero (NULL). If any are, then this vector has not been 
			# initialized yet and we should return zero

			# Make sure nothing is NULL
			if start_val == 0 or finish_val == 0:
				return 0
			# Make sure start is less than finish
			if start_val >= finish_val:
				return 0

			num_children = (finish_val-start_val)
			if (num_children % self.data_size) != 0:
				return 0
			else:
				num_children = num_children/self.data_size
			return num_children
		except:
			return 0;

	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;
		try:
			offset = index * self.data_size
			return self.start.CreateChildAtOffset('['+str(index)+']',offset,self.data_type)
		except:
			return None

	def update(self):
		logger = lldb.formatters.Logger.Logger()
		try:
			self.start = self.valobj.GetChildMemberWithName('__begin_')
			self.finish = self.valobj.GetChildMemberWithName('__end_')
			# the purpose of this field is unclear, but it is the only field whose type is clearly T* for a vector<T>
			# if this ends up not being correct, we can use the APIs to get at template arguments
			data_type_finder = self.valobj.GetChildMemberWithName('__end_cap_').GetChildMemberWithName('__first_')
			self.data_type = data_type_finder.GetType().GetPointeeType()
			self.data_size = self.data_type.GetByteSize()
		except:
			pass

	def has_children(self):
		return True

# Just an example: the actual summary is produced by a summary string: size=${svar%#}
def stdvector_SummaryProvider(valobj,dict):
	prov = stdvector_SynthProvider(valobj,None)
	return 'size=' + str(prov.num_children())

class stdlist_entry:

	def __init__(self,entry):
		logger = lldb.formatters.Logger.Logger()
		self.entry = entry

	def _next_impl(self):
		logger = lldb.formatters.Logger.Logger()
		return stdlist_entry(self.entry.GetChildMemberWithName('__next_'))

	def _prev_impl(self):
		logger = lldb.formatters.Logger.Logger()
		return stdlist_entry(self.entry.GetChildMemberWithName('__prev_'))

	def _value_impl(self):
		logger = lldb.formatters.Logger.Logger()
		return self.entry.GetValueAsUnsigned(0)

	def _isnull_impl(self):
		logger = lldb.formatters.Logger.Logger()
		return self._value_impl() == 0

	def _sbvalue_impl(self):
		logger = lldb.formatters.Logger.Logger()
		return self.entry

	next = property(_next_impl,None)
	value = property(_value_impl,None)
	is_null = property(_isnull_impl,None)
	sbvalue = property(_sbvalue_impl,None)

class stdlist_iterator:

	def increment_node(self,node):
		logger = lldb.formatters.Logger.Logger()
		if node.is_null:
			return None
		return node.next

	def __init__(self,node):
		logger = lldb.formatters.Logger.Logger()
		self.node = stdlist_entry(node) # we convert the SBValue to an internal node object on entry

	def value(self):
		logger = lldb.formatters.Logger.Logger()
		return self.node.sbvalue # and return the SBValue back on exit

	def next(self):
		logger = lldb.formatters.Logger.Logger()
		node = self.increment_node(self.node)
		if node != None and node.sbvalue.IsValid() and not(node.is_null):
			self.node = node
			return self.value()
		else:
			return None

	def advance(self,N):
		logger = lldb.formatters.Logger.Logger()
		if N < 0:
			return None
		if N == 0:
			return self.value()
		if N == 1:
			return self.next()
		while N > 0:
			self.next()
			N = N - 1
		return self.value()


class stdlist_SynthProvider:
	def __init__(self, valobj, dict):
		logger = lldb.formatters.Logger.Logger()
		self.valobj = valobj
		self.count = None

	def next_node(self,node):
		logger = lldb.formatters.Logger.Logger()
		return node.GetChildMemberWithName('__next_')

	def value(self,node):
		logger = lldb.formatters.Logger.Logger()
		return node.GetValueAsUnsigned()

	# Floyd's cycle-finding algorithm
	# try to detect if this list has a loop
	def has_loop(self):
		global _list_uses_loop_detector
		logger = lldb.formatters.Logger.Logger()
		if _list_uses_loop_detector == False:
			logger >> "Asked not to use loop detection"
			return False
		slow = stdlist_entry(self.head)
		fast1 = stdlist_entry(self.head)
		fast2 = stdlist_entry(self.head)
		while slow.next.value != self.node_address:
			slow_value = slow.value
			fast1 = fast2.next
			fast2 = fast1.next
			if fast1.value == slow_value or fast2.value == slow_value:
				return True
			slow = slow.next
		return False

	def num_children(self):
		global _list_capping_size
		logger = lldb.formatters.Logger.Logger()
		if self.count == None:
			self.count = self.num_children_impl()
			if self.count > _list_capping_size:
				self.count = _list_capping_size
		return self.count

	def num_children_impl(self):
		global _list_capping_size
		logger = lldb.formatters.Logger.Logger()
		try:
			next_val = self.head.GetValueAsUnsigned(0)
			prev_val = self.tail.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
			if self.has_loop():
				return 0
			size = 2
			current = stdlist_entry(self.head)
			while current.next.value != self.node_address:
				size = size + 1
				current = current.next
				if size > _list_capping_size:
					return _list_capping_size
			return (size - 1)
		except:
			return 0;

	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 >> "Fetching child " + str(index)
		if index < 0:
			return None;
		if index >= self.num_children():
			return None;
		try:
			current = stdlist_iterator(self.head)
			current = current.advance(index)
			# we do not return __value_ because then all our children would be named __value_
			# we need to make a copy of __value__ with the right name - unfortunate
			obj = current.GetChildMemberWithName('__value_')
			obj_data = obj.GetData()
			return self.valobj.CreateValueFromData('[' + str(index) + ']',obj_data,self.data_type)
		except:
			return None

	def extract_type(self):
		logger = lldb.formatters.Logger.Logger()
		list_type = self.valobj.GetType().GetUnqualifiedType()
		if list_type.IsReferenceType():
			list_type = list_type.GetDereferencedType()
		if list_type.GetNumberOfTemplateArguments() > 0:
			data_type = list_type.GetTemplateArgumentType(0)
		else:
			data_type = None
		return data_type

	def update(self):
		logger = lldb.formatters.Logger.Logger()
		self.count = None
		try:
			impl = self.valobj.GetChildMemberWithName('__end_')
			self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0)
			self.head = impl.GetChildMemberWithName('__next_')
			self.tail = impl.GetChildMemberWithName('__prev_')
			self.data_type = self.extract_type()
			self.data_size = self.data_type.GetByteSize()
		except:
			pass

	def has_children(self):
		return True


# Just an example: the actual summary is produced by a summary string: size=${svar%#}
def stdlist_SummaryProvider(valobj,dict):
	prov = stdlist_SynthProvider(valobj,None)
	return 'size=' + str(prov.num_children())

# a tree node - this class makes the syntax in the actual iterator nicer to read and maintain
class stdmap_iterator_node:
	def _left_impl(self):
		logger = lldb.formatters.Logger.Logger()
		return stdmap_iterator_node(self.node.GetChildMemberWithName("__left_"))

	def _right_impl(self):
		logger = lldb.formatters.Logger.Logger()
		return stdmap_iterator_node(self.node.GetChildMemberWithName("__right_"))

	def _parent_impl(self):
		logger = lldb.formatters.Logger.Logger()
		return stdmap_iterator_node(self.node.GetChildMemberWithName("__parent_"))

	def _value_impl(self):
		logger = lldb.formatters.Logger.Logger()
		return self.node.GetValueAsUnsigned(0)

	def _sbvalue_impl(self):
		logger = lldb.formatters.Logger.Logger()
		return self.node

	def _null_impl(self):
		logger = lldb.formatters.Logger.Logger()
		return self.value == 0

	def __init__(self,node):
		logger = lldb.formatters.Logger.Logger()
		self.node = node

	left = property(_left_impl,None)
	right = property(_right_impl,None)
	parent = property(_parent_impl,None)
	value = property(_value_impl,None)
	is_null = property(_null_impl,None)
	sbvalue = property(_sbvalue_impl,None)

# a Python implementation of the tree iterator used by libc++
class stdmap_iterator:

	def tree_min(self,x):
		logger = lldb.formatters.Logger.Logger()
		steps = 0
		if x.is_null:
			return None
		while (not x.left.is_null):
			x = x.left
			steps += 1
			if steps > self.max_count:
				logger >> "Returning None - we overflowed"
				return None
		return x

	def tree_max(self,x):
		logger = lldb.formatters.Logger.Logger()
		if x.is_null:
			return None
		while (not x.right.is_null):
			x =  x.right
		return x

	def tree_is_left_child(self,x):
		logger = lldb.formatters.Logger.Logger()
		if x.is_null:
			return None
		return True if x.value == x.parent.left.value else False

	def increment_node(self,node):
		logger = lldb.formatters.Logger.Logger()
		if node.is_null:
			return None
		if not node.right.is_null:
			return self.tree_min(node.right)
		steps = 0
		while (not self.tree_is_left_child(node)):
			steps += 1
			if steps > self.max_count:
				logger >> "Returning None - we overflowed"
				return None
			node = node.parent
		return node.parent

	def __init__(self,node,max_count=0):
		logger = lldb.formatters.Logger.Logger()
		self.node = stdmap_iterator_node(node) # we convert the SBValue to an internal node object on entry
		self.max_count = max_count

	def value(self):
		logger = lldb.formatters.Logger.Logger()
		return self.node.sbvalue # and return the SBValue back on exit

	def next(self):
		logger = lldb.formatters.Logger.Logger()
		node = self.increment_node(self.node)
		if node != None and node.sbvalue.IsValid() and not(node.is_null):
			self.node = node
			return self.value()
		else:
			return None

	def advance(self,N):
		logger = lldb.formatters.Logger.Logger()
		if N < 0:
			return None
		if N == 0:
			return self.value()
		if N == 1:
			return self.next()
		while N > 0:
			if self.next() == None:
				return None
			N = N - 1
		return self.value()

class stdmap_SynthProvider:

	def __init__(self, valobj, dict):
		logger = lldb.formatters.Logger.Logger()
		self.valobj = valobj;
		self.pointer_size = self.valobj.GetProcess().GetAddressByteSize()
		self.count = None

	def update(self):
		logger = lldb.formatters.Logger.Logger()
		self.count = None
		try:
			# we will set this to True if we find out that discovering a node in the map takes more steps than the overall size of the RB tree
			# if this gets set to True, then we will merrily return None for any child from that moment on
			self.garbage = False
			self.tree = self.valobj.GetChildMemberWithName('__tree_')
			self.root_node = self.tree.GetChildMemberWithName('__begin_node_')
			# this data is either lazily-calculated, or cannot be inferred at this moment
			# we still need to mark it as None, meaning "please set me ASAP"
			self.data_type = None
			self.data_size = None
			self.skip_size = None
		except:
			pass

	def num_children(self):
		global _map_capping_size
		logger = lldb.formatters.Logger.Logger()
		if self.count == None:
			self.count = self.num_children_impl()
			if self.count > _map_capping_size:
				self.count = _map_capping_size
		return self.count

	def num_children_impl(self):
		logger = lldb.formatters.Logger.Logger()
		try:
			return self.valobj.GetChildMemberWithName('__tree_').GetChildMemberWithName('__pair3_').GetChildMemberWithName('__first_').GetValueAsUnsigned()
		except:
			return 0;

	def has_children(self):
		return True

	def get_data_type(self):
		logger = lldb.formatters.Logger.Logger()
		if self.data_type == None or self.data_size == None:
			if self.num_children() == 0:
				return False
			deref = self.root_node.Dereference()
			if not(deref.IsValid()):
				return False
			value = deref.GetChildMemberWithName('__value_')
			if not(value.IsValid()):
				return False
			self.data_type = value.GetType()
			self.data_size = self.data_type.GetByteSize()
			self.skip_size = None
			return True
		else:
			return True

	def get_value_offset(self,node):
		logger = lldb.formatters.Logger.Logger()
		if self.skip_size == None:
			node_type = node.GetType()
			fields_count = node_type.GetNumberOfFields()
			for i in range(fields_count):
				field = node_type.GetFieldAtIndex(i)
				if field.GetName() == '__value_':
					self.skip_size = field.GetOffsetInBytes()
					break
		return (self.skip_size != None)

	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;
		if self.garbage:
			logger >> "Returning None since this tree is garbage"
			return None
		try:
			iterator = stdmap_iterator(self.root_node,max_count=self.num_children())
			# the debug info for libc++ std::map is such that __begin_node_ has a very nice and useful type
			# out of which we can grab the information we need - every other node has a less informative
			# type which omits all value information and only contains housekeeping information for the RB tree
			# hence, we need to know if we are at a node != 0, so that we can still get at the data
			need_to_skip = (index > 0)
			current = iterator.advance(index)
			if current == None:
				logger >> "Tree is garbage - returning None"
				self.garbage = True
				return None
			if self.get_data_type():
				if not(need_to_skip):
					current = current.Dereference()
					obj = current.GetChildMemberWithName('__value_')
					obj_data = obj.GetData()
					self.get_value_offset(current) # make sure we have a valid offset for the next items
					# we do not return __value_ because then we would end up with a child named
					# __value_ instead of [0]
					return self.valobj.CreateValueFromData('[' + str(index) + ']',obj_data,self.data_type)
				else:
					# FIXME we need to have accessed item 0 before accessing any other item!
					if self.skip_size == None:
						logger >> "You asked for item > 0 before asking for item == 0, I will fetch 0 now then retry"
						if self.get_child_at_index(0):
							return self.get_child_at_index(index)
						else:
							logger >> "item == 0 could not be found. sorry, nothing can be done here."
							return None
					return current.CreateChildAtOffset('[' + str(index) + ']',self.skip_size,self.data_type)
			else:
				logger >> "Unable to infer data-type - returning None (should mark tree as garbage here?)"
				return None
		except Exception as err:
			logger >> "Hit an exception: " + str(err)
			return None

# Just an example: the actual summary is produced by a summary string: size=${svar%#}
def stdmap_SummaryProvider(valobj,dict):
	prov = stdmap_SynthProvider(valobj,None)
	return 'size=' + str(prov.num_children())

class stddeque_SynthProvider:
    def __init__(self, valobj, d):
        logger = lldb.formatters.Logger.Logger()
        logger.write("init")
        self.valobj = valobj
        self.pointer_size = self.valobj.GetProcess().GetAddressByteSize()
        self.count = None
        try:
            self.find_block_size()
        except:
            self.block_size = -1
            self.element_size = -1
        logger.write("block_size=%d, element_size=%d" % (self.block_size, self.element_size))

    def find_block_size(self):
        # in order to use the deque we must have the block size, or else
        # it's impossible to know what memory addresses are valid
        self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
        self.element_size = self.element_type.GetByteSize()
        # The code says this, but there must be a better way:
        # template <class _Tp, class _Allocator>
        # class __deque_base {
        #    static const difference_type __block_size = sizeof(value_type) < 256 ? 4096 / sizeof(value_type) : 16;
        # }
        if self.element_size < 256:
            self.block_size =  4096 / self.element_size
        else:
            self.block_size = 16

    def num_children(self):
        global _deque_capping_size
        logger = lldb.formatters.Logger.Logger()
        if self.count is None:
            return 0
        return min(self.count, _deque_capping_size)

    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.write("Fetching child " + str(index))
        if index < 0 or self.count is None:
                return None;
        if index >= self.num_children():
                return None;
        try:
            i, j = divmod(self.start+index, self.block_size)
            return self.first.CreateValueFromExpression('[' + str(index) + ']',
                                                        '*(*(%s + %d) + %d)' % (self.first.get_expr_path(), i, j))
        except:
            return None

    def update(self):
        logger = lldb.formatters.Logger.Logger()
        try:
            # A deque is effectively a two-dim array, with fixed width.
            # 'map' contains pointers to the rows of this array. The
            # full memory area allocated by the deque is delimited
            # by 'first' and 'end_cap'. However, only a subset of this
            # memory contains valid data since a deque may have some slack
            # at the front and back in order to have O(1) insertion at
            # both ends. The rows in active use are delimited by
            # 'begin' and 'end'.
            #
            # To find the elements that are actually constructed, the 'start'
            # variable tells which element in this NxM array is the 0th
            # one, and the 'size' element gives the number of elements
            # in the deque.
            count = self.valobj.GetChildMemberWithName('__size_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0)
            # give up now if we cant access memory reliably
            if self.block_size < 0:
                logger.write("block_size < 0")
                return
            map_ = self.valobj.GetChildMemberWithName('__map_')
            start = self.valobj.GetChildMemberWithName('__start_').GetValueAsUnsigned(0)
            first = map_.GetChildMemberWithName('__first_')
            map_first = first.GetValueAsUnsigned(0)
            map_begin = map_.GetChildMemberWithName('__begin_').GetValueAsUnsigned(0)
            map_end   = map_.GetChildMemberWithName('__end_').GetValueAsUnsigned(0)
            map_endcap= map_.GetChildMemberWithName('__end_cap_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0)
            # check consistency
            if not map_first <= map_begin <= map_end <= map_endcap:
                logger.write("map pointers are not monotonic")
                return
            total_rows, junk = divmod(map_endcap - map_first, self.pointer_size)
            if junk:
                logger.write("endcap-first doesnt align correctly")
                return
            active_rows, junk = divmod(map_end - map_begin, self.pointer_size)
            if junk:
                logger.write("end-begin doesnt align correctly")
                return
            start_row, junk = divmod(map_begin - map_first, self.pointer_size)
            if junk:
                logger.write("begin-first doesnt align correctly")
                return
            if not start_row*self.block_size <= start < (start_row+1)*self.block_size:
                logger.write("0th element must be in the 'begin' row")
                return
            end_row = start_row + active_rows
            if not count:
                if active_rows:
                    logger.write("empty deque but begin!=end")
                    return                            
            elif not (end_row-1)*self.block_size <= start+count < end_row*self.block_size:
                logger.write("nth element must be before the 'end' row")
                return
            logger.write("update success: count=%r, start=%r, first=%r" % (count,start,first))
            # if consistent, save all we really need:
            self.count = count
            self.start = start
            self.first = first
        except:
            self.count = None
            self.start = None
            self.map_first = None
            self.map_begin = None

class stdsharedptr_SynthProvider:
    def __init__(self, valobj, d):
        logger = lldb.formatters.Logger.Logger()
        logger.write("init")
        self.valobj = valobj
        #self.element_ptr_type = self.valobj.GetType().GetTemplateArgumentType(0).GetPointerType()
        self.ptr = None
        self.cntrl = None
        process = valobj.GetProcess()
        self.endianness = process.GetByteOrder()
        self.pointer_size = process.GetAddressByteSize()
        self.count_type = valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)

    def num_children(self):
        return 1

    def has_children(self):
        return True

    def get_child_index(self,name):
        if name=="__ptr_":
            return 0
        if name=="count":
            return 1
        if name=="weak_count":
            return 2
        return -1

    def get_child_at_index(self,index):
        if index == 0:
            return self.ptr
        if index == 1:
            if self.cntrl == None:
                count = 0
            else:
                count = 1 + self.cntrl.GetChildMemberWithName('__shared_owners_').GetValueAsSigned()
            return self.valobj.CreateValueFromData("count",
                                                   lldb.SBData.CreateDataFromUInt64Array(self.endianness, self.pointer_size, [count]),
                                                   self.count_type)
        if index == 2:
            if self.cntrl == None:
                count = 0
            else:
                count = 1 + self.cntrl.GetChildMemberWithName('__shared_weak_owners_').GetValueAsSigned()
            return self.valobj.CreateValueFromData("weak_count",
                                                   lldb.SBData.CreateDataFromUInt64Array(self.endianness, self.pointer_size, [count]),
                                                   self.count_type)
        return None

    def update(self):
        logger = lldb.formatters.Logger.Logger()
        self.ptr = self.valobj.GetChildMemberWithName('__ptr_')#.Cast(self.element_ptr_type)
        cntrl = self.valobj.GetChildMemberWithName('__cntrl_')
        if cntrl.GetValueAsUnsigned(0):
            self.cntrl = cntrl.Dereference()
        else:
            self.cntrl = None

# we can use two different categories for old and new formatters - type names are different enough that we should make no confusion
# talking with libc++ developer: "std::__1::class_name is set in stone until we decide to change the ABI. That shouldn't happen within a 5 year time frame"
def __lldb_init_module(debugger,dict):
	debugger.HandleCommand('type summary add -F libcxx.stdstring_SummaryProvider "std::__1::string" -w libcxx')
	debugger.HandleCommand('type summary add -F libcxx.stdstring_SummaryProvider "std::__1::basic_string<char, class std::__1::char_traits<char>, class std::__1::allocator<char> >" -w libcxx')
	debugger.HandleCommand('type synthetic add -l libcxx.stdvector_SynthProvider -x "^(std::__1::)vector<.+>$" -w libcxx')
	debugger.HandleCommand('type summary add -F libcxx.stdvector_SummaryProvider -e -x "^(std::__1::)vector<.+>$" -w libcxx')
	debugger.HandleCommand('type synthetic add -l libcxx.stdlist_SynthProvider -x "^(std::__1::)list<.+>$" -w libcxx')
	debugger.HandleCommand('type summary add -F libcxx.stdlist_SummaryProvider -e -x "^(std::__1::)list<.+>$" -w libcxx')
	debugger.HandleCommand('type synthetic add -l libcxx.stdmap_SynthProvider -x "^(std::__1::)map<.+> >$" -w libcxx')
	debugger.HandleCommand('type summary add -F libcxx.stdmap_SummaryProvider -e -x "^(std::__1::)map<.+> >$" -w libcxx')
	debugger.HandleCommand("type category enable libcxx")
	debugger.HandleCommand('type synthetic add -l libcxx.stddeque_SynthProvider -x "^(std::__1::)deque<.+>$" -w libcxx')
	debugger.HandleCommand('type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)shared_ptr<.+>$" -w libcxx')
	# turns out the structs look the same, so weak_ptr can be handled the same!
	debugger.HandleCommand('type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)weak_ptr<.+>$" -w libcxx')

_map_capping_size = 255
_list_capping_size = 255
_list_uses_loop_detector = True
_deque_capping_size = 255
