Ада защищенная процедура Put не пишет в одной строке - PullRequest
0 голосов
/ 02 декабря 2018

Моя проблема в том, что я создал защищенный Safe_Printer;но когда я использую его процедуру, он портит функцию Put.Каждый раз он печатает на новую строку.Как я мог предотвратить это ?По сути, я хотел бы напечатать свою матрицу с ней в читаемом формате.

Вот мой код:

with Ada.Text_IO;
use Ada.Text_IO;

procedure main is

   type Matrix is array(integer range <>, integer range <>) of integer; 

    protected Safe_Printer is
        procedure Put(S: String);
        procedure Put(M: Matrix);
    end Safe_Printer;

    protected body Safe_Printer is

        procedure Put(S: String) is
        begin
            for I in S'range loop
                Put(S(I));
            end loop;
            New_Line;
        end Put;

        procedure Put(M:Matrix) is
        begin
            for I in m'range(1) loop
                for j in m'range(2) loop
                    put(integer'image(m(i,j)) & " ");
                end loop;
                new_line(1);
            end loop;
        end Put;
    end Safe_Printer;

m:Matrix := ((1,2,3),
            (4,5,6));
begin

    Safe_Printer.Put(m);


        for I in m'range(1) loop
            for j in m'range(2) loop
                put(integer'image(m(i,j)) & " ");
            end loop;
         new_line(1);
        end loop;

end main;

И мой вывод:

 1
 2
 3

 4
 5
 6

 1  2  3
 4  5  6

Ответы [ 2 ]

0 голосов
/ 06 января 2019

Вы не должны вызывать «потенциально блокирующую операцию» изнутри защищенного объекта.Вызов Text_IO.Put является потенциально блокирующей операцией.См. Раздел Справочного руководства Ada 9.5.1.Я удивлен, что ваш компилятор не жаловался, на самом деле.

В этой ситуации вы можете использовать одну задачу вместо защищенного объекта.

Например:

with Ada.Text_IO;

procedure Main is

   type Matrix is array (Integer range <>, Integer range <>) of Integer; 

   task Safe_Printer is
      entry Put (S: in String);
      entry Put (M: in Matrix);
   end Safe_Printer;

   task body Safe_Printer is
      S: access String;
      M: access Matrix;
   begin
      loop
         select
            accept Put (S: in String) do
               Safe_Printer.S := new String (S'Range);
               Safe_Printer.S.all := S;
            end;
            Ada.Text_IO.Put_Line (S.all);
         or
            accept Put (M: in Matrix) do
               Safe_Printer.M := new Matrix (M'Range (1), M'Range (2));
               Safe_Printer.M.all := M;
            end;
            for I in M'Range (1) loop
               for J in M'Range (2) loop
                  Ada.Text_IO.Put (Integer'Image (M (I, J)) & " ");
               end loop;
               Ada.Text_IO.New_Line;
            end loop;
         or
            terminate;
         end select;
      end loop;
   end Safe_Printer;

   M: Matrix := ((1,2,3),
                 (4,5,6));
begin
   Safe_Printer.Put (M);
end Main;

Дополнительным преимуществом этого подхода является то, что вызовы Text_IO.Put[_Line] фактически выполняются параллельно с основной задачей.Недостатком является то, что (для безопасности) копируемая строка или матрица копируется.

Лучшая версия этого кода может использовать Unchecked_Deallocation или Ada.Containers.Indefinite_Holders для хорошей очистки после себя.

Бонусный вопрос: Как вы думаете, границы массива матрицы Mв Main процедуре есть?

0 голосов
/ 02 декабря 2018

Поскольку атрибут 'Image возвращает String, ваша реализация Put(M : Matrix) вызывает Safe_Printer.Put(S : String) во внутреннем цикле;каждая матричная запись затем получает New_Line.Одним из решений является вызов языка, определенного Put в явном виде в Safe_Printer.Put(M : Matrix):

procedure Put(M : Matrix) is
begin
    for I in M'range(1) loop
        for j in M'range(2) loop
            Ada.Text_IO.Put(integer'image(M(i,j)) & " ");
        end loop;
        New_Line;
    end loop;
end Put;

При тестировании:

with Ada.Text_IO;
use Ada.Text_IO;

procedure main is

   type Matrix is array(integer range <>, integer range <>) of integer; 

    protected Safe_Printer is
        procedure Put(S : String);
        procedure Put(M: Matrix);
    end Safe_Printer;

    protected body Safe_Printer is

       procedure Put(S : String) is
       begin
           for I in S'range loop
               Put(S(I));
           end loop;
           New_Line;
       end Put;

        procedure Put(M : Matrix) is
        begin
            for I in M'range(1) loop
                for j in M'range(2) loop
                    Ada.Text_IO.Put(integer'image(M(i,j)) & " ");
                end loop;
                New_Line;
            end loop;
        end Put;
    end Safe_Printer;



M : Matrix := ((1,2,3),
               (4,5,6));
begin
    Safe_Printer.Put(M);
end main;

Консоль:

$ ./main
 1  2  3 
 4  5  6 

В качестве альтернативы, как @ SimonWright комментарии , вы можете «удалить New_Line in Safe_Printer.Put(String)».Выбранный вами подход будет зависеть от желаемого эффекта, предлагаемого в спецификации Safe_Printer.Также подумайте об ограничении объема предложения use.

...