PageRenderTime 39ms CodeModel.GetById 28ms app.highlight 4ms RepoModel.GetById 1ms app.codeStats 1ms

/src/lib/string/fixed_string.e

http://github.com/tybor/Liberty
Specman e | 453 lines | 368 code | 43 blank | 42 comment | 14 complexity | 81e0c67213a88209c8d4a5355438c32a MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4class FIXED_STRING
  5   --
  6   -- Immutable character STRINGs indexed from `1' to `count'.
  7   --
  8
  9inherit
 10   NATIVELY_STORED_STRING
 11      redefine
 12         immutable, out_in_tagged_out_memory, fill_tagged_out_memory,
 13         check_can_have_storage_signature
 14      end
 15
 16create {ANY}
 17   make_from_string, copy, from_external_copy, from_external_sized_copy, from_external
 18
 19create {FIXED_STRING}
 20   make_from_fixed_string
 21
 22feature {ANY} -- Creation:
 23   make_from_string (model: STRING)
 24         -- Initialize from the characters of `model'.
 25      require
 26         not immutable
 27         model /= Void
 28      local
 29         new_count, new_capacity: INTEGER
 30      do
 31         new_count := model.count
 32         if new_count > 0 and then model.last = '%U' then
 33            new_capacity := new_count
 34            storage := storage.calloc(new_capacity)
 35            model.copy_slice_to_native(model.lower, model.upper, storage, 0)
 36         else
 37            new_capacity := new_count + 1
 38            storage := storage.calloc(new_capacity)
 39            if new_count > 0 then
 40               model.copy_slice_to_native(model.lower, model.upper, storage, 0)
 41            end
 42            storage.put('%U', new_count)
 43         end
 44         capacity := new_capacity
 45         count := new_count
 46         immutable := True
 47         original := Void
 48         holders := new_holders
 49         hash_code := computed_hash_code
 50
 51         debug("FIXED_STRING")
 52            debug_string := out
 53         end
 54      ensure
 55         count = model.count
 56         immutable
 57      end
 58
 59feature {ANY}
 60   hash_code: INTEGER
 61
 62   intern: FIXED_STRING
 63         -- A shared version of this string.
 64      local
 65         strings: FAST_ARRAY[FIXED_STRING]
 66         i: INTEGER
 67      do
 68         if is_interned then
 69            Result := Current
 70         else
 71            strings := interned.reference_at(hash_code)
 72            if strings = Void then
 73               create strings.with_capacity(4)
 74               interned.add(strings, hash_code)
 75            end
 76            i := strings.first_index_of(Current)
 77            if strings.valid_index(i) then
 78               Result := strings.item(i)
 79            else
 80               do_intern(strings)
 81               Result := Current
 82            end
 83         end
 84      end
 85
 86   out_in_tagged_out_memory
 87      do
 88         fill_tagged_out_memory
 89      end
 90
 91   fill_tagged_out_memory
 92      do
 93         tagged_out_memory.append(Current)
 94      end
 95
 96feature {ANY}
 97   copy (other: like Current)
 98         -- In fact this feature can only be used at creation time (see `immutable').
 99      do
