# 機能設計書 101-Printf

## 概要

本ドキュメントは、Julia標準ライブラリ `Printf` モジュールが提供するCスタイルフォーマット出力機能の設計を記述する。`@printf` マクロおよび `@sprintf` マクロにより、C言語の `printf` 関数と互換性のあるフォーマット指定子を用いた書式付き出力を実現する。

### 本機能の処理概要

**業務上の目的・背景**：数値やデータを人間が読みやすい形式で出力するため、C言語由来のフォーマット文字列構文を提供する。科学技術計算や数値解析において、精度制御や桁揃えを伴う出力は不可欠であり、C/Fortranユーザーが慣れ親しんだ構文をそのまま利用可能にすることで、移行コストを低減する。

**機能の利用シーン**：数値データの精度指定出力、ログメッセージのフォーマット、レポート生成、デバッグ出力、文字列テンプレートの動的生成など、書式付きテキスト出力が必要なあらゆる場面で利用される。

**主要な処理内容**：
1. フォーマット文字列の構文解析（`Format` コンストラクタ）
2. 各フォーマット指定子（`%d`, `%f`, `%s`, `%e`, `%g`, `%x`, `%o`, `%c`, `%p`, `%a` 等）に対応する型付き `Spec` オブジェクトの生成
3. 引数をフォーマット指定子に従ってバイトバッファに書き込み（`fmt` 関数群）
4. 動的幅・動的精度（`*`）のサポート
5. `@printf` によるIO出力、`@sprintf` による文字列生成
6. BigFloat向けMPFR連携によるフォーマット出力

**関連システム・外部連携**：Base.Ryu ライブラリ（浮動小数点数の高速フォーマット）、MPFR ライブラリ（BigFloat出力時の `mpfr_snprintf`）。

**権限による制御**：特になし。全ユーザーが利用可能。

## 関連画面

本機能に直接関連する画面はない。ただし、REPL上での出力やロギング出力と組み合わせて使用される。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | REPLや各種出力先での書式付き出力に利用 |

## 機能種別

計算処理 / テキスト変換処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| format_str | String | Yes | Cスタイルのフォーマット文字列（`%d`, `%f`等を含む） | 不正な指定子の場合 `InvalidFormatStringError` を送出 |
| io | IO | No | 出力先ストリーム（`@printf`の第一引数、省略時はstdout） | IO型であること |
| args... | Any | Yes | フォーマット指定子に対応する引数群 | 引数の数がフォーマット指定子の数と一致すること |

### 入力データソース

ユーザーがコード中で直接指定するフォーマット文字列リテラルおよび引数。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| formatted_output | String（`@sprintf`） / Nothing（`@printf`） | フォーマットされた文字列またはIOへの出力 |

### 出力先

- `@printf`：指定されたIOストリーム（デフォルトは `stdout`）
- `@sprintf`：戻り値として `String` を返す
- `Printf.format`：IO引数指定時はIOへ出力、省略時はStringを返す

## 処理フロー

### 処理シーケンス

```
1. マクロ展開時にフォーマット文字列を解析
   └─ Format(format_str) を呼び出し、Spec タプルと部分文字列範囲を構築
2. 引数の数とフォーマット指定子の数を検証
   └─ numarguments と length(args) の一致確認
3. 出力バッファサイズを計算
   └─ computelen() で各指定子の最大出力長を合算
4. 各フォーマット指定子について引数をバッファに書き込み
   └─ fmt(buf, pos, arg, spec) を指定子型ごとにディスパッチ
5. 結果を出力
   └─ @printf: write(io, buf) / @sprintf: String(buf)
```

### フローチャート

