# 機能設計書 56-diff

## 概要

本ドキュメントは、Hack Standard Library (HSL) の `Vec\diff` 関数の機能設計書である。この関数は最初のTraversableにのみ存在する要素を返し、他のTraversableに含まれる要素を除外したvecを生成する。

### 本機能の処理概要

**業務上の目的・背景**：
集合演算はデータ処理において頻繁に必要とされる。特に「差分」の計算は、あるコレクションから別のコレクションに含まれる要素を除外したい場合に使用される。例えば、全ユーザーリストから既に処理済みのユーザーを除外したい場合や、新しいデータと既存データの差分を取得したい場合などが該当する。`Vec\diff` 関数はこの差集合演算を効率的に提供する。

**機能の利用シーン**：
- ユーザーリストから特定グループのメンバーを除外
- 全商品リストから在庫切れ商品を除外
- 新規データと既存データの差分取得
- アクセス権限リストの差分計算
- タグやカテゴリのフィルタリング

**主要な処理内容**：
1. 最初のTraversable（差分の基準）を受け取る
2. 2番目以降のTraversable（除外対象）を受け取る
3. 除外対象のすべての要素をkeysetに統合
4. 基準となるTraversableから、keysetに含まれない要素のみを抽出
5. 結果をvecとして返却

**関連システム・外部連携**：
内部実装では `Keyset\union` と `Vec\filter` を使用している。非arraykey型の要素を扱う場合は `Vec\diff_by` を使用する。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | 画面なし | - | 本プロジェクトはUIを持たないライブラリのため該当なし |

## 機能種別

集合演算処理 / データフィルタリング

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| $first | Traversable<Tv1 as arraykey> | Yes | 差分の基準となるコレクション | arraykey型の要素を持つTraversable |
| $second | Traversable<Tv2 as arraykey> | Yes | 除外対象のコレクション | arraykey型の要素を持つTraversable |
| ...$rest | Container<Tv2> | No | 追加の除外対象コレクション（可変長） | arraykey型の要素を持つContainer |

### 入力データソース

関数呼び出し時の引数として直接渡される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | vec<Tv1> | 最初のTraversableから除外対象の要素を除いたvec |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. 入力検証
   └─ $first が空の場合、空のvecを返却
2. ショートカット判定
   └─ $second と $rest が両方空の場合、$first をそのままvecに変換して返却
3. 除外集合の構築
   └─ $rest がない場合: $second を keyset に変換
   └─ $rest がある場合: Keyset\union($second, ...$rest) で統合
4. 差分計算
   └─ $first の各要素について、除外集合に含まれない要素のみを抽出
5. 結果返却
   └─ 抽出された要素をvecとして返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[入力: $first, $second, ...$rest]
    B --> C{$first は空?}
    C -->|Yes| D[空のvecを返却]
    C -->|No| E{$second と $rest は空?}
    E -->|Yes| F[$first をvecに変換して返却]
    E -->|No| G{$rest は空?}
    G -->|Yes| H[union = keyset 変換した $second]
    G -->|No| I[union = Keyset\union で統合]
    H --> J[filter: unionに含まれない要素を抽出]
    I --> J
    J --> K[結果vecを返却]
    D --> L[終了]
    F --> L
    K --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-56-01 | arraykey制約 | 要素はarraykey型（intまたはstring）に限定 | 常時 |
| BR-56-02 | 順序保持 | $first の要素の順序は結果でも保持される | 常時 |
| BR-56-03 | 重複許容 | $first に重複があった場合、条件を満たせばすべて保持 | $first に重複がある場合 |
| BR-56-04 | 厳密等価 | 要素の比較は厳密等価で行われる | 常時 |

### 計算ロジック

- 計算量: O(n + m) - nは$firstのサイズ、mは$secondと$restの合計サイズ
- 空間計算量: O(n + m) - nは$firstのサイズ、mは除外集合のサイズ

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

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

本機能はデータベース操作を行わない純粋関数である。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | 本関数は例外をスローしない | - |

### リトライ仕様

リトライは不要（同期的な純粋関数のため）

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

該当なし（データベース操作を行わないため）

## パフォーマンス要件

- 計算量: O(n + m) - 効率的なハッシュベースの集合演算
- 純粋関数 `[]` として定義されており、副作用なし
- keysetを使用した高速な存在確認

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

- 入力データの検証は呼び出し側の責任
- 機密データを含むコレクションの差分計算時は結果の取り扱いに注意

## 備考

- 非arraykey型の要素を扱う場合は `Vec\diff_by()` を使用
- 結果は常に新しいvecとして返される（入力は変更されない）
- 空のコレクションを渡した場合のショートカット最適化あり

---

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

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

### 推奨読解順序

#### Step 1: 型パラメータを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | select.php | `src/vec/select.php` | 関数シグネチャの型パラメータ（27-31行目） |

**読解のコツ**:
- `Tv1 as arraykey` と `Tv2 as arraykey` は異なる型パラメータだが、どちらもarraykey制約
- `Container<Tv2> ...$rest` は可変長引数で追加の除外対象を受け取る

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

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

**主要処理フロー**:
1. **32-34行目**: $first が空の場合の早期リターン
2. **36-38行目**: $second と $rest が両方空の場合のショートカット
3. **40行目**: 除外集合の構築（keyset または Keyset\union）
4. **41行目**: filter で差分を計算

#### Step 3: 依存関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | select.php | `src/keyset/select.php` | Keyset\union の実装 |
| 3-2 | select.php | `src/vec/select.php` | Vec\filter の実装（108-120行目） |

**主要ポイント**:
- `C\contains_key` でkeyset内の存在確認を行う（O(1)）

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

```
Vec\diff($first, $second, ...$rest)
    │
    ├─ [empty check] $first が空 → vec[] を返却
    │
    ├─ [shortcut] $second と $rest が空 → cast_clear_legacy_array_mark($first)
    │
    └─ [main logic]
           │
           ├─ Keyset\union($second, ...$rest)  // 除外集合の構築
           │
           └─ Vec\filter($first, ...)  // 差分計算
                  │
                  └─ C\contains_key($union, $value)  // 存在確認
```

### データフロー図

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

$first ─────────────────▶
 (Traversable<Tv1>)        Vec\diff ─────────────▶ vec<Tv1>
                               │                   (差分結果)
$second ────────────────▶      │
 (Traversable<Tv2>)            │
                               ▼
...$rest ───────────────▶  Keyset\union
 (Container<Tv2>...)           │
                               ▼
                           Vec\filter
                               │
                               ▼
                           結果vec
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| select.php | `src/vec/select.php` | ソース | diff関数のパブリックインターフェース |
| select.php | `src/keyset/select.php` | ソース | Keyset\union関数 |
| VecSelectTest.php | `tests/vec/VecSelectTest.php` | テスト | diff関数のユニットテスト |
