Overview
Comment: | string_slices: new package implementing copyless substrings |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
0fe763f79ae8a72cfb74c71ba73ec69e |
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; |