comp.lang.ada
 help / color / mirror / Atom feed
* C++ STL Components and Ada
@ 2001-07-16  0:37 James Rogers
  2001-07-17  4:26 ` Brian Rogoff
  0 siblings, 1 reply; 9+ messages in thread
From: James Rogers @ 2001-07-16  0:37 UTC (permalink / raw)


Occasionally I read questions from Ada newbies about the presence of
Ada equivalents to the C++ STL. 

After many years of reading about and hearing from C++ programmers that
the STL is the best thing since the invention of fire, I decided to
look into exactly what the STL is. Ok, I took a little longer than 
others :-).

I started by looking at the definition of the C++ Vector class, which
has an analog in Java. I have come to the conclusion that the Vector
class is one of the most used components from the STL. I am aware that
C++ needed some standard kind of "safe" array. The array type
inherited from C certainly does not fit this description. I found the
Vector class to be very flexible, if not overly safe. It does prevent
reading beyond the end of the Vector object. It does not prevent
writing beyond the end of the Vector object because the Vector is
an extensible structure.

In the best case a Vector is about as efficient as an Ada array.
In the worst case it is far less efficient. I cannot imagine using
a Vector in an embedded application with limited memory. I do think
that most C++ code, like most Java code, is not written in the
embedded domain. Therefore, the inefficiencies may not often be
visible.

I have learned a lot about the Vector class by creating an Ada
implementation. The implementation works. It is not particularly
pretty. I suspect it can be improved.

The following code is my generic Vector in Ada.

-- File: Tagged_Vector.ads
--
-- Generic vector for tagged types following C++ rules

generic
	type Element_Type is tagged private;
	with function ">=" (Left, Right : Element_Type) return Boolean;
package Tagged_Vector is
   type Group is array(Positive range <>) of Element_Type;
	type Vector is private;
	function First(Item : in Vector) return Natural;
	function Last(Item : in Vector) return Natural;
	function Size(Item : in Vector) return Natural;
	function Capacity(Item : in Vector) return Natural;
	function Is_Empty(Item : in Vector) return Boolean;
	function Element(Num : in Positive; 
	                 Item : in Vector) return Element_Type;
	procedure Reserve(Num_Items : in Positive;
	                  Item : in out Vector);
	function Front(Item : in Vector) return Element_Type;
	function Back(Item : in Vector) return Element_Type;
	procedure Push_Back(Value : in Element_Type;
	                    Onto  : in out Vector);
	procedure Pop_Back(Value : out Element_Type;
	                   From  : in out Vector);
	procedure Insert(Value  : in Element_Type;
	                 Before : in Positive;
			Onto   : in out Vector);
	procedure Insert(Value      : in Element_Type;
	                 Num_Copies : in Positive;
			Before     : in Positive;
			Onto       : in out Vector);
	procedure Insert(The_Group : in Group;
	                 Before    : in Positive;
			 Onto      : in out Vector);
	procedure Erase(Index : in Positive;
	                From  : in out Vector);
	procedure Erase(First : in Positive;
	                Last  : in Positive;
			From  : in out Vector);
	procedure Resize(Num  : in Positive;
	                 Item : in out Vector);
	function "="(Left, Right : Vector) return Boolean;
	function "<"(Left, Right : Vector) return Boolean;
	
	Vector_Empty_Error : Exception;
private
   type Group_Access is access all Group;
   type Vector is record
	Buffer : Group_Access := new Group(1..20);
	Num_Elements : Natural := 0;
   end record;
end Tagged_Vector; 


-- File : Tagged_Vector.adb
   with Ada.Unchecked_Deallocation;

   package body Tagged_Vector is
      procedure Free is new Ada.Unchecked_Deallocation(
                        Object => Group,
                        Name =>Group_Access);
   
      function First(Item : in Vector) return Natural is
      begin
         if Item.Num_Elements > 0 then
            return 1;
         else
            return 0;
         end if;
      end First;
   
      function Last(Item : in Vector) return Natural is
      begin
         return Item.Num_Elements;
      end Last;
   
      function Size(Item : in Vector) return Natural is
      begin
         return Item.Num_Elements;
      end Size;
   
      function Capacity(Item : in Vector) return Natural is
      begin
         if Item.Buffer /= null then
            return Item.Buffer.all'Last;
         else
            return 0;
         end if;
      end Capacity;
   
      function Is_Empty(Item : in Vector) return Boolean is
      begin
         return Item.Num_Elements = 0;
      end Is_Empty;
   
      function Element(Num : in Positive;
                       Item : in Vector) return Element_Type is
      begin
         if Num <= Item.Num_Elements then
            return Item.Buffer.all(Num);
         else
            return Item.Buffer.all(Item.Num_Elements);
         end if;
      end Element;
   
      procedure Reserve(Num_Items : in Positive;
                        Item : in out Vector) is
         Temp : Group_Access;
      begin
         if Num_Items > Item.Buffer.all'Last then
            Temp := new Group(1..(2 * Num_Items));
         -- Copy Elements to new buffer
            Temp.all(1..Item.Num_Elements) :=
                    Item.Buffer.all(1..Item.Num_Elements);
            Free(Item.Buffer);
         end if;
         Item.Buffer := Temp;
      end Reserve;
   
      function Front(Item : in Vector) return Element_Type is
      begin
         if Item.Num_Elements = 0 then
            raise Vector_Empty_Error;
         end if;
         return Item.Buffer.all(1);
      end Front;
   
      function Back(Item : in Vector) return Element_Type is
      begin
         if Item.Num_Elements = 0 then
            raise Vector_Empty_Error;
         end if;
         return Item.Buffer.all(Item.Num_Elements);
      end Back;
   
      procedure Push_Back(Value : in Element_Type;
                          Onto  : in out Vector) is
         Temp : Group_Access;
      begin
         if Onto.Num_Elements = Onto.Buffer.All'Last then
            Temp := new Group(1..(2 * Onto.Num_Elements));
            Temp.all(1..Onto.Num_Elements) :=
                   Onto.Buffer.all(1..Onto.Num_Elements);
            Free(Onto.Buffer);
            Onto.Buffer := Temp;
         end if;
         Onto.Num_Elements := Onto.Num_Elements + 1;
         Onto.Buffer.all(Onto.Num_Elements) := Value;
      end Push_Back;
   
      procedure Pop_Back(Value : out Element_Type;
                         From  : in out Vector) is
      begin
         if From.Num_Elements = 0 then
            raise Vector_Empty_Error;
         end if;
         Value := From.Buffer.all(From.Num_Elements);
         From.Num_Elements := From.Num_Elements - 1;
      end Pop_Back;
   
      procedure Insert(Value : in Element_Type;
                       Before : in Positive;
                       Onto   : in out Vector) is
         Temp : Group_Access;
         new_Pos : Positive;
      begin
         if Onto.Num_Elements = Onto.Buffer.All'Last then
            Temp := new Group(1..(2 * Onto.Num_Elements));
            Temp.all(1..Onto.Num_Elements) := 
                Onto.Buffer.all(1..Onto.Num_elements);
            Free(Onto.Buffer);
            Onto.Buffer := Temp;
         end if;
         if Before <= Onto.Num_Elements then
            for num in reverse Before..Onto.Num_Elements loop
               Onto.Buffer.all(Num + 1) := Onto.Buffer.All(Num);
            end loop;
            New_Pos := Before;
         else
            New_Pos := Onto.Num_Elements + 1;
         end if;
         Onto.Buffer.All(New_Pos) := Value;
         Onto.Num_Elements := Onto.Num_Elements + 1;
      end Insert;
   
      procedure Insert(Value      : in Element_Type;
                       Num_Copies : in Positive;
                       Before     : in Positive;
                       Onto       : in out Vector) is
      begin
         for copy in 1..Num_Copies loop
            Insert(Value => Value, Before => Before, Onto => Onto);
         end loop;
      end Insert;
   
      procedure Insert(The_Group : in Group;
                       Before    : in Positive;
                       Onto      : in out Vector) is
      begin
         for Index in reverse The_Group'Range loop
            Insert(Value  => The_Group(Index),
                   Before => Before,
                   Onto   => Onto);
         end loop;
      end Insert;
   
      procedure Erase(Index : in Positive;
                      From  : in out Vector) is
      begin
         if Index <= From.Num_Elements then
            for num in Index + 1..From.Num_Elements loop
               From.Buffer.all(Num - 1) := From.Buffer.all(Num);
            end loop;
            From.Num_Elements := From.Num_Elements - 1;
         end if;
      end Erase;
   
      procedure Erase(First : in Positive;
                      Last  : in Positive;
                      From  : in out Vector) is
         Final : Positive;
      begin
         if Last >= First then
            if Last > From.Num_Elements then
               Final := From.Num_Elements;
            else
               Final := Last;
            end if;
            for num in First..Final loop
               Erase(Index => First, From => From);
            end loop;
         end if;
      end Erase;
   
      procedure Resize(Num : in Positive;
                       Item : in out Vector) is
         Temp : Group_Access;
      begin
         if Num >= (2 * Item.Num_Elements) then
            Temp := new Group(1..Num);
            for index in 1..Item.Num_Elements loop
               Temp.all(index) := Item.Buffer.all(Index);
            end loop;
            Free(Item.Buffer);
            Item.Buffer := Temp;
         end if;
      end Resize;
   
      function "="(Left, Right : in Vector) return Boolean is
         Result : Boolean;
      begin
         if Left.Num_Elements = Right.Num_Elements then
            Result := True;
            for index in 1..Left.Num_Elements loop
               if Left.Buffer.all(index) /= Right.Buffer.all(Index) then
                  Result := False;
               end if;
               exit when Result = False;
            end loop;
         else
            Result := False;
         end if;
         return Result;
      end "=";
   
      function "<"(Left, Right : in Vector) return Boolean is
         Result : Boolean;
      begin
         if Left.Num_Elements <= Right.Num_Elements then
            Result := True;
            for index in 1..Left.Num_Elements loop
               if Left.Buffer.all(Index) >= Right.Buffer.all(Index) then
                  Result := False;
               end if;
               exit when Result = False;
            end loop;
         else
            Result := False;
         end if;
         return Result;
      end "<";
   end Tagged_Vector;

Jim Rogers
Coloardo Springs, Colorado USA



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

end of thread, other threads:[~2001-07-20  0:40 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-07-16  0:37 C++ STL Components and Ada James Rogers
2001-07-17  4:26 ` Brian Rogoff
2001-07-17 14:48   ` James Rogers
2001-07-17 19:47     ` Jon Orris
2001-07-18  3:09       ` James Rogers
2001-07-18 15:48         ` Matthias Benkmann
2001-07-18 18:00         ` Jon Orris
2001-07-19 20:48     ` Ray Blaak
2001-07-20  0:40       ` Brian Rogoff

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