PageRenderTime 5ms CodeModel.GetById 1ms app.highlight 2ms RepoModel.GetById 1ms app.codeStats 0ms

/src/lib/string/natively_stored_string.e

http://github.com/tybor/Liberty
Specman e | 329 lines | 257 code | 30 blank | 42 comment | 16 complexity | eb326d08d68dcbe5638136d1c5d9dd18 MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4deferred class NATIVELY_STORED_STRING
  5   -- An ABSTRACT_STRING of CHARACTERs stored into with a NATIVE_ARRAY.
  6
  7   -- Implementation note: it is NOT guaranteed that the memory buffer will contain a binary 0 to mark its
  8   -- end, except when using `to_external'
  9
 10inherit
 11   ABSTRACT_STRING
 12      redefine
 13         print_on, copy_slice_to_native
 14      end
 15
 16feature {STRING_HANDLER}
 17   storage: NATIVE_ARRAY[CHARACTER]
 18         -- The place where characters are stored.
 19
 20   storage_lower: INTEGER
 21         -- The index of the first character of `storage' effectively used.
 22      attribute
 23      end
 24
 25feature {ANY}
 26   count: INTEGER
 27      attribute
 28      end
 29
 30   capacity: INTEGER
 31         -- Capacity of the `storage' area.
 32
 33   item (i: INTEGER): CHARACTER
 34      do
 35         Result := storage.item(i - lower + storage_lower)
 36      end
 37
 38   is_equal (other: ABSTRACT_STRING): BOOLEAN
 39         -- It `other' does not conform to NATIVELY_STORED_STRING this query is an O(count.max(other.count))
 40         -- operation, requiring iterating over both strings.
 41      local
 42         nss: NATIVELY_STORED_STRING; i, j: INTEGER
 43      do
 44         if nss ?:= other then -- direct comparison of memory areas is possible
 45            nss ::= other
 46            Result := count = nss.count
 47               and then (storage = nss.storage
 48                         or else storage.slice_fast_memcmp(storage_lower, nss.storage, nss.storage_lower, nss.storage_lower + count - 1))
 49         else -- compare character by character
 50            from
 51               Result := count = other.count
 52               i := lower
 53               j := other.lower
 54            until
 55               not Result or else i > upper
 56            loop
 57               Result := item(i) = other.item(j)
 58               i := i + 1
 59               j := j + 1
 60            end
 61            check
 62               Result implies j > other.upper
 63            end
 64         end
 65      end
 66
 67   same_as (other: ABSTRACT_STRING): BOOLEAN
 68      local
 69         nss: NATIVELY_STORED_STRING
 70         i, j: INTEGER
 71      do
 72         if nss ?:= other then -- direct comparison of memory areas is possible, try that first
 73            nss ::= other
 74            Result := count = nss.count
 75               and then (storage = nss.storage
 76                         or else storage.slice_fast_memcmp(storage_lower, nss.storage, nss.storage_lower, nss.storage_lower + count - 1))
 77         end
 78         if not Result then
 79            from
 80               Result := count = other.count
 81               i := lower
 82               j := other.lower
 83            until
 84               not Result or else i > upper
 85            loop
 86               Result := item(i).same_as(other.item(j))
 87               i := i + 1
 88               j := j + 1
 89            end
 90            check
 91               Result implies j > other.upper
 92            end
 93         end
 94      end
 95
 96   index_of, fast_index_of (c: CHARACTER; start_index: INTEGER): INTEGER
 97      local
 98         index: INTEGER
 99      do
