src/necsus/runtime/query

Search:
Group by:

Types

AnyQuery[Comps] = Query[Comps] | FullQuery[Comps]
FullQuery[Comps] = distinct RawQuery[Comps]
Allows systems to query for entities with specific components. Where Comps is a tuple of the components to fetch in this query. Provides access to the EntityId
Not[Comps] = distinct int8
A query flag that indicates a component should be excluded from a query. Where Comps is the single component that should be excluded.
Query[Comps] = distinct RawQuery[Comps]
Allows systems to query for entities with specific components. Where Comps is a tuple of the components to fetch in this query. Does not provide access to the entity ID
QueryCols[Comps] = object
  rows*: uint32
  hasAccessories*: bool ## Whether any argument at all landed on an accessory this archetype carries, which
                        ## is what says whether the rows have to be filtered as they are walked
  eids*: ptr UncheckedArray[EntityId]
  columns*: array[Comps.tupleLen, Column]
  accessories*: array[Comps.tupleLen, Column] ## The presence column standing behind each argument, or no column when there is
                                              ## nothing to check -- either because the argument is not an accessory at all, or
                                              ## because this archetype does not carry the one it named.
                                              ## 
                                              ## Which arguments are accessories is settled at compile time, but it cannot be
                                              ## carried in the type: `Query[Comps]` is what a system declares, so `Comps` is all
                                              ## these columns get to be generic over. It rides along as a value instead

The columns of one archetype that a query asked for, resolved once, alongside the entity ids sitting next to them and how many rows they hold.

Working out where a column sits happens here rather than once per row, which is what the global component index buys: the same id names the same component in every archetype, so nothing about this depends on which archetype it came from

QueryGetCols[Comps] = proc (appStatePtr: pointer; state: var uint;
                            cols: var QueryCols[Comps]): bool {....gcsafe,
    raises: [], nimcall.}
QueryItem[Comps] = tuple[entityId: EntityId, components: Comps]
An individual value yielded by a query. Where Comps is a tuple of the components to fetch in this query
RawQuery[Comps] = ref object
Allows systems to query for entities with specific components. Where Comps is a tuple of the components to fetch in this query.

Consts

NO_ACCESSORY = 65535'u16
Names no presence column at all, which is what an argument that is not an accessory has in place of one

Procs

proc asFullQuery[Comps](rawQuery: RawQuery[Comps]): FullQuery[Comps]
proc asQuery[Comps](rawQuery: RawQuery[Comps]): Query[Comps]
proc len[Comps: tuple](query: AnyQuery[Comps]): Natural {....gcsafe, raises: [].}
Returns the number of entities in this query
proc newQuery[Comps: tuple](appState: pointer; getLen: QueryGetLen;
                            getCols: QueryGetCols[Comps]): RawQuery[Comps]
proc newQueryCols[Comps: tuple](store: ArchetypeStore;
                                components: openArray[ComponentId];
                                accessories: openArray[ComponentId]): QueryCols[
    Comps] {.inline.}

Picks out the columns a query wants from an archetype.

A component the archetype does not have leaves a nil column behind, which is exactly what an excluded or absent optional argument wants -- so nothing here has to be told which arguments those are

proc single[Comps: tuple](query: AnyQuery[Comps]): Option[Comps]
Returns a single element from a query

Iterators

iterator items[Comps: tuple](query: AnyQuery[Comps]): Comps
Iterates through the entities in a query
iterator pairs[Comps: tuple](query: FullQuery[Comps]): QueryItem[Comps]
Iterates through the entities in a query

Templates

template declSlot(slot: untyped; Comps: typedesc)

Declares the value a query fills in as it walks a row.

Every field is written before the body gets to see it, so zeroing the slot first is wasted work. But it is worse than wasted. Zeroing takes the slot's address, and an address-taken local is one the C compiler has to keep in memory: it then writes each component into the stack even when the body only reads a field or two of it, and widening the loop is off the table. Left uninitialised, the slot scalarises into registers and the components nothing looks at stop being loaded at all.

Only safe while nothing in the tuple has a lifetime to manage. Assigning over a garbage string would hand its destructor a garbage pointer, so a tuple carrying one keeps the zeroing

template read[Comps: tuple](cols: QueryCols[Comps]; idx: uint32; slot: var Comps): bool
Fills a slot with one row, and says whether the row was a match at all -- which it may not be, when the row is missing an accessory that was asked for
template readAccCol[T](column: Column; presence: Column; idx: uint32;
                       slot: var Option[ptr T]): bool
An optional component asked for by pointer. Without this, the option overload above matches with T bound to ptr T and reads the component itself as a pointer
template readAccCol[T](column: Column; presence: Column; idx: uint32;
                       slot: var Not[T]): bool
An excluded component usually has no column at all, which the archetype settled once and for all. An excluded accessory does have one. The archetype holds entities both with and without it, so it is the row that has to be checked
template readAccCol[T](column: Column; presence: Column; idx: uint32;
                       slot: var Option[T]): bool
An optional component. The archetype says whether the column is there at all, and the presence column says whether this row is one of the ones that has it
template readAccCol[T](column: Column; presence: Column; idx: uint32;
                       slot: var ptr T): bool
A required component asked for by pointer, straight into the column
template readAccCol[T](column: Column; presence: Column; idx: uint32;
                       slot: var T): bool
Reads a required component that may be held as an accessory, and says whether the row turned out to have it.
template readCol[T](column: Column; idx: uint32; slot: var Not[T])
An excluded component has no column. The archetype already established it is absent, so there is nothing to read and nothing to check
template readCol[T](column: Column; idx: uint32; slot: var Option[ptr T])
An optional component asked for by pointer. Without this, the option overload above matches with T bound to ptr T and reads the component itself as a pointer
template readCol[T](column: Column; idx: uint32; slot: var Option[T])
An optional component is present or it is not, and an empty column is how the archetype says which
template readCol[T](column: Column; idx: uint32; slot: var ptr T)
A query that asked for a pointer gets one straight into the column, so nothing is copied and writes land back in the store
template readCol[T](column: Column; idx: uint32; slot: var T)
Reads one component out of a column. The slot is what says how to read it