def get_earliest_accommodating_moment_index(
    moment_or_operation: _MOMENT_OR_OP,
    qubit_indices: dict[cirq.Qid, int],
    mkey_indices: dict[cirq.MeasurementKey, int],
    ckey_indices: dict[cirq.MeasurementKey, int],
    length: int | None = None,
) -> int:
    """Get the index of the earliest moment that can accommodate the given moment or operation.

    Updates the dictionaries keeping track of the last moment index addressing a given qubit,
    measurement key, and control key.

    Args:
        moment_or_operation: The moment operation in question.
        qubit_indices: A dictionary mapping qubits to the latest moments that address them.
        mkey_indices: A dictionary mapping measurement keys to the latest moments that address them.
        ckey_indices: A dictionary mapping control keys to the latest moments that address them.
        length: The length of the circuit that we are trying to insert a moment or operation into.
            Should probably be equal to the maximum of the values in `qubit_indices`,
            `mkey_indices`, and `ckey_indices`.

    Returns:
        The integer index of the earliest moment that can accommodate the given moment or operation.
    """
    mop_qubits = moment_or_operation.qubits
    mop_mkeys = protocols.measurement_key_objs(moment_or_operation)
    mop_ckeys = protocols.control_keys(moment_or_operation)

    if isinstance(moment_or_operation, Moment):
        # For consistency with `Circuit.append`, moments always get placed at the end of a circuit.
        if length is not None:
            last_conflict = length - 1
        else:
            last_conflict = max(
                [*qubit_indices.values(), *mkey_indices.values(), *ckey_indices.values(), -1]
            )

    else:
        # We start by searching for the `latest_conflict` moment index, which we will increment by
        # `1` to identify the earliest moment that *does not* conflict with the given operation.
        # The `latest_conflict` is initialized to `-1` before searching for later conflicting
        # moments.
        last_conflict = -1

        # Look for the maximum conflict; i.e. a moment that has a qubit the same as one of this op's
        # qubits, that has a measurement or control key the same as one of this op's measurement
        # keys, or that has a measurement key the same as one of this op's control keys. (Control
        # keys alone can commute past each other). The `ifs` are logically unnecessary but seem to
        # make this slightly faster.
        if mop_qubits:
            last_conflict = max(
                last_conflict, *[qubit_indices.get(qubit, -1) for qubit in mop_qubits]
            )
        if mop_mkeys:
            last_conflict = max(last_conflict, *[mkey_indices.get(key, -1) for key in mop_mkeys])
            last_conflict = max(last_conflict, *[ckey_indices.get(key, -1) for key in mop_mkeys])
        if mop_ckeys:
            last_conflict = max(last_conflict, *[mkey_indices.get(key, -1) for key in mop_ckeys])

    # The index of the moment to place this moment or operation ("mop") into.
    mop_index = last_conflict + 1

    # Update our dicts with data from this `mop` placement. Note `mop_index` will always be greater
    # than the existing value for all of these, by construction.
    for qubit in mop_qubits:
        qubit_indices[qubit] = mop_index
    for key in mop_mkeys:
        mkey_indices[key] = mop_index
    for key in mop_ckeys:
        ckey_indices[key] = mop_index

    return mop_index
Get the index of the earliest moment that can accommodate the given moment or operation.

    Updates the dictionaries keeping track of the last moment index addressing a given qubit,
    measurement key, and control key.

    Args:
        moment_or_operation: The moment operation in question.
        qubit_indices: A dictionary mapping qubits to the latest moments that address them.
        mkey_indices: A dictionary mapping measurement keys to the latest moments that address them.
        ckey_indices: A dictionary mapping control keys to the latest moments that address them.
        length: The length of the circuit that we are trying to insert a moment or operation into.
            Should probably be equal to the maximum of the values in `qubit_indices`,
            `mkey_indices`, and `ckey_indices`.

    Returns:
        The integer index of the earliest moment that can accommodate the given moment or operation.
    
cirq-core/cirq/circuits/circuit.py