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