Each architecture must implement the following types and APIs.
Architectures can either inherit from `ArchAPI<ArchRanges>`, which is a pure virtual description of the architecture API; or `BaseArch<ArchRanges>` which provides some default implementations described below.
`ArchRanges` is a `struct` of `using`s that allows arches to return custom range types. These ranges can be anything that has a `begin()` and `end()` method that return const forward iterators. This can be a `std::list<T>`, `std::vector<T>`, a (const) reference to those, or anything else that behaves in a similar way.
The contents of `ArchRanges` is as follows:
| Type | Range of |
|---------------------------|----------------------------------|
|`ArchArgsT` | N/A (struct of device params) |
|`AllBelsRangeT` | `BelId` |
|`TileBelsRangeT` | `BelId` |
|`BelAttrsRangeT` | std::pair<IdString, std::string> |
|`BelPinsRangeT` | `IdString` |
|`CellBelPinRangeT` | `IdString` |
|`AllWiresRangeT` | `WireId` |
|`DownhillPipRangeT` | `PipId` |
|`UphillPipRangeT` | `PipId` |
|`WireBelPinRangeT` | `BelPin` |
|`AllPipsRangeT` | `PipId` |
|`PipAttrsRangeT` | std::pair<IdString, std::string> |
|`AllGroupsRangeT` | `GroupId` |
|`GroupBelsRangeT` | `BelId` |
|`GroupWiresRangeT` | `WireId` |
|`GroupPipsRangeT` | `PipId` |
|`GroupGroupsRangeT` | `GroupId` |
|`DecalGfxRangeT` | `GraphicElement` |