Ada 202x (15日目) - 'Image¶
折り返し? お、折り返しでしょうか? まだまだ終わりそうにないのです?
経緯¶
今回は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
を使って無駄に文字列を経由させるよりも効率的です。
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;
自分で用意したバッファに出力させることもできます。
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¶
Ada.Strings.Text_Buffers.Bounded¶
Ada.Strings.Text_Buffers.Unbounded¶
関連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