```mermaid
flowchart TD
    A["マクロ呼び出し (@printf/@sprintf)"] --> B["Format(format_str): フォーマット文字列解析"]
    B --> C{"引数数チェック"}
    C -->|不一致| D["ArgumentError送出"]
    C -->|一致| E["computelen(): バッファサイズ計算"]
    E --> F["StringVector(len) バッファ確保"]
    F --> G["format(buf, 1, f, args...): 各指定子処理"]
    G --> H{"@printf or @sprintf?"}
    H -->|@printf| I["write(io, buf)"]
    H -->|@sprintf| J["String(buf) を返す"]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-101-1 | フォーマット指定子互換性 | C標準のprintf書式（`%d`, `%i`, `%u`, `%x`, `%X`, `%o`, `%e`, `%E`, `%f`, `%F`, `%g`, `%G`, `%a`, `%A`, `%c`, `%s`, `%p`, `%n`）をサポート | 常時 |
| BR-101-2 | 動的幅・精度 | `*` による動的幅・精度指定をサポート（Julia 1.10以降） | フォーマット文字列に `*` を含む場合 |
| BR-101-3 | Inf/NaN一貫性 | `Inf`/`NaN`は全浮動小数点フォーマットで一貫した表記 | 引数がInf/NaNの場合 |
| BR-101-4 | BigFloat対応 | BigFloat引数はMPFRを通じて高精度フォーマット | 引数がBigFloat型の場合 |

### 計算ロジック

- 浮動小数点フォーマットは `Base.Ryu` ライブラリの `writeexp`/`writefixed`/`writeshortest` を使用
- 整数フォーマットは8進・10進・16進に対応し、`ndigits` で桁数を計算
- 幅・精度によるパディング（スペースまたはゼロ）と左右寄せを実装

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

該当なし。本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | InvalidFormatStringError | 不正なフォーマット指定子 | フォーマット文字列を修正する |
| - | ArgumentError | 引数の数がフォーマット指定子の数と不一致 | 引数の数を一致させる |
| - | ArgumentError | BigFloat出力が__BIG_FLOAT_MAX__(8192bytes)を超過 | カスタム印刷ルーチンを使用する |

### リトライ仕様

リトライ不要（即時エラー通知）。

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

該当なし。

## パフォーマンス要件

- マクロ展開時にフォーマット文字列を解析するため、実行時の文字列パースコストはゼロ
- 最大16個のフォーマット指定子まで `@nexprs` によるループアンロールで最適化
- バッファサイズの事前計算により、メモリ再割り当てを最小化

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

- `%n` 指定子（PositionCounter）は書き込みバイト数を `Ref{Integer}` に格納するが、Cの `%n` のようなメモリ破壊の危険はない（Juliaの型安全性による保護）
- ユーザー入力をフォーマット文字列として使用する場合、任意コード実行のリスクはないが、不正なフォーマット文字列による例外が発生する可能性がある

## 備考

- `Printf.Format` オブジェクトを事前に生成して再利用することで、同じフォーマットの繰り返し使用時にパースコストを削減可能
- `Printf.tofloat` メソッドをオーバーロードすることで、カスタム数値型のフォーマット出力を拡張可能

---

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

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

### 推奨読解順序

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

フォーマット指定子の型表現と、フォーマット全体の構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Printf.jl | `stdlib/Printf/src/Printf.jl` | `Spec{T}` 構造体（33-43行目）: フォーマット指定子1つを表す型。`T`は`Val{'d'}`等のValType |
| 1-2 | Printf.jl | `stdlib/Printf/src/Printf.jl` | `Format{S,T}` 構造体（82-93行目）: フォーマット文字列全体を表す型。部分文字列範囲とSpecタプルを保持 |
| 1-3 | Printf.jl | `stdlib/Printf/src/Printf.jl` | `InvalidFormatStringError`（99-125行目）: パースエラー型。色付きエラー表示を含む |

**読解のコツ**: `Spec{T}` の型パラメータ `T` は `Val{'d'}` のような `Val` 型で、フォーマット指定子の文字を型レベルで表現している。これにより、Juliaの多重ディスパッチで指定子ごとに異なる `fmt` メソッドが呼ばれる。

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

マクロ定義と `format` 関数を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Printf.jl | `stdlib/Printf/src/Printf.jl` | `@printf` マクロ（1009-1021行目）: IO引数の有無を判定し `format(io, fmt, args...)` を呼び出す |
| 2-2 | Printf.jl | `stdlib/Printf/src/Printf.jl` | `@sprintf` マクロ（1034-1038行目）: `format(fmt, args...)` で文字列を返す |
| 2-3 | Printf.jl | `stdlib/Printf/src/Printf.jl` | `format` 関数（935-948行目）: バッファ確保、フォーマット実行、結果出力の本体 |

**主要処理フロー**:
1. **1010-1012行目**: フォーマット文字列を `Format()` でコンパイル時に解析
2. **936行目**: 引数数の検証
3. **937行目**: `computelen` でバッファサイズを計算
4. **938行目**: `format(buf, 1, f, args...)` でバッファに書き込み
5. **939行目**: `write(io, resize!(buf, pos - 1))` で出力

#### Step 3: フォーマット文字列パーサーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Printf.jl | `stdlib/Printf/src/Printf.jl` | `Format(f::AbstractString)` コンストラクタ（128-275行目）: `%` を検出して各指定子のフラグ・幅・精度・型を解析 |

**主要処理フロー**:
- **138-152行目**: 最初の `%` を探す（`%%`はエスケープ）
- **161-178行目**: フラグ解析（`-`, `+`, ` `, `0`, `#`）
- **183-197行目**: 幅の解析（`*` または数値）
- **198-223行目**: 精度の解析（`.` の後に `*` または数値）
- **225-239行目**: 長さ修飾子の解析（`h`, `l`, `L` 等、無視される）
- **241-255行目**: 型指定子の解析と `Spec` オブジェクト生成

