agpl_1.0.0_b5da3320/src/agpl-segmented_thing.ads

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
--  Support for segmented things (initially implemented for segmented files).
--  Allows to keep info about an object which is integrally composed of seg-
--  ments.
--  Semantics are:
--  Equal data adjacent segments are merged automatically.
--  No position is without segment.

with Ada.Containers.Ordered_Sets;

generic
   type Segment_Data  is private;
   type Index_Type    is range <>;
package Agpl.Segmented_Thing is

   pragma Preelaborate;

   ------------------------------------------------------------------------
   -- Object                                                             --
   ------------------------------------------------------------------------
   type Object is private;

   type Chunk_Type is record
      Data  : Segment_Data;
      First : Index_Type;
      Last  : Index_Type;
   end record;

   function "<" (L, R : in Chunk_Type) return Boolean with Inline;
   function "=" (L, R : in Chunk_Type) return Boolean with Inline;

   ------------------------------------------------------------------------
   -- Create                                                             --
   ------------------------------------------------------------------------
   --  Creates a segmented object with initially a single segment comprending
   --  all the object.
   --  It's illegal to call any other function without the object
   --  having been created.
   procedure Create (
      This         :    out Object;
      First        : in     Index_Type;
      Last         : in     Index_Type;
      Initial_Data : in     Segment_Data);

   ------------------------------------------------------------------------
   -- Count                                                              --
   ------------------------------------------------------------------------
   --  Says the number of segments.
   function Count (This : in Object) return Natural;

   ------------------------------------------------------------------------
   -- Indexes                                                            --
   ------------------------------------------------------------------------
   function First (This : in Object) return Index_Type;
   function Last  (This : in Object) return Index_Type;
   pragma Inline (First, Last);

   ------------------------------------------------------------------------
   -- Get                                                                --
   ------------------------------------------------------------------------
   --  Return a numbered piece
   --  Warning! cost O (N)
   function Get (This : in Object; Index : in Positive) return Chunk_Type;
   pragma Inline (Get);

   --  This has variable cost: O (1) for sequential advance.
   procedure Get (
      This  : in out Object;
      Index : in     Positive;
      Data  :    out Chunk_Type);

   ------------------------------------------------------------------------
   -- Get_At                                                             --
   ------------------------------------------------------------------------
   --  Return the data at given point
   function Get_At (This : in Object; Pos : in Index_Type) return Segment_Data;
   pragma Inline (Get_At);

   --  Or at a given ratio (1 .. Total):
   function Get_At (This : in Object; Offset, Total : in Index_Type) return Segment_Data;
   pragma Inline (Get_At);

   ------------------------------------------------------------------------
   -- Set                                                                --
   ------------------------------------------------------------------------
   --  Set data for a given segment. Splitting and merging are done if necessary.
   --  Last must point to the last element in the segment, not to the first in
   --  the next segment.
   procedure Set (
      This  : in out Object;
      First : in     Index_Type;
      Last  : in     Index_Type;
      Data  : in     Segment_Data);

   ------------------------------------------------------------------------
   -- Debug_Dump                                                         --
   ------------------------------------------------------------------------
   generic
      with function Image (Data : in Segment_Data) return String is <>;
   procedure Debug_Dump (This : in Object);

private

   package Ordered_Segments is new Ada.Containers.Ordered_Sets (
      Chunk_Type, "<", "=");

   function Key (This : in Chunk_Type) return Index_Type; pragma Inline (Key);
   function "<" (L : in Index_Type; R : in Chunk_Type) return Boolean;
   pragma Inline ("<");
   function ">" (L : in Index_Type; R : in Chunk_Type) return Boolean;
   pragma Inline (">");

   package Ordered_Keys is new Ordered_Segments.Generic_Keys (
      Index_Type, Key, "<");

   --  Implementation detail: each segment starts at the ending position of the
   --  previous, plus one (discrete nature).

   type Object is record
      Segments : Ordered_Segments.Set;
      First    : Index_Type;
      Last     : Index_Type;

      --  We use these two to provide a moving cursor in the object and avoid O (n) cost.
      Pos      : Natural := 0; -- 0 means unpositioned, goes in 1 .. Length (Segments);
      Idx      : Ordered_Segments.Cursor;
   end record;

end Agpl.Segmented_Thing;