Ada 202x (15日目) - 'Image ========================== .. post:: Dec 15, 2019 :tags: ada, ada_2022 折り返し? お、折り返しでしょうか? まだまだ終わりそうにないのです? 経緯 ---- 今回は7日目の宿題回収です。 今まで ``'Image`` 属性は数値型や列挙型でしか使えませんでした。 また返す文字列の書式も固定でした。 Ada 202xでの改善 ---------------- 全ての型で ``'Image`` 属性が使えるようになりました。 わー拍手。 ``record`` や配列にはaggregate式風の文字列が返りますし、class-wide型にはqualified式風の文字列が返ります。 access型にはアドレスを16進表記した文字列が返ります。 printデバッグが捗ります。 Ada 2012のTechnical Corrigendum 1の時点で関数形式の ``T'Image (V)`` だけでなく直接 ``O'Image`` と書けるようになっていたことも覚えておくと更に捗ります。 また ``'Image`` 属性の返す文字列は型ごとにカスタマイズできるようになりました。 'Put_Image ++++++++++ ``'Image`` 属性をカスタマイズするには ``'Put_Image`` 属性を自分で用意した手続きで上書きすればいいです。 ``'Read`` や ``'Write`` をカスタマイズするのと同じ感じです。 ``'Put_Image`` は渡されたバッファに値を文字列化したものを入れる属性です。 ``'Image`` 属性は ``'Put_Image`` 属性を使ってテンポラリバッファを埋め、それからバッファの中身を文字列にして返す、という挙動になったわけです。 バッファの型として最初は ``Ada.Streams.Storage`` が使われる予定だったのですが、バイナリではなく文字列をメモリ上で作る出力先として ``Ada.Strings.Text_Buffers`` が用意されました。 (JavaやC#の ``StringBuffer`` みたいなものです。) ``'Image`` ではなく ``'Put_Image`` を直接使うこともできます。 例えば入れ子の実装には ``'Image`` を使って無駄に文字列を経由させるよりも効率的です。 .. code-block:: ada type My_Rec is record X : Float; Y : Character; end record; procedure My_Put_Image (Buffer : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class; Arg : in My_Rec); for T'Put_Image use My_Put_Image; procedure My_Put_Image (Buffer : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class; Arg : in My_Rec) is begin Ada.Strings.Text_Buffers.Put (Buffer, "(X => "); Float'Put_Image (Buffer, Arg.X); Ada.Strings.Text_Buffers.Put (Buffer, ", Y => "); Character'Put_Image (Buffer, Arg.Y); Ada.Strings.Text_Buffers.Put (Buffer, ")"); end My_Put_Image; 自分で用意したバッファに出力させることもできます。 .. code-block:: ada declare Buffer : Ada.Strings.Text_Buffers.Unbounded.Buffer_Type; Obj : My_Rec := (X => 5.0, Y => 'A'); begin Ada.Strings.Text_Buffers.Put (Buffer, "Obj = "); My_Rec'Put_Image (Buffer, Obj); この例では ``Buffer`` には ``"Obj = (X => 5.0, Y => 'A')"`` が入ります。 ``Ada.Strings.Text_Buffers.Root_Buffer_Type`` がabstract型ですので派生型を作れば出力先を変えることもできます。 例えば文字列を介さず直接 ``Text_IO`` に出力するようにすること等が考えられます。 (これは ``StringBuffer`` と異なる点です。) 注意点としまして ``'Image`` 属性はカスタマイズできるようになりましたが ``'Value`` 属性は従来のまま数値型や列挙型にしか使えませんしカスタマイズもできないという点です。 ``'Image`` 属性の結果は ``'Value`` 属性で元の値にできることが期待されているため、数値型や列挙型の ``'Image`` 属性をカスタマイズするときは ``'Value`` 属性が処理できる形に留める必要があります。 例えば16進数にする場合は単に ``"FF"`` としたりC系風に ``"0xFF"`` としてしまいますと ``'Value`` 属性が処理できませんので ``"16#FF#"`` とする必要があります。 ``'Image`` 属性はあくまで簡易な文字列化です。 主な用途はデバッグやシリアライズに留めて、ちゃんとした出力にはちゃんとした書式化ができるライブラリを使うようにしましょう。 Ada.Strings.Text_Buffers ++++++++++++++++++++++++ | http://www.ada-auth.org/standards/2xrm/html/RM-A-4-12.html#p3 Ada.Strings.Text_Buffers.Bounded ++++++++++++++++++++++++++++++++ | http://www.ada-auth.org/standards/2xrm/html/RM-A-4-12.html#p22 Ada.Strings.Text_Buffers.Unbounded ++++++++++++++++++++++++++++++++++ | http://www.ada-auth.org/standards/2xrm/html/RM-A-4-12.html#p18 関連AI ------ - `AI12-0020-1`_ **'Image for all types** - `AI12-0315-1`_ **Image Attributes subclause improvements** - `AI12-0340-1`_ **Put_Image should use a Text_Buffer** .. _`AI12-0020-1`: http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0020-1.txt .. _`AI12-0315-1`: http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0315-1.txt .. _`AI12-0340-1`: http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0340-1.txt