'Determines whether the block specified by (address, size) should be merged with adjacent blocks.
:param int address: Starting address of the block to be merged.
:param int size: Size of the block to be merged.
:param str sort: Type of the block.
:param int idx: ID of the address.
:return: None'

def _insert_and_merge(self, address, size, sort, idx):

    if ((idx > 0) and ((address + size) <= self._list[(idx - 1)].start)):
        l.warning('BUG    FOUND:    new    segment    should    always    be    greater    than    _list[idx].')
        self._insert_and_merge(address, size, sort, (idx - 1))
        return
    if (idx == len(self._list)):
        self._list.append(Segment(address, (address + size), sort))
    else:
        self._list.insert(idx, Segment(address, (address + size), sort))
    self._bytes_occupied += size
    pos = idx
    while (pos < len(self._list)):
        (merged, pos, bytes_change) = self._insert_and_merge_core(pos, 'forward')
        if (not merged):
            break
        self._bytes_occupied += bytes_change
    if (pos >= len(self._list)):
        pos = (len(self._list) - 1)
    while (pos > 0):
        (merged, pos, bytes_change) = self._insert_and_merge_core(pos, 'backward')
        if (not merged):
            break
        self._bytes_occupied += bytes_change
