From d52943a119db54809682ea8f26a946c93a83ca5c Mon Sep 17 00:00:00 2001 From: John Lapeyre Date: Wed, 5 Jun 2024 13:44:57 -0400 Subject: [PATCH] Use unsafe Array initialization to avoid manually counting number of None's The number of standard gates is specified by STANDARD_GATE_SIZE. To add a gate, the dev has to read the value from one source file, then add (possible count) `None`s in two places in another file to initialize arrays. After learning it all once it's not so bad, but it still could be better. After this commit the dev is required to change only the value of STANDARD_GATE_SIZE. --- crates/circuit/src/imports.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/crates/circuit/src/imports.rs b/crates/circuit/src/imports.rs index b26e8f0b586a..9182530f4a74 100644 --- a/crates/circuit/src/imports.rs +++ b/crates/circuit/src/imports.rs @@ -100,19 +100,28 @@ static STDGATE_IMPORT_PATHS: [[&str; 2]; STANDARD_GATE_SIZE] = [ static mut STDGATE_PYTHON_GATES: GILOnceCell<[Option; STANDARD_GATE_SIZE]> = GILOnceCell::new(); +// A fixed size array is initialized like this because using the `[T; 5]` syntax +// requires T to be `Copy`. But `PyObject` isn't Copy so therefore Option +// as T isn't Copy. +fn _array_of_option_pyobject() -> [Option; STANDARD_GATE_SIZE] { + use std::mem::{self, MaybeUninit}; + let array = unsafe { + let mut data: [MaybeUninit>; STANDARD_GATE_SIZE] = MaybeUninit::uninit().assume_init(); + for elem in &mut data[..] { + *elem = MaybeUninit::new(None); + } + mem::transmute::<_, [Option; STANDARD_GATE_SIZE]>(data) + }; + array +} + #[inline] pub fn populate_std_gate_map(py: Python, rs_gate: StandardGate, py_gate: PyObject) { let gate_map = unsafe { match STDGATE_PYTHON_GATES.get_mut() { Some(gate_map) => gate_map, None => { - // A fixed size array is initialized like this because using the `[T; 5]` syntax - // requires T to be `Copy`. But `PyObject` isn't Copy so therefore Option - // as T isn't Copy. To avoid that we just list out None STANDARD_GATE_SIZE times - let array: [Option; STANDARD_GATE_SIZE] = [ - None, None, None, None, None, None, None, None, None, None, None, None, None, - None, None, None, None, None, None, - ]; + let array = _array_of_option_pyobject(); STDGATE_PYTHON_GATES.set(py, array).unwrap(); STDGATE_PYTHON_GATES.get_mut().unwrap() } @@ -127,16 +136,7 @@ pub fn populate_std_gate_map(py: Python, rs_gate: StandardGate, py_gate: PyObjec #[inline] pub fn get_std_gate_class(py: Python, rs_gate: StandardGate) -> PyResult { let gate_map = unsafe { - STDGATE_PYTHON_GATES.get_or_init(py, || { - // A fixed size array is initialized like this because using the `[T; 5]` syntax - // requires T to be `Copy`. But `PyObject` isn't Copy so therefore Option - // as T isn't Copy. To avoid that we just list out None STANDARD_GATE_SIZE times - let array: [Option; STANDARD_GATE_SIZE] = [ - None, None, None, None, None, None, None, None, None, None, None, None, None, None, - None, None, None, None, None, - ]; - array - }) + STDGATE_PYTHON_GATES.get_or_init(py, _array_of_option_pyobject) }; let gate = &gate_map[rs_gate as usize]; let populate = gate.is_none();