@@ -23,10 +23,11 @@ use qiskit_circuit::bit::{ClassicalRegister, QuantumRegister};
2323use qiskit_circuit:: bit:: { ShareableClbit , ShareableQubit } ;
2424use qiskit_circuit:: circuit_data:: CircuitData ;
2525use qiskit_circuit:: dag_circuit:: DAGCircuit ;
26+ use qiskit_circuit:: interner:: Interner ;
2627use qiskit_circuit:: operations:: {
2728 ArrayType , DelayUnit , Operation , Param , StandardGate , StandardInstruction , UnitaryGate ,
2829} ;
29- use qiskit_circuit:: packed_instruction:: PackedOperation ;
30+ use qiskit_circuit:: packed_instruction:: { PackedInstruction , PackedOperation } ;
3031use qiskit_circuit:: { Clbit , Qubit } ;
3132
3233#[ cfg( feature = "python_binding" ) ]
@@ -876,6 +877,44 @@ pub struct CInstruction {
876877 /// The number of parameters for this instruction.
877878 num_params : u32 ,
878879}
880+ impl CInstruction {
881+ /// Create a `CInstruction` that owns pointers to copies of the information in the given
882+ /// `PackedInstruction`.
883+ ///
884+ /// This must be cleared by a call to `qk_circuit_instruction_clear` to avoid leaking its
885+ /// allocations.
886+ ///
887+ /// Panics if the operation name contains a nul, or if the instruction has non-float parameters.
888+ pub ( crate ) fn from_packed_instruction_with_floats (
889+ packed : & PackedInstruction ,
890+ qargs_interner : & Interner < [ Qubit ] > ,
891+ cargs_interner : & Interner < [ Clbit ] > ,
892+ ) -> Self {
893+ let name = CString :: new ( packed. op . name ( ) )
894+ . expect ( "names do not contain nul" )
895+ . into_raw ( ) ;
896+ let qargs = qargs_interner. get ( packed. qubits ) ;
897+ let cargs = cargs_interner. get ( packed. clbits ) ;
898+ let params = packed
899+ . params_view ( )
900+ . iter ( )
901+ . map ( |p| match p {
902+ Param :: Float ( p) => Some ( * p) ,
903+ _ => None ,
904+ } )
905+ . collect :: < Option < Box < [ f64 ] > > > ( )
906+ . expect ( "caller is responsible for ensuring all parameters are floats" ) ;
907+ Self {
908+ name,
909+ num_qubits : qargs. len ( ) as u32 ,
910+ qubits : Box :: leak ( qargs. iter ( ) . map ( |q| q. 0 ) . collect :: < Box < [ u32 ] > > ( ) ) . as_mut_ptr ( ) ,
911+ num_clbits : cargs. len ( ) as u32 ,
912+ clbits : Box :: leak ( cargs. iter ( ) . map ( |c| c. 0 ) . collect :: < Box < [ u32 ] > > ( ) ) . as_mut_ptr ( ) ,
913+ num_params : params. len ( ) as u32 ,
914+ params : Box :: leak ( params) . as_mut_ptr ( ) ,
915+ }
916+ }
917+ }
879918
880919/// @ingroup QkCircuit
881920/// Return the instruction details for an instruction in the circuit.
@@ -915,63 +954,15 @@ pub unsafe extern "C" fn qk_circuit_get_instruction(
915954 index : usize ,
916955 instruction : * mut CInstruction ,
917956) {
918- // SAFETY: Per documentation, the pointer is non-null and aligned .
957+ // SAFETY: Per documentation, `circuit` is a pointer to valid data .
919958 let circuit = unsafe { const_ptr_as_ref ( circuit) } ;
920- if index >= circuit. __len__ ( ) {
921- panic ! ( "Invalid index" )
922- }
923- let packed_inst = & circuit. data ( ) [ index] ;
924- let mut qargs = {
925- let qargs = circuit. get_qargs ( packed_inst. qubits ) ;
926- let qargs_vec: Vec < u32 > = qargs. iter ( ) . map ( |x| x. 0 ) . collect ( ) ;
927- qargs_vec. into_boxed_slice ( )
928- } ;
929- let mut cargs = {
930- let cargs = circuit. get_cargs ( packed_inst. clbits ) ;
931- let cargs_vec: Vec < u32 > = cargs. iter ( ) . map ( |x| x. 0 ) . collect ( ) ;
932- cargs_vec. into_boxed_slice ( )
933- } ;
934- let mut params = {
935- let params = packed_inst. params_view ( ) ;
936- let params_vec: Vec < f64 > = params
937- . iter ( )
938- . map ( |x| match x {
939- Param :: Float ( val) => * val,
940- _ => panic ! ( "Invalid parameter on instruction" ) ,
941- } )
942- . collect ( ) ;
943- params_vec. into_boxed_slice ( )
944- } ;
945- // These lists (e.g. 'qargs') are Box<[T]>, so we use .as_mut_ptr()
946- // to get a mutable pointer to the underlying slice/array on
947- // the heap and Box::into_raw() to consume the Box without freeing
948- // it (so the underlying array doesn't get freed when we return)
949- let out_qargs = qargs. as_mut_ptr ( ) ;
950- let out_qargs_len = qargs. len ( ) as u32 ;
951- let _ = Box :: into_raw ( qargs) ;
952- let out_cargs = cargs. as_mut_ptr ( ) ;
953- let out_cargs_len = cargs. len ( ) as u32 ;
954- let _ = Box :: into_raw ( cargs) ;
955- let out_params = params. as_mut_ptr ( ) ;
956- let out_params_len = params. len ( ) as u32 ;
957- let _ = Box :: into_raw ( params) ;
958-
959- // SAFETY: The pointer must point to a CInstruction size allocation
960- // per the docstring.
961- unsafe {
962- std:: ptr:: write (
963- instruction,
964- CInstruction {
965- name : CString :: new ( packed_inst. op . name ( ) ) . unwrap ( ) . into_raw ( ) ,
966- num_qubits : out_qargs_len,
967- qubits : out_qargs,
968- num_clbits : out_cargs_len,
969- clbits : out_cargs,
970- num_params : out_params_len,
971- params : out_params,
972- } ,
973- ) ;
974- }
959+ let inst = CInstruction :: from_packed_instruction_with_floats (
960+ & circuit. data ( ) [ index] ,
961+ circuit. qargs_interner ( ) ,
962+ circuit. cargs_interner ( ) ,
963+ ) ;
964+ // SAFETY: per documentation, `instruction` is a pointer to a sufficient allocation.
965+ unsafe { instruction. write ( inst) } ;
975966}
976967
977968/// @ingroup QkCircuit
0 commit comments