/src/lib/storage/collection/array.e

http://github.com/tybor/Liberty · Specman e · 495 lines · 396 code · 43 blank · 56 comment · 26 complexity · dcb44b1da02b7ad7b6fe6d62411c7e89 MD5 · raw file

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