# Indirect value

This unit provides indirect value, it's simplest offering being "ivalue", the
indirect version of "value" [usage/to] :

  create data 12 , 42 , 54 ,
  create ptr data ,
  ptr ivalue myval
  myval . \ prints 12
  15 to myval \ replaces "12" in data with "15"
  4 ptr +!
  myval . \ prints 42

## ivalmap

ivalue, alright, but that's not why you're here. Double indirection becomes
interesting when we transform it into maps, that is, a list of offset relative
to the indirect base. If this makes you think about [lib/struct], you're not
crazy. These are very similar, but also different:

1. Their base doesn't come from PS, but from a pointer in memory, inherent to
   the mapped words.
2. A "ivalmap" doesn't create a structure word to be used as types in other
   languages.

ivalmap is ideally suited for device register maps. You begin defining one with
a "ivalmap" call, then the mapping is read from the input stream with the "rest
of line" logic [usage/io]. Each mapping has 3 elements: an offset, a qualifier
and a name. Example mapping:

  variable ptr
  ptr ivalmap
    0  N4  mydword \
    4  LE2 mywle   \
    6  BE2 mywbe   \
    8  REF myarray

This creates 3 "ivalue-like" words called "mydword", "mywle" and "mywbe". Here
are their equivalents:

  mydword    --> ptr @ @
  to mydword --> ptr @ !
  mywle      --> ptr @ 4+ wle@
  to mywle   --> ptr @ 4+ wle!
  mywbe      --> ptr @ 6 + wbe@
  to mywbe   --> ptr @ 6 + wbe!

## Qualifier list

Qualifiers are names that link to a pair of get/set routines. Here's the list:

  N4   @       !     \ "N" is for "native"
  N2   w@      w!
  N1   c@      c!
  LE4  le@     le!   \ "L" is for "little-endian"
  LE2  wle@    wle!
  BE4  be@     be!   \ "B" is for "big-endian"
  BE2  wbe@    wbe!
  XT   execute !
  REF  noop    error

Some other units define their own IQAL, which can transparently be used in maps:

  * [drv/pc/ioport]

## addrof

Lack of big moustache [lib/bm] support is unfortunate, but the tradeoff calculus
is done: not worth adding double indirections. It means we forego the speedup
moustaches bring for the sake of simplicity.

One thing that goes beyond the realm of mere speed, however, is moustaches'
magical "&" flag, that is, the ability to get the address of a moustache.
There's no way to have that outside moustache semantics.

That is why this unit provides alternate semantics for this service: "addrof".
This word reads a word from the input stream and looks in up in scrying mode
[usage/word], expecting it to be tagged [usage/tag]. If it's tagged with one
of the supported tags, it yields the address where the data of that word lives.

It works with those tags:

  * IVAL: indirect values, from this very unit
  * VALU: regular "value"
  * LVAR: V1, V2, V3, V4

This means, for example, that "addrof mywle" from the example above will be the
equivalent of "ptr @ 4+".

This doesn't work on fields [lib/struct]. Use "offsetof" instead.

This word is an immediate that works both in compile and interpret mode. In
interpret mode, it will yield the address directly. In compile mode, it will
compile the indirection fetching and apply the offset on it.

## IVAL and IQUA tags

This unit defines two tags [usage/tag], IVAL and IQUA. IVAL tags an entry that
is either a "ivalue" or a member of an "ivalmap". It has those fields:

  +0  Address of pointer
  +4  Offset to apply

IQUA is a data tag that precedes ivalmap qualifiers. It has these fields

  +0  Fetch xt
  +4  Store xt

## API

ivalue ( ptr "name" -- )
  Create a new indirect value as per above.

createiqual ( "name" "get" "set" -- )
  Create a new IQUAL record to be used in ivalmap.

ivalmap ( ptr -- )
  Create indirect mappings as per above

absvalmap ( a -- )
  A shortcut for creating a variable with "a" in it, which never changes, and
  then calling "ivalmap" with that variable.

addrof ( "name" -- a ) *I*
  Yield the address on which the getter/setter of specified IVAL/VALU/LVAR would
  act if the word was called directly or with "to".
