[rtems-central commit] validation: Split file

Sebastian Huber sebh at rtems.org
Wed Jun 16 17:10:18 UTC 2021


Module:    rtems-central
Branch:    master
Commit:    cdb62c9f8cd591297bff1c3384dc56d5c752a7bd
Changeset: http://git.rtems.org/rtems-central/commit/?id=cdb62c9f8cd591297bff1c3384dc56d5c752a7bd

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Wed Jun 16 19:06:38 2021 +0200

validation: Split file

---

 rtemsspec/transitionmap.py | 670 +++++++++++++++++++++++++++++++++++++++++++++
 rtemsspec/validation.py    | 645 +------------------------------------------
 specview.py                |   2 +-
 3 files changed, 676 insertions(+), 641 deletions(-)

diff --git a/rtemsspec/transitionmap.py b/rtemsspec/transitionmap.py
new file mode 100644
index 0000000..c7f2193
--- /dev/null
+++ b/rtemsspec/transitionmap.py
@@ -0,0 +1,670 @@
+# SPDX-License-Identifier: BSD-2-Clause
+"""
+This module provides the Transition and TransitionMap classes used to work with
+action requirements.
+"""
+
+# Copyright (C) 2020, 2021 embedded brains GmbH (http://www.embedded-brains.de)
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import itertools
+import math
+import textwrap
+from typing import Any, Dict, Iterator, List, NamedTuple, Optional, Tuple
+
+from rtemsspec.content import CContent, enabled_by_to_exp, ExpressionMapper
+from rtemsspec.items import is_enabled, Item
+
+
+class Transition(NamedTuple):
+    """ Represents a action requirement transition map entry.  """
+    desc_idx: int
+    enabled_by: Any
+    skip: int
+    pre_cond_na: Tuple[int, ...]
+    post_cond: Tuple[Any, ...]
+
+
+def _variant_to_key(variant: Transition) -> str:
+    return "".join((enabled_by_to_exp(variant.enabled_by,
+                                      ExpressionMapper()), str(variant.skip),
+                    str(variant.pre_cond_na), str(variant.post_cond)))
+
+
+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 += _variant_to_key(variant)
+        self.variants.append(variant)
+
+    def replace(self, index: int, variant: Transition) -> None:
+        """ Replace the variant at transition variant index. """
+        self.key = self.key.replace(_variant_to_key(self.variants[index]),
+                                    _variant_to_key(variant))
+        self.variants[index] = variant
+
+
+_TransitionMap = List[_TransitionEntry]
+
+
+def _to_st_idx(conditions: List[Any]) -> Tuple[Dict[str, int], ...]:
+    return tuple(
+        dict((state["name"], st_idx) for st_idx, state in enumerate(
+            itertools.chain(condition["states"], [{
+                "name": "N/A"
+            }]))) for condition in conditions)
+
+
+def _to_st_name(conditions: List[Any]) -> Tuple[Tuple[str, ...], ...]:
+    return tuple(
+        tuple(
+            itertools.chain((state["name"]
+                             for state in condition["states"]), ["NA"]))
+        for condition in conditions)
+
+
+class _PostCondContext(NamedTuple):
+    transition_map: "TransitionMap"
+    map_idx: int
+    pre_co_states: Tuple[int, ...]
+    post_co_states: Tuple[Any, ...]
+    post_co_idx: int
+    ops: Any
+
+
+def _post_cond_bool_and(ctx: _PostCondContext, exp: Any) -> bool:
+    for element in exp:
+        if not _post_cond_bool_exp(ctx, element):
+            return False
+    return True
+
+
+def _post_cond_bool_not(ctx: _PostCondContext, exp: Any) -> bool:
+    return not _post_cond_bool_exp(ctx, exp)
+
+
+def _post_cond_bool_or(ctx: _PostCondContext, exp: Any) -> bool:
+    for element in exp:
+        if _post_cond_bool_exp(ctx, element):
+            return True
+    return False
+
+
+def _post_cond_bool_post_cond(ctx: _PostCondContext, exp: Any) -> bool:
+    for post_co_name, status in exp.items():
+        if isinstance(status, str):
+            status = [status]
+        post_co_idx = ctx.transition_map.post_co_name_to_co_idx(post_co_name)
+        st_idx = [
+            ctx.transition_map.post_co_idx_st_name_to_st_idx(
+                post_co_idx, st_name) for st_name in status
+        ]
+        if ctx.post_co_states[post_co_idx] not in st_idx:
+            return False
+    return True
+
+
+def _post_cond_bool_pre_cond(ctx: _PostCondContext, exp: Any) -> bool:
+    for pre_co_name, status in exp.items():
+        if isinstance(status, str):
+            status = [status]
+        pre_co_idx = ctx.transition_map.pre_co_name_to_co_idx(pre_co_name)
+        st_idx = [
+            ctx.transition_map.pre_co_idx_st_name_to_st_idx(
+                pre_co_idx, st_name) for st_name in status
+        ]
+        if ctx.pre_co_states[pre_co_idx] not in st_idx:
+            return False
+    return True
+
+
+_POST_COND_BOOL_OPS = {
+    "and": _post_cond_bool_and,
+    "not": _post_cond_bool_not,
+    "or": _post_cond_bool_or,
+    "post-conditions": _post_cond_bool_post_cond,
+    "pre-conditions": _post_cond_bool_pre_cond,
+}
+
+
+def _post_cond_bool_exp(ctx: _PostCondContext, exp: Any) -> Optional[int]:
+    if isinstance(exp, list):
+        return _post_cond_bool_or(ctx, exp)
+    key = next(iter(exp))
+    return _POST_COND_BOOL_OPS[key](ctx, exp[key])
+
+
+def _post_cond_do_specified_by(ctx: _PostCondContext, pre_co_name: str) -> int:
+    pre_co_idx = ctx.transition_map.pre_co_name_to_co_idx(pre_co_name)
+    st_name = ctx.transition_map.pre_co_idx_st_idx_to_st_name(
+        pre_co_idx, ctx.pre_co_states[pre_co_idx])
+    return ctx.transition_map.post_co_idx_st_name_to_st_idx(
+        ctx.post_co_idx, st_name)
+
+
+def _post_cond_if(ctx: _PostCondContext) -> Optional[int]:
+    if _post_cond_bool_exp(ctx, ctx.ops["if"]):
+        if "then-specified-by" in ctx.ops:
+            return _post_cond_do_specified_by(ctx,
+                                              ctx.ops["then-specified-by"])
+        return ctx.transition_map.post_co_idx_st_name_to_st_idx(
+            ctx.post_co_idx, ctx.ops["then"])
+    return None
+
+
+def _post_cond_specified_by(ctx: _PostCondContext) -> Optional[int]:
+    return _post_cond_do_specified_by(ctx, ctx.ops["specified-by"])
+
+
+def _post_cond_else(ctx: _PostCondContext) -> Optional[int]:
+    return ctx.transition_map.post_co_idx_st_name_to_st_idx(
+        ctx.post_co_idx, ctx.ops["else"])
+
+
+_POST_COND_OP = {
+    "else": _post_cond_else,
+    "if": _post_cond_if,
+    "specified-by": _post_cond_specified_by,
+}
+
+PostCond = Tuple[int, ...]
+
+PreCondsOfPostCond = List[Tuple[List[int], ...]]
+
+
+def _compact(pre_conds: PreCondsOfPostCond) -> PreCondsOfPostCond:
+    while True:
+        last = pre_conds[0]
+        combined_pre_conds = [last]
+        combined_count = 0
+        for row in pre_conds[1:]:
+            diff = [
+                index for index, states in enumerate(last)
+                if states != row[index]
+            ]
+            if len(diff) == 1:
+                index = diff[0]
+                combined_count += 1
+                last[index].extend(row[index])
+            else:
+                combined_pre_conds.append(row)
+                last = row
+        pre_conds = combined_pre_conds
+        if combined_count == 0:
+            break
+    return pre_conds
+
+
+def _compact_more(pre_conds: PreCondsOfPostCond) -> PreCondsOfPostCond:
+    while True:
+        combined_count = 0
+        next_pre_conds = []
+        while pre_conds:
+            first = pre_conds.pop(0)
+            next_pre_conds.append(first)
+            for row in pre_conds:
+                diff = [
+                    index for index, states in enumerate(first)
+                    if states != row[index]
+                ]
+                if len(diff) <= 1:
+                    if diff:
+                        index = diff[0]
+                        first[index].extend(row[index])
+                    combined_count += 1
+                    pre_conds.remove(row)
+        pre_conds = next_pre_conds
+        if combined_count == 0:
+            break
+    return pre_conds
+
+
+class TransitionMap:
+    """ Representation of an action requirement transition map. """
+
+    # pylint: disable=too-many-instance-attributes
+    def __init__(self, item: Item):
+        self._item = item
+        self._pre_co_count = len(item["pre-conditions"])
+        self._post_co_count = len(item["post-conditions"])
+        self.pre_co_summary = tuple(0 for _ in range(self._pre_co_count + 1))
+        self._pre_co_idx_st_idx_to_st_name = _to_st_name(
+            item["pre-conditions"])
+        self._post_co_idx_st_idx_to_st_name = _to_st_name(
+            item["post-conditions"])
+        self._pre_co_idx_st_name_to_st_idx = _to_st_idx(item["pre-conditions"])
+        self._post_co_idx_st_name_to_st_idx = _to_st_idx(
+            item["post-conditions"])
+        self._pre_co_idx_to_cond = dict(
+            (co_idx, condition)
+            for co_idx, condition in enumerate(item["pre-conditions"]))
+        self._pre_co_name_to_co_idx = dict(
+            (condition["name"], co_idx)
+            for co_idx, condition in enumerate(item["pre-conditions"]))
+        self._post_co_name_to_co_idx = dict(
+            (condition["name"], co_idx)
+            for co_idx, condition in enumerate(item["post-conditions"]))
+        self._post_co_idx_to_co_name = dict(
+            (co_idx, condition["name"])
+            for co_idx, condition in enumerate(item["post-conditions"]))
+        self._skip_idx_to_name = dict(
+            (skip_idx + 1, key)
+            for skip_idx, key in enumerate(item["skip-reasons"].keys()))
+        self._skip_name_to_idx = dict(
+            (key, skip_idx + 1)
+            for skip_idx, key in enumerate(item["skip-reasons"].keys()))
+        self._entries = {}  # type: Dict[str, List[Any]]
+        self._map = self._build_map()
+        self._post_process()
+
+    def __getitem__(self, key: str):
+        return self._item[key]
+
+    def __iter__(self):
+        yield from self._map
+
+    def entries(self) -> Iterator[List[Any]]:
+        """ Yields the transition map entry variants sorted by frequency. """
+        yield from sorted(self._entries.values(), key=lambda x: x[1])
+
+    def get_variants(self,
+                     enabled: List[str]) -> Iterator[Tuple[int, Transition]]:
+        """
+        Yields the map index and the transition variants enabled by the enabled
+        list.
+        """
+        for map_idx, transitions in enumerate(self._map):
+            for variant in transitions[1:]:
+                if is_enabled(enabled, variant.enabled_by):
+                    break
+            else:
+                variant = transitions[0]
+            yield map_idx, variant
+
+    def get_post_conditions(
+            self, enabled: List[str]
+    ) -> Iterator[Tuple[PostCond, PreCondsOfPostCond]]:
+        """
+        Yields tuples of post-condition variants and the corresponding
+        pre-condition variants which are enabled by the enabled list.
+
+        The first entry of the post-condition variant is the skip index.  The
+        remaining entries are post-condition indices.  The pre-condition
+        variants are a list of tuples.  Each tuple entry corresponds to a
+        pre-condition and provides a list of corresponding pre-condition state
+        indices.
+        """
+        entries = {}  # type: Dict[PostCond, PreCondsOfPostCond]
+        for map_idx, variant in self.get_variants(enabled):
+            key = (variant.skip, ) + variant.post_cond
+            entry = entries.setdefault(key, [])
+            entry.append(
+                tuple([state] for state in self.map_idx_to_pre_co_states(
+                    map_idx, variant.pre_cond_na)))
+        for post_cond, pre_conds in sorted(entries.items(),
+                                           key=lambda x: (x[0][0], len(x[1]))):
+            pre_conds = _compact_more(_compact(pre_conds))
+            yield post_cond, pre_conds
+
+    def _post_process(self) -> None:
+        for map_idx, transitions in enumerate(self):
+            if not transitions or not isinstance(
+                    transitions[0].enabled_by,
+                    bool) or not transitions[0].enabled_by:
+                raise ValueError(
+                    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.setdefault(transitions.key,
+                                             [0, 0, transitions, []])
+            entry[0] += 1
+            entry[3].append(map_idx)
+        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 = []
+        for condition in reversed(self._item["pre-conditions"]):
+            states = condition["states"]
+            count = len(states)
+            st_idx = int(map_idx % count)
+            conditions.append(f"{condition['name']}={states[st_idx]['name']}")
+            map_idx //= count
+        return ", ".join(reversed(conditions))
+
+    def map_idx_to_pre_co_states(
+            self, map_idx: int, pre_cond_na: Tuple[int,
+                                                   ...]) -> Tuple[int, ...]:
+        """
+        Maps the transition map index and the associated pre-condition state
+        indices.
+        """
+        co_states = []
+        for condition in reversed(self._item["pre-conditions"]):
+            count = len(condition["states"])
+            co_states.append(count if pre_cond_na[self._pre_co_name_to_co_idx[
+                condition["name"]]] else int(map_idx % count))
+            map_idx //= count
+        return tuple(reversed(co_states))
+
+    def pre_co_name_to_co_idx(self, co_name: str) -> int:
+        """
+        Maps the pre-condition name to the associated pre-condition index.
+        """
+        return self._pre_co_name_to_co_idx[co_name]
+
+    def pre_co_idx_to_co_name(self, co_idx: int) -> str:
+        """
+        Maps the pre-condition index to the associated pre-condition name.
+        """
+        return self._pre_co_idx_to_cond[co_idx]["name"]
+
+    def post_co_name_to_co_idx(self, co_name: str) -> int:
+        """
+        Maps the post-condition name to the associated post-condition index.
+        """
+        return self._post_co_name_to_co_idx[co_name]
+
+    def post_co_idx_to_co_name(self, co_idx: int) -> str:
+        """
+        Maps the post-condition index to the associated post-condition name.
+        """
+        return self._post_co_idx_to_co_name[co_idx]
+
+    def pre_co_idx_st_idx_to_st_name(self, co_idx: int, st_idx: int) -> str:
+        """
+        Maps the pre-condition name and state index to the associated state
+        name.
+        """
+        return self._pre_co_idx_st_idx_to_st_name[co_idx][st_idx]
+
+    def post_co_idx_st_idx_to_st_name(self, co_idx: int, st_idx: int) -> str:
+        """
+        Maps the post-condition name and state index to the associated state
+        name.
+        """
+        return self._post_co_idx_st_idx_to_st_name[co_idx][st_idx]
+
+    def pre_co_idx_st_name_to_st_idx(self, co_idx: int, st_name: str) -> int:
+        """
+        Maps the pre-condition index and state name to the associated state
+        index.
+        """
+        return self._pre_co_idx_st_name_to_st_idx[co_idx][st_name]
+
+    def post_co_idx_st_name_to_st_idx(self, co_idx: int, st_name: str) -> int:
+        """
+        Maps the post-condition index and state name to the associated state
+        index.
+        """
+        return self._post_co_idx_st_name_to_st_idx[co_idx][st_name]
+
+    def skip_idx_to_name(self, skip_idx: int) -> str:
+        """
+        Maps the skip index the associated skip name index.
+        """
+        return self._skip_idx_to_name[skip_idx]
+
+    def _map_post_cond(self, map_idx: int, co_idx: int,
+                       variant: Transition) -> Transition:
+        if isinstance(variant.post_cond[co_idx], int):
+            return variant
+        pre_co_states = self.map_idx_to_pre_co_states(map_idx,
+                                                      variant.pre_cond_na)
+        for ops in variant.post_cond[co_idx]:
+            idx = _POST_COND_OP[next(iter(ops))](_PostCondContext(
+                self, map_idx, pre_co_states, variant.post_cond, co_idx, ops))
+            if idx is not None:
+                return Transition(
+                    variant.desc_idx, variant.enabled_by, variant.skip,
+                    variant.pre_cond_na, variant.post_cond[0:co_idx] +
+                    (idx, ) + variant.post_cond[co_idx + 1:])
+        raise ValueError(
+            "cannot determine state for post-condition "
+            f"'{self._post_co_idx_to_co_name[co_idx]}' of transition map "
+            f"descriptor {variant.desc_idx} of {self._item.spec} for "
+            "pre-condition set "
+            f"{{{self._map_index_to_pre_conditions(map_idx)}}}")
+
+    def _make_post_cond(self, map_idx: int, variant: Transition) -> Transition:
+        for co_idx in range(len(variant.post_cond)):
+            variant = self._map_post_cond(map_idx, co_idx, variant)
+        return variant
+
+    def _add_variant(self, transition_map: _TransitionMap, map_idx: int,
+                     variant: Transition) -> None:
+        if transition_map[map_idx]:
+            for index, existing in enumerate(transition_map[map_idx].variants):
+                if existing.enabled_by == variant.enabled_by:
+                    if variant.skip:
+                        # Allow transition map variants with a skip reason to
+                        # overwrite existing variants with the same enabled-by
+                        # attribute.  This is important if variants use N/A for
+                        # some pre-conditions.  It makes it also easier to skip
+                        # pre-conditon states which are controlled by build
+                        # options.
+                        transition_map[map_idx].replace(index, variant)
+                        return
+                    raise ValueError(
+                        f"transition map descriptor {variant.desc_idx} of "
+                        f"{self._item.spec} duplicates pre-condition set "
+                        f"{{{self._map_index_to_pre_conditions(map_idx)}}}"
+                        " defined by transition map descriptor "
+                        f"{existing.desc_idx}")
+            default = transition_map[map_idx][0]
+            if (default.post_cond, default.skip,
+                    default.pre_cond_na) == (variant.post_cond, variant.skip,
+                                             variant.pre_cond_na):
+                return
+        elif not isinstance(variant.enabled_by,
+                            bool) or not variant.enabled_by:
+            raise ValueError(
+                f"transition map descriptor {variant.desc_idx} of "
+                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")
+        self.pre_co_summary = tuple(
+            a + b for a, b in zip(self.pre_co_summary, (variant.skip, ) +
+                                  variant.pre_cond_na))
+        transition_map[map_idx].add(variant)
+
+    def _add_transitions(self, transition_map: _TransitionMap,
+                         desc: Dict[str, Any], desc_idx: int,
+                         skip_post_cond: Tuple[Any, ...], co_idx: int,
+                         map_idx: int, pre_cond_na: Tuple[int, ...]) -> None:
+        # pylint: disable=too-many-arguments
+        # pylint: disable=too-many-locals
+        if co_idx < self._pre_co_count:
+            condition = self._pre_co_idx_to_cond[co_idx]
+            state_count = len(condition["states"])
+            map_idx *= state_count
+            states = desc["pre-conditions"][condition["name"]]
+            if isinstance(states, str):
+                assert states in ["all", "N/A"]
+                for st_idx in range(state_count):
+                    self._add_transitions(
+                        transition_map, desc, desc_idx, skip_post_cond,
+                        co_idx + 1, map_idx + st_idx,
+                        pre_cond_na + (int(states == "N/A"), ))
+            else:
+                for st_name in states:
+                    try:
+                        st_idx = self._pre_co_idx_st_name_to_st_idx[co_idx][
+                            st_name]
+                    except KeyError as err:
+                        msg = (f"transition map descriptor {desc_idx} of "
+                               f"{self._item.spec} refers to non-existent "
+                               f"state {err} of pre-condition "
+                               f"'{condition['name']}'")
+                        raise ValueError(msg) from err
+                    self._add_transitions(transition_map, desc, desc_idx,
+                                          skip_post_cond, co_idx + 1,
+                                          map_idx + st_idx,
+                                          pre_cond_na + (0, ))
+        else:
+            variant = self._make_post_cond(
+                map_idx,
+                Transition(desc_idx, desc["enabled-by"], skip_post_cond[0],
+                           pre_cond_na, skip_post_cond[1:]))
+            self._add_variant(transition_map, map_idx, variant)
+
+    def _add_default(self, transition_map: _TransitionMap, desc: Dict[str,
+                                                                      Any],
+                     desc_idx: int, skip_post_cond: Tuple[int, ...]) -> None:
+        enabled_by = desc["enabled-by"]
+        for map_idx, transition in enumerate(transition_map):
+            if not transition:
+                transition.add(
+                    self._make_post_cond(
+                        map_idx,
+                        Transition(desc_idx, enabled_by, skip_post_cond[0],
+                                   (0, ) * self._pre_co_count,
+                                   skip_post_cond[1:])))
+
+    def _get_post_cond(self, desc: Dict[str, Any], co_idx: int) -> Any:
+        info = desc["post-conditions"][self._post_co_idx_to_co_name[co_idx]]
+        if isinstance(info, str):
+            return self._post_co_idx_st_name_to_st_idx[co_idx][info]
+        return info
+
+    def _build_map(self) -> _TransitionMap:
+        transition_count = 1
+        for condition in self["pre-conditions"]:
+            state_count = len(condition["states"])
+            if state_count == 0:
+                raise ValueError(f"pre-condition '{condition['name']}' of "
+                                 f"{self._item.spec} has no states")
+            transition_count *= state_count
+        transition_map = [_TransitionEntry() for _ in range(transition_count)]
+        for desc_idx, desc in enumerate(self["transition-map"]):
+            if isinstance(desc["post-conditions"], dict):
+                try:
+                    skip_post_cond = (0, ) + tuple(
+                        self._get_post_cond(desc, co_idx)
+                        for co_idx in range(self._post_co_count))
+                except KeyError as err:
+                    msg = (f"transition map descriptor {desc_idx} of "
+                           f"{self._item.spec} refers to non-existent "
+                           f"post-condition state {err}")
+                    raise ValueError(msg) from err
+            else:
+                skip_post_cond = (
+                    self._skip_name_to_idx[desc["post-conditions"]], ) + tuple(
+                        self._post_co_idx_st_name_to_st_idx[co_idx]["N/A"]
+                        for co_idx in range(self._post_co_count))
+            if isinstance(desc["pre-conditions"], dict):
+                self._add_transitions(transition_map, desc, desc_idx,
+                                      skip_post_cond, 0, 0, ())
+            else:
+                assert desc["pre-conditions"] == "default"
+                self._add_default(transition_map, desc, desc_idx,
+                                  skip_post_cond)
+        return transition_map
+
+    def _get_entry(self, ident: str, variant: Transition) -> str:
+        text = "{ " + ", ".join(
+            itertools.chain(
+                map(str, (int(variant.skip != 0), ) + 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 = 79
+        return "\n".join(wrapper.wrap(text)) + " },"
+
+    def _get_entry_bits(self) -> int:
+        bits = self._pre_co_count + 1
+        for st_idx_to_st_name in self._post_co_idx_st_idx_to_st_name:
+            bits += math.ceil(math.log2(len(st_idx_to_st_name)))
+        return 2**max(math.ceil(math.log2(bits)), 3)
+
+    def add_map(self, content: CContent, ident: str) -> None:
+        """ Adds the transition map definitions to the content. """
+        entries = []
+        mapper = ExpressionMapper()
+        for entry in self.entries():
+            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 transitions[1:]:
+                    enumerators.append(
+                        ifelse + enabled_by_to_exp(variant.enabled_by, mapper))
+                    enumerators.append(self._get_entry(ident, variant))
+                    ifelse = "#elif "
+                enumerators.append("#else")
+                enumerators.append(self._get_entry(ident, transitions[0]))
+                enumerators.append("#endif")
+                entries.append("\n".join(enumerators))
+        bits = self._get_entry_bits()
+        content.add("typedef struct {")
+        with content.indent():
+            content.append(f"uint{bits}_t Skip : 1;")
+            for condition in self["pre-conditions"]:
+                content.append(f"uint{bits}_t Pre_{condition['name']}_NA : 1;")
+            for condition in self["post-conditions"]:
+                state_bits = math.ceil(math.log2(len(condition["states"]) + 1))
+                content.append(
+                    f"uint{bits}_t Post_{condition['name']} : {state_bits};")
+        content.add(f"}} {ident}_Entry;")
+        content.add([f"static const {ident}_Entry", f"{ident}_Entries[] = {{"])
+        entries[-1] = entries[-1].replace("},", "}")
+        content.append(entries)
+        bits = max(8, 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:
+        """
+        Gets the post-condition entry member name for the post-condition index.
+        """
+        return f"Post_{self._post_co_idx_to_co_name[co_idx]}"
diff --git a/rtemsspec/validation.py b/rtemsspec/validation.py
index 70ed738..24efc21 100644
--- a/rtemsspec/validation.py
+++ b/rtemsspec/validation.py
@@ -24,20 +24,17 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 # POSSIBILITY OF SUCH DAMAGE.
 
-# pylint: disable=too-many-lines
-
 import itertools
-import math
 import os
 import re
-import textwrap
-from typing import Any, Dict, Iterator, List, NamedTuple, Optional, Tuple
+from typing import Any, Dict, List, Optional, Tuple
 
-from rtemsspec.content import CContent, CInclude, enabled_by_to_exp, \
-    ExpressionMapper, GenericContent, get_value_params, get_value_plural, \
+from rtemsspec.content import CContent, CInclude, \
+    GenericContent, get_value_params, get_value_plural, \
     get_value_doxygen_group, get_value_doxygen_function, to_camel_case
-from rtemsspec.items import is_enabled, Item, ItemCache, \
+from rtemsspec.items import Item, ItemCache, \
     ItemGetValueContext, ItemMapper
+from rtemsspec.transitionmap import TransitionMap
 
 ItemMap = Dict[str, Item]
 
@@ -466,639 +463,7 @@ class _TestSuiteItem(_TestItem):
         content.add("/** @} */")
 
 
-class Transition(NamedTuple):
-    """ Represents a action requirement transition map entry.  """
-    desc_idx: int
-    enabled_by: Any
-    skip: int
-    pre_cond_na: Tuple[int, ...]
-    post_cond: Tuple[Any, ...]
-
-
-def _variant_to_key(variant: Transition) -> str:
-    return "".join((enabled_by_to_exp(variant.enabled_by,
-                                      ExpressionMapper()), str(variant.skip),
-                    str(variant.pre_cond_na), str(variant.post_cond)))
-
-
-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 += _variant_to_key(variant)
-        self.variants.append(variant)
-
-    def replace(self, index: int, variant: Transition) -> None:
-        """ Replace the variant at transition variant index. """
-        self.key = self.key.replace(_variant_to_key(self.variants[index]),
-                                    _variant_to_key(variant))
-        self.variants[index] = variant
-
-
 _IdxToX = Tuple[Tuple[str, ...], ...]
-_TransitionMap = List[_TransitionEntry]
-
-
-def _to_st_idx(conditions: List[Any]) -> Tuple[Dict[str, int], ...]:
-    return tuple(
-        dict((state["name"], st_idx) for st_idx, state in enumerate(
-            itertools.chain(condition["states"], [{
-                "name": "N/A"
-            }]))) for condition in conditions)
-
-
-def _to_st_name(conditions: List[Any]) -> _IdxToX:
-    return tuple(
-        tuple(
-            itertools.chain((state["name"]
-                             for state in condition["states"]), ["NA"]))
-        for condition in conditions)
-
-
-class _PostCondContext(NamedTuple):
-    transition_map: "TransitionMap"
-    map_idx: int
-    pre_co_states: Tuple[int, ...]
-    post_co_states: Tuple[Any, ...]
-    post_co_idx: int
-    ops: Any
-
-
-def _post_cond_bool_and(ctx: _PostCondContext, exp: Any) -> bool:
-    for element in exp:
-        if not _post_cond_bool_exp(ctx, element):
-            return False
-    return True
-
-
-def _post_cond_bool_not(ctx: _PostCondContext, exp: Any) -> bool:
-    return not _post_cond_bool_exp(ctx, exp)
-
-
-def _post_cond_bool_or(ctx: _PostCondContext, exp: Any) -> bool:
-    for element in exp:
-        if _post_cond_bool_exp(ctx, element):
-            return True
-    return False
-
-
-def _post_cond_bool_post_cond(ctx: _PostCondContext, exp: Any) -> bool:
-    for post_co_name, status in exp.items():
-        if isinstance(status, str):
-            status = [status]
-        post_co_idx = ctx.transition_map.post_co_name_to_co_idx(post_co_name)
-        st_idx = [
-            ctx.transition_map.post_co_idx_st_name_to_st_idx(
-                post_co_idx, st_name) for st_name in status
-        ]
-        if ctx.post_co_states[post_co_idx] not in st_idx:
-            return False
-    return True
-
-
-def _post_cond_bool_pre_cond(ctx: _PostCondContext, exp: Any) -> bool:
-    for pre_co_name, status in exp.items():
-        if isinstance(status, str):
-            status = [status]
-        pre_co_idx = ctx.transition_map.pre_co_name_to_co_idx(pre_co_name)
-        st_idx = [
-            ctx.transition_map.pre_co_idx_st_name_to_st_idx(
-                pre_co_idx, st_name) for st_name in status
-        ]
-        if ctx.pre_co_states[pre_co_idx] not in st_idx:
-            return False
-    return True
-
-
-_POST_COND_BOOL_OPS = {
-    "and": _post_cond_bool_and,
-    "not": _post_cond_bool_not,
-    "or": _post_cond_bool_or,
-    "post-conditions": _post_cond_bool_post_cond,
-    "pre-conditions": _post_cond_bool_pre_cond,
-}
-
-
-def _post_cond_bool_exp(ctx: _PostCondContext, exp: Any) -> Optional[int]:
-    if isinstance(exp, list):
-        return _post_cond_bool_or(ctx, exp)
-    key = next(iter(exp))
-    return _POST_COND_BOOL_OPS[key](ctx, exp[key])
-
-
-def _post_cond_do_specified_by(ctx: _PostCondContext, pre_co_name: str) -> int:
-    pre_co_idx = ctx.transition_map.pre_co_name_to_co_idx(pre_co_name)
-    st_name = ctx.transition_map.pre_co_idx_st_idx_to_st_name(
-        pre_co_idx, ctx.pre_co_states[pre_co_idx])
-    return ctx.transition_map.post_co_idx_st_name_to_st_idx(
-        ctx.post_co_idx, st_name)
-
-
-def _post_cond_if(ctx: _PostCondContext) -> Optional[int]:
-    if _post_cond_bool_exp(ctx, ctx.ops["if"]):
-        if "then-specified-by" in ctx.ops:
-            return _post_cond_do_specified_by(ctx,
-                                              ctx.ops["then-specified-by"])
-        return ctx.transition_map.post_co_idx_st_name_to_st_idx(
-            ctx.post_co_idx, ctx.ops["then"])
-    return None
-
-
-def _post_cond_specified_by(ctx: _PostCondContext) -> Optional[int]:
-    return _post_cond_do_specified_by(ctx, ctx.ops["specified-by"])
-
-
-def _post_cond_else(ctx: _PostCondContext) -> Optional[int]:
-    return ctx.transition_map.post_co_idx_st_name_to_st_idx(
-        ctx.post_co_idx, ctx.ops["else"])
-
-
-_POST_COND_OP = {
-    "else": _post_cond_else,
-    "if": _post_cond_if,
-    "specified-by": _post_cond_specified_by,
-}
-
-PostCond = Tuple[int, ...]
-
-PreCondsOfPostCond = List[Tuple[List[int], ...]]
-
-
-def _compact(pre_conds: PreCondsOfPostCond) -> PreCondsOfPostCond:
-    while True:
-        last = pre_conds[0]
-        combined_pre_conds = [last]
-        combined_count = 0
-        for row in pre_conds[1:]:
-            diff = [
-                index for index, states in enumerate(last)
-                if states != row[index]
-            ]
-            if len(diff) == 1:
-                index = diff[0]
-                combined_count += 1
-                last[index].extend(row[index])
-            else:
-                combined_pre_conds.append(row)
-                last = row
-        pre_conds = combined_pre_conds
-        if combined_count == 0:
-            break
-    return pre_conds
-
-
-def _compact_more(pre_conds: PreCondsOfPostCond) -> PreCondsOfPostCond:
-    while True:
-        combined_count = 0
-        next_pre_conds = []
-        while pre_conds:
-            first = pre_conds.pop(0)
-            next_pre_conds.append(first)
-            for row in pre_conds:
-                diff = [
-                    index for index, states in enumerate(first)
-                    if states != row[index]
-                ]
-                if len(diff) <= 1:
-                    if diff:
-                        index = diff[0]
-                        first[index].extend(row[index])
-                    combined_count += 1
-                    pre_conds.remove(row)
-        pre_conds = next_pre_conds
-        if combined_count == 0:
-            break
-    return pre_conds
-
-
-class TransitionMap:
-    """ Representation of an action requirement transition map. """
-
-    # pylint: disable=too-many-instance-attributes
-    def __init__(self, item: Item):
-        self._item = item
-        self._pre_co_count = len(item["pre-conditions"])
-        self._post_co_count = len(item["post-conditions"])
-        self.pre_co_summary = tuple(0 for _ in range(self._pre_co_count + 1))
-        self._pre_co_idx_st_idx_to_st_name = _to_st_name(
-            item["pre-conditions"])
-        self._post_co_idx_st_idx_to_st_name = _to_st_name(
-            item["post-conditions"])
-        self._pre_co_idx_st_name_to_st_idx = _to_st_idx(item["pre-conditions"])
-        self._post_co_idx_st_name_to_st_idx = _to_st_idx(
-            item["post-conditions"])
-        self._pre_co_idx_to_cond = dict(
-            (co_idx, condition)
-            for co_idx, condition in enumerate(item["pre-conditions"]))
-        self._pre_co_name_to_co_idx = dict(
-            (condition["name"], co_idx)
-            for co_idx, condition in enumerate(item["pre-conditions"]))
-        self._post_co_name_to_co_idx = dict(
-            (condition["name"], co_idx)
-            for co_idx, condition in enumerate(item["post-conditions"]))
-        self._post_co_idx_to_co_name = dict(
-            (co_idx, condition["name"])
-            for co_idx, condition in enumerate(item["post-conditions"]))
-        self._skip_idx_to_name = dict(
-            (skip_idx + 1, key)
-            for skip_idx, key in enumerate(item["skip-reasons"].keys()))
-        self._skip_name_to_idx = dict(
-            (key, skip_idx + 1)
-            for skip_idx, key in enumerate(item["skip-reasons"].keys()))
-        self._entries = {}  # type: Dict[str, List[Any]]
-        self._map = self._build_map()
-        self._post_process()
-
-    def __getitem__(self, key: str):
-        return self._item[key]
-
-    def __iter__(self):
-        yield from self._map
-
-    def entries(self) -> Iterator[List[Any]]:
-        """ Yields the transition map entry variants sorted by frequency. """
-        yield from sorted(self._entries.values(), key=lambda x: x[1])
-
-    def get_variants(self,
-                     enabled: List[str]) -> Iterator[Tuple[int, Transition]]:
-        """
-        Yields the map index and the transition variants enabled by the enabled
-        list.
-        """
-        for map_idx, transitions in enumerate(self._map):
-            for variant in transitions[1:]:
-                if is_enabled(enabled, variant.enabled_by):
-                    break
-            else:
-                variant = transitions[0]
-            yield map_idx, variant
-
-    def get_post_conditions(
-            self, enabled: List[str]
-    ) -> Iterator[Tuple[PostCond, PreCondsOfPostCond]]:
-        """
-        Yields tuples of post-condition variants and the corresponding
-        pre-condition variants which are enabled by the enabled list.
-
-        The first entry of the post-condition variant is the skip index.  The
-        remaining entries are post-condition indices.  The pre-condition
-        variants are a list of tuples.  Each tuple entry corresponds to a
-        pre-condition and provides a list of corresponding pre-condition state
-        indices.
-        """
-        entries = {}  # type: Dict[PostCond, PreCondsOfPostCond]
-        for map_idx, variant in self.get_variants(enabled):
-            key = (variant.skip, ) + variant.post_cond
-            entry = entries.setdefault(key, [])
-            entry.append(
-                tuple([state] for state in self.map_idx_to_pre_co_states(
-                    map_idx, variant.pre_cond_na)))
-        for post_cond, pre_conds in sorted(entries.items(),
-                                           key=lambda x: (x[0][0], len(x[1]))):
-            pre_conds = _compact_more(_compact(pre_conds))
-            yield post_cond, pre_conds
-
-    def _post_process(self) -> None:
-        for map_idx, transitions in enumerate(self):
-            if not transitions or not isinstance(
-                    transitions[0].enabled_by,
-                    bool) or not transitions[0].enabled_by:
-                raise ValueError(
-                    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.setdefault(transitions.key,
-                                             [0, 0, transitions, []])
-            entry[0] += 1
-            entry[3].append(map_idx)
-        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 = []
-        for condition in reversed(self._item["pre-conditions"]):
-            states = condition["states"]
-            count = len(states)
-            st_idx = int(map_idx % count)
-            conditions.append(f"{condition['name']}={states[st_idx]['name']}")
-            map_idx //= count
-        return ", ".join(reversed(conditions))
-
-    def map_idx_to_pre_co_states(
-            self, map_idx: int, pre_cond_na: Tuple[int,
-                                                   ...]) -> Tuple[int, ...]:
-        """
-        Maps the transition map index and the associated pre-condition state
-        indices.
-        """
-        co_states = []
-        for condition in reversed(self._item["pre-conditions"]):
-            count = len(condition["states"])
-            co_states.append(count if pre_cond_na[self._pre_co_name_to_co_idx[
-                condition["name"]]] else int(map_idx % count))
-            map_idx //= count
-        return tuple(reversed(co_states))
-
-    def pre_co_name_to_co_idx(self, co_name: str) -> int:
-        """
-        Maps the pre-condition name to the associated pre-condition index.
-        """
-        return self._pre_co_name_to_co_idx[co_name]
-
-    def pre_co_idx_to_co_name(self, co_idx: int) -> str:
-        """
-        Maps the pre-condition index to the associated pre-condition name.
-        """
-        return self._pre_co_idx_to_cond[co_idx]["name"]
-
-    def post_co_name_to_co_idx(self, co_name: str) -> int:
-        """
-        Maps the post-condition name to the associated post-condition index.
-        """
-        return self._post_co_name_to_co_idx[co_name]
-
-    def post_co_idx_to_co_name(self, co_idx: int) -> str:
-        """
-        Maps the post-condition index to the associated post-condition name.
-        """
-        return self._post_co_idx_to_co_name[co_idx]
-
-    def pre_co_idx_st_idx_to_st_name(self, co_idx: int, st_idx: int) -> str:
-        """
-        Maps the pre-condition name and state index to the associated state
-        name.
-        """
-        return self._pre_co_idx_st_idx_to_st_name[co_idx][st_idx]
-
-    def post_co_idx_st_idx_to_st_name(self, co_idx: int, st_idx: int) -> str:
-        """
-        Maps the post-condition name and state index to the associated state
-        name.
-        """
-        return self._post_co_idx_st_idx_to_st_name[co_idx][st_idx]
-
-    def pre_co_idx_st_name_to_st_idx(self, co_idx: int, st_name: str) -> int:
-        """
-        Maps the pre-condition index and state name to the associated state
-        index.
-        """
-        return self._pre_co_idx_st_name_to_st_idx[co_idx][st_name]
-
-    def post_co_idx_st_name_to_st_idx(self, co_idx: int, st_name: str) -> int:
-        """
-        Maps the post-condition index and state name to the associated state
-        index.
-        """
-        return self._post_co_idx_st_name_to_st_idx[co_idx][st_name]
-
-    def skip_idx_to_name(self, skip_idx: int) -> str:
-        """
-        Maps the skip index the associated skip name index.
-        """
-        return self._skip_idx_to_name[skip_idx]
-
-    def _map_post_cond(self, map_idx: int, co_idx: int,
-                       variant: Transition) -> Transition:
-        if isinstance(variant.post_cond[co_idx], int):
-            return variant
-        pre_co_states = self.map_idx_to_pre_co_states(map_idx,
-                                                      variant.pre_cond_na)
-        for ops in variant.post_cond[co_idx]:
-            idx = _POST_COND_OP[next(iter(ops))](_PostCondContext(
-                self, map_idx, pre_co_states, variant.post_cond, co_idx, ops))
-            if idx is not None:
-                return Transition(
-                    variant.desc_idx, variant.enabled_by, variant.skip,
-                    variant.pre_cond_na, variant.post_cond[0:co_idx] +
-                    (idx, ) + variant.post_cond[co_idx + 1:])
-        raise ValueError(
-            "cannot determine state for post-condition "
-            f"'{self._post_co_idx_to_co_name[co_idx]}' of transition map "
-            f"descriptor {variant.desc_idx} of {self._item.spec} for "
-            "pre-condition set "
-            f"{{{self._map_index_to_pre_conditions(map_idx)}}}")
-
-    def _make_post_cond(self, map_idx: int, variant: Transition) -> Transition:
-        for co_idx in range(len(variant.post_cond)):
-            variant = self._map_post_cond(map_idx, co_idx, variant)
-        return variant
-
-    def _add_variant(self, transition_map: _TransitionMap, map_idx: int,
-                     variant: Transition) -> None:
-        if transition_map[map_idx]:
-            for index, existing in enumerate(transition_map[map_idx].variants):
-                if existing.enabled_by == variant.enabled_by:
-                    if variant.skip:
-                        # Allow transition map variants with a skip reason to
-                        # overwrite existing variants with the same enabled-by
-                        # attribute.  This is important if variants use N/A for
-                        # some pre-conditions.  It makes it also easier to skip
-                        # pre-conditon states which are controlled by build
-                        # options.
-                        transition_map[map_idx].replace(index, variant)
-                        return
-                    raise ValueError(
-                        f"transition map descriptor {variant.desc_idx} of "
-                        f"{self._item.spec} duplicates pre-condition set "
-                        f"{{{self._map_index_to_pre_conditions(map_idx)}}}"
-                        " defined by transition map descriptor "
-                        f"{existing.desc_idx}")
-            default = transition_map[map_idx][0]
-            if (default.post_cond, default.skip,
-                    default.pre_cond_na) == (variant.post_cond, variant.skip,
-                                             variant.pre_cond_na):
-                return
-        elif not isinstance(variant.enabled_by,
-                            bool) or not variant.enabled_by:
-            raise ValueError(
-                f"transition map descriptor {variant.desc_idx} of "
-                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")
-        self.pre_co_summary = tuple(
-            a + b for a, b in zip(self.pre_co_summary, (variant.skip, ) +
-                                  variant.pre_cond_na))
-        transition_map[map_idx].add(variant)
-
-    def _add_transitions(self, transition_map: _TransitionMap,
-                         desc: Dict[str, Any], desc_idx: int,
-                         skip_post_cond: Tuple[Any, ...], co_idx: int,
-                         map_idx: int, pre_cond_na: Tuple[int, ...]) -> None:
-        # pylint: disable=too-many-arguments
-        # pylint: disable=too-many-locals
-        if co_idx < self._pre_co_count:
-            condition = self._pre_co_idx_to_cond[co_idx]
-            state_count = len(condition["states"])
-            map_idx *= state_count
-            states = desc["pre-conditions"][condition["name"]]
-            if isinstance(states, str):
-                assert states in ["all", "N/A"]
-                for st_idx in range(state_count):
-                    self._add_transitions(
-                        transition_map, desc, desc_idx, skip_post_cond,
-                        co_idx + 1, map_idx + st_idx,
-                        pre_cond_na + (int(states == "N/A"), ))
-            else:
-                for st_name in states:
-                    try:
-                        st_idx = self._pre_co_idx_st_name_to_st_idx[co_idx][
-                            st_name]
-                    except KeyError as err:
-                        msg = (f"transition map descriptor {desc_idx} of "
-                               f"{self._item.spec} refers to non-existent "
-                               f"state {err} of pre-condition "
-                               f"'{condition['name']}'")
-                        raise ValueError(msg) from err
-                    self._add_transitions(transition_map, desc, desc_idx,
-                                          skip_post_cond, co_idx + 1,
-                                          map_idx + st_idx,
-                                          pre_cond_na + (0, ))
-        else:
-            variant = self._make_post_cond(
-                map_idx,
-                Transition(desc_idx, desc["enabled-by"], skip_post_cond[0],
-                           pre_cond_na, skip_post_cond[1:]))
-            self._add_variant(transition_map, map_idx, variant)
-
-    def _add_default(self, transition_map: _TransitionMap, desc: Dict[str,
-                                                                      Any],
-                     desc_idx: int, skip_post_cond: Tuple[int, ...]) -> None:
-        enabled_by = desc["enabled-by"]
-        for map_idx, transition in enumerate(transition_map):
-            if not transition:
-                transition.add(
-                    self._make_post_cond(
-                        map_idx,
-                        Transition(desc_idx, enabled_by, skip_post_cond[0],
-                                   (0, ) * self._pre_co_count,
-                                   skip_post_cond[1:])))
-
-    def _get_post_cond(self, desc: Dict[str, Any], co_idx: int) -> Any:
-        info = desc["post-conditions"][self._post_co_idx_to_co_name[co_idx]]
-        if isinstance(info, str):
-            return self._post_co_idx_st_name_to_st_idx[co_idx][info]
-        return info
-
-    def _build_map(self) -> _TransitionMap:
-        transition_count = 1
-        for condition in self["pre-conditions"]:
-            state_count = len(condition["states"])
-            if state_count == 0:
-                raise ValueError(f"pre-condition '{condition['name']}' of "
-                                 f"{self._item.spec} has no states")
-            transition_count *= state_count
-        transition_map = [_TransitionEntry() for _ in range(transition_count)]
-        for desc_idx, desc in enumerate(self["transition-map"]):
-            if isinstance(desc["post-conditions"], dict):
-                try:
-                    skip_post_cond = (0, ) + tuple(
-                        self._get_post_cond(desc, co_idx)
-                        for co_idx in range(self._post_co_count))
-                except KeyError as err:
-                    msg = (f"transition map descriptor {desc_idx} of "
-                           f"{self._item.spec} refers to non-existent "
-                           f"post-condition state {err}")
-                    raise ValueError(msg) from err
-            else:
-                skip_post_cond = (
-                    self._skip_name_to_idx[desc["post-conditions"]], ) + tuple(
-                        self._post_co_idx_st_name_to_st_idx[co_idx]["N/A"]
-                        for co_idx in range(self._post_co_count))
-            if isinstance(desc["pre-conditions"], dict):
-                self._add_transitions(transition_map, desc, desc_idx,
-                                      skip_post_cond, 0, 0, ())
-            else:
-                assert desc["pre-conditions"] == "default"
-                self._add_default(transition_map, desc, desc_idx,
-                                  skip_post_cond)
-        return transition_map
-
-    def _get_entry(self, ident: str, variant: Transition) -> str:
-        text = "{ " + ", ".join(
-            itertools.chain(
-                map(str, (int(variant.skip != 0), ) + 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 = 79
-        return "\n".join(wrapper.wrap(text)) + " },"
-
-    def _get_entry_bits(self) -> int:
-        bits = self._pre_co_count + 1
-        for st_idx_to_st_name in self._post_co_idx_st_idx_to_st_name:
-            bits += math.ceil(math.log2(len(st_idx_to_st_name)))
-        return 2**max(math.ceil(math.log2(bits)), 3)
-
-    def add_map(self, content: CContent, ident: str) -> None:
-        """ Adds the transition map definitions to the content. """
-        entries = []
-        mapper = ExpressionMapper()
-        for entry in self.entries():
-            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 transitions[1:]:
-                    enumerators.append(
-                        ifelse + enabled_by_to_exp(variant.enabled_by, mapper))
-                    enumerators.append(self._get_entry(ident, variant))
-                    ifelse = "#elif "
-                enumerators.append("#else")
-                enumerators.append(self._get_entry(ident, transitions[0]))
-                enumerators.append("#endif")
-                entries.append("\n".join(enumerators))
-        bits = self._get_entry_bits()
-        content.add("typedef struct {")
-        with content.indent():
-            content.append(f"uint{bits}_t Skip : 1;")
-            for condition in self["pre-conditions"]:
-                content.append(f"uint{bits}_t Pre_{condition['name']}_NA : 1;")
-            for condition in self["post-conditions"]:
-                state_bits = math.ceil(math.log2(len(condition["states"]) + 1))
-                content.append(
-                    f"uint{bits}_t Post_{condition['name']} : {state_bits};")
-        content.add(f"}} {ident}_Entry;")
-        content.add([f"static const {ident}_Entry", f"{ident}_Entries[] = {{"])
-        entries[-1] = entries[-1].replace("},", "}")
-        content.append(entries)
-        bits = max(8, 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:
-        """
-        Gets the post-condition entry member name for the post-condition index.
-        """
-        return f"Post_{self._post_co_idx_to_co_name[co_idx]}"
 
 
 def _to_enum(prefix: str, conditions: List[Any]) -> _IdxToX:
diff --git a/specview.py b/specview.py
index d834b3e..86dc20e 100755
--- a/specview.py
+++ b/specview.py
@@ -34,7 +34,7 @@ from rtemsspec.items import EmptyItem, Item, ItemCache, ItemMapper, \
     ItemGetValueContext, Link
 from rtemsspec.sphinxcontent import SphinxContent
 from rtemsspec.util import load_config
-from rtemsspec.validation import Transition, TransitionMap
+from rtemsspec.transitionmap import Transition, TransitionMap
 
 _CHILD_ROLES = [
     "requirement-refinement", "interface-ingroup", "interface-ingroup-hidden",



More information about the vc mailing list