#### Step 4: 各型のフォーマット処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Printf.jl | `stdlib/Printf/src/Printf.jl` | `fmt(buf, pos, arg, spec::Spec{T<:Chars})`（318-336行目）: 文字フォーマット |
| 4-2 | Printf.jl | `stdlib/Printf/src/Printf.jl` | `fmt(buf, pos, arg, spec::Spec{T<:Strings})`（339-377行目）: 文字列フォーマット |
| 4-3 | Printf.jl | `stdlib/Printf/src/Printf.jl` | `fmt(buf, pos, arg, spec::Spec{T<:Ints})`（386-462行目）: 整数フォーマット（8/10/16進数） |
| 4-4 | Printf.jl | `stdlib/Printf/src/Printf.jl` | `fmt(buf, pos, arg, spec::Spec{T<:Floats})`（500-676行目）: 浮動小数点フォーマット（Ryu/MPFR使用） |

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

```
@printf / @sprintf (マクロ展開)
    │
    ├─ Format(format_str)             -- フォーマット文字列解析
    │      └─ Spec{T}()              -- 各指定子オブジェクト生成
    │
    └─ Printf.format(io/buf, fmt, args...)
           │
           ├─ computelen()            -- バッファサイズ事前計算
           │      └─ plength()        -- 各指定子の最大出力長
           │
           └─ format(buf, 1, f, args...)  -- バッファへの書き込み
                  │
                  ├─ fmt(buf, pos, args, argp, spec)  -- 動的幅精度解決
                  │      └─ rmdynamic()
                  │
                  └─ fmt(buf, pos, arg, spec::Spec{T})  -- 型別フォーマット
                         ├─ Chars: writechar()
                         ├─ Strings: string() + textwidth()
                         ├─ Ints: ndigits() + 基数変換
                         ├─ Floats: Ryu.writeexp/writefixed/writeshortest
                         │         └─ BigFloat: mpfr_snprintf
                         ├─ Pointer: ptrfmt() -> Ints処理
                         └─ PositionCounter: pos書き込み
```

### データフロー図

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

format_str ───────▶ Format()パーサー ──▶ Format{S,T}オブジェクト
                                              │
args... ──────────▶ format(buf, f, args...)    │
                         │                     │
                         ▼                     ▼
                    computelen() ──▶ バッファ確保
                         │
                         ▼
                    fmt() x N ──▶ バイトバッファ書き込み
                         │
                         ▼
                    write(io)/String() ──▶ stdout / String
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Printf.jl | `stdlib/Printf/src/Printf.jl` | ソース | Printf モジュール全体（唯一のソースファイル） |
| runtests.jl | `stdlib/Printf/test/runtests.jl` | テスト | Printf モジュールのテストスイート |
| ryu.jl | `base/ryu/` | ソース | Ryu浮動小数点フォーマットライブラリ（Base内蔵） |
