/src/lib/storage/collection/fast_array.e

http://github.com/tybor/Liberty · Specman e · 435 lines · 341 code · 40 blank · 54 comment · 17 complexity · 2514229e088836df147fe361bce89826 MD5 · raw file

  1. -- This file is part of a Liberty Eiffel library.
  2. -- See the full copyright at the end.
  3. --
  4. class FAST_ARRAY[E_]
  5. --
  6. -- General purpose resizable FAST_ARRAYs. The only difference with ARRAY is the fact that the `lower' bound
  7. -- is actually frozen to 0. The `item' access is likely to be more efficient as well as loop going from
  8. -- `upper' to `lower' just because `lower' is 0. Keep in mind that even if the `lower' is frozen to 0
  9. -- it is really better to use the `lower' attribute, and not 0 directly, just because you may decide in the
  10. -- future to use another COLLECTION implementation.
  11. --
  12. -- Like ARRAY, the FAST_ARRAY implementation uses only one chunk of memory, the `storage' area which is a
  13. -- NATIVE_ARRAY. One must keep in mind that this internal `storage' area is always kept left align. Thus,
  14. -- you can expect good performances while using a FAST_ARRAY to modelize a stack behavior with `add_last' /
  15. -- `last' / `remove_last'. Conversely `add_first' and `remove_first' are likely to slow down your program if
  16. -- they are too often used. If the fact that `lower' is stuck to 0 do matter, also consider ARRAY.
  17. -- `add_first' and `remove_first' are O(count) commands for FAST_ARRAY.
  18. inherit
  19. COLLECTION[E_]
  20. undefine default_create
  21. redefine default_create
  22. end
  23. ARRAYED_COLLECTION[E_]
  24. redefine default_create
  25. end
  26. insert
  27. NATIVE_ARRAY_COLLECTOR[E_]
  28. undefine default_create, out_in_tagged_out_memory
  29. redefine default_create
  30. end
  31. create {ANY}
  32. default_create, make, with_capacity, from_collection, from_external, manifest_creation
  33. feature {ANY}
  34. lower: INTEGER 0
  35. -- Frozen lower bound.
  36. feature {ANY} -- Creation and modification:
  37. default_create
  38. -- Create a new with empty FAST_ARRAY with capacity 32.
  39. do
  40. with_capacity(32)
  41. end
  42. make (new_count: INTEGER)
  43. -- Make array with range [0 .. `new_count' - 1].
  44. -- When `new_count' = 0 the array is empty.
  45. require
  46. new_count >= 0
  47. do
  48. if new_count > capacity then
  49. -- The new one is bigger:
  50. storage := storage.calloc(new_count)
  51. capacity := new_count
  52. elseif capacity > 0 then
  53. -- storage is big enough and just need to be cleared:
  54. upper := upper.max(new_count - 1)
  55. if upper >= 0 then
  56. storage.clear_all(upper)
  57. end
  58. end
  59. upper := new_count - 1
  60. next_generation
  61. ensure
  62. count = new_count
  63. capacity >= old capacity
  64. all_default
  65. end
  66. with_capacity (needed_capacity: INTEGER)
  67. -- Create an empty array with at least `needed_capacity'.
  68. require
  69. needed_capacity >= 0
  70. do
  71. if capacity < needed_capacity then
  72. storage := storage.calloc(needed_capacity)
  73. capacity := needed_capacity
  74. elseif capacity > needed_capacity then
  75. storage.clear(0, upper)
  76. end
  77. upper := -1
  78. next_generation
  79. ensure
  80. capacity >= needed_capacity
  81. is_empty
  82. end
  83. feature {ANY} -- Modification:
  84. resize (new_count: INTEGER)
  85. -- Resize the array. When `new_count' is greater than `count', new positions are initialized
  86. -- with appropriate default values.
  87. require
  88. new_count >= 0
  89. local
  90. new_capacity, old_count: INTEGER
  91. do
  92. old_count := count
  93. if new_count > old_count then
  94. if capacity = 0 then
  95. storage := storage.calloc(new_count)
  96. capacity := new_count
  97. elseif capacity < new_count then
  98. storage.clear(old_count, capacity - 1)
  99. from
  100. new_capacity := capacity * 2
  101. until
  102. new_capacity >= new_count
  103. loop
  104. new_capacity := new_capacity * 2
  105. end
  106. storage := storage.realloc(capacity, new_capacity)
  107. capacity := new_capacity
  108. else
  109. storage.clear(old_count, new_count - 1)
  110. end
  111. end
  112. upper := new_count - 1
  113. next_generation
  114. ensure
  115. count = new_count
  116. capacity >= old capacity
  117. end
  118. feature {ANY} -- Implementation of deferred:
  119. is_empty: BOOLEAN
  120. do
  121. Result := upper < 0
  122. end
  123. item (i: INTEGER): E_
  124. do
  125. Result := storage.item(i)
  126. end
  127. put (element: E_; i: INTEGER)
  128. do
  129. storage.put(element, i)
  130. next_generation
  131. end
  132. add_first (element: like item)
  133. do
  134. add_last(element)
  135. if upper = 0 then
  136. elseif upper = 1 then
  137. swap(0, 1)
  138. else
  139. move(0, upper - 1, 1)
  140. storage.put(element, 0)
  141. end
  142. next_generation
  143. end
  144. add_last (element: like item)
  145. local
  146. new_capacity: INTEGER
  147. do
  148. if upper + 1 <= capacity - 1 then
  149. upper := upper + 1
  150. elseif capacity = 0 then
  151. storage := storage.calloc(2)
  152. capacity := 2
  153. upper := 0
  154. else
  155. new_capacity := capacity * 2
  156. storage := storage.realloc(capacity, new_capacity)
  157. capacity := new_capacity
  158. upper := upper + 1
  159. end
  160. storage.put(element, upper)
  161. next_generation
  162. end
  163. count: INTEGER
  164. do
  165. Result := upper + 1
  166. end
  167. clear_count, clear_count_and_capacity
  168. do
  169. upper := -1
  170. next_generation
  171. ensure then
  172. capacity = old capacity
  173. end
  174. copy (other: like Current)
  175. -- Copy `other' onto Current.
  176. local
  177. other_upper, new_capacity: INTEGER
  178. do
  179. other_upper := other.upper
  180. if other_upper >= 0 then
  181. new_capacity := other_upper + 1
  182. if capacity < new_capacity then
  183. storage := storage.calloc(new_capacity)
  184. capacity := new_capacity
  185. end
  186. storage.copy_from(other.storage, other_upper)
  187. end
  188. upper := other_upper
  189. next_generation
  190. end
  191. set_all_with (v: like item)
  192. do
  193. storage.set_all_with(v, upper)
  194. end
  195. from_collection (model: TRAVERSABLE[like item])
  196. local
  197. i1, i2, up: INTEGER
  198. do
  199. from
  200. with_capacity(model.count)
  201. upper := model.count - 1
  202. i1 := 0
  203. i2 := model.lower
  204. up := model.upper
  205. until
  206. i2 > up
  207. loop
  208. storage.put(model.item(i2), i1)
  209. i1 := i1 + 1
  210. i2 := i2 + 1
  211. end
  212. next_generation
  213. end
  214. fast_is_equal (other: like Current): BOOLEAN
  215. do
  216. if Current = other then
  217. Result := True
  218. elseif upper = other.upper then
  219. Result := storage.fast_memcmp(other.storage, upper + 1)
  220. end
  221. end
  222. is_equal (other: like Current): BOOLEAN
  223. do
  224. if Current = other then
  225. Result := True
  226. elseif upper = other.upper then
  227. Result := storage.memcmp(other.storage, upper + 1)
  228. end
  229. end
  230. all_default: BOOLEAN
  231. do
  232. Result := storage.all_default(upper)
  233. end
  234. occurrences (element: like item): INTEGER
  235. do
  236. Result := storage.occurrences(element, upper)
  237. end
  238. fast_occurrences (element: E_): INTEGER
  239. do
  240. Result := storage.fast_occurrences(element, upper)
  241. end
  242. first_index_of (element: like item): INTEGER
  243. do
  244. if upper >= 0 then
  245. Result := storage.first_index_of(element, upper)
  246. else
  247. check
  248. Result = 0
  249. end
  250. end
  251. end
  252. index_of (element: like item; start_index: INTEGER): INTEGER
  253. do
  254. if upper >= 0 then
  255. Result := storage.index_of(element, start_index, upper)
  256. else
  257. check
  258. Result = 0
  259. end
  260. end
  261. end
  262. reverse_index_of (element: like item; start_index: INTEGER): INTEGER
  263. do
  264. Result := storage.reverse_index_of(element, start_index)
  265. end
  266. fast_first_index_of (element: like item): INTEGER
  267. do
  268. if upper >= 0 then
  269. Result := storage.fast_index_of(element, lower, upper)
  270. else
  271. check
  272. Result = 0
  273. end
  274. end
  275. end
  276. fast_index_of (element: like item; start_index: INTEGER): INTEGER
  277. do
  278. if upper >= 0 then
  279. Result := storage.fast_index_of(element, start_index, upper)
  280. else
  281. check
  282. Result = 0
  283. end
  284. end
  285. end
  286. fast_reverse_index_of (element: like item; start_index: INTEGER): INTEGER
  287. do
  288. Result := storage.fast_reverse_index_of(element, start_index)
  289. end
  290. subarray, slice (min, max: INTEGER): like Current
  291. do
  292. create Result.make(max - min + 1)
  293. Result.storage.slice_copy(0, storage, min, max)
  294. end
  295. force (element: E_; index: INTEGER)
  296. do
  297. if index <= upper then
  298. storage.put(element, index)
  299. elseif index = upper + 1 then
  300. add_last(element)
  301. else
  302. resize(index + 1)
  303. storage.put(element, index)
  304. end
  305. next_generation
  306. end
  307. remove_first
  308. local
  309. void_storage: like storage
  310. do
  311. if upper = 0 then
  312. storage := void_storage
  313. capacity := 0
  314. upper := -1
  315. else
  316. storage.remove_first(upper)
  317. upper := upper - 1
  318. end
  319. next_generation
  320. ensure then
  321. lower = old lower
  322. end
  323. remove_head (n: INTEGER)
  324. do
  325. storage.move(n, upper, -n)
  326. upper := upper - n
  327. next_generation
  328. end
  329. remove (index: INTEGER)
  330. do
  331. storage.remove(index, upper)
  332. upper := upper - 1
  333. next_generation
  334. end
  335. new_iterator: ITERATOR[E_]
  336. do
  337. create {ITERATOR_ON_TRAVERSABLE[E_]} Result.make(Current)
  338. end
  339. feature {} -- Garbage collector tuning (very low-level):
  340. mark_native_arrays
  341. -- For performance reasons, the unused area of `storage' is always left as it is when
  342. -- some elements are removed. No time is lost to clean the released area with a Void
  343. -- or a 0 value. (Look for example the `remove_last' implementation.)
  344. -- Thus, the unused area of `storage' may contains references of actually unreachable
  345. -- objects. The following `mark_native_arrays' actually replace the
  346. -- default behavior (the call is automatic) in order to mark only reachable objects.
  347. --
  348. local
  349. i: INTEGER
  350. do
  351. from
  352. i := upper
  353. until
  354. i < 0
  355. loop
  356. mark_item(storage, i)
  357. i := i - 1
  358. end
  359. end
  360. feature {} -- Implement manifest generic creation (very low-level):
  361. manifest_make (needed_capacity: INTEGER)
  362. -- Manifest creation of a FAST_ARRAY[E_].
  363. require
  364. needed_capacity > 0
  365. do
  366. make(needed_capacity)
  367. end
  368. manifest_put (index: INTEGER; element: like item)
  369. do
  370. check
  371. index < capacity
  372. end
  373. put(element, index)
  374. end
  375. end -- class FAST_ARRAY
  376. --
  377. -- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
  378. --
  379. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  380. -- of this software and associated documentation files (the "Software"), to deal
  381. -- in the Software without restriction, including without limitation the rights
  382. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  383. -- copies of the Software, and to permit persons to whom the Software is
  384. -- furnished to do so, subject to the following conditions:
  385. --
  386. -- The above copyright notice and this permission notice shall be included in
  387. -- all copies or substantial portions of the Software.
  388. --
  389. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  390. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  391. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  392. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  393. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  394. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  395. -- THE SOFTWARE.