# 機能設計書 38-Range拡張

## 概要

本ドキュメントは、mrubyのRangeクラスにcover?, size, first, last, max, min, overlap?等の拡張メソッドを追加するgem（mruby-range-ext）の機能設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：CRuby互換のRange操作メソッドを提供し、範囲オブジェクトの操作性を向上させる。包含判定（cover?）、要素数取得（size）、端点取得（first, last）、最大/最小値取得（max, min）、重複判定（overlap?）等を利用可能にする。

**機能の利用シーン**：値が範囲内にあるかの判定（cover?）、範囲の要素数計算（size）、範囲の先頭/末尾要素の取得（first/last）、数値範囲の最大/最小値取得（max/min）、2つの範囲の重なり判定（overlap?）等。

**主要な処理内容**：
1. 包含判定: cover?（値またはRange引数が範囲内かを判定）
2. サイズ計算: size（数値範囲の要素数を返す）
3. 端点取得: first（先頭要素/先頭n要素）、last（末尾要素/末尾n要素）
4. 最大/最小: max（最大値取得、Numericファストパス付き）、min（最小値取得、Numericファストパス付き）
5. 重複判定: overlap?（2つのRangeが共通要素を持つか判定）
6. 内部ヘルパー: __empty_range?（範囲が空かどうかの判定）

**関連システム・外部連携**：なし。

**権限による制御**：なし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面なし |

## 機能種別

範囲操作 / 包含判定処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| obj/range | Object/Range | Yes(cover?) | 判定対象（値またはRange） | - |
| n | Integer | No(first/last) | 取得要素数 | 非負整数 |
| other | Range | Yes(overlap?) | 比較対象Range | Rangeであること |
| block | Block | No(max/min) | 比較用ブロック | - |

### 入力データソース

メソッド呼び出し時の引数。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Boolean | true/false | cover?, overlap?の判定結果 |
| Integer/Float/nil | Numeric/nil | sizeの計算結果（非数値範囲はnil） |
| Object | Object | first, last（引数なし時）、max, minの結果 |
| Array | Array | first(n), last(n)の結果 |

### 出力先

メソッドの戻り値。

## 処理フロー

### 処理シーケンス

```
1. cover?: beginとendのnil判定後、mrb_cmpで比較演算
   - Range引数時: 始端同士・終端同士の比較で包含判定
   - 値引数時: begin <= val かつ val < end (excl) / val <= end (!excl)
2. size: begin/endが数値であれば差分計算、非数値はnil
3. first(n): eachでn個収集
4. last(n): to_a.last(n)に委譲
5. max: Numericファストパスで直接計算、非数値はEnumerable#maxに委譲
6. min: Numericファストパスで直接計算、非数値はEnumerable#minに委譲
7. overlap?: __empty_range?で空範囲チェック後、包含関係を判定
```

### フローチャート

