summaryrefslogtreecommitdiffstats
path: root/rtemsspec/validation.py
diff options
context:
space:
mode:
Diffstat (limited to 'rtemsspec/validation.py')
-rw-r--r--rtemsspec/validation.py146
1 files changed, 83 insertions, 63 deletions
diff --git a/rtemsspec/validation.py b/rtemsspec/validation.py
index c3034f85..e75aff95 100644
--- a/rtemsspec/validation.py
+++ b/rtemsspec/validation.py
@@ -467,8 +467,31 @@ class Transition(NamedTuple):
post_cond: Tuple[int, ...]
+class _TransitionEntry:
+ def __init__(self):
+ self.key = ""
+ self.variants = [] # type: List[Transition]
+
+ def __bool__(self):
+ return bool(self.variants)
+
+ def __getitem__(self, key):
+ return self.variants[key]
+
+ def __len__(self):
+ return len(self.variants)
+
+ def add(self, variant: Transition) -> None:
+ """ Adds the variant to the transitions of the entry. """
+ self.key += "".join(
+ (enabled_by_to_exp(variant.enabled_by,
+ ExpressionMapper()), str(variant.skip),
+ str(variant.pre_cond_na), str(variant.post_cond)))
+ self.variants.append(variant)
+
+
_IdxToX = Tuple[Tuple[str, ...], ...]
-_TransitionMap = List[List[Transition]]
+_TransitionMap = List[_TransitionEntry]
def _to_st_idx(conditions: List[Any]) -> Tuple[Dict[str, int], ...]:
@@ -619,8 +642,9 @@ class TransitionMap:
self._post_co_idx_to_co_name = dict(
(co_idx, condition["name"])
for co_idx, condition in enumerate(item["post-conditions"]))
+ self._entries = {} # type: Dict[str, List[Any]]
self._map = self._build_map()
- self._check_completeness()
+ self._post_process()
def __getitem__(self, key: str):
return self._item[key]
@@ -628,7 +652,7 @@ class TransitionMap:
def __iter__(self):
yield from self._map
- def _check_completeness(self) -> None:
+ def _post_process(self) -> None:
for map_idx, transitions in enumerate(self):
if not transitions or not isinstance(
transitions[0].enabled_by,
@@ -637,6 +661,14 @@ class TransitionMap:
f"transition map of {self._item.spec} contains no default "
"entry for pre-condition set "
f"{{{self._map_index_to_pre_conditions(map_idx)}}}")
+ entry = self._entries.get(transitions.key, [0, 0, transitions])
+ entry[0] += 1
+ self._entries[transitions.key] = entry
+ for index, entry in enumerate(
+ sorted(self._entries.values(),
+ key=lambda x: x[0],
+ reverse=True)):
+ entry[1] = index
def _map_index_to_pre_conditions(self, map_idx: int) -> str:
conditions = []
@@ -776,7 +808,7 @@ class TransitionMap:
f"{self._item.spec} is the first variant for "
f"{{{self._map_index_to_pre_conditions(map_idx)}}} "
"and it is not enabled by default")
- transition_map[map_idx].append(
+ transition_map[map_idx].add(
Transition(desc_idx, enabled_by, skip_post_cond[0],
pre_cond_na, post_cond))
@@ -786,7 +818,7 @@ class TransitionMap:
enabled_by = desc["enabled-by"]
for map_idx, transition in enumerate(transition_map):
if not transition:
- transition.append(
+ transition.add(
Transition(
desc_idx, enabled_by, skip_post_cond[0],
(0, ) * self._pre_co_count,
@@ -807,8 +839,7 @@ class TransitionMap:
raise ValueError(f"pre-condition '{condition['name']}' of "
f"{self._item.spec} has no states")
transition_count *= state_count
- transition_map = [list() for _ in range(transition_count)
- ] # type: _TransitionMap
+ transition_map = [_TransitionEntry() for _ in range(transition_count)]
for desc_idx, desc in enumerate(self["transition-map"]):
if isinstance(desc["post-conditions"], dict):
try:
@@ -833,25 +864,17 @@ class TransitionMap:
skip_post_cond)
return transition_map
- def _get_entry(self, variant: Transition) -> str:
- skip_pre_cond_na = (variant.skip, ) + variant.pre_cond_na
- for value in skip_pre_cond_na:
- if value != 0:
- text = "E( " + ", ".join(
- itertools.chain(
- map(str, skip_pre_cond_na),
- (self._post_co_idx_st_idx_to_st_name[co_idx][st_idx]
- for co_idx, st_idx in enumerate(variant.post_cond))))
- break
- else:
- text = "EZ( " + ", ".join(
- self._post_co_idx_st_idx_to_st_name[co_idx][st_idx]
- for co_idx, st_idx in enumerate(variant.post_cond))
+ def _get_entry(self, ident: str, variant: Transition) -> str:
+ text = "{ " + ", ".join(
+ itertools.chain(map(str, (variant.skip, ) + variant.pre_cond_na), (
+ (f"{ident}_Post_{self._post_co_idx_to_co_name[co_idx]}"
+ f"_{self._post_co_idx_st_idx_to_st_name[co_idx][st_idx]}")
+ for co_idx, st_idx in enumerate(variant.post_cond))))
wrapper = textwrap.TextWrapper()
wrapper.initial_indent = " "
- wrapper.subsequent_indent = " "
- wrapper.width = 75
- return "\n".join(wrapper.wrap(text)) + " ),"
+ wrapper.subsequent_indent = " "
+ wrapper.width = 79
+ return "\n".join(wrapper.wrap(text)) + " },"
def _get_entry_bits(self) -> int:
bits = self._pre_co_count + 1
@@ -859,42 +882,24 @@ class TransitionMap:
bits += math.ceil(math.log2(len(st_idx_to_st_name)))
return 2**max(math.ceil(math.log2(bits)), 3)
- def _add_entry_macro(self, content: CContent, ident: str, name: str,
- pre_count_0: int, pre_count_1: int) -> None:
- # pylint: disable=too-many-arguments
- entry = f"#define {name}( "
- entry += ", ".join(
- f"x{index}" for index in range(pre_count_0 + self._post_co_count))
- entry += ") { "
- entry += ", ".join(
- itertools.chain(
- (f"x{index}" for index in range(pre_count_0)),
- ("0" for index in range(pre_count_1)),
- (f"{ident}_Post_{condition['name']}_##x{pre_count_0 + co_idx}"
- for co_idx, condition in enumerate(self["post-conditions"]))))
- wrapper = textwrap.TextWrapper()
- wrapper.initial_indent = ""
- wrapper.subsequent_indent = " "
- wrapper.width = 77
- content.add(" \\\n".join(wrapper.wrap(entry)) + " }")
-
def add_map(self, content: CContent, ident: str) -> None:
""" Adds the transition map definitions to the content. """
entries = []
mapper = ExpressionMapper()
- for transistions in self._map:
- if len(transistions) == 1:
- entries.append(self._get_entry(transistions[0]))
+ for entry in sorted(self._entries.values(), key=lambda x: x[1]):
+ transitions = entry[2]
+ if len(transitions) == 1:
+ entries.append(self._get_entry(ident, transitions[0]))
else:
ifelse = "#if "
enumerators = [] # type: List[str]
- for variant in transistions[1:]:
+ for variant in transitions[1:]:
enumerators.append(
ifelse + enabled_by_to_exp(variant.enabled_by, mapper))
- enumerators.append(self._get_entry(variant))
+ enumerators.append(self._get_entry(ident, variant))
ifelse = "#elif "
enumerators.append("#else")
- enumerators.append(self._get_entry(transistions[0]))
+ enumerators.append(self._get_entry(ident, transitions[0]))
enumerators.append("#endif")
entries.append("\n".join(enumerators))
bits = self._get_entry_bits()
@@ -908,13 +913,21 @@ class TransitionMap:
content.append(
f"uint{bits}_t Post_{condition['name']} : {state_bits};")
content.add(f"}} {ident}_Entry;")
- pre_count = 1 + self._pre_co_count
- self._add_entry_macro(content, ident, "E", pre_count, 0)
- self._add_entry_macro(content, ident, "EZ", 0, pre_count)
- content.add([f"static const {ident}_Entry", f"{ident}_Map[] = {{"])
- entries[-1] = entries[-1].replace("),", ")")
+ content.add([f"static const {ident}_Entry", f"{ident}_Entries[] = {{"])
+ entries[-1] = entries[-1].replace("},", "}")
content.append(entries)
- content.append(["};", "", "#undef E", "#undef EZ"])
+ bits = math.ceil(math.log2(len(self._entries)) / 8) * 8
+ content.append(
+ ["};", "", f"static const uint{bits}_t", f"{ident}_Map[] = {{"])
+ text = ", ".join(
+ str(self._entries[transitions.key][1])
+ for transitions in self._map)
+ wrapper = textwrap.TextWrapper()
+ wrapper.initial_indent = " "
+ wrapper.subsequent_indent = " "
+ wrapper.width = 79
+ content.append(wrapper.wrap(text))
+ content.append("};")
def get_post_entry_member(self, co_idx: int) -> str:
"""
@@ -996,7 +1009,7 @@ class _ActionRequirementTestItem(_TestItem):
def _add_loop_body(self, content: CContent,
transition_map: TransitionMap) -> None:
- with content.condition(f"{self.ident}_Map[ index ].Skip"):
+ with content.condition("entry.Skip"):
content.append(["++index;", "continue;"])
content.add_blank_line()
self._add_call(content, "test-prepare", "Prepare")
@@ -1005,7 +1018,6 @@ class _ActionRequirementTestItem(_TestItem):
content.call_function(None, f"{enum[0]}_Prepare",
["ctx", f"ctx->pcs[ {index} ]"])
self._add_call(content, "test-action", "Action")
- content.append(f"entry = {self.ident}_Map[ index ];")
for index, enum in enumerate(self._post_co_idx_to_enum):
content.gap = False
content.call_function(None, f"{enum[0]}_Check", [
@@ -1022,11 +1034,10 @@ class _ActionRequirementTestItem(_TestItem):
end = self._pre_co_idx_to_enum[index][-1]
with content.for_loop(f"{var} = {begin}", f"{var} < {end}",
f"++{var}"):
- if index + 1 == self._pre_co_count:
- content.add(f"{self.ident}_Entry entry;")
name = self._item['pre-conditions'][index]["name"]
- pre_na = f"{self.ident}_Map[ index ].Pre_{name}_NA"
- with content.condition(pre_na):
+ content.call_function("entry =", f"{self.ident}_GetEntry",
+ ["index"])
+ with content.condition(f"entry.Pre_{name}_NA"):
content.append(f"{var} = {end};")
content.append(f"index += ( {end} - 1 )")
for index_2 in range(index + 1, self._pre_co_count):
@@ -1040,6 +1051,15 @@ class _ActionRequirementTestItem(_TestItem):
def _add_test_case(self, content: CContent, transition_map: TransitionMap,
header: Dict[str, Any]) -> None:
+ ret = f"static inline {self.ident}_Entry"
+ name = f"{self.ident}_GetEntry"
+ params = ["size_t index"]
+ with content.function(ret, name, params, align=True):
+ content.add([
+ f"return {self.ident}_Entries[",
+ f" {self.ident}_Map[ index ]", "];"
+ ])
+ entry = f"{self.ident}_Entry entry;"
fixture = f"{self.ident}_Fixture"
prologue = CContent()
epilogue = CContent()
@@ -1048,7 +1068,7 @@ class _ActionRequirementTestItem(_TestItem):
ret = "void"
name = f"{self.ident}_Run"
params = self._get_run_params(header)
- prologue.add([f"{self.context} *ctx;", "size_t index;"])
+ prologue.add([f"{self.context} *ctx;", entry, "size_t index;"])
prologue.call_function("ctx =", "T_push_fixture",
[f"&{self.ident}_Node", f"&{fixture}"])
prologue.add([
@@ -1066,7 +1086,7 @@ class _ActionRequirementTestItem(_TestItem):
name = "T_TEST_CASE_FIXTURE"
params = [f"{self.ident}", f"&{fixture}"]
prologue.add([
- f"{self.context} *ctx;", "size_t index;", "",
+ f"{self.context} *ctx;", entry, "size_t index;", "",
"ctx = T_fixture_context();", "ctx->in_action_loop = true;",
"index = 0;"
])