型語彙スキル (Type Vocabulary Skill)
スキルの目的
設計仕様書を記述する際に、実装非依存な型システムを提供する。C++の型名を直接使用せず、意図を表す自然言語ベースの型名を使用することで、仕様の可読性と一意性を向上させ、実装への導出を容易にする。
いつこのスキルを使用するか
- •コンポーネント仕様書のデータ構造を記述するとき
- •API定義(引数・戻り値)を記述するとき
- •既存仕様のリファクタリング(型の明確化)を行うとき
- •実装コードへの型エイリアス定義を作成するとき
設計原則
- •実装非依存: C++の型名(
uint32_t,std::span等)を直接記述せず、意図を表す型名を使用する - •一貫性: すべてのコンポーネント仕様で統一された型語彙を使用する
- •一意性: 型記述から実装が一意に導出できる厳密さを確保する
- •可読性: 自然言語ベースで読みやすさを維持する
使用方法
ステップ1: 型語彙の選択
仕様書でデータ構造やAPIを記述する際、以下の型語彙から適切なものを選択する。型は3つのカテゴリに分類される:
- •プリミティブ型 (Primitive Types): 基本的な数値・真偽値
- •複合型 (Composite Types): 構造化データ、コンテナ
- •参照型 (Reference Types): 他のデータへのポインタ・参照
型語彙リファレンス
ステップ2: 仕様書での記述
以下の型語彙を使用して、データ構造とAPIを記述する。
1. プリミティブ型 (Primitive Types)
1.1 数値型
| 仕様型名 | 意味 | サイズ | 符号 | 実装例 |
|---|---|---|---|---|
| アドレス値 | メモリアドレスを表す整数値 | 32bit | 符号なし | uint32_t |
| オフセット | 基点からの相対バイト位置 | 32bit | 符号なし | uint32_t |
| バイト数 | メモリサイズまたは長さ(バイト単位) | 32bit | 符号なし | size_t, uint32_t |
| エントリ数 | 配列・テーブルの要素数 | 32bit | 符号なし | size_t, uint32_t |
| 命令カウント | 実行された命令の回数 | 32bit | 符号なし | uint32_t |
| 関数インデックス | 関数テーブル内の位置 | 32bit | 符号なし | uint32_t |
| シフト量 | ビットシフト演算の量(2のべき乗を表現) | 8bit | 符号なし | uint8_t |
| 回数 | 反復回数、閾値 | 32bit | 符号なし | uint32_t |
使用例:
プログラムカウンタ | ゲストの現在のプログラム実行位置 | オフセット | 32bit符号なし、モジュール先頭からのバイト単位
1.2 ビットフラグ型
| 仕様型名 | 意味 | サイズ | 実装例 |
|---|---|---|---|
| ビットフラグ | 複数の状態を1つの整数で管理 | 8/16/32bit | uint8_t, uint32_t, std::bitset<N> |
| ブール値 | 真偽値 | 1bit以上 | bool |
使用例:
割り込みフラグ | ゲストに通知された仮想割り込みの状態 | ビットフラグ | 32bit、各ビット定義は[vMMIO仕様§3.2]を参照
記述規則:
- •ビット幅を明記(8bit, 16bit, 32bit)
- •各ビットの意味は別表または参照先へのリンクで定義
2. 複合型 (Composite Types)
2.1 データビュー型
データビュー型は、既存のメモリ領域への非所有参照を提供する。データのコピーを避け、ROM上のデータやRAM上の一時バッファを効率的に参照するために使用される。
2.1.1 基本型定義
| 仕様型名 | 意味 | 構造 | 所有権 | 実装例 |
|---|---|---|---|---|
| バイナリビュー | ROM上のバイト列への読取専用参照 | 先頭ポインタ + サイズ | 非所有 | std::span<const uint8_t> |
| データ範囲 | メモリ上の特定範囲を示す | 開始位置 + 終了位置(またはサイズ) | 非所有 | std::span<T>, 構造体 |
使用例:
WASMバイナリ | ROM上のWASMバイナリデータ | バイナリビュー | ROM上のデータを直接参照(コピーなし)
4.1.2 所有権モデル
| 項目 | 内容 |
|---|---|
| 所有権 | ビュー自体はデータを所有しない(非所有参照) |
| メモリ管理 | ビューの破棄時にデータは解放されない |
| コピー | ビューのコピーは軽量(ポインタとサイズのみ) |
| ムーブ | ビューのムーブもコピーと同等(トリビアル) |
重要: ビューは「窓」であり、参照先データの所有権を持たない。
4.1.3 ライフサイクル制約
ビューの使用には、参照先データのライフサイクルを考慮した厳格な制約がある。
| 制約 | 説明 | 違反時のリスク |
|---|---|---|
| 参照先の生存期間 | ビューのライフタイムは参照先データのライフタイムを超えてはならない | ダングリングポインタ、未定義動作 |
| 不変性の保証 | 読取専用ビュー(const)の場合、参照先データが変更されないことが前提 | データ競合、バグ |
| アライメント | 参照先データが適切にアライメントされていることが前提 | 未定義動作、クラッシュ |
| 境界の妥当性 | ビューが指す範囲が有効なメモリ領域内であること | バッファオーバーラン |
4.1.4 参照先データの分類とライフサイクル
参照先データの種別により、ライフサイクルの扱いが異なる。
ROM上のデータ(静的データ)
| 項目 | 内容 |
|---|---|
| ライフタイム | プログラム全体(静的) |
| 可変性 | 不変(読取専用) |
| 使用例 | WASMバイナリ、コンステクスプル文字列、テンプレートコード |
| 注意点 | ROMデータへのビューは実質的にライフタイム制約なし |
// ROM上のWASMバイナリへのビュー
constexpr uint8_t wasm_module[] = { /* ... */ };
binary_view module_view{wasm_module, sizeof(wasm_module)};
// module_viewは wasm_module の生存期間中(プログラム全体)有効
RAM上の永続データ(静的バッファ)
| 項目 | 内容 |
|---|---|
| ライフタイム | プログラム全体(静的) |
| 可変性 | 可変 |
| 使用例 | JITコードキャッシュ、グローバルスタック、静的バッファ |
| 注意点 | データの再初期化時にビューの再構築が必要 |
// 静的に確保されたJITキャッシュ
static uint8_t jit_cache[64 * 1024];
data_range<uint8_t> cache_view{jit_cache, sizeof(jit_cache)};
// cache_viewは jit_cache の生存期間中(プログラム全体)有効
RAM上の一時データ(ローカル変数、関数引数)
| 項目 | 内容 |
|---|---|
| ライフタイム | スコープ内のみ |
| 可変性 | 可変 |
| 使用例 | 関数の引数として渡されるバッファ、スタック上の一時配列 |
| 注意点 | スコープを超えてビューを保持してはならない |
void parse_section(binary_view section) {
// section は呼び出し元のデータを参照
// この関数を抜けた後、section を保持してはならない
}
// 正しい使用法
uint8_t buffer[256];
binary_view view{buffer, sizeof(buffer)};
parse_section(view); // OK: buffer はまだ有効
// 誤った使用法
binary_view dangerous_view;
{
uint8_t temp[256];
dangerous_view = binary_view{temp, sizeof(temp)};
}
// dangerous_view は無効!temp は破棄されている(ダングリングポインタ)
ヒープ上のデータ(動的確保)
| 項目 | 内容 |
|---|---|
| ライフタイム | 確保から解放まで |
| 可変性 | 可変 |
| 使用例 | (Fireballでは原則使用しない) |
| 注意点 | Fireballでは動的メモリ確保を避けるため、この用途は限定的 |
4.1.5 使用上の設計原則
| 原則 | 説明 |
|---|---|
| 短命なビュー | ビューはできるだけ短命にし、関数のスコープ内でのみ使用する |
| 保存の禁止 | ビューをクラスのメンバ変数として長期間保持しない(例外: ROM参照) |
| 検証の責任 | ビュー作成側が参照先の妥当性を検証する責任を持つ |
| const-correctness | 読取専用ビューは const データへの参照として扱う |
設計ルール:
- •✅ 推奨: 関数の引数としてビューを渡す(短命)
- •✅ 推奨: ROM上のデータへのビューをクラスメンバに保持する(静的ライフタイム)
- •❌ 非推奨: RAM上の一時データへのビューをクラスメンバに保持する
- •❌ 禁止: スコープを超えてローカル変数へのビューを保持する
4.1.6 ビュー型の型エイリアス
| C++型エイリアス | 基底型 | 用途 |
|---|---|---|
binary_view | std::span<const uint8_t> | ROM上のバイナリデータ(読取専用) |
mutable_binary_view | std::span<uint8_t> | RAM上のバイナリデータ(書込可能) |
data_range<T> | std::span<T> | 任意の型のデータ範囲 |
定義例:
using binary_view = std::span<const uint8_t>; using mutable_binary_view = std::span<uint8_t>; template<typename T> using data_range = std::span<T>;
特性:
- •RAMへのコピーを避け、ROM上のデータを直接参照
- •読み取り専用で、データの所有権を持たない
- •参照先データのライフサイクルを超えて使用してはならない
4.2 結果・オプショナル型
| 仕様型名 | 意味 | 構造 | 実装例 |
|---|---|---|---|
| 結果型 | 成功値またはエラーコードを返却 | 判別共用体(Ok<T> または Err<E>) | result<T, E> |
| オプショナル値 | 値の有無を表現 | 判別共用体(Some<T> または None) | optional<T> |
| 検証結果 | 検証の成否と失敗時の詳細情報 | 成功フラグ + エラー情報(条件付き) | verification_result |
使用例:
戻り値 | モジュールロードの成否 | 結果型 | 成功時は空、失敗時は`load_error`を返却
記述規則:
- •成功時の型
Tと失敗時の型Eを明記 - •エラーコードの定義へのリンクを記載
4.3 索引・辞書型
| 仕様型名 | 意味 | 構造 | 実装例 |
|---|---|---|---|
| ソート済み配列 | キーでソートされた固定長配列 | 連続メモリ配列 + 二分探索 | 固定長配列 |
| ハッシュテーブル | キー・バリュー連想配列(ハッシュ方式) | ハッシュ関数 + バケット配列 | カスタム実装 |
| アクセス辞書 | ROM上のデータへの高速アクセスを提供する索引 | オフセット配列 + アクセサ | module_view |
使用例:
関数索引 | 関数名から関数インデックスへの変換テーブル | ソート済み配列 | 二分探索により O(log N) で検索
特性:
- •動的メモリ確保を避けるため、
std::map,std::unordered_mapは使用しない - •stdlib.md § 3を参照
4.4 コールバック・関数型
| 仕様型名 | 意味 | 実装例 |
|---|---|---|
| 関数ポインタ | 実行可能コードへの参照 | void (*)(...) |
| 経済的な関数 | 型消去された関数オブジェクト(ヒープレス) | economic_function<Signature> |
| デコードメソッド | ROM上のデータを読み取り、値を返すメソッド | アクセサのメンバ関数 |
使用例:
コールバック | vMMIOアクセス時に呼び出される処理 | 経済的な関数 | シグネチャ: `void(uint32_t addr, uint8_t* data)`
4.5 アロケータ型
| 仕様型名 | 意味 | 実装例 |
|---|---|---|
| バンプアロケータ | 単方向線形メモリ割り当て | bump_allocator |
| 独立ヒープ | 特定用途に分離されたヒープ領域 | パーティション化されたメモリ領域 |
特性:
- •
malloc/freeを使用せず、決定論的なメモリ管理を実現
4.6 メソッド・関数型
メソッドおよび関数の型は、引数の受け渡し方と戻り値のパターンにより分類される。
4.6.1 引数の渡し方
| 仕様型名 | 表記 | 意味 | 実装例 | 用途 |
|---|---|---|---|---|
| 値渡し | T | 引数をコピーして渡す | void func(uint32_t value) | プリミティブ型、小さな構造体 |
| const参照渡し | const T& | 読取専用参照として渡す(コピーなし) | void func(const config_t& cfg) | 大きな構造体、読取専用 |
| 可変参照渡し | T& | 書込可能参照として渡す | void func(context_t& ctx) | 引数を変更する場合 |
| ポインタ渡し | T* | ポインタで渡す(nullableの可能性) | void func(module_t* mod) | NULL許容、配列、レガシーAPI |
| constポインタ渡し | const T* | 読取専用ポインタで渡す | void func(const uint8_t* data) | NULL許容、配列(読取専用) |
使用ガイドライン:
| サイズ | 可変性 | 推奨される渡し方 | 理由 |
|---|---|---|---|
| ≤ 8 bytes | - | 値渡し (T) | レジスタ渡しで効率的 |
| > 8 bytes | 読取専用 | const参照渡し (const T&) | コピーコストを回避 |
| > 8 bytes | 可変 | 可変参照渡し (T&) | コピーコストを回避しつつ変更可能 |
| 配列/ビュー | - | ビュー型 (binary_view, data_range<T>) | サイズと境界を明示 |
コード例:
// プリミティブ型: 値渡し void set_timeout(uint32_t milliseconds); // 大きな構造体: const参照渡し(読取専用) void initialize(const vsoc_config& config); // 構造体の変更: 可変参照渡し void execute_step(execution_context& ctx); // バイナリデータ: ビュー型 module_view load_module(binary_view wasm_binary);
4.6.2 戻り値のパターン
| 仕様型名 | 表記 | 意味 | 実装例 | 用途 |
|---|---|---|---|---|
| void戻り値 | void | 戻り値なし(副作用のみ) | void notify_interrupt(...) | 副作用のみの関数 |
| 値戻り値 | T | 値をコピーして返す | uint32_t get_pc(...) | プリミティブ型、小さな構造体 |
| 結果型戻り値 | result<T, E> | 成功値またはエラー | result<void, load_error> load(...) | エラーハンドリングが必要 |
| オプショナル戻り値 | optional<T> | 値の有無 | optional<uint32_t> find_symbol(...) | 値が存在しない可能性 |
| ビュー戻り値 | binary_view, data_range<T> | データへの参照 | binary_view get_section(...) | 大きなデータへの参照 |
| ポインタ戻り値 | T* | ポインタを返す(nullableの可能性) | module_t* find_module(...) | NULL許容、レガシーAPI |
戻り値選択のガイドライン:
| 状況 | 推奨される戻り値型 | 例 |
|---|---|---|
| エラーが発生しない | 値型 (T) | uint32_t get_pc() |
| エラーが発生する可能性 | 結果型 (result<T, E>) | result<void, error> load() |
| 値が存在しない可能性 | オプショナル型 (optional<T>) | optional<uint32_t> find() |
| 副作用のみ | void | void notify() |
| 大きなデータへの参照 | ビュー型 | binary_view get_data() |
コード例:
// void: 副作用のみ void notify_interrupt(uint32_t irq_id); // 値: プリミティブ型 uint32_t get_program_counter(); // 結果型: エラーハンドリング result<void, load_error> load_module(binary_view binary); // オプショナル: 値が存在しない可能性 optional<uint32_t> lookup_symbol(const char* name); // ビュー: データへの参照 binary_view get_code_section(uint32_t func_index);
4.6.3 メソッドシグネチャの表記
仕様書でのメソッドシグネチャ表記方法を統一する。
表記形式:
機能名(引数名: 型分類【, 引数名: 型分類】...) -> 戻り値型分類
例:
| 仕様書での表記 | C++実装例 |
|---|---|
load(binary: バイナリビュー) -> 結果型 | result<void, load_error> load(binary_view binary) |
get_pc() -> オフセット | offset_t get_pc() |
step(ctx: 可変参照) -> void | void step(execution_context& ctx) |
find(name: 文字列) -> オプショナル値 | optional<uint32_t> find(const char* name) |
4.6.4 関数ポインタとコールバック
| 仕様型名 | 意味 | 実装例 | 用途 |
|---|---|---|---|
| 関数ポインタ | 特定シグネチャの関数への直接ポインタ | void (*handler)(uint32_t) | シンプルなコールバック |
| 経済的な関数 | 型消去された関数オブジェクト(ヒープレス) | economic_function<void(uint32_t)> | 状態を持つコールバック |
| メンバ関数ポインタ | クラスのメンバ関数へのポインタ | void (Class::*method)(uint32_t) | (使用は限定的) |
使用ガイドライン:
| 用途 | 推奨型 | 理由 |
|---|---|---|
| 状態を持たないコールバック | 関数ポインタ | シンプル、高速 |
| 状態を持つコールバック | 経済的な関数 | ヒープ不要、柔軟性 |
| ラムダ式のキャプチャ | 経済的な関数 | 型消去により統一的に扱える |
コード例:
// 関数ポインタ using interrupt_handler = void (*)(uint32_t irq_id); void register_handler(interrupt_handler handler); // 経済的な関数 using vmmio_callback = economic_function<void(address, byte_count)>; void register_vmmio_hook(vmmio_callback callback);
4.6.5 メンバ関数の修飾子
| 修飾子 | 意味 | 仕様での表記 | 実装例 |
|---|---|---|---|
const | メンバ変数を変更しない | 「読取専用メソッド」 | uint32_t get_size() const |
noexcept | 例外を投げない | 「例外なし」 | void clear() noexcept |
[[nodiscard]] | 戻り値を無視してはならない | 「戻り値必須」 | [[nodiscard]] result<T> get() |
Fireballでの使用方針:
- •
const: 読取専用メソッドには常に付与 - •
noexcept: 例外を使用しないため、通常は不要(プロジェクト方針による) - •
[[nodiscard]]: 結果型、オプショナル型を返すメソッドには推奨
4.6.6 仕様書でのAPI定義テンプレート
推奨形式:
| 項目 | 内容 |
|---|---|
| 機能概要 | メソッドの目的と責務を簡潔に記述 |
| シグネチャ | メソッド名(引数: 型分類) -> 戻り値型分類 形式で記述 |
| 引数 | 各引数の名前、型分類、意味を1行ずつ記述 |
| 戻り値 | 型分類、成功時/失敗時の値を記述 |
| 事前条件 | メソッド呼び出し前に満たすべき条件 |
| 事後条件 | メソッド正常終了後に保証される状態 |
| 不変条件 | メソッド実行中/後も維持される条件 |
| エラー時の挙動 | エラー発生時の戻り値と副作用 |
記述例:
load_module
| 項目 | 内容 |
|---|---|
| 機能概要 | ROM上のWASMバイナリを読み込み、実行準備を完了させる |
| シグネチャ | load_module(binary: バイナリビュー) -> 結果型 |
| 引数 | binary: ROM上のWASMバイナリデータ(バイナリビュー、読取専用) |
| 戻り値 | 結果型(成功時は空、失敗時はload_errorを返却) |
| 事前条件 | binaryが有効なWASMバイナリを指していること |
| 事後条件 | モジュールがロードされ、実行可能状態になる |
| 不変条件 | 既存のロード済みモジュールに影響を与えない |
| エラー時の挙動 | 不正なバイナリの場合はロードを中断し、エラー値を返す |
5. 参照型 (Reference Types)
5.1 ポインタ・参照
| 仕様型名 | 意味 | 所有権 | 可変性 | 実装例 |
|---|---|---|---|---|
| 構造体への参照 | 他コンポーネントのデータ構造への参照 | 非所有 | 読取専用 | const T*, const T& |
| 可変参照 | 他コンポーネントのデータ構造への書込可能参照 | 非所有 | 可変 | T*, T& |
| インターフェイスへの参照 | 他コンポーネントの抽象インターフェイスへの参照 | 非所有 | - | interface* (純粋仮想) |
| テーブルポインタ | 配列・テーブルの先頭を指すポインタ | 非所有 | - | T* |
| 環境ポインタ | 実行環境(vSoC等)への参照 | 非所有 | 可変 | vsoc_runtime* |
使用例:
モジュールビュー | ロード済みWASMモジュールの索引情報への参照 | 構造体への参照 | [`module_view`](loader.md#module_view) へのポインタ(非所有)
記述規則:
- •参照先の型定義へのリンクを必ず記載
- •所有権を明記(所有 / 非所有)
- •可変性を明記(読取専用 / 可変)
5.2 プロキシ・アクセサ
| 仕様型名 | 意味 | ライフタイム | 実装例 |
|---|---|---|---|
| アクセサ | ROM上のデータへの一時的なプロキシオブジェクト | 短命(メソッド呼び出し時のみ) | function_accessor, global_accessor |
使用例:
関数アクセサ | 関数の詳細情報へアクセスするプロキシ | アクセサ | メソッド呼び出し時にROM上のデータをデコード
特性:
- •データをRAMにコピーせず、呼び出し時にROMから読み取る
- •一時的なオブジェクトで、長期間保持しない
6. 記述形式
6.1 データ構造の表記(推奨形式)
4列形式:
| 項目名 | 機能と役割 | 型分類 | サイズ・制約 |
|---|
- •項目名: メンバ変数名(自然言語)
- •機能と役割: 項目の目的と責務
- •型分類: 本語彙表の型名を使用
- •サイズ・制約: ビット幅、符号、範囲、参照先へのリンク
記述例:
| 項目名 | 機能と役割 | 型分類 | サイズ・制約 |
|---|---|---|---|
| プログラムカウンタ | ゲストの現在のプログラム実行位置 | オフセット | 32bit符号なし、モジュール先頭からのバイト単位 |
| 割り込みフラグ | ゲストに通知された仮想割り込みの状態 | ビットフラグ | 32bit、各ビット定義は[vMMIO仕様§3.2]を参照 |
| モジュールビュー | ロード済みWASMモジュールの索引情報への参照 | 構造体への参照 | module_view(非所有) |
| スタック容量 | オペランドスタックとして確保する総バイト数 | バイト数 | 32bit符号なし |
6.2 API定義の表記
必須項目:
- •機能概要
- •引数: 名前、型分類、サイズ・制約(1行1引数)
- •戻り値: 型分類、サイズ・制約
- •事前条件
- •事後条件
- •エラー時の挙動
記述例:
load_module
| 項目 | 内容 |
|---|---|
| 機能概要 | 指定されたWASMバイナリデータを読み込み、実行準備を完了させる。 |
| 引数 | ctx: 実行コンテキストへの可変参照<br>binary: WASMバイナリのバイナリビュー(ROM上のデータを直接参照) |
| 戻り値 | 結果型(成功時は空、失敗時はload_errorを返却) |
| 事前条件 | ctxが初期化済みであること |
| 事後条件 | ctx.module_viewが構築され、実行可能状態になる |
| エラー時の挙動 | 不正なバイナリの場合はロードを中断し、エラー値を返す |
7. 実装への変換
7.1 仕様型 → C++型の対応表
| 仕様型名 | C++型 (推奨) | 備考 |
|---|---|---|
| アドレス値 | uint32_t | |
| オフセット | uint32_t | |
| バイト数 | size_t, uint32_t | 環境により選択 |
| エントリ数 | size_t, uint32_t | |
| 命令カウント | uint32_t | |
| 関数インデックス | uint32_t | |
| シフト量 | uint8_t | |
| ビットフラグ (32bit) | uint32_t, std::bitset<32> | 用途により選択 |
| ブール値 | bool | |
| バイナリビュー | std::span<const uint8_t> | C++20 |
| データ範囲 | std::span<T> | C++20 |
| 結果型 | result<T, E> | 独自実装 |
| オプショナル値 | optional<T> | 独自実装またはstd::optional |
| ソート済み配列 | 固定長配列 | |
| 構造体への参照 (非所有) | const T*, const T& | |
| 可変参照 (非所有) | T*, T& | |
| 関数ポインタ | void (*)(...) | |
| 経済的な関数 | economic_function<Sig> | 独自実装 |
7.2 型エイリアス定義 (C++ using 宣言)
実装時には、以下の型エイリアスを共通ヘッダ(例: inc/core/types.hxx)で定義することを推奨する。
7.2.1 プリミティブ型エイリアス
| 仕様型名 | C++型エイリアス | 基底型 | 説明 |
|---|---|---|---|
| アドレス値 | address | uint32_t | メモリアドレスを表す整数値 |
| オフセット | offset | uint32_t | 基点からの相対バイト位置 |
| バイト数 | byte_count | uint32_t | メモリサイズまたは長さ(バイト単位) |
| エントリ数 | entry_count | uint32_t | 配列・テーブルの要素数 |
| 命令カウント | instruction_count | uint32_t | 実行された命令の回数 |
| 関数インデックス | function_index | uint32_t | 関数テーブル内の位置 |
| シフト量 | shift_amount | uint8_t | ビットシフト演算の量(2のべき乗表現用) |
| ビットフラグ (32bit) | interrupt_flags | uint32_t | 割り込みフラグ等の状態ビット集合 |
| ブール値 | - | bool | 型エイリアス不要(標準型をそのまま使用) |
定義例:
using address = uint32_t; using offset = uint32_t; using byte_count = uint32_t; using entry_count = uint32_t; using instruction_count = uint32_t; using function_index = uint32_t; using shift_amount = uint8_t; using interrupt_flags = uint32_t;
7.2.2 複合型エイリアス
| 仕様型名 | C++型エイリアス | 実装型 | 説明 |
|---|---|---|---|
| バイナリビュー | binary_view | std::span<const uint8_t> | ROM上のバイト列への読取専用参照 |
| バイナリビュー(可変) | mutable_binary_view | std::span<uint8_t> | RAM上のバイト列への書込可能参照 |
| データ範囲 | data_range<T> | std::span<T> | メモリ上の特定範囲(テンプレート) |
| 結果型 | result<T, E> | 独自実装 | 成功値またはエラーコードを返却 |
| オプショナル値 | optional<T> | 独自実装 | 値の有無を表現 |
| 経済的な関数 | economic_function<Sig> | 独自実装 | 型消去された関数オブジェクト(ヒープレス) |
定義例:
using binary_view = std::span<const uint8_t>; using mutable_binary_view = std::span<uint8_t>; template<typename T> using data_range = std::span<T>; template<typename T, typename E> using result = /* result型の独自実装 */; template<typename T> using optional = /* optional型の独自実装 */; template<typename Signature> using economic_function = /* economic_function型の独自実装 */;
7.2.3 コンポーネント固有エイリアス
| 仕様型名(文脈) | C++型エイリアス | 基底型 | 用途コンポーネント |
|---|---|---|---|
| WASMプログラムカウンタ | wasm_pc | offset | Interpreter, JIT |
| WASM命令コード | wasm_opcode | uint8_t | Interpreter, Loader |
| JITコードオフセット | code_offset | uint16_t | JIT Compiler |
| カードインデックス | card_index | uint16_t | JIT Hotspot Detector |
| モジュール識別子 | module_id | uint32_t | Loader, vSoC |
| タスク識別子 | task_id | uint16_t | Scheduler, COOS |
定義例:
// WASM関連 using wasm_pc = offset; using wasm_opcode = uint8_t; // JIT関連 using code_offset = uint16_t; using card_index = uint16_t; // vSoC関連 using module_id = uint32_t; using task_id = uint16_t;
7.2.4 使用例
仕様書での記述:
| 項目名 | 機能と役割 | 型分類 | サイズ・制約 | | プログラムカウンタ | ゲストの現在のプログラム実行位置 | オフセット | 32bit符号なし | | 割り込みフラグ | ゲストに通知された仮想割り込みの状態 | ビットフラグ | 32bit | | メモリサイズ | ゲストリニアメモリの有効サイズ | バイト数 | 32bit符号なし |
対応する実装コード:
struct execution_context {
wasm_pc pc_; // プログラムカウンタ (wasm_pc = offset)
interrupt_flags irq_flags_; // 割り込みフラグ (interrupt_flags = uint32_t)
byte_count memory_size_; // メモリサイズ (byte_count = uint32_t)
};
7.2.5 型エイリアス使用の利点
| 利点 | 説明 | 例 |
|---|---|---|
| 可読性 | 意図が明確になる | uint32_t pc_ → wasm_pc pc_ |
| 保守性 | 型定義を1箇所で変更可能 | 64bit対応時に offset の定義を変更するだけ |
| 一貫性 | 仕様書の型語彙とコードが対応 | 仕様書「オフセット」→ コード offset |
| 型安全性 | 異なる意味の同じ基底型を区別 | offset と byte_count は両方 uint32_t だが意図が異なる |
7.2.6 命名規則
| 型の種類 | 命名規則 | 例 |
|---|---|---|
| プリミティブ型エイリアス | snake_case(postfixなし) | address, offset |
| テンプレート型エイリアス | snake_case(postfixなし) | result<T,E>, optional<T> |
| コンポーネント固有エイリアス | コンポーネント_型名 | wasm_pc, jit_entry |
注: _tサフィックスはtypedefのときのみ使用し、usingでは使用しない。
7.2.7 完全な型定義ヘッダ例
// inc/core/types.hxx
#ifndef FIREBALL_CORE_TYPES_HXX
#define FIREBALL_CORE_TYPES_HXX
#include <cstdint>
#include <span>
namespace fireball {
// ========================================
// プリミティブ型エイリアス
// ========================================
using address = uint32_t;
using offset = uint32_t;
using byte_count = uint32_t;
using entry_count = uint32_t;
using instruction_count = uint32_t;
using function_index = uint32_t;
using shift_amount = uint8_t;
using interrupt_flags = uint32_t;
// ========================================
// 複合型エイリアス
// ========================================
using binary_view = std::span<const uint8_t>;
template<typename T>
using data_range = std::span<T>;
// 結果型、オプショナル型、経済的な関数は別ヘッダで定義
// ========================================
// WASM関連エイリアス
// ========================================
using wasm_pc = offset;
using wasm_opcode = uint8_t;
// ========================================
// JIT関連エイリアス
// ========================================
using code_offset = uint16_t;
using card_index = uint16_t;
// ========================================
// vSoC関連エイリアス
// ========================================
using module_id = uint32_t;
using task_id = uint16_t;
} // namespace fireball
#endif // FIREBALL_CORE_TYPES_HXX
8. 語彙の拡張
新しい型が必要な場合
- •まず既存の型語彙で表現できないか検討
- •必要なら仕様型名を定義
- •本ドキュメントに追加し、プロジェクト共通の語彙として管理
記録すべき情報
- •仕様型名(意図を表す自然言語)
- •意味・目的
- •構造・サイズ
- •実装例(参考情報)
- •使用例
9. チェックリスト
設計書作成時に以下を確認:
- • すべてのデータ構造が型分類列で本語彙表の型名を使用しているか
- • サイズ・制約列でビット幅、符号、範囲が明記されているか
- • 参照型の場合、参照先の型定義へのリンクが記載されているか
- • API定義で、引数・戻り値の型分類が明記されているか
- • エラー時の戻り値が結果型または具体的な値で定義されているか
- • C++型名を直接記述せず、本語彙表の型名を使用しているか
10. 用語集(クイックリファレンス)
| 仕様型名 | カテゴリ | 簡易説明 |
|---|---|---|
| アドレス値 | プリミティブ | メモリアドレスを表す整数値 (32bit符号なし) |
| オフセット | プリミティブ | 基点からの相対バイト位置 (32bit符号なし) |
| バイト数 | プリミティブ | メモリサイズまたは長さ (32bit符号なし) |
| エントリ数 | プリミティブ | 配列・テーブルの要素数 (32bit符号なし) |
| ビットフラグ | プリミティブ | 複数の状態を1つの整数で管理 (8/16/32bit) |
| ブール値 | プリミティブ | 真偽値 |
| バイナリビュー | 複合 | ROM上のバイト列への読取専用参照 |
| データ範囲 | 複合 | メモリ上の特定範囲を示す |
| 結果型 | 複合 | 成功値またはエラーコードを返却 |
| オプショナル値 | 複合 | 値の有無を表現 |
| ソート済み配列 | 複合 | キーでソートされた固定長配列 |
| 経済的な関数 | 複合 | 型消去された関数オブジェクト(ヒープレス) |
| 構造体への参照 | 参照 | 他コンポーネントのデータ構造への読取専用参照 |
| 可変参照 | 参照 | 他コンポーネントのデータ構造への書込可能参照 |
| インターフェイスへの参照 | 参照 | 他コンポーネントの抽象インターフェイスへの参照 |
| アクセサ | 参照 | ROM上のデータへの一時的なプロキシオブジェクト |
まとめ: 設計時のワークフロー
ステップ3: 実装への変換
仕様書作成完了後、以下の手順で実装コードを生成する:
- •
共通型定義ヘッダの作成
- •
inc/core/types.hxxにプリミティブ型エイリアスを定義 - •§ 7.2 の型エイリアス定義を参照
- •
- •
コンポーネント固有型の追加
- •各コンポーネント固有の型エイリアスを追加
- •例:
wasm_pc,jit_entryなど
- •
データ構造の実装
- •仕様書の4列形式の表から構造体を生成
- •型分類列をC++型エイリアスに変換
- •
API実装
- •シグネチャ表記から関数宣言を生成
- •引数・戻り値の型分類を変換
チェックリスト
仕様書レビュー時の確認項目:
- • 全てのデータ構造が4列形式で記述されているか
- • 型分類列で本語彙表の型名が使用されているか
- • サイズ・制約列が明記されているか
- • 参照型に参照先リンクが記載されているか
- • API定義にシグネチャ表記があるか
- • 引数・戻り値の型分類が明記されているか
- • C++型名が直接記述されていないか
クイックリファレンス
よく使用する型語彙の一覧:
| 仕様型名 | 用途 | C++型エイリアス |
|---|---|---|
| アドレス値 | メモリアドレス | address |
| オフセット | 相対バイト位置 | offset |
| バイト数 | サイズ・長さ | byte_count |
| ビットフラグ | 状態ビット集合 | interrupt_flags |
| バイナリビュー | ROM上データ参照 | binary_view |
| 結果型 | エラーハンドリング | result<T, E> |
| オプショナル値 | 値の有無 | optional<T> |
関連スキルとドキュメント
- •proj_fireball.md: アーキテクチャ原則と設計パターン
- •cpp_embedded.md: 組み込みC++の実装ガイドライン
- •stdlib.md: 禁止コンテナと代替手法
- •harness.md: Stateless Interface パターン
スキル適用の成功基準:
- •仕様書から実装が一意に導出できる
- •C++型名が直接記述されていない
- •型の意図が自然言語で明確に伝わる
- •全てのデータ構造・APIが統一形式に従っている