```mermaid
flowchart TD
    A[cover? 呼び出し] --> B{引数はRange?}
    B -->|Yes| C[Range同士の包含判定]
    C --> D{begin/endのnil組合せ}
    D -->|begin/end共にnil| E[true返却]
    D -->|endlesss| F[beg比較のみ]
    D -->|beginless| G[end比較のみ]
    D -->|通常| H[beg/end両方比較]
    B -->|No| I{begin <= val?}
    I -->|Yes| J{val < end / val <= end?}
    J -->|Yes| K[true返却]
    J -->|No| L[false返却]
    I -->|No| L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | cover?のRange引数対応 | Range引数時は始端/終端の包含関係で判定する | cover?でRange引数時 |
| BR-02 | sizeの非数値nil返却 | begin/endが数値でない場合はnilを返す | size呼び出し時 |
| BR-03 | endless rangeのsize | Integer始端でendがnilの場合はInfinityを返す | size呼び出し時 |
| BR-04 | maxのexclude_end制約 | exclude_end?かつendがIntegerでない場合TypeError | max呼び出し時 |
| BR-05 | overlap?の型チェック | 引数がRangeでない場合TypeError | overlap?呼び出し時 |
| BR-06 | beginless rangeのfirst | beginがnilの場合RangeError | first呼び出し時 |
| BR-07 | endless rangeのlast | endがnilの場合RangeError | last呼び出し時 |

### 計算ロジック

- **size**: `floor(end - begin + err) + 1`（exclude_end時は`floor(end - begin - err)`）。errは浮動小数点誤差補正値 `(|begin| + |end| + |end-begin|) * FLOAT_EPSILON`
- **r_less**: `mrb_cmp`の結果を利用し、excl時は等値を含まない比較
- **max(Numeric)**: `exclude_end? ? end - 1 : end`
- **overlap?**: `__empty_range?`を4回呼び出して空範囲を排除した上で包含判定

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | TypeError | sizeでFloat始端 | "can't iterate from Float" |
| - | TypeError | sizeでnil始端 | "can't iterate from nil" |
| - | TypeError | maxでexclude_end?かつ非Integer終端 | TypeError |
| - | TypeError | overlap?で非Range引数 | "argument must be a range" |
| - | RangeError | firstでbeginless range | "cannot get the first element of beginless range" |
| - | RangeError | lastでendless range | "cannot get the last element of endless range" |
| - | RangeError | maxでendless range | "cannot get the maximum of endless range" |
| - | RangeError | min(block)でendless range | "cannot get the minimum of endless range with custom comparison method" |
| - | ArgumentError | first/lastで負のn | "negative array size (or size too big)" |

### リトライ仕様

なし。

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

なし。

## パフォーマンス要件

- cover?(値): O(1)（比較演算のみ）
- cover?(Range): O(1)（比較演算のみ）
- size: O(1)（算術計算のみ）
- first(n): O(n)（eachで収集）
- last(n): O(全要素)（to_aに変換後last）
- max/min: O(1)（Numericファストパス時）、O(全要素)（Enumerable委譲時）
- overlap?: O(1)（比較演算のみ）

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

なし。

## 備考

- CとRubyのハイブリッド実装
- cover?とsizeと__empty_range?がC実装、first/last/max/min/overlap?がRuby実装
- cover?はbeginless range（..b）とendless range（a..）に対応
- sizeはMRB_NO_FLOAT条件コンパイルで整数のみの簡易版に切り替わる
- max/minはNumeric型のファストパスを持ち、非Numericの場合はEnumerable#max/minに委譲

---

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

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

### 推奨読解順序

#### Step 1: ヘルパー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | range.c | `mrbgems/mruby-range-ext/src/range.c` | r_less関数（7-20行目） |

**読解のコツ**: `r_less`は`mrb_cmp`のラッパーで、excl（排他端）フラグにより等値判定を制御する。戻り値-2は比較不能を意味する。

#### Step 2: C実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | range.c | `mrbgems/mruby-range-ext/src/range.c` | 各メソッドのC実装 |

**主要処理フロー**:
- **7-20行目**: r_less - 比較ヘルパー（mrb_cmpベース、excl対応）
- **40-96行目**: range_cover - cover?（値/Range両対応、beginless/endless対応）
- **110-170行目**: range_size - size（Float版、誤差補正付き）
- **172-195行目**: range_size - size（MRB_NO_FLOAT版、整数のみ）
- **205-217行目**: range_empty_p - __empty_range?（内部ヘルパー）
- **219-223行目**: ROMメソッドテーブル登録

#### Step 3: Ruby実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | range.rb | `mrbgems/mruby-range-ext/mrblib/range.rb` | Ruby実装メソッド群 |

**主要処理フロー**:
- **13-28行目**: first - 先頭要素/先頭n要素取得（eachベース）
- **45-54行目**: last - 末尾要素/末尾n要素取得（to_aベース）
- **69-89行目**: max - 最大値取得（Numericファストパス + Enumerable委譲）
- **102-122行目**: min - 最小値取得（Numericファストパス + Enumerable委譲）
- **134-154行目**: overlap? - 重複判定（__empty_range?を利用）

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

```
Range#cover?
    +-- range_cover (C実装)
            +-- mrb_range_ptr -> RANGE_BEG/RANGE_END
            +-- r_less (比較ヘルパー)
                    +-- mrb_cmp

Range#size
    +-- range_size (C実装)
            +-- [Float版] floor() + 誤差補正
            +-- [NO_FLOAT版] 整数差分計算

Range#max
    +-- [Numericファストパス] end - 1 (excl) / end (!excl)
    +-- [非Numeric/block] super (Enumerable#max)

Range#overlap?
    +-- __empty_range? (C実装)
            +-- mrb_cmp
```

### データフロー図

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

Range (self)    ──────▶ C/Ruby処理関数 ──────▶ Boolean / Numeric / Array
obj/other引数          包含判定/サイズ計算      結果
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| range.c | `mrbgems/mruby-range-ext/src/range.c` | ソース(C) | C実装メソッド群（cover?, size, __empty_range?） |
| range.rb | `mrbgems/mruby-range-ext/mrblib/range.rb` | ソース(Ruby) | Ruby実装メソッド群（first, last, max, min, overlap?） |
| mrbgem.rake | `mrbgems/mruby-range-ext/mrbgem.rake` | 設定 | gem定義 |
| range.rb | `mrbgems/mruby-range-ext/test/range.rb` | テスト | テストケース |
