comp.lang.ada
 help / color / mirror / Atom feed
* how to delete from Ada.Containers.Doubly_Linked_Lists
@ 2014-08-18 18:51 Björn Lundin
  2014-08-18 19:57 ` Jeffrey Carter
  0 siblings, 1 reply; 3+ messages in thread
From: Björn Lundin @ 2014-08-18 18:51 UTC (permalink / raw)



Hi,
I try to get aquinted with Ada.Containers.Doubly_Linked_Lists,
which I feel may replace a homebrew list class we
use at work.

Especailly the 'for of' notation
seems nice to have.

But How do I delete an item in the list
while looping it?

I've got a sample below,
but I fell it is clumpsy.
How should a nice solution look like ?

/Björn


with Text_Io;
with Ada.Containers.Doubly_Linked_Lists;

procedure Test_List is
    type Example_Type is record
      A :Integer := 0;
      B: Integer := 0;
    end record;

    procedure To_String(E : Example_Type) is
    begin
      Text_io.Put_Line(E.A'Img & E.B'Img);
    end To_String;

begin

  Text_io.Put_Line("start Ada.Containers.Doubly_Linked_Lists; ");

  declare
    Data : Example_Type;
    package Example_Pkg is new
Ada.Containers.Doubly_Linked_Lists(Example_Type);
    List : Example_Pkg.List;
  begin

    Text_io.Put_Line("insert 5 elements at tail, ");
    for i in 1..5 loop
      Data := (A => i, B => 2 * i);
      List.Append(Data);
    end loop;

    for i of List loop
      To_String(i);
    end loop;

    Text_io.Put_Line("Update in place");

    for i of List loop
      I.A := 5*I.A;
      I.B := 50*I.B;
    end loop;

    for i of List loop
      To_String(i);
    end loop;

    Text_io.Put_Line("delete if I.a = 15");

    for c in List.Iterate loop
      declare
        i : Example_Type := Example_Pkg.Element(C);
      begin
        if I.A = 15 then
           List.Delete(C);      <-- program_error raised
        end if;
      end ;
    end loop;

    --works but clumplsy

    declare
      C_Save : Example_Pkg.Cursor;
    begin
      for c in List.Iterate loop
        declare
          i : Example_Type := Example_Pkg.Element(C);
        begin
          if I.A = 15 then
            C_Save := C;
            exit;
          end if;
        end ;
      end loop;
      List.Delete(C_Save);
    end;

    for i of List loop
      To_String(i);
    end loop;
    Text_io.Put_Line("done");
  end;
end Test_List;


sample run:

insert 5 elements at tail,
 1 2
 2 4
 3 6
 4 8
 5 10
Update in place
 5 100
 10 200
 15 300
 20 400
 25 500
delete if I.a = 15

Execution terminated by unhandled exception
Exception name: PROGRAM_ERROR
Message: attempt to tamper with cursors (list is busy)



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: how to delete from Ada.Containers.Doubly_Linked_Lists
  2014-08-18 18:51 how to delete from Ada.Containers.Doubly_Linked_Lists Björn Lundin
@ 2014-08-18 19:57 ` Jeffrey Carter
  2014-08-19  8:56   ` Björn Lundin
  0 siblings, 1 reply; 3+ messages in thread
From: Jeffrey Carter @ 2014-08-18 19:57 UTC (permalink / raw)


On 08/18/2014 11:51 AM, Björn Lundin wrote:
> 
> 
> I've got a sample below,
> but I fell it is clumpsy.
> How should a nice solution look like ?

You probably ought to read about "tampering with cursors" in the ARM (A.18.3).
In your case, iterating over the list needs the list to remain unchanged until
iteration finishes. Deleting during iteration would violate this.

This restriction is intended for safety, and sometimes seems onerous. I've had
to iterate over one data structure, storing cursors in another data structure,
then iterate over the 2nd data structure to delete using the stored cursors.

You can delete during iteration if you don't invoke an Iterate subprogram:

   declare
      C    : Example_Pkg.Cursor := List.First;
      Next : Example_Pkg.Cursor;

      use type Example_Pkg.Cursor;
   begin
      loop
         exit when C = Example_Pkg.No_Element;

         declare
            I : constant Example_Type := Example_Pkg.Element (C);
         begin
            if I.A /= 15 then
               Example_Pkg.Next (Position => C);
            else
               Next := Example_Pkg.Next (C);
               List.Delete (Position => C);
               C := Next;
            end if;
         end ;
      end loop;
   end;

-- 
Jeff Carter
"You a big nose have it."
Never Give a Sucker an Even Break
107

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: how to delete from Ada.Containers.Doubly_Linked_Lists
  2014-08-18 19:57 ` Jeffrey Carter
@ 2014-08-19  8:56   ` Björn Lundin
  0 siblings, 0 replies; 3+ messages in thread
From: Björn Lundin @ 2014-08-19  8:56 UTC (permalink / raw)


On 2014-08-18 21:57, Jeffrey Carter wrote:
> On 08/18/2014 11:51 AM, Björn Lundin wrote:

>> How should a nice solution look like ?
> 
> You probably ought to read about "tampering with cursors" in the ARM (A.18.3).
> In your case, iterating over the list needs the list to remain unchanged until
> iteration finishes. Deleting during iteration would violate this.

Hmm, yes I see that now.

> This restriction is intended for safety, and sometimes seems onerous.

That was my suspicion

> I've had
> to iterate over one data structure, storing cursors in another data structure,
> then iterate over the 2nd data structure to delete using the stored cursors.

Yes, basically what my last sample did - saving the cursor 'c' into
'C_Save' and delete outside the loop. That is what I thought was
inelegant/clumpsy

> You can delete during iteration if you don't invoke an Iterate subprogram:

Still a bit inelegant, but thanks for the example.
It is way better that mine.


/Björn






^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2014-08-19  8:56 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-18 18:51 how to delete from Ada.Containers.Doubly_Linked_Lists Björn Lundin
2014-08-18 19:57 ` Jeffrey Carter
2014-08-19  8:56   ` Björn Lundin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox