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