A Scala library for Context-Dependent Environments, where a key-value environment is passed down a module hierarchy and each returned value depends on the key and the query’s origin. CDE is provably superior to existing parameterization schemes because it avoids introducing non-local source code changes when a design is modified, while also enabling features for large-scale design space exploration of compositions of generators.
User Guide
The library presents its key-value storage under an abstract class Parameters. Values stored in Parameters are each associated with a case object extends Field[T].
The main interface for user to create a Parameters object is using Config object. Its apply method takes (View, View, View) => PartialFunction[Any, Any] as a lookup table.
//Field MyKey1 contains value of type Int
case object MyKey1 extends Field[Int]
//Field MyKey2 contains value of type String, with default value "None"
case object MyKey2 extends Field[String]("None")
// The meaning of parameter (site, here, up) will be explained later
val p: Parameters = Config((site, here, up) => {
case MyKey1 => 0
case MyKey2 => "MyValue"
})
// Apply Paramaters object to Field to query
assert(p(MyKey1) == 0)
Parameter Overrides
We can use one Parameters to override another. Each single Config is like a row in a table, while each Field is a column in the table. To concat two table together, we have alter and orElse methods.
alter puts the rhs at bottom of the table and orElse puts the rhs at top of the table.
A query will inspect the table from bottom to up, row by row, until it finds the first row having the key defined.
For example: Config1.alter(Config2).alter(Config3) yields
Key1
Key2
Key3
…
Config1
V1
Config2
V2
V3
Config3
V4
And now p(Key1) == V2, p(Key2) == V3 and p(Key3) == V4.
The same Parameters can also be defined by Config3.orElse(Config2).orElse(Config1). There is also deprecated shorthand ++ for orElse, so Config3 ++ Config2 ++ Config1 is also valid.
Environment Reference
Each query contains the entire environment of where the query originates. This is pass to the lookup table of each Config by (site, here, up) arguments.
here dynamically refers to the current row of the table
up dynamically refers to the rows appearing up than the current row
site dynamically refers to the entire table. When it gets called by here or up queries, it still refers to the entire table instead of current row or upper half as indicated by here or up respectively.
For example, in the following Parameters
Key1
Key2
Key3
Key4
Config1
1
site(Key1)
Config2
2
here(Key1)
up(Key2)
Config3
3
The value for each key is
Key1: 3, given by Config3
Key2: 3, as it is value of Key1 in the entire table
Key3: 2, as it is value of Key1 defined in the current row
Key4: 3, as it is value of Key2 defined in the upper row, which is in turn value of Key1 defined in the table, which should be 3 as overriden by Config3.
If one config layer does not refer environment at all, alterMap and alterPartial can be used to avoid create a redundant Config object, as they accept Map and PartialFunction as their parameter.
Implementation Details
This section discusses the internal data structure used to track environment information. Normal reader can skip the section.
alter and orElse function wraps two operand as ChainParameters, which forms a binary tree when alter are called multiple times. Query on ChainParameters calls chain method.
The chain method traverses the tree by wrapping the right child in ChainView, which records up for later reference, and invoking chain on the left child. This happens recursively until a leaf node is found. Then if the requested key is not in the node, we can turn to chain of currently up node.
The following figure illustrates a querying process of Parameters constructed by C1.alter(C2).alter(C3).orElse(C4). chain is invoked on the node in blue, and ChainView generated is in red.
CDE
A Scala library for Context-Dependent Environments, where a key-value environment is passed down a module hierarchy and each returned value depends on the key and the query’s origin. CDE is provably superior to existing parameterization schemes because it avoids introducing non-local source code changes when a design is modified, while also enabling features for large-scale design space exploration of compositions of generators.
User Guide
The library presents its key-value storage under an abstract class
Parameters. Values stored inParametersare each associated with a case object extendsField[T].The main interface for user to create a
Parametersobject is usingConfigobject. Itsapplymethod takes(View, View, View) => PartialFunction[Any, Any]as a lookup table.Parameter Overrides
We can use one
Parametersto override another. Each singleConfigis like a row in a table, while eachFieldis a column in the table. To concat two table together, we havealterandorElsemethods.alterputs the rhs at bottom of the table andorElseputs the rhs at top of the table.A query will inspect the table from bottom to up, row by row, until it finds the first row having the key defined.
For example:
Config1.alter(Config2).alter(Config3)yieldsConfig1Config2Config3And now
p(Key1) == V2,p(Key2) == V3andp(Key3) == V4.The same
Parameterscan also be defined byConfig3.orElse(Config2).orElse(Config1). There is also deprecated shorthand++fororElse, soConfig3 ++ Config2 ++ Config1is also valid.Environment Reference
Each query contains the entire environment of where the query originates. This is pass to the lookup table of each
Configby(site, here, up)arguments.heredynamically refers to the current row of the tableupdynamically refers to the rows appearing up than the current rowsitedynamically refers to the entire table. When it gets called byhereorupqueries, it still refers to the entire table instead of current row or upper half as indicated byhereoruprespectively.For example, in the following
ParametersConfig1site(Key1)Config2here(Key1)up(Key2)Config3The value for each key is
Config3Key1in the entire tableKey1defined in the current rowKey2defined in the upper row, which is in turn value ofKey1defined in the table, which should be 3 as overriden byConfig3.If one config layer does not refer environment at all,
alterMapandalterPartialcan be used to avoid create a redundantConfigobject, as they acceptMapandPartialFunctionas their parameter.Implementation Details
This section discusses the internal data structure used to track environment information. Normal reader can skip the section.
alterandorElsefunction wraps two operand asChainParameters, which forms a binary tree whenalterare called multiple times. Query onChainParameterscallschainmethod.The
chainmethod traverses the tree by wrapping the right child inChainView, which recordsupfor later reference, and invokingchainon the left child. This happens recursively until a leaf node is found. Then if the requested key is not in the node, we can turn tochainof currentlyupnode.The following figure illustrates a querying process of
Parametersconstructed byC1.alter(C2).alter(C3).orElse(C4).chainis invoked on the node in blue, andChainViewgenerated is in red.