Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move interners from trait to generic structs
This rewrites the interner mechanisms be defined in terms of two generic structs (`Interner` and `Interned`) that formalise the idea that the interned values are owned versions of a given reference type, and move the logically separate intern-related actions (get a key from the value, and get the value from the key) into separate functions (`get` and `insert`, respectively). This has a few advantages: 1. we now have both `insert` and `insert_owned` methods, which was awkward to add within the trait-based structure. This allows a more efficient path when the owned variant has already necessarily been constructed. 2. additionally, the standard `insert` path now takes only a reference type. For large circuits, most intern lookups will, in general, find a pre-existing key, so in situations where the interned value is sufficiently small that it can be within a static allocation (which is the case for almost all `qargs` and `cargs`), it's more efficient not to construct the owned type on the heap. 3. the type of the values retrieved from an interner are no longer indirected through the owned type that's stored. For example, where `IndexedInterner<Vec<Qubit>>` gave out `&Vec<Qubit>`s as its lookups, `Interner<[Qubit]>` returns the more standard `&[Qubit]`, which is only singly indirect rather than double. The following replacements are made: 1. The `IndexedInterner` struct from before is now just called `Interner` (and internally, it uses an `IndexSet` rather than manually tracking the indices). Its generic type is related to the references it returns, rather than the owned value it stores, so `IndexedInterner<Vec<Qubit>>` becomes `Interner<[Qubit]>`. 2. The `Interner` trait is now gone. Everything is just accessed as concrete methods on the `Interner` struct. 3. `<&IndexedInterner as Interner>::intern` (lookup of the value from an interner key) is now called `Interner::get`. 4. `<&mut IndexedInterner as Interner>::intern` (conversion of an owned value to an interner key) is now called `Interner::insert_owned`. 5. A new method, `Interner::insert`, can now be used when one need not have an owned allocation of the storage type; the correct value will be allocated if required (which is expected to be less frequent). 6. The intern key is no longer called `interner::Index`, but `Interned<T>`, where the generic parameter `T` matches the generic of the `Interner<T>` that gave out the key.
- Loading branch information