'Merges this state with the other states. Returns the merging result, merged state, and the merge flag.
:param states: the states to merge
:param merge_conditions: a tuple of the conditions under which each state holds
:param common_ancestor: a state that represents the common history between the states being merged
:param plugin_whitelist: a list of plugin names that will be merged. If this option is given and is not None,
any plugin that is not inside this list will not be merged, and will be created as a
fresh instance in the new state.
:return: (merged state, merge flag, a bool indicating if any merging occured)'

def merge(self, *others, **kwargs):

    merge_conditions = kwargs.pop('merge_conditions', None)
    common_ancestor = kwargs.pop('common_ancestor', None)
    plugin_whitelist = kwargs.pop('plugin_whitelist', None)
    if (len(kwargs) != 0):
        raise ValueError(('invalid    arguments:    %s' % kwargs.keys()))
    if (merge_conditions is None):
        merge_flag = self.se.BVS(('state_merge_%d' % merge_counter.next()), 16)
        merge_values = range((len(others) + 1))
        merge_conditions = [(merge_flag == b) for b in merge_values]
    else:
        merge_conditions = [(self.se.true if (len(mc) == 0) else self.se.And(*mc)) for mc in merge_conditions]
    if (len(set((o.arch.name for o in others))) != 1):
        import ipdb
        ipdb.set_trace()
        raise SimMergeError('Unable    to    merge    due    to    different    architectures.')
    all_plugins = (set(self.plugins.keys()) | set.union(*(set(o.plugins.keys()) for o in others)))
    if (plugin_whitelist is not None):
        all_plugins = all_plugins.intersection(set(plugin_whitelist))
    merged = self.copy()
    merging_occurred = False
    merged.history.parent = self.history
    for p in all_plugins:
        our_plugin = (merged.plugins[p] if (p in merged.plugins) else None)
        their_plugins = [(pl.plugins[p] if (p in pl.plugins) else None) for pl in others]
        plugin_classes = ((set([our_plugin.__class__]) | set((pl.__class__ for pl in their_plugins))) - set([None.__class__]))
        if (len(plugin_classes) != 1):
            raise SimMergeError(('There    are    differing    plugin    classes    (%s)    for    plugin    %s' % (plugin_classes, p)))
        plugin_class = plugin_classes.pop()
        our_filled_plugin = (our_plugin if (our_plugin is not None) else merged.register_plugin(p, plugin_class()))
        their_filled_plugins = [(tp if (tp is not None) else t.register_plugin(p, plugin_class())) for (t, tp) in zip(others, their_plugins)]
        plugin_state_merged = our_filled_plugin.merge(their_filled_plugins, merge_conditions, common_ancestor=(common_ancestor.plugins[p] if ((common_ancestor is not None) and (p in common_ancestor.plugins)) else None))
        if plugin_state_merged:
            l.debug('Merging    occured    in    %s', p)
            merging_occurred = True
    merged.add_constraints(merged.se.Or(*merge_conditions))
    return (merged, merge_conditions, merging_occurred)