100         if start_index <= count then
101            index := storage.fast_index_of(c, start_index + storage_lower - lower, storage_lower + count - lower)
102            Result := lower + index - storage_lower
103         else
104            Result := upper + 1
105         end
106      end
107
108   reverse_index_of, fast_reverse_index_of (c: CHARACTER; start_index: INTEGER): INTEGER
109         -- Index of first occurrence of `c' at or before `start_index',
110         -- The index will be invalid, smaller than `lower' when no occurrence is found;
111         -- The search is done in reverse direction, which means from the
112         -- `start_index' down to the first character.
113         --
114         -- See also `index_of', `last_index_of', `first_index_of'.
115      do
116         -- Implementation note: the actual value of Result when no occurrence
117         -- is found has deliberately not been written in public documentation
118         -- because an eventual heir may redefine the value of lower
119         if count > 0 then
120            Result := storage.fast_reverse_index_of(c, start_index + storage_lower - lower) - storage_lower + lower
121            if Result <= 0 then
122               Result := lower - 1
123            end
124         end
125      end
126
127   has, fast_has (c: CHARACTER): BOOLEAN
128      do
129         Result := storage.slice_fast_has(c, storage_lower, storage_lower + count - 1)
130      end
131
132   occurrences (c: CHARACTER): INTEGER
133      do
134         Result := storage.slice_fast_occurrences(c, storage_lower, storage_lower + count - 1)
135      end
136
137feature {ANY} -- Concatenation
138   infix "&" (another: ABSTRACT_STRING): ABSTRACT_STRING
139         -- Current and `another' concatenating into a new object. The actual effective type of Result
140         -- chosen by the implementation, possibly based on heuristics.
141      do
142         if another.is_empty then
143            Result := Current
144         elseif is_empty then
145            Result := another
146         else
147            Result := Current | another
148         end
149      end
150
151feature {ANY} -- Access
152   first: CHARACTER
153      do
154         Result := storage.item(storage_lower)
155      end
156
157   last: CHARACTER
158      do
159         Result := storage.item(storage_lower + count - 1)
160      end
161
162   fill_tagged_out_memory
163      do
164         tagged_out_memory.append(once "[count: ")
165         count.append_in(tagged_out_memory)
166         tagged_out_memory.append(once "capacity: ")
167         capacity.append_in(tagged_out_memory)
168         tagged_out_memory.append(once "storage: %"")
169         tagged_out_memory.append(Current)
170         tagged_out_memory.append(once "%"]")
171      end
172
173   print_on (file: OUTPUT_STREAM)
174      do
175         file.put_natively_stored_string(Current)
176      end
177
178feature {STRING_HANDLER}
179   set_count (new_count: like count)
180      require
181         new_count <= capacity
182      do
183         count := new_count
184      ensure
185         count = new_count
186      end
187
188   ensure_capacity (needed_capacity: like capacity)
189      require
190         needed_capacity >= 0
191      local
192         actual_capacity, new_capacity: like capacity
193      do
194         storage_signature_count := 0
195         check
196            check_can_have_storage_signature
197         end
198         actual_capacity := capacity + storage_signature_count
199         if storage.is_null then -- implies actual_capacity = 0
200            check
201               not has_storage_signature
202            end
203            new_capacity := needed_capacity
204            if new_capacity + storage_signature_count > 0 then
205               storage := storage.calloc(new_capacity + storage_signature_count)
206            end
207            capacity := new_capacity
208            check
209               check_set_storage_signature
210               has_storage_signature implies check_valid_storage_signature
211            end
212         elseif capacity < needed_capacity then
213            check
214               has_storage_signature implies check_valid_storage_signature
215            end
216            new_capacity := needed_capacity.max((capacity #* 2).max(32 - storage_signature_count))
217            storage := storage.realloc(actual_capacity, new_capacity + storage_signature_count)
218            capacity := new_capacity
219            check
220               check_set_storage_signature
221               has_storage_signature implies check_valid_storage_signature
222            end
223         else
224            check
225               has_storage_signature implies check_valid_storage_signature
226            end
227         end
228      ensure
229         capacity >= needed_capacity
230      end
231
232   set_storage (new_storage: like storage; new_capacity: like capacity)
233      require
234         count <= new_capacity
235      do
236         storage_signature_count := 0
237         check
238            check_can_have_storage_signature
239         end
240         storage := new_storage
241         capacity := new_capacity
242         check
243            check_set_storage_signature
244         end
245      ensure
246         storage = new_storage
247         capacity = new_capacity
248      end
249
250feature {STRING_HANDLER}
251   copy_slice_to_native (start_index, end_index: INTEGER; target: NATIVE_ARRAY[CHARACTER]; target_offset: INTEGER)
252      do
253         target.slice_copy(target_offset, storage, storage_lower + start_index - lower, storage_lower + end_index - lower)
254      end
255
256feature {} -- storage signature: only in all_check mode
257   check_set_storage_signature: BOOLEAN
258      require
259         storage.is_not_null
260         storage_signature_count = 4
261      do
262         storage.put('%/0/' , capacity    )
263         storage.put('%/3/' , capacity + 1)
264         storage.put('%/9/' , capacity + 2)
265         storage.put('%/27/', capacity + 3)
266         has_storage_signature := True
267         Result := True
268      ensure
269         has_storage_signature
270      end
271
272feature {STRING_HANDLER}
273   has_storage_signature: BOOLEAN
274
275   check_valid_storage_signature: BOOLEAN
276      require
277         has_storage_signature
278      do
279         Result :=   storage.item(capacity    ) = '%/0/'
280            and then storage.item(capacity + 1) = '%/3/'
281            and then storage.item(capacity + 2) = '%/9/'
282            and then storage.item(capacity + 3) = '%/27/'
283         if not Result then
284            sedb_breakpoint
285         end
286      end
287
288   check_can_have_storage_signature: BOOLEAN
289      do
290         if storage_signature_count = 0 then
291            storage_signature_count := 4
292            check
293               storage.is_not_null implies check_set_storage_signature
294            end
295         end
296         Result := True
297      end
298
299   storage_signature_count: INTEGER
300
301invariant
302   capacity > 0 implies storage.is_not_null
303   count <= capacity
304   storage_lower >= 0
305   storage_signature_count > 0 implies (has_storage_signature implies check_valid_storage_signature)
306   storage_signature_count = 0 or storage_signature_count = 4
307
308end -- class NATIVELY_STORED_STRING
309
310--
311-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
312--
313-- Permission is hereby granted, free of charge, to any person obtaining a copy
314-- of this software and associated documentation files (the "Software"), to deal
315-- in the Software without restriction, including without limitation the rights
316-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
317-- copies of the Software, and to permit persons to whom the Software is
318-- furnished to do so, subject to the following conditions:
319--
320-- The above copyright notice and this permission notice shall be included in
321-- all copies or substantial portions of the Software.
322--
323-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
324-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
325-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
326-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
327-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
328-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
329-- THE SOFTWARE.