# 機能設計書 115-last_keyx

## 概要

本ドキュメントは、Hack Standard Library (HSL) の `C\last_keyx` 関数の機能設計について記述する。この関数は、KeyedTraversable（キー付き走査可能コレクション）から最後のキーを取得し、空の場合は例外をスローする。

### 本機能の処理概要

`C\last_keyx` 関数は、KeyedTraversable（dict、vec、keyset、Map、Vector、Set等のキー付きコレクション）の最後のキーを取得する関数である。コレクションが空の場合は `InvariantException` をスローし、要素が存在することを保証する必要がある場面で使用される。

**業務上の目的・背景**：コレクション操作において、最後のキーが必ず存在することを前提とした処理を行う場合、null チェックを省略し、より簡潔で型安全なコードを記述できるようにする。空のコレクションは即座に例外として検出されるため、後続処理での不正な状態を防止できる。

**機能の利用シーン**：
- コレクションが空でないことが事前に保証されている場合のキー取得
- 空のコレクションをエラーとして扱いたい場合
- null を返す `last_key` 関数の後に null チェックを行う代わりに、より簡潔に記述したい場合
- vecの最後のインデックス取得（空でないことが前提）

**主要な処理内容**：
1. 入力がKeyedContainerかどうかを型チェック
2. KeyedContainerの場合、ネイティブ関数 `_Private\Native\last_key` を呼び出し
3. 取得したキーがnonnullでないことを検証（空チェック）
4. KeyedContainerでない場合、foreach で全要素を走査し最後のキーを取得
5. イテレーションがない場合は例外をスロー

**関連システム・外部連携**：本機能は外部システムとの連携はなく、HSL内部の `_Private\Native\last_key` ネイティブ関数に依存する。

**権限による制御**：特になし。純粋な関数であり、権限による制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 画面なし | - | 本機能はUIを持たないライブラリ関数 |

## 機能種別

データアクセス / 要素選択

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| $traversable | KeyedTraversable<Tk, Tv> | Yes | キー付き走査可能コレクション | 空でないこと（空の場合は例外） |

### 入力データソース

関数呼び出し時の引数として直接渡される。dict、vec、keyset、Map、Vector、Set、Generator等のKeyedTraversableを実装する任意の型を受け付ける。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | Tk | コレクションの最後のキー |

### 出力先

関数の戻り値として呼び出し元に返却される。

## 処理フロー

### 処理シーケンス

```
1. 型チェック: KeyedContainer判定
   └─ $traversable is KeyedContainer<_, _> で型を判定
2. KeyedContainerの場合
   └─ _Private\Native\last_key($traversable) を呼び出し
   └─ 結果が nonnull か検証（invariant）
   └─ nullの場合は InvariantException をスロー
   └─ キーを返却
3. KeyedContainerでない場合（Generator等）
   └─ foreach で全要素を走査
   └─ 最後のキーを保持し、イテレーションフラグを立てる
   └─ イテレーションがない場合は invariant で例外をスロー
   └─ 最後のキーを返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{KeyedContainer?}
    B -->|Yes| C[Native\last_key呼び出し]
    C --> D{キーがnonnull?}
    D -->|Yes| E[キーを返却]
    D -->|No| F[InvariantException]
    B -->|No| G[foreachで全走査]
    G --> H{イテレーションあり?}
    H -->|Yes| I[最後のキーを返却]
    H -->|No| J[InvariantException]
    E --> K[終了]
    I --> K
    F --> K
    J --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-115-01 | 空コレクション禁止 | 空のコレクションが渡された場合は例外をスロー | 常に適用 |
| BR-115-02 | 最後のキー取得 | 挿入順序における最後のキーを返す | コレクションが空でない場合 |

### 計算ロジック

特に計算ロジックは存在しない。コレクションの最後のキーをそのまま返却する。

## データベース操作仕様

### 操作別データベース影響一覧

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | InvariantException | コレクションが空の場合 | 呼び出し前にコレクションが空でないことを確認するか、`last_key` を使用 |

### リトライ仕様

リトライは不要。例外発生時は呼び出し元で適切にハンドリングする。

## トランザクション仕様

本機能はトランザクション管理を行わない純粋関数である。

## パフォーマンス要件

- 時間計算量: O(1) - Containerの場合、O(n) - それ以外
- 空間計算量: O(1)
- KeyedContainerの場合はネイティブ実装による高速なアクセス

## セキュリティ考慮事項

本機能は純粋関数であり、特別なセキュリティ考慮事項はない。入力データの検証は型システムにより保証される。

## 備考

- `last_key` 関数（null を返す版）との使い分けが重要
- 空のコレクションがエラーケースである場合は本関数を使用
- 空のコレクションが正常ケースである場合は `last_key` を使用
- Generator で null キーをサポート（yield null => value）

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

Hack言語のKeyedTraversable型とKeyedContainer型の違いを理解することが重要。KeyedContainerは長さを持つキー付きコレクション（dict、vec、keyset等）、KeyedTraversableはより広い概念でGeneratorなども含む。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | select.php | `src/c/select.php` | 関数シグネチャと型パラメータ Tk, Tv の理解 |

**読解のコツ**: `KeyedTraversable<Tk, Tv>` は2つの型パラメータを持ち、Tk がキーの型、Tv が値の型を表す。戻り値 `Tk` は null ではなく必ず値が返ることを意味する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | select.php | `src/c/select.php` | last_keyx 関数の実装（278-298行目） |

**主要処理フロー**:
1. **278-280行目**: 関数シグネチャ - KeyedTraversable<Tk, Tv> を受け取り Tk を返す
2. **281-288行目**: KeyedContainerの場合、ネイティブ関数呼び出しと検証
3. **282行目**: ネイティブ関数を呼び出し
4. **283-287行目**: invariant で null チェック、空の場合は例外
5. **290-294行目**: その他の場合、foreach で全走査してイテレーション確認
6. **295行目**: イテレーションがなければ例外
7. **297行目**: 最後のキーを返却

#### Step 3: 関連関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | select.php | `src/c/select.php` | last_key 関数（253-267行目）- null を返す版との比較 |
| 3-2 | select.php | `src/c/select.php` | first_keyx 関数（164-180行目）- 最初のキー取得との比較 |

**主要処理フロー**:
- **253-267行目**: last_key は空の場合 null を返す
- **278-298行目**: last_keyx は空の場合例外をスロー

### プログラム呼び出し階層図

```
C\last_keyx($traversable)
    │
    ├─ $traversable is KeyedContainer<_, _> [型チェック]
    │      │
    │      └─ _Private\Native\last_key($traversable) [ネイティブ関数]
    │             └─ invariant($last_key is nonnull, ...) [null検証]
    │
    └─ foreach ($traversable as $key => $_) [イテレーション]
           └─ invariant($did_iterate, ...) [空の場合]
```

### データフロー図

```
[入力]                       [処理]                         [出力]

KeyedTraversable ───▶ 型判定 ───▶ ネイティブ関数呼び出し ───▶ Tk（キー）
     <Tk, Tv>              │         または
                           │      foreach イテレーション
                           │
                           └─────▶ 空の場合 ───▶ InvariantException
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| select.php | `src/c/select.php` | ソース | last_keyx 関数の実装 |
| introspect.php | `src/c/introspect.php` | ソース | is_empty 等の補助関数 |
| CSelectTest.php | `tests/c/CSelectTest.php` | テスト | last_keyx のユニットテスト（584-680行目） |
