| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Control.Monad.Foil.Registry
Description
Deterministic stripe assignment for separately checked units.
Each unit of a module system allocates its top-level names inside its own
reservation (see Control.Monad.Foil.Blocks), and the assignment of
reservations has to be deterministic: a unit's declarations are numbered
base, base + 1, and so on in declaration order, whatever else is
checked around it. Determinism is what makes raw names cacheable, since a
unit checked today and a unit loaded tomorrow then agree name for name. It
is also what discharges the trust obligation of
checkExtScope.
The registry is that assignment: an append-only map from unit names to stripe indices, handing out the next index on first use. A build persists it beside the build products, since a cached artifact survives a change elsewhere in the build exactly when the assignment does not move.
Where the stripes lie on the raw-name line is a StripeLayout and a
policy of the client. The library is region-agnostic, and the allocator
admits negative names.
Synopsis
- newtype StripeIndex = StripeIndex Int
- newtype StripeSize = StripeSize Int
- newtype StripeLayout = StripeLayout {
- stripeRange :: StripeIndex -> NameRange
- stripesBelowZero :: StripeSize -> StripeLayout
- stripesAbove :: RawName -> StripeSize -> StripeLayout
- newtype RegionWidth = RegionWidth Int
- newtype RegionsPerUnit = RegionsPerUnit Int
- data RegionLayout = RegionLayout {
- firstRegionOf :: StripeIndex -> NameRange
- nextRegion :: NameRange -> NameRange
- regionsAbove :: RawName -> RegionsPerUnit -> RegionWidth -> RegionLayout
- type Registry name = Map name StripeIndex
- emptyRegistry :: Registry name
- registrySize :: Registry name -> Int
- registerUnit :: Ord name => name -> Registry name -> (Registry name, StripeIndex)
Stripe indices
newtype StripeIndex Source #
A stripe's position in the registry: which run of names a unit draws from. Its own type, so that a stripe index cannot be confused with a name, a count, or an offset.
Since: 0.4.0
Constructors
| StripeIndex Int |
Instances
| Binary StripeIndex Source # | |
Defined in Control.Monad.Foil.Registry | |
| Read StripeIndex Source # | |
Defined in Control.Monad.Foil.Registry Methods readsPrec :: Int -> ReadS StripeIndex # readList :: ReadS [StripeIndex] # readPrec :: ReadPrec StripeIndex # readListPrec :: ReadPrec [StripeIndex] # | |
| Show StripeIndex Source # | |
Defined in Control.Monad.Foil.Registry Methods showsPrec :: Int -> StripeIndex -> ShowS # show :: StripeIndex -> String # showList :: [StripeIndex] -> ShowS # | |
| Eq StripeIndex Source # | |
Defined in Control.Monad.Foil.Registry | |
| Ord StripeIndex Source # | |
Defined in Control.Monad.Foil.Registry Methods compare :: StripeIndex -> StripeIndex -> Ordering # (<) :: StripeIndex -> StripeIndex -> Bool # (<=) :: StripeIndex -> StripeIndex -> Bool # (>) :: StripeIndex -> StripeIndex -> Bool # (>=) :: StripeIndex -> StripeIndex -> Bool # max :: StripeIndex -> StripeIndex -> StripeIndex # min :: StripeIndex -> StripeIndex -> StripeIndex # | |
Layouts
newtype StripeSize Source #
How many names a unit may declare: the width of every stripe a layout hands out. Its own type, so that a size cannot be confused with a name, an index, or a base.
Since: 0.4.0
Constructors
| StripeSize Int |
Instances
| Read StripeSize Source # | |
Defined in Control.Monad.Foil.Registry Methods readsPrec :: Int -> ReadS StripeSize # readList :: ReadS [StripeSize] # readPrec :: ReadPrec StripeSize # readListPrec :: ReadPrec [StripeSize] # | |
| Show StripeSize Source # | |
Defined in Control.Monad.Foil.Registry Methods showsPrec :: Int -> StripeSize -> ShowS # show :: StripeSize -> String # showList :: [StripeSize] -> ShowS # | |
| Eq StripeSize Source # | |
Defined in Control.Monad.Foil.Registry | |
| Ord StripeSize Source # | |
Defined in Control.Monad.Foil.Registry Methods compare :: StripeSize -> StripeSize -> Ordering # (<) :: StripeSize -> StripeSize -> Bool # (<=) :: StripeSize -> StripeSize -> Bool # (>) :: StripeSize -> StripeSize -> Bool # (>=) :: StripeSize -> StripeSize -> Bool # max :: StripeSize -> StripeSize -> StripeSize # min :: StripeSize -> StripeSize -> StripeSize # | |
newtype StripeLayout Source #
Where stripe i lies on the raw-name line.
The library does not choose: whether stripes descend below zero, ascend
from some base, or interleave with other reservations is a policy of the
client, and everything in Control.Monad.Foil.Blocks works from the
resulting NameRanges alone. A layout should give disjoint ranges to
distinct indices. Nothing checks this here, but
withDisjointUnion refuses the overlap at the
point where it would do harm.
Since: 0.4.0
Constructors
| StripeLayout | |
Fields
| |
stripesBelowZero :: StripeSize -> StripeLayout Source #
Stripe i is the i-th run of size names below zero, counting
downwards, so stripe 0 is [-size .. -1]. Within a stripe, allocation
still ascends (see withFreshIn), so declaration order
is ascending name order.
This layout leaves the whole non-negative range free for a client's local names.
>>>stripeRange (stripesBelowZero (StripeSize 100)) (StripeIndex 0)NameRange {nameRangeLo = -100, nameRangeHi = -1}>>>stripeRange (stripesBelowZero (StripeSize 100)) (StripeIndex 2)NameRange {nameRangeLo = -300, nameRangeHi = -201}
Since: 0.4.0
Arguments
| :: RawName | The base: the low end of stripe 0. |
| -> StripeSize | |
| -> StripeLayout |
Stripe i is the i-th run of size names at or above a base,
counting upwards, so stripe 0 is [base .. base + size - 1].
>>>stripeRange (stripesAbove 0 (StripeSize 100)) (StripeIndex 1)NameRange {nameRangeLo = 100, nameRangeHi = 199}
Since: 0.4.0
Local-region layouts
newtype RegionWidth Source #
How far apart consecutive local-region floors sit within a unit's runs. This is spacing, not a hard width: a run is open-ended above its floor, and a scope-driven allocator would have to hold this many names /in scope at once/ to reach the next floor.
Since: 0.4.0
Constructors
| RegionWidth Int |
Instances
| Read RegionWidth Source # | |
Defined in Control.Monad.Foil.Registry Methods readsPrec :: Int -> ReadS RegionWidth # readList :: ReadS [RegionWidth] # readPrec :: ReadPrec RegionWidth # readListPrec :: ReadPrec [RegionWidth] # | |
| Show RegionWidth Source # | |
Defined in Control.Monad.Foil.Registry Methods showsPrec :: Int -> RegionWidth -> ShowS # show :: RegionWidth -> String # showList :: [RegionWidth] -> ShowS # | |
| Eq RegionWidth Source # | |
Defined in Control.Monad.Foil.Registry | |
| Ord RegionWidth Source # | |
Defined in Control.Monad.Foil.Registry Methods compare :: RegionWidth -> RegionWidth -> Ordering # (<) :: RegionWidth -> RegionWidth -> Bool # (<=) :: RegionWidth -> RegionWidth -> Bool # (>) :: RegionWidth -> RegionWidth -> Bool # (>=) :: RegionWidth -> RegionWidth -> Bool # max :: RegionWidth -> RegionWidth -> RegionWidth # min :: RegionWidth -> RegionWidth -> RegionWidth # | |
newtype RegionsPerUnit Source #
How many runs of local names a unit may hold before its runs would
spill into the next unit's. A spill is not unsound for a client that
refreshes on clash. It only forfeits the disjointness described under
RegionLayout for the runs past the cap.
Since: 0.4.0
Constructors
| RegionsPerUnit Int |
Instances
| Read RegionsPerUnit Source # | |
Defined in Control.Monad.Foil.Registry Methods readsPrec :: Int -> ReadS RegionsPerUnit # readList :: ReadS [RegionsPerUnit] # | |
| Show RegionsPerUnit Source # | |
Defined in Control.Monad.Foil.Registry Methods showsPrec :: Int -> RegionsPerUnit -> ShowS # show :: RegionsPerUnit -> String # showList :: [RegionsPerUnit] -> ShowS # | |
| Eq RegionsPerUnit Source # | |
Defined in Control.Monad.Foil.Registry Methods (==) :: RegionsPerUnit -> RegionsPerUnit -> Bool # (/=) :: RegionsPerUnit -> RegionsPerUnit -> Bool # | |
| Ord RegionsPerUnit Source # | |
Defined in Control.Monad.Foil.Registry Methods compare :: RegionsPerUnit -> RegionsPerUnit -> Ordering # (<) :: RegionsPerUnit -> RegionsPerUnit -> Bool # (<=) :: RegionsPerUnit -> RegionsPerUnit -> Bool # (>) :: RegionsPerUnit -> RegionsPerUnit -> Bool # (>=) :: RegionsPerUnit -> RegionsPerUnit -> Bool # max :: RegionsPerUnit -> RegionsPerUnit -> RegionsPerUnit # min :: RegionsPerUnit -> RegionsPerUnit -> RegionsPerUnit # | |
data RegionLayout Source #
Where a unit's runs of local names lie: one open-ended region per
declaration (or command) of the unit, advanced with nextRegion as the
unit's declarations are processed.
Stripes make a unit's top-level names disjoint from every other unit's, and runs of local regions do the same for the names a checker invents inside a declaration. A term stored under one declaration then never collides with another declaration's live locals when it is reopened, so a refreshing substitution takes its no-rename fast path throughout.
The first run is derived from the unit's stripe index rather than from a counter shared across units, so a unit's elaboration depends only on the unit itself and editing a neighbour moves no name. That is the determinism a cache rests on.
The trade-off is that local names carry large offsets. A client that shows raw indices directly may prefer a single flat region, and accept the transient renames instead.
Since: 0.4.0
Constructors
| RegionLayout | |
Fields
| |
regionsAbove :: RawName -> RegionsPerUnit -> RegionWidth -> RegionLayout Source #
Runs ascending from a base: the unit with stripe index i starts its
runs at base + i * perUnit * width, and each declaration's floor sits
width above the previous one. The top of every run is open.
>>>let locals = regionsAbove 0 (RegionsPerUnit 0x10) (RegionWidth 0x100)>>>nameRangeLo (firstRegionOf locals (StripeIndex 2))8192>>>nameRangeLo (nextRegion locals (firstRegionOf locals (StripeIndex 2)))8448
Since: 0.4.0
The registry
type Registry name = Map name StripeIndex Source #
Which stripe each unit's declarations live in, by the unit's name.
Append-only: a name, once registered, keeps its stripe for the lifetime of the registry, and the next stripe index is always the registry's size.
Since: 0.4.0
emptyRegistry :: Registry name Source #
The registry before any unit has ever been checked.
Since: 0.4.0
registrySize :: Registry name -> Int Source #
How many units have been registered, which is also the next free stripe.
Since: 0.4.0
registerUnit :: Ord name => name -> Registry name -> (Registry name, StripeIndex) Source #
The stripe index of a unit, assigning the next one on first use.
Registration hands out the index and not a range. A unit's index
determines every reservation derived for it: its stripe under a
StripeLayout, and its runs of local names under a RegionLayout. The
layouts interpret the index, rather than being consulted here.
>>>let layout = stripesBelowZero (StripeSize 10)>>>let (r1, iA) = registerUnit "A" emptyRegistry>>>stripeRange layout iANameRange {nameRangeLo = -10, nameRangeHi = -1}>>>stripeRange layout (snd (registerUnit "B" r1))NameRange {nameRangeLo = -20, nameRangeHi = -11}
Registration is idempotent, which is the determinism a cache rests on:
>>>snd (registerUnit "A" r1) == iATrue
Since: 0.4.0