def pair_SAM_alignments_with_buffer(
        alignments,
        max_buffer_size=30000000,
        primary_only=False):
    '''Iterate over SAM aligments with buffer, position-sorted paired-end
    Args:
        alignments (iterator of SAM/BAM alignments): the alignments to wrap
        max_buffer_size (int): maxmal numer of alignments to keep in memory.
        primary_only (bool): for each read, consider only the primary line
            (SAM flag 0x900 = 0). The SAM specification requires one and only
            one of those for each read.
    Yields:
        2-tuples with each pair of alignments.
    '''
    almnt_buffer = {}
    ambiguous_pairing_counter = 0
    for almnt in alignments:
        if not almnt.paired_end:
            raise ValueError(
                "Sequence of paired-end alignments expected, but got single-end alignment.")
        if almnt.pe_which == "unknown":
            raise ValueError(
                "Cannot process paired-end alignment found with 'unknown' 'pe_which' status.")
        if primary_only and (almnt.not_primary_alignment or almnt.supplementary):
            continue
        matekey = (
            almnt.read.name,
            "second" if almnt.pe_which == "first" else "first",
            almnt.mate_start.chrom if almnt.mate_aligned else None,
            almnt.mate_start.pos if almnt.mate_aligned else None,
            almnt.iv.chrom if almnt.aligned else None,
            almnt.iv.start if almnt.aligned else None,
            -almnt.inferred_insert_size if almnt.aligned and almnt.mate_aligned else None)
        if matekey in almnt_buffer:
            if len(almnt_buffer[matekey]) == 1:
                mate = almnt_buffer[matekey][0]
                del almnt_buffer[matekey]
            else:
                mate = almnt_buffer[matekey].pop(0)
                if ambiguous_pairing_counter == 0:
                    ambiguous_pairing_first_occurance = matekey
                ambiguous_pairing_counter += 1
            if almnt.pe_which == "first":
                yield (almnt, mate)
            else:
                yield (mate, almnt)
        else:
            almntkey = (
                almnt.read.name, almnt.pe_which,
                almnt.iv.chrom if almnt.aligned else None,
                almnt.iv.start if almnt.aligned else None,
                almnt.mate_start.chrom if almnt.mate_aligned else None,
                almnt.mate_start.pos if almnt.mate_aligned else None,
                almnt.inferred_insert_size if almnt.aligned and almnt.mate_aligned else None)
            if almntkey not in almnt_buffer:
                almnt_buffer[almntkey] = [almnt]
            else:
                almnt_buffer[almntkey].append(almnt)
            if len(almnt_buffer) > max_buffer_size:
                raise ValueError(
                    "Maximum alignment buffer size exceeded while pairing SAM alignments.")
    if len(almnt_buffer) > 0:
        warnings.warn(
            "Mate records missing for %d records; first such record: %s." %
            (len(almnt_buffer), str(list(almnt_buffer.values())[0][0])))
        for almnt_list in list(almnt_buffer.values()):
            for almnt in almnt_list:
                if almnt.pe_which == "first":
                    yield (almnt, None)
                else:
                    yield (None, almnt)
    if ambiguous_pairing_counter > 0:
        warnings.warn(
            "Mate pairing was ambiguous for %d records; mate key for first such record: %s." %
            (ambiguous_pairing_counter, str(ambiguous_pairing_first_occurance)))