Natools

Check-in [0fe763f79a]
Login
Overview
Comment:string_slices: new package implementing copyless substrings
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0fe763f79ae8a72cfb74c71ba73ec69e98c04c24
User & Date: nat on 2013-09-27 18:29:04
Other Links: manifest | tags
Context
2013-09-28
19:31
string_slice_tests: full-coverage test suite for string slices check-in: c6d912c37b user: nat tags: trunk
2013-09-27
18:29
string_slices: new package implementing copyless substrings check-in: 0fe763f79a user: nat tags: trunk
2013-09-26
21:55
coverage.sh: suppress test output spam check-in: a44fa6898f user: nat tags: trunk
Changes

Added src/natools-string_slices.adb version [4b6fed0e78].

























































































































































































































































































































































































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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
------------------------------------------------------------------------------
-- Copyright (c) 2013, Natacha Porté                                        --
--                                                                          --
-- Permission to use, copy, modify, and distribute this software for any    --
-- purpose with or without fee is hereby granted, provided that the above   --
-- copyright notice and this permission notice appear in all copies.        --
--                                                                          --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF         --
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  --
-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES   --
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    --
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  --
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.           --
------------------------------------------------------------------------------

package body Natools.String_Slices is

   use type String_Refs.Reference;


   -----------------------------
   -- String_Range primitives --
   -----------------------------

   function Is_In (Point : Natural; Reference : String_Range) return Boolean is
   begin
      return Point >= Reference.First
        and Point < Reference.First + Reference.Length;
   end Is_In;


   function Is_Subrange (Sample, Reference : String_Range) return Boolean is
   begin
      return Sample.First >= Reference.First
        and then Sample.First + Sample.Length
                   <= Reference.First + Reference.Length;
   end Is_Subrange;


   function Last (Self : String_Range) return Natural is
   begin
      return Self.First + Self.Length - 1;
   end Last;


   function To_Range (First : Positive; Last : Natural) return String_Range is
   begin
      if Last >= First then
         return (First => First, Length => Last - First + 1);
      else
         return (First => First, Length => 0);
      end if;
   end To_Range;


   function Get_Range (S : String) return String_Range is
   begin
      return (S'First, S'Length);
   end Get_Range;


   procedure Set_First (Self : in out String_Range; New_First : in Positive) is
   begin
      if New_First >= Self.First + Self.Length then
         Self.Length := 0;
      else
         Self.Length := Self.Length - (New_First - Self.First);
      end if;

      Self.First := New_First;
   end Set_First;


   procedure Set_Last (Self : in out String_Range; New_Last : in Natural) is
   begin
      if New_Last < Self.First then
         Self.Length := 0;
      else
         Self.Length := New_Last - Self.First + 1;
      end if;
   end Set_Last;


   procedure Set_Length
     (Self : in out String_Range; New_Length : in Natural) is
   begin
      Self.Length := New_Length;
   end Set_Length;


   function Image (Interval : String_Range) return String is
      First_Img : String := Integer'Image (Interval.First);
   begin
      pragma Assert (First_Img (First_Img'First) = ' ');

      if Interval.Length = 0 then
         return "empty at" & First_Img;
      end if;

      First_Img (First_Img'First) := '[';

      if Interval.Length = 1 then
         return First_Img & ']';
      else
         return First_Img
           & ','
           & Integer'Image (Last (Interval))
           & ']';
      end if;
   end Image;



   --------------------------
   -- Conversion functions --
   --------------------------

   function To_Slice (S : String) return Slice is
      function Create return String;

      function Create return String is
      begin
         return S;
      end Create;
   begin
      return Slice'(Bounds => (S'First, S'Length),
                    Ref    => String_Refs.Create (Create'Access));
   end To_Slice;


   function To_String (S : Slice) return String is
   begin
      if S.Ref.Is_Empty then
         return "";
      else
         return S.Ref.Query.Data.all (S.Bounds.First .. Last (S.Bounds));
      end if;
   end To_String;



   ---------------
   -- Accessors --
   ---------------

   procedure Export (S : in Slice; Output : out String) is
   begin
      if not S.Ref.Is_Empty then
         Output := S.Ref.Query.Data.all (S.Bounds.First .. Last (S.Bounds));
      end if;
   end Export;


   procedure Query
     (S : in Slice;
      Process : not null access procedure (Text : in String)) is
   begin
      if S.Bounds.Length = 0 or else S.Ref.Is_Empty then
         Process.all ("");
      else
         Process.all
           (S.Ref.Query.Data.all (S.Bounds.First .. Last (S.Bounds)));
      end if;
   end Query;


   function Get_Range (S : Slice) return String_Range is
   begin
      return S.Bounds;
   end Get_Range;


   function First (S : Slice) return Positive is
   begin
      return S.Bounds.First;
   end First;


   function Last (S : Slice) return Natural is
   begin
      return Last (S.Bounds);
   end Last;


   function Length (S : Slice) return Natural is
   begin
      return S.Bounds.Length;
   end Length;



   ---------------
   -- Extenders --
   ---------------

   function Parent (S : Slice) return Slice is
   begin
      if S.Ref.Is_Empty then
         return Slice'(others => <>);
      else
         return Slice'(Bounds => Get_Range (S.Ref.Query.Data.all),
                       Ref    => S.Ref);
      end if;
   end Parent;


   function Extend (S : Slice; New_Range : in String_Range) return Slice is
   begin
      if not Is_Subrange (New_Range, Get_Range (S.Ref.Query.Data.all)) then
         raise Constraint_Error with "Extend slice beyond complete range";
      end if;

      return Slice'(Bounds => New_Range,
                    Ref    => S.Ref);
   end Extend;


   function Extend (S : Slice; First : Positive; Last : Natural)
     return Slice is
   begin
      return Extend (S, To_Range (First, Last));
   end Extend;


   procedure Extend (S : in out Slice; New_Range : in String_Range) is
   begin
      if not Is_Subrange (New_Range, Get_Range (S.Ref.Query.Data.all)) then
         raise Constraint_Error with "Extend slice beyond complete range";
      end if;

      S.Bounds := New_Range;
   end Extend;


   procedure Extend
     (S : in out Slice; First : in Positive; Last : in Natural) is
   begin
      Extend (S, To_Range (First, Last));
   end Extend;



   -----------------
   -- Restrictors --
   -----------------

   function Subslice (S : Slice; New_Range : String_Range) return Slice is
   begin
      if S.Ref.Is_Empty then
         if New_Range.Length = 0 then
            return Slice'(Bounds => New_Range, Ref => <>);
         else
            raise Constraint_Error with "Subslice of null slice";
         end if;
      end if;

      if not Is_Subrange (New_Range, S.Bounds) then
         raise Constraint_Error with "Subslice out of parent range";
      end if;

      return Slice'(Bounds => New_Range,
                    Ref    => S.Ref);
   end Subslice;


   function Subslice (S : Slice; First : Positive; Last : Natural)
     return Slice is
   begin
      return Subslice (S, To_Range (First, Last));
   end Subslice;


   procedure Restrict (S : in out Slice; New_Range : in String_Range) is
   begin
      if S.Ref.Is_Empty and New_Range.Length /= 0 then
         raise Constraint_Error with "Restrict of null slice";
      end if;

      if not Is_Subrange (New_Range, S.Bounds) then
         raise Constraint_Error with "Restriction with not a subrange";
      end if;

      S.Bounds := New_Range;
   end Restrict;


   procedure Restrict
     (S : in out Slice; First : in Positive; Last : in Natural) is
   begin
      Restrict (S, To_Range (First, Last));
   end Restrict;


   procedure Set_First (S : in out Slice; New_First : in Positive) is
   begin
      if New_First < S.Bounds.First then
         raise Constraint_Error with "New_First out of slice range";
      end if;

      Set_First (S.Bounds, New_First);
   end Set_First;


   procedure Set_Last (S : in out Slice; New_Last : in Natural) is
   begin
      if New_Last > Last (S.Bounds) then
         raise Constraint_Error with "New_Last out of slice range";
      end if;

      Set_Last (S.Bounds, New_Last);
   end Set_Last;


   procedure Set_Length (S : in out Slice; New_Length : in Natural) is
   begin
      if New_Length > S.Bounds.Length then
         raise Constraint_Error with "New_Length out of slice range";
      end if;

      S.Bounds.Length := New_Length;
   end Set_Length;



   ----------------------
   -- Slice comparison --
   ----------------------

   function Is_Empty (S : Slice) return Boolean is
   begin
      return S.Bounds.Length = 0 or else S.Ref.Is_Empty;
   end Is_Empty;


   function Is_Null (S : Slice) return Boolean is
   begin
      return S.Ref.Is_Empty;
   end Is_Null;


   function Is_Related (Left, Right : Slice) return Boolean is
   begin
      return Left.Ref = Right.Ref;
   end Is_Related;


   function Is_Subslice (S, Reference : Slice) return Boolean is
   begin
      return S.Ref = Reference.Ref
        and then Is_Subrange (S.Bounds, Reference.Bounds);
   end Is_Subslice;



   ------------------
   -- Constructors --
   ------------------

   function Duplicate (S : Slice) return Slice is
      function Factory return String;

      function Factory return String is
      begin
         return S.Ref.Query.Data.all;
      end Factory;
   begin
      if S.Bounds.Length = 0 or else S.Ref.Is_Empty then
         return Null_Slice;
      else
         return Slice'(Bounds => S.Bounds,
                       Ref => String_Refs.Create (Factory'Access));
      end if;
   end Duplicate;

end Natools.String_Slices;

Added src/natools-string_slices.ads version [117c1cbe46].




































































































































































































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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
------------------------------------------------------------------------------
-- Copyright (c) 2013, Natacha Porté                                        --
--                                                                          --
-- Permission to use, copy, modify, and distribute this software for any    --
-- purpose with or without fee is hereby granted, provided that the above   --
-- copyright notice and this permission notice appear in all copies.        --
--                                                                          --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF         --
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  --
-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES   --
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    --
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  --
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.           --
------------------------------------------------------------------------------

------------------------------------------------------------------------------
-- Natools.String_Slices provide an object that represents a substring of a --
-- shared parent string.                                                    --
------------------------------------------------------------------------------

private with Natools.References;

package Natools.String_Slices is
   pragma Preelaborate (String_Slices);

   -----------------------
   -- String range type --
   -----------------------

   type String_Range is record
      First  : Positive;
      Length : Natural;
   end record;

   function Is_In (Point : Natural; Reference : String_Range) return Boolean;
   function Is_Subrange (Sample, Reference : String_Range) return Boolean;
      --  Inclusion tests

   function Last (Self : String_Range) return Natural;
      --  Return last bound of the given range

   function To_Range (First : Positive; Last : Natural) return String_Range;
      --  Create a range with the given bounds

   function Get_Range (S : String) return String_Range;
      --  Return the String_Range representation of S index range.
      --  Semantically equivalent to (To_Range (S'First, S'Last))
      --  and to (String_Range'(First => S'First, Length => S'Length)).

   procedure Set_First (Self : in out String_Range; New_First : in Positive);
      --  Update first bound keeping last bound intact

   procedure Set_Last (Self : in out String_Range; New_Last : in Natural);
      --  Update range for the given last bound, keeping the first one intact

   procedure Set_Length (Self : in out String_Range; New_Length : in Natural);
      --  Basic mutator included for completeness sake

   function Image (Interval : String_Range) return String;
      --  Interval representation of the given range


   ----------------
   -- Slice type --
   ----------------

   type Slice is tagged private;

   Null_Slice : constant Slice;


   --------------------------
   -- Conversion functions --
   --------------------------

   function To_Slice (S : String) return Slice;
      --  Create a new slice containing the whole given string

   function To_String (S : Slice) return String;
      --  Return the string represented by the slice


   ---------------
   -- Accessors --
   ---------------

   procedure Export (S : in Slice; Output : out String);
      --  Fill Output with string contents in S
      --  Raise Constraint_Error when Output'Length /= Length(S)

   procedure Query
     (S : in Slice;
      Process : not null access procedure (Text : in String));
      --  Query the string object directly from memory

   function Get_Range (S : Slice) return String_Range;
      --  Return the range embedded in S

   function First (S : Slice) return Positive;
      --  Return the lowest index of S

   function Last (S : Slice) return Natural;
      --  Return the largest index of S

   function Length (S : Slice) return Natural;
      --  Return the length of S


   ---------------
   -- Extenders --
   ---------------

   --  These subprograms allow access to the parent string beyond the
   --  current range. However Constraint_Error is raised when trying to reach
   --  beyond the parent string range.

   function Parent (S : Slice) return Slice;
      --  Return a slice representing the whole string available

   function Extend (S : Slice; New_Range : in String_Range) return Slice;
   function Extend (S : Slice; First : Positive; Last : Natural) return Slice;
   procedure Extend (S : in out Slice; New_Range : in String_Range);
   procedure Extend (S : in out Slice; First : in Positive; Last : in Natural);
      --  Extend the range represented by S


   -----------------
   -- Restrictors --
   -----------------

   --  All the subprograms here raise Constraint_Error when the new range
   --  is not a subrange of the source range.

   function Subslice (S : Slice; New_Range : String_Range) return Slice;
   function Subslice (S : Slice; First : Positive; Last : Natural)
     return Slice;
      --  Return a subslice of S

   procedure Restrict (S : in out Slice; New_Range : in String_Range);
   procedure Restrict
     (S : in out Slice; First : in Positive; Last : in Natural);
      --  Update the range in S

   procedure Set_First (S : in out Slice; New_First : in Positive);
      --  Update the range of S keeping the upper bound intact

   procedure Set_Last (S : in out Slice; New_Last : in Natural);
      --  Update the range of S keeping the lower bound intact

   procedure Set_Length (S : in out Slice; New_Length : in Natural);
      --  Truncate S range to the given length, keeping the lower bound intact


   ----------------------
   -- Slice comparison --
   ----------------------

   function Is_Empty (S : Slice) return Boolean;
      --  Return whether the slice represents an empty string.
      --  Semantically equivalent to (To_String (S) = "").

   function Is_Null (S : Slice) return Boolean;
      --  Return whether the slice has a parent string

   function Is_Related (Left, Right : Slice) return Boolean;
      --  Return whether both slices have the same parent string

   function Is_Subslice (S, Reference : Slice) return Boolean;
      --  Return whether S represent of a subrange of Reference with the
      --  same parent string.

   function Duplicate (S : Slice) return Slice;
      --  Create a new parent string and a slice designating it.
      --  This does not copy parts of S parent string outside of S range.
      --  Semantically equivalent to (To_Slice (To_String (S))).

private

   type Access_In_Default_Pool is access Boolean;
      --  Access type only used to infer default storage pool

   package String_Refs is new References
     (String,
      Access_In_Default_Pool'Storage_Pool,
      Access_In_Default_Pool'Storage_Pool);

   type Slice is tagged record
      Bounds : String_Range := (1, 0);
      Ref : String_Refs.Reference;
   end record;

   Null_Slice : constant Slice := ((1, 0), Ref => <>);

end Natools.String_Slices;