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

/src/lib/string/rope.e

http://github.com/tybor/Liberty
Specman e | 263 lines | 196 code | 29 blank | 38 comment | 13 complexity | 49ede04d68d23305d82b1330dcb932e6 MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4class ROPE
  5   --
  6   -- A string of characters allowing for efficient concatenation.
  7   --
  8   -- See also LAZY_STRING, FIXED_STRING, and STRING
  9   --
 10   -- https://en.wikipedia.org/wiki/Rope_(data_structure)
 11
 12   --|NOTE: this class works on the assumption that lower = 1 (see ABSTRACT_STRING invariant)
 13
 14inherit
 15   ABSTRACT_STRING
 16      redefine
 17         new_iterator, infix "<", out_in_tagged_out_memory
 18      end
 19
 20create {ANY}
 21   from_strings
 22
 23feature {ANY} -- Creation
 24   from_strings (left_string, right_string: ABSTRACT_STRING)
 25      require
 26         left_string /= Void
 27         right_string /= Void
 28      do
 29         left := left_string
 30         right := right_string
 31      end
 32
 33   copy (another: like Current)
 34      do
 35         from_strings(another.left, another.right)
 36      end
 37
 38feature {ANY}
 39   count: INTEGER
 40      do
 41         Result := left.count + right.count
 42      end
 43
 44   item (an_index: INTEGER): CHARACTER
 45         -- Random access is an O(count) operation for a ROPE.
 46      do
 47         if an_index <= split_index then
 48            Result := left.item(an_index)
 49         else
 50            Result := right.item(an_index - split_index)
 51         end
 52      end
 53
 54   substring (start_index, end_index: INTEGER): like Current
 55      local
 56         left_substring, right_substring: ABSTRACT_STRING
 57      do
 58         if end_index <= split_index then
 59            left_substring := left.substring(start_index, end_index)
 60            right_substring := once ""
 61         elseif start_index > split_index then
 62            left_substring := once ""
 63            right_substring := right.substring(start_index - split_index, end_index - split_index)
 64         else
 65            left_substring := left.substring(start_index, split_index)
 66            right_substring := right.substring(1, end_index - split_index)
 67         end
 68         create Result.from_strings(left_substring, right_substring)
 69      end
 70
 71   occurrences (c: CHARACTER): INTEGER
 72      do
 73         Result := left.occurrences(c) + right.occurrences(c)
 74      end
 75
 76feature {ANY}
 77   infix "<" (other: ABSTRACT_STRING): BOOLEAN
 78      local
 79         i: INTEGER; done: BOOLEAN
 80      do
 81         from
 82            i := lower
 83            check
 84               i = other.lower
 85            end
 86         until
 87            done or else i > upper or else i > other.upper
 88         loop
 89            if item(i) /= other.item(i) then
 90               Result := item(i) < other.item(i)
 91               done := True
 92            end
 93            i := i + 1
 94         end
 95      end
 96
 97   is_equal (other: ABSTRACT_STRING): BOOLEAN
 98         -- O(min(count,other.count))
 99      do
100         Result := same_as(other)
101      end
102
103   hash_code: INTEGER
104      do
105         Result := computed_hash_code
106      end
107
108   same_as (other: ABSTRACT_STRING): BOOLEAN
109         -- O(min(count,other.count))
110      local
111         i: INTEGER
112      do
113         from
114            i := lower
115            check
116               i = other.lower
117            end
118            Result := True
119         until
120            not Result or else i > upper or else i > other.upper
121         loop
122            Result := item(i) = other.item(i)
123            i := i + 1
124         end
125      end
126
127   first: CHARACTER
128      do
129         Result := left.first
130      end
131
132   last: CHARACTER
133      do
134         Result := right.last
135      end
136
137   has, fast_has (c: CHARACTER): BOOLEAN
138      do
139         Result := left.has(c) or else right.has(c)
140      end
141
142   index_of, fast_index_of (c: CHARACTER; start_index: INTEGER): INTEGER
143      do
144         if start_index > split_index then
145            Result := right.index_of(c, start_index - split_index) + split_index
146         else
147            Result := left.index_of(c, start_index)
148            if not left.valid_index(Result) then
149               Result := right.index_of(c, right.lower) + split_index
150            end
151         end
152      end
153
154   reverse_index_of, fast_reverse_index_of (c: CHARACTER; start_index: INTEGER): INTEGER
155      do
156         if start_index <= split_index then
157            Result := left.reverse_index_of(c, start_index)
158         else
159            Result := right.reverse_index_of(c, start_index - split_index)
160            if right.valid_index(Result) then
161               Result := Result + split_index
162            else
163               Result := left.reverse_index_of(c, left.upper)
164            end
165         end
166      end
167
168   out_in_tagged_out_memory
169      do
170         tagged_out_memory.append(left)
171         tagged_out_memory.append(right)
172      end
173
174   fill_tagged_out_memory
175      do
176         tagged_out_memory.append(once "[left: ")
177         left.fill_tagged_out_memory
178         tagged_out_memory.append(once " | right: ")
179         right.fill_tagged_out_memory
180         tagged_out_memory.append(once "]")
181      end
182
183feature {ANY} -- Concatenation
184   infix "&" (another: ABSTRACT_STRING): ABSTRACT_STRING
185         -- A newly allocated string containing Current and `another'
186         -- concatenated. Implementation may choose any effective heir of
187         -- ABSTRACT_STRING.
188      do
189         if another.is_empty then
190            Result := Current
191         elseif is_empty then
192            Result := another
193         elseif left.is_empty then
194            Result := right | another
195         elseif right.is_empty then
196            Result := left | another
197         else
198            Result := Current | another
199         end
200      end
201
202feature {ANY} -- Iterating and other features
203   new_iterator: ITERATOR[CHARACTER]
204      do
205         create {ITERATOR_ON_ROPE} Result.make(Current)
206      end
207
208   intern: FIXED_STRING
209      do
210         Result := out.intern
211      end
212
213feature {ANY} -- Interfacing with C string:
214   to_external: POINTER
215      do
216         Result := out.to_external
217      end
218
219feature {ANY}
220   recycle
221      do
222         left := once ""
223         right := left
224      end
225
226feature {ABSTRACT_STRING, ITERATOR_ON_ROPE} -- Implementation
227   left, right: ABSTRACT_STRING
228         -- The left and right parts of the ROPE
229
230feature {} -- Split index
231   split_index: INTEGER
232         -- The index where the rope is split. It corresponds to the length of the left part of the ROPE.
233      do
234         Result := left.upper
235      ensure
236         definition: Result = left.upper
237      end
238
239invariant
240   left /= Void
241   right /= Void
242
243end -- class ROPE
244--
245-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
246--
247-- Permission is hereby granted, free of charge, to any person obtaining a copy
248-- of this software and associated documentation files (the "Software"), to deal
249-- in the Software without restriction, including without limitation the rights
250-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
251-- copies of the Software, and to permit persons to whom the Software is
252-- furnished to do so, subject to the following conditions:
253--
254-- The above copyright notice and this permission notice shall be included in
255-- all copies or substantial portions of the Software.
256--
257-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
258-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
259-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
260-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
261-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
262-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
263-- THE SOFTWARE.