100         check
101            not immutable
102         end
103         storage := other.storage
104         storage_lower := other.storage_lower
105         hash_code := other.hash_code
106         count := other.count
107         capacity := other.capacity
108         immutable := True
109         original := Void
110         share_with(other)
111      ensure then
112         count = other.count
113         immutable
114         is_shared
115         other.is_shared
116      end
117
118   immutable: BOOLEAN
119
120feature {ABSTRACT_STRING}
121   do_intern (strings: FAST_ARRAY[FIXED_STRING])
122      require
123         interned.fast_reference_at(hash_code) = strings
124         not is_interned
125         not strings.has(Current)
126      do
127         strings.add_last(Current)
128         is_interned := True
129      ensure
130         is_interned
131      end
132
133feature {ANY}
134   is_interned: BOOLEAN
135
136feature {ANY} -- Other features:
137   substring (start_index, end_index: INTEGER): like Current
138      do
139         create Result.make_from_fixed_string(Current, start_index, end_index)
140      end
141
142feature {}
143   make_from_fixed_string (other: FIXED_STRING; start_index, end_index: INTEGER)
144      require
145         other /= Void
146         valid_start_index: other.valid_index(start_index)
147         valid_end_index: other.valid_index(end_index) -- end_index <= other.count
148         meaningful_interval: start_index <= end_index + 1
149      do
150         storage := other.storage
151         storage_lower := start_index - other.lower + other.storage_lower
152         count := end_index - start_index + 1
153         capacity := other.capacity
154         immutable := True
155         original := Void
156         share_with(other)
157         hash_code := computed_hash_code
158
159         debug("FIXED_STRING")
160            debug_string := out
161         end
162      ensure
163         immutable
164         is_shared
165         other.is_shared
166         substring_count: count = end_index - start_index + 1
167      end
168
169feature {ANY} -- Interfacing with C string:
170   to_external: POINTER
171      do
172         if is_shared then
173            unshare
174         end
175         Result := storage.to_external + storage_lower
176      end
177
178feature {STRING_HANDLER} -- Creation from C string:
179   from_external (p: POINTER)
180         -- Internal `storage' is set using a copy of `p'. Assume `p' has a null character at the end in order
181         -- to compute the Eiffel `count'. This extra null character is not part of the Eiffel
182         -- FIXED_STRING.
183         -- Also consider `from_external_copy' to choose the most appropriate.
184      require
185         p.is_not_null
186      local
187         s: like storage; i: INTEGER
188      do
189         from
190            s := s.from_pointer(p)
191         until
192            s.item(i) = '%U'
193         loop
194            i := i + 1
195         end
196
197         count := i
198         capacity := i + 1
199         storage := s
200
201         immutable := True
202         original := Void
203         holders := new_holders
204         hash_code := computed_hash_code
205
206         debug("FIXED_STRING")
207            debug_string := out
208         end
209      ensure
210         immutable
211      end
212
213   from_external_copy (p: POINTER)
214         -- Internal `storage' is set using a copy of `p'. Assume `p' has a null character at the end in order
215         -- to compute the Eiffel `count'. This extra null character is not part of the Eiffel
216         -- FIXED_STRING.
217         -- Also consider `from_external' to choose the most appropriate.
218      require
219         p.is_not_null
220      local
221         s: like storage; i: INTEGER
222      do
223         from
224            s := s.from_pointer(p)
225         until
226            s.item(i) = '%U'
227         loop
228            i := i + 1
229         end
230
231         count := i
232         capacity := i + 1
233         storage := storage.calloc(capacity)
234         storage.copy_from(s, count)
235
236         immutable := True
237         original := Void
238         holders := new_holders
239         hash_code := computed_hash_code
240
241         debug("FIXED_STRING")
242            debug_string := out
243         end
244      ensure
245         immutable
246      end
247
248   from_external_sized_copy (p: POINTER; size: INTEGER)
249         -- Internal `storage' is set using a copy of `p'.  'size' characters are copied, setting then 'count'
250         -- to at most `size'. If the C string is shorter though then its size is used instead.
251         -- Also consider `from_external_copy' to choose the most appropriate.
252      require
253         p.is_not_null
254         size >= 0
255      local
256         s: like storage; i: INTEGER
257      do
258         from
259            s := s.from_pointer(p)
260         until
261            i = size or else s.item(i) = '%U'
262         loop
263            i := i + 1
264         end
265
266         count := i
267         capacity := i + 1
268         storage := storage.calloc(capacity)
269         storage.copy_from(s, count - 1)
270         storage.put('%U', count)
271
272         immutable := True
273         original := Void
274         holders := new_holders
275         hash_code := computed_hash_code
276
277         debug("FIXED_STRING")
278            debug_string := out
279         end
280      ensure
281         immutable
282         count <= size
283      end
284
285feature {RECYCLING_POOL, STRING_RECYCLING_POOL, STRING_HANDLER}
286   recycle
287      local
288         s: like storage
289      do
290         immutable := False
291         storage := s
292         capacity := 0
293         count := 0
294      end
295
296feature {STRING_HANDLER} -- Copy On Write:
297   is_shared: BOOLEAN
298      do
299         Result := holders.count > 1
300      end
301
302   holders: FAST_ARRAY[FIXED_STRING]
303
304   share_with (other: like Current)
305      do
306         if holders = Void then
307            -- when called by twin
308         elseif holders.count = 1 then
309            check
310               holders.first = Current
311            end
312            holders.remove_first
313            free_holders(holders)
314         else
315            holders.remove(holders.fast_first_index_of(Current))
316         end
317         holders := other.holders
318         holders.add_last(Current)
319      end
320
321   unshare
322      require
323         is_shared
324      local
325         s: like storage
326      do
327         capacity := count + 1
328         s := s.calloc(capacity)
329         s.slice_copy(0, storage, storage_lower, storage_lower + count - 1)
330         s.put('%U', count)
331         storage := s
332         storage_lower := 0
333         holders.remove(holders.fast_first_index_of(Current))
334         check
335            not holders.is_empty
336         end
337         holders := new_holders
338      ensure
339         not is_shared
340      end
341
342feature {} -- Holders management:
343   new_holders: like holders
344      local
345         wr: WEAK_REFERENCE[FAST_ARRAY[FIXED_STRING]]
346      do
347         from
348         until
349            Result /= Void or else holders_memory.is_empty
350         loop
351            wr := holders_memory.last
352            holders_memory.remove_last
353            Result := wr.item
354            if Result /= Void then
355               wr.set_item(Void)
356            end
357            weakrefs.add_last(wr)
358         end
359         if Result = Void then
360            create {FAST_ARRAY[FIXED_STRING]} Result.with_capacity(1)
361         end
362         check
363            Result.is_empty
364         end
365         Result.add_last(Current)
366      ensure
367         Result.count = 1
368         Result.first = Current
369      end
370
371   free_holders (a_holders: like holders)
372      require
373         a_holders.is_empty
374      local
375         wr: WEAK_REFERENCE[FAST_ARRAY[FIXED_STRING]]
376      do
377         if weakrefs.is_empty then
378            create wr.set_item(a_holders)
379         else
380            wr := weakrefs.last
381            weakrefs.remove_last
382            check
383               wr.item = Void
384            end
385            wr.set_item(a_holders)
386         end
387         holders_memory.add_last(wr)
388      end
389
390   holders_memory: FAST_ARRAY[WEAK_REFERENCE[FAST_ARRAY[FIXED_STRING]]]
391      once
392         create Result.with_capacity(1024)
393      end
394
395   weakrefs: FAST_ARRAY[WEAK_REFERENCE[FAST_ARRAY[FIXED_STRING]]]
396      once
397         create Result.with_capacity(1024)
398      end
399
400feature {} -- Invariant checking:
401   is_storage_unchanged: BOOLEAN
402      do
403         if original = Void then
404            original := twin
405            Result := True
406         else
407            Result := is_equal(original)
408         end
409      end
410
411   original: like Current
412
413feature {STRING_HANDLER}
414   check_can_have_storage_signature: BOOLEAN
415      do
416         Result := True
417      end
418
419invariant
420   0 <= count
421   capacity >= count
422   not has_storage_signature
423   immutable implies storage.is_not_null
424   ;(immutable and not is_shared) implies capacity.in_range(count, count + 1)
425   ;(immutable and not is_shared) implies (count = 0 implies storage.item(0) = '%U')
426   ;(immutable and not is_shared) implies (count > 0 implies (storage.item(count - 1) = '%U' or else storage.item(count) = '%U'))
427   holders.fast_has(Current)
428   holders.for_all(agent (holder: FIXED_STRING; p: POINTER): BOOLEAN do Result := holder.storage.to_pointer = p end (?, storage.to_pointer))
429   is_interned = (interned.fast_has(hash_code) and then interned.fast_reference_at(hash_code).fast_has(Current))
430   is_interned implies immutable
431   --is_storage_unchanged
432
433end -- class FIXED_STRING
434--
435-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
436--
437-- Permission is hereby granted, free of charge, to any person obtaining a copy
438-- of this software and associated documentation files (the "Software"), to deal
439-- in the Software without restriction, including without limitation the rights
440-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
441-- copies of the Software, and to permit persons to whom the Software is
442-- furnished to do so, subject to the following conditions:
443--
444-- The above copyright notice and this permission notice shall be included in
445-- all copies or substantial portions of the Software.
446--
447-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
448-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
449-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
450-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
451-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
452-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
453-- THE SOFTWARE.