179 lines
5.0 KiB
Ada
179 lines
5.0 KiB
Ada
|
with Ada.Unchecked_Deallocation;
|
||
|
|
||
|
with ada.text_io;
|
||
|
|
||
|
package body H3.Strings is
|
||
|
BUFFER_ALIGN: constant := 16;
|
||
|
|
||
|
function To_Character_Array (Str: in Elastic_String) return Character_Array is
|
||
|
begin
|
||
|
return Str.Buffer.Slot(Str.Buffer.Slot'First .. Str.Buffer.Last);
|
||
|
end To_Character_Array;
|
||
|
|
||
|
function Get_Capacity (Str: in Elastic_String) return System_Size is
|
||
|
begin
|
||
|
return Str.Buffer.Slot'Length - 1;
|
||
|
end Get_Capacity;
|
||
|
|
||
|
function Get_Length (Str: in Elastic_String) return System_Size is
|
||
|
begin
|
||
|
return Str.Buffer.Last - Str.Buffer.Slot'First + 1;
|
||
|
end Get_Length;
|
||
|
|
||
|
function Get_Item (Str: in Elastic_String; Pos: in System_Index) return Character_Type is
|
||
|
begin
|
||
|
return Str.Buffer.Slot(Pos);
|
||
|
end Get_Item;
|
||
|
|
||
|
-- unsafe as it exposes the internal buffer which can go away.
|
||
|
-- assume the system address is equal to the thin pointer in size.
|
||
|
function Get_Slot_Pointer (Str: in Elastic_String) return Thin_Character_Array_Pointer is
|
||
|
A: System.Address := Str.Buffer.Slot(Str.Buffer.Slot'First)'Address;
|
||
|
P: Thin_Character_Array_Pointer;
|
||
|
for P'Address use A'Address;
|
||
|
pragma Import (Ada, P);
|
||
|
begin
|
||
|
return P;
|
||
|
end Get_Slot_Pointer;
|
||
|
|
||
|
function Is_Shared(Str: in Elastic_String) return Standard.Boolean is
|
||
|
begin
|
||
|
return Str.Buffer /= Empty_Buffer'Access and then Str.Buffer.Refs > 1;
|
||
|
end Is_Shared;
|
||
|
|
||
|
procedure Free_Buffer (Str: in out Elastic_String) is
|
||
|
begin
|
||
|
if Str.Buffer /= Empty_Buffer'Access then
|
||
|
declare
|
||
|
procedure Free is new Ada.Unchecked_Deallocation(Buffer_Record, Buffer_Pointer);
|
||
|
begin
|
||
|
Free (Str.Buffer);
|
||
|
end;
|
||
|
end if;
|
||
|
end Free_Buffer;
|
||
|
|
||
|
procedure Ref_Buffer (Buf: in out Buffer_Pointer) is
|
||
|
begin
|
||
|
if Buf /= Empty_Buffer'Access then
|
||
|
ada.text_io.put_line ("ref_buffer -> " & Buf.Refs'Img);
|
||
|
Buf.Refs := Buf.Refs + 1;
|
||
|
end if;
|
||
|
end Ref_Buffer;
|
||
|
|
||
|
procedure Deref_Buffer (Buf: in out Buffer_Pointer) is
|
||
|
begin
|
||
|
if Buf /= Empty_Buffer'Access then
|
||
|
ada.text_io.put_line ("deref_buffer -> " & Buf.Refs'Img);
|
||
|
if Buf.Refs = 1 then
|
||
|
declare
|
||
|
procedure Free is new Ada.Unchecked_Deallocation(Buffer_Record, Buffer_Pointer);
|
||
|
begin
|
||
|
Free (Buf);
|
||
|
end;
|
||
|
else
|
||
|
Buf.Refs := Buf.Refs - 1;
|
||
|
end if;
|
||
|
end if;
|
||
|
end Deref_Buffer;
|
||
|
|
||
|
procedure Prepare_Buffer (Str: in out Elastic_String) is
|
||
|
Tmp: Buffer_Pointer;
|
||
|
begin
|
||
|
if Str.Buffer /= Empty_Buffer'Access then
|
||
|
if Is_Shared(Str) then
|
||
|
Tmp := new Buffer_Record(Str.Buffer.Slot'Length);
|
||
|
Tmp.Slot := Str.Buffer.Slot;
|
||
|
Tmp.Last := Str.Buffer.Last;
|
||
|
Tmp.Refs := 1; --Ref_Buffer (Tmp);
|
||
|
Deref_Buffer (Str.Buffer);
|
||
|
Str.Buffer := Tmp;
|
||
|
end if;
|
||
|
end if;
|
||
|
end Prepare_Buffer;
|
||
|
|
||
|
procedure Prepare_Buffer (Str: in out Elastic_String; ReqCapa: in System_Size) is
|
||
|
Tmp: Buffer_Pointer;
|
||
|
begin
|
||
|
if Str.Buffer /= Empty_Buffer'Access then
|
||
|
if Is_Shared(Str) then
|
||
|
-- ReqCapa must be greater than Str.Buffer.Slot'Length
|
||
|
Tmp := new Buffer_Record(ReqCapa);
|
||
|
Tmp.Slot(Str.Buffer.Slot'First .. Str.Buffer.Last + 1) := Str.Buffer.Slot(Str.Buffer.Slot'First .. Str.Buffer.Last + 1);
|
||
|
Tmp.Last := Str.Buffer.Last;
|
||
|
Tmp.Refs := 1; --Ref_Buffer (Tmp);
|
||
|
Deref_Buffer (Str.Buffer);
|
||
|
Str.Buffer := Tmp;
|
||
|
end if;
|
||
|
end if;
|
||
|
end Prepare_Buffer;
|
||
|
|
||
|
procedure Clear (Str: in out Elastic_String) is
|
||
|
begin
|
||
|
Prepare_Buffer (Str);
|
||
|
Str.Buffer.Last := Str.Buffer.Slot'First - 1;
|
||
|
end Clear;
|
||
|
|
||
|
procedure Purge (Str: in out Elastic_String) is
|
||
|
begin
|
||
|
Deref_Buffer (Str.Buffer);
|
||
|
Str.Buffer := Empty_Buffer'Access;
|
||
|
end Purge;
|
||
|
|
||
|
-- TODO: operator "&"
|
||
|
procedure Append (Str: in out Elastic_String; V: in Character_Array) is
|
||
|
ReqCapa: System_Size;
|
||
|
Tmp: Buffer_Pointer;
|
||
|
begin
|
||
|
if V'Length > 0 then
|
||
|
ReqCapa := H3.Align(Str.Buffer.Last + V'Length + 1, BUFFER_ALIGN);
|
||
|
Prepare_Buffer (Str, ReqCapa);
|
||
|
|
||
|
if ReqCapa > Get_Capacity(Str) then
|
||
|
Tmp := new Buffer_Record(ReqCapa);
|
||
|
Tmp.Slot(Str.Buffer.Slot'First .. Str.Buffer.Last) := Str.Buffer.Slot(Str.Buffer.Slot'First .. Str.Buffer.Last);
|
||
|
Tmp.Last := Str.Buffer.Last;
|
||
|
Free_Buffer (Str);
|
||
|
Str.Buffer := Tmp;
|
||
|
end if;
|
||
|
|
||
|
Str.Buffer.Slot(Str.Buffer.Last + 1 .. Str.Buffer.Last + V'Length) := V;
|
||
|
Str.Buffer.Last := Str.Buffer.Last + V'Length;
|
||
|
Str.Buffer.Slot(Str.Buffer.Last + 1) := Null_Character;
|
||
|
end if;
|
||
|
end Append;
|
||
|
|
||
|
procedure Append (Str: in out Elastic_String; V: in Character_Type) is
|
||
|
Tmp: Character_Array(1 .. 1) := (1 => V);
|
||
|
begin
|
||
|
Append (Str, Tmp);
|
||
|
end Append;
|
||
|
|
||
|
procedure Delete (Str: in out Elastic_String; Pos: in System_Index; Length: in System_Length) is
|
||
|
begin
|
||
|
null;
|
||
|
end Delete;
|
||
|
|
||
|
|
||
|
|
||
|
-- ---------------------------------------------------------------------
|
||
|
-- Controlled Management
|
||
|
-- ---------------------------------------------------------------------
|
||
|
procedure Initialize (Str: in out Elastic_String) is
|
||
|
begin
|
||
|
ada.text_io.put_line("ES Initialize");
|
||
|
null;
|
||
|
end Initialize;
|
||
|
|
||
|
procedure Adjust (Str: in out Elastic_String) is
|
||
|
begin
|
||
|
ada.text_io.put_line("ES Adhust");
|
||
|
Ref_Buffer (Str.Buffer);
|
||
|
end Adjust;
|
||
|
|
||
|
procedure Finalize (Str: in out Elastic_String) is
|
||
|
begin
|
||
|
ada.text_io.put_line("ES Finalize");
|
||
|
Deref_Buffer (Str.Buffer);
|
||
|
end Finalize;
|
||
|
end H3.Strings;
|