/src/lib/storage/collection/ring_array.e

http://github.com/tybor/Liberty · Specman e · 902 lines · 762 code · 57 blank · 83 comment · 67 complexity · 1d2cac95c4c5bd4d22388fe491d8132c MD5 · raw file

  1. -- This file is part of a Liberty Eiffel library.
  2. -- See the full copyright at the end.
  3. --
  4. class RING_ARRAY[E_]
  5. --
  6. -- The main purpose of the RING_ARRAY implementation is to allow efficient manipulation of the queue
  7. -- concept (i.e. using for example `add_last' / `first' / `remove_first'). Actually, the RING_ARRAY
  8. -- implementation provides very good performance for all of the following features: `add_last', `last',
  9. -- `remove_last', `add_first', `first', `remove_first'.
  10. -- Furthermore, the RING_ARRAY implementation also has a common point with traditional ARRAY: the `lower'
  11. -- bound can be any arbitrary value, even a negative one.
  12. -- As ARRAY or FAST_ARRAY, the RING_ARRAY uses only one chunk of memory, the `storage' area which is a
  13. -- NATIVE_ARRAY. This internal `storage' area is used in a circular way (no left- or right-alignment),
  14. -- hence the very good performances for using it as a queue. Finally, if you have to perform many insertions
  15. -- in the middle of your COLLECTION, do not expect good performance with a RING_ARRAY, but consider
  16. -- LINKED_LIST or TWO_WAY_LINKED_LIST.
  17. --
  18. inherit
  19. COLLECTION[E_]
  20. redefine default_create
  21. end
  22. insert
  23. ARRAYED_COLLECTION[E_]
  24. redefine first, to_external, default_create
  25. end
  26. NATIVE_ARRAY_COLLECTOR[E_]
  27. undefine out_in_tagged_out_memory
  28. redefine default_create
  29. end
  30. create {ANY}
  31. make, with_capacity, from_collection, manifest_creation, default_create
  32. feature {}
  33. default_create
  34. do
  35. make(0, -1)
  36. end
  37. feature {ANY}
  38. lower: INTEGER
  39. -- Lower index bound
  40. feature {ANY} -- Creation and Modification:
  41. make (min_index, max_index: INTEGER)
  42. -- Prepare the array to hold values for indexes in range
  43. -- [`min_index' .. `max_index']. Set all values to default.
  44. -- When `max_index' = `min_index' - 1, the array `is_empty'.
  45. require
  46. valid_bounds: min_index <= max_index + 1
  47. local
  48. needed: INTEGER
  49. do
  50. lower := min_index
  51. upper := max_index
  52. needed := max_index - min_index + 1
  53. storage_lower := 0
  54. if needed > 0 then
  55. if capacity < needed then
  56. storage := storage.calloc(needed)
  57. capacity := needed
  58. else
  59. clear_all
  60. end
  61. end
  62. next_generation
  63. ensure
  64. left_aligned: storage_lower = 0
  65. lower_set: lower = min_index
  66. upper_set: upper = max_index
  67. items_set: all_default
  68. end
  69. with_capacity (needed_capacity, low: INTEGER)
  70. -- Create an empty array with `capacity' initialized
  71. -- at least to `needed_capacity' and `lower' set to `low'.
  72. require
  73. needed_capacity >= 0
  74. do
  75. if capacity < needed_capacity then
  76. storage := storage.calloc(needed_capacity)
  77. capacity := needed_capacity
  78. end
  79. lower := low
  80. upper := low - 1
  81. storage_lower := 0
  82. next_generation
  83. ensure
  84. left_aligned: storage_lower = 0
  85. empty: is_empty
  86. big_enough: needed_capacity <= capacity
  87. lower_set: lower = low
  88. end
  89. feature {ANY} -- Modification:
  90. resize (min_index, max_index: INTEGER)
  91. -- Resize to bounds `min_index' and `max_index'. Do not lose any
  92. -- item whose index is in both [`lower' .. `upper'] and
  93. -- [`min_index' .. `max_index']. New positions if any are
  94. -- initialized with the appropriate default value.
  95. require
  96. min_index <= max_index + 1
  97. local
  98. bubble, old_wrap, needed, inter_max, inter_min: INTEGER
  99. do
  100. needed := max_index - min_index + 1
  101. if needed > 0 then
  102. bubble := needed - capacity
  103. if needed > capacity then
  104. old_wrap := wrap_point
  105. if capacity = 0 then
  106. storage := storage.calloc(needed)
  107. else
  108. storage := storage.realloc(capacity, needed)
  109. end
  110. capacity := needed
  111. end
  112. inter_max := max_index.min(upper)
  113. inter_min := min_index.max(lower)
  114. if inter_max >= inter_min then
  115. if old_wrap.in_range(inter_min, inter_max) then
  116. if bubble > 0 then
  117. -- A bubble was created inside the data. Update upper to acknowledge this (preconditions
  118. -- will fail if we don't)
  119. upper := upper + bubble
  120. squeeze_bubble(inter_min, inter_max + bubble, old_wrap, bubble)
  121. -- Upper is written below, no need to re-adjust
  122. end
  123. end
  124. storage_lower := storage_lower - lower + min_index
  125. if storage_lower < 0 then
  126. storage_lower := storage_lower + capacity
  127. elseif storage_lower >= capacity then
  128. storage_lower := storage_lower - capacity
  129. end
  130. lower := min_index
  131. upper := max_index
  132. if inter_min > lower then
  133. clear_slice(lower, inter_min - 1)
  134. end
  135. if inter_max < upper then
  136. clear_slice(inter_max + 1, upper)
  137. end
  138. else
  139. lower := min_index
  140. upper := max_index
  141. clear_all
  142. end
  143. else
  144. lower := min_index
  145. upper := max_index
  146. end
  147. next_generation
  148. ensure
  149. lower = min_index
  150. upper = max_index
  151. end
  152. reindex (new_lower: INTEGER)
  153. -- Change indexing to take in account the expected `new_lower'
  154. -- index. The `upper' index is translated accordingly.
  155. do
  156. upper := upper + new_lower - lower
  157. lower := new_lower
  158. ensure
  159. lower = new_lower
  160. count = old count
  161. end
  162. feature {ANY} -- Implementation of deferred:
  163. count: INTEGER
  164. do
  165. Result := upper - lower + 1
  166. end
  167. is_empty: BOOLEAN
  168. do
  169. Result := upper < lower -- *** Is there a better implementation ? *** Dom march 30th 2006 ***
  170. end
  171. subarray (min, max: INTEGER): like Current
  172. do
  173. Result := slice(min, max)
  174. Result.reindex(min)
  175. ensure then
  176. Result.lower = min
  177. end
  178. item (i: INTEGER): E_
  179. do
  180. Result := storage.item(storage_index(i))
  181. end
  182. put (element: like item; i: INTEGER)
  183. do
  184. storage.put(element, storage_index(i))
  185. next_generation
  186. end
  187. force (element: like item; index: INTEGER)
  188. require else
  189. True
  190. do
  191. if upper < index then
  192. if index = upper + 1 then
  193. add_last(element)
  194. else
  195. resize(lower, index)
  196. put(element, index)
  197. end
  198. elseif index < lower then
  199. if index = lower - 1 then
  200. add_first(element)
  201. reindex(lower - 1)
  202. else
  203. resize(index, upper)
  204. put(element, index)
  205. end
  206. else
  207. put(element, index)
  208. end
  209. ensure then
  210. lower = index.min(old lower)
  211. end
  212. copy (other: like Current)
  213. local
  214. needed_capacity, o_s_u: INTEGER
  215. do
  216. storage_lower := 0
  217. lower := other.lower
  218. upper := other.upper
  219. needed_capacity := upper - lower + 1
  220. if capacity < needed_capacity then
  221. storage := storage.calloc(needed_capacity)
  222. capacity := needed_capacity
  223. end
  224. if needed_capacity > 0 then
  225. o_s_u := other.storage_upper
  226. if o_s_u >= other.storage_lower then
  227. storage.slice_copy(0, other.storage, other.storage_lower, o_s_u)
  228. else
  229. storage.slice_copy(0, other.storage, other.storage_lower, other.capacity - 1)
  230. storage.slice_copy(other.capacity - other.storage_lower, other.storage, 0, o_s_u)
  231. end
  232. end
  233. next_generation
  234. end
  235. set_all_with (v: like item)
  236. local
  237. s_u: INTEGER
  238. do
  239. if is_empty then
  240. else
  241. s_u := storage_upper
  242. if storage_lower <= s_u then
  243. storage.set_slice_with(v, storage_lower, s_u)
  244. else
  245. storage.set_all_with(v, s_u)
  246. storage.set_slice_with(v, storage_lower, capacity - 1)
  247. end
  248. end
  249. next_generation
  250. end
  251. remove_first
  252. do
  253. lower := lower + 1
  254. storage_lower := storage_lower + 1
  255. if storage_lower = capacity then
  256. storage_lower := 0
  257. end
  258. next_generation
  259. ensure then
  260. upper = old upper
  261. end
  262. remove_head (n: INTEGER)
  263. local
  264. i: INTEGER
  265. do
  266. from
  267. i := n
  268. until
  269. i = 0
  270. loop
  271. remove_first
  272. i := i - 1
  273. end
  274. next_generation
  275. ensure then
  276. upper = old upper
  277. end
  278. remove (index: INTEGER)
  279. do
  280. if index /= upper then
  281. if index /= lower then
  282. squeeze_bubble(lower, upper, index, 1)
  283. else
  284. storage_lower := storage_lower + 1
  285. if storage_lower = capacity then
  286. storage_lower := 0
  287. end
  288. end
  289. end
  290. upper := upper - 1
  291. next_generation
  292. end
  293. clear_count
  294. do
  295. upper := lower - 1
  296. next_generation
  297. ensure then
  298. capacity = old capacity
  299. end
  300. clear_count_and_capacity
  301. local
  302. null_storage: like storage
  303. do
  304. upper := lower - 1
  305. storage := null_storage
  306. capacity := 0
  307. next_generation
  308. ensure then
  309. capacity = 0
  310. end
  311. add_first (element: like item)
  312. do
  313. make_space_for_one
  314. upper := upper + 1
  315. storage_lower := storage_lower - 1
  316. if storage_lower < 0 then
  317. storage_lower := storage_lower + capacity
  318. end
  319. storage.put(element, storage_lower)
  320. next_generation
  321. end
  322. add_last (element: like item)
  323. do
  324. make_space_for_one
  325. upper := upper + 1
  326. put(element, upper)
  327. end
  328. from_collection (model: TRAVERSABLE[like item])
  329. local
  330. i, up: INTEGER
  331. do
  332. from
  333. with_capacity(model.count, model.lower)
  334. i := model.lower
  335. up := model.upper
  336. until
  337. i > up
  338. loop
  339. add_last(model.item(i))
  340. i := i + 1
  341. end
  342. next_generation
  343. ensure then
  344. lower = model.lower
  345. upper = model.upper
  346. end
  347. all_default: BOOLEAN
  348. local
  349. s_u: INTEGER
  350. do
  351. if is_empty then
  352. Result := True
  353. else
  354. s_u := storage_upper
  355. if storage_lower <= s_u then
  356. Result := storage.slice_default(storage_lower, s_u)
  357. else
  358. Result := storage.all_default(s_u) and then storage.slice_default(storage_lower, capacity - 1)
  359. end
  360. end
  361. end
  362. occurrences (element: like item): INTEGER
  363. local
  364. s_u: INTEGER
  365. do
  366. if is_empty then
  367. else
  368. s_u := storage_upper
  369. if storage_lower <= s_u then
  370. Result := storage.slice_occurrences(element, storage_lower, s_u)
  371. else
  372. Result := storage.occurrences(element, s_u) + storage.slice_occurrences(element, storage_lower, capacity - 1)
  373. end
  374. end
  375. end
  376. fast_occurrences (element: like item): INTEGER
  377. local
  378. s_u: INTEGER
  379. do
  380. if is_empty then
  381. else
  382. s_u := storage_upper
  383. if storage_lower <= s_u then
  384. Result := storage.slice_fast_occurrences(element, storage_lower, s_u)
  385. else
  386. Result := storage.fast_occurrences(element, s_u) + storage.slice_fast_occurrences(element, storage_lower, capacity - 1)
  387. end
  388. end
  389. end
  390. first_index_of (element: like item): INTEGER
  391. local
  392. s_u: INTEGER
  393. do
  394. if is_empty then
  395. Result := upper + 1
  396. else
  397. s_u := storage_upper
  398. if storage_lower <= s_u then
  399. Result := storage.index_of(element, storage_lower, s_u) + lower - storage_lower
  400. else
  401. Result := storage.index_of(element, storage_lower, capacity - 1)
  402. if Result = capacity then
  403. Result := storage.first_index_of(element, s_u) + upper - s_u
  404. else
  405. Result := Result + lower - storage_lower
  406. end
  407. end
  408. end
  409. end
  410. index_of (element: like item; start_index: INTEGER): INTEGER
  411. local
  412. s_start_index, s_u: INTEGER
  413. do
  414. if is_empty then
  415. Result := upper + 1
  416. else
  417. s_u := storage_upper
  418. s_start_index := storage_index(start_index)
  419. if s_start_index <= s_u then
  420. Result := storage.index_of(element, s_start_index, s_u) + lower - storage_lower
  421. else
  422. Result := storage.index_of(element, s_start_index, capacity - 1)
  423. if Result = capacity then
  424. Result := storage.first_index_of(element, s_u) + upper - s_u
  425. else
  426. Result := Result + lower - storage_lower
  427. end
  428. end
  429. end
  430. end
  431. reverse_index_of (element: like item; start_index: INTEGER): INTEGER
  432. local
  433. safe_equal: SAFE_EQUAL[E_]
  434. do
  435. from
  436. Result := start_index
  437. until
  438. Result < lower or else safe_equal.test(item(Result), element)
  439. loop
  440. Result := Result - 1
  441. end
  442. end
  443. fast_first_index_of (element: like item): INTEGER
  444. local
  445. s_u: INTEGER
  446. do
  447. if is_empty then
  448. Result := upper + 1
  449. else
  450. s_u := storage_upper
  451. if storage_lower <= s_u then
  452. Result := storage.fast_index_of(element, storage_lower, s_u) + lower - storage_lower
  453. else
  454. Result := storage.fast_index_of(element, storage_lower, capacity - 1)
  455. if Result = capacity then
  456. Result := storage.fast_first_index_of(element, s_u) + upper - s_u
  457. else
  458. Result := Result + lower - storage_lower
  459. end
  460. end
  461. end
  462. end
  463. fast_index_of (element: like item; start_index: INTEGER): INTEGER
  464. local
  465. s_start_index, s_u: INTEGER
  466. do
  467. if is_empty then
  468. Result := upper + 1
  469. else
  470. s_u := storage_upper
  471. s_start_index := storage_index(start_index)
  472. if s_start_index <= s_u then
  473. Result := storage.fast_index_of(element, s_start_index, s_u) + lower - storage_lower
  474. else
  475. Result := storage.fast_index_of(element, s_start_index, capacity - 1)
  476. if Result = capacity then
  477. Result := storage.fast_first_index_of(element, s_u) + upper - s_u
  478. else
  479. Result := Result + lower - storage_lower
  480. end
  481. end
  482. end
  483. end
  484. fast_reverse_index_of (element: like item; start_index: INTEGER): INTEGER
  485. do
  486. from
  487. Result := start_index
  488. until
  489. Result < lower or else item(Result) = element
  490. loop
  491. Result := Result - 1
  492. end
  493. end
  494. fast_is_equal (other: like Current): BOOLEAN
  495. local
  496. wp, owp: INTEGER
  497. do
  498. if Current = other then
  499. Result := True
  500. elseif lower = other.lower and then upper = other.upper then
  501. wp := wrap_point
  502. owp := other.wrap_point
  503. if wp < owp then
  504. Result := other.slices_are_equal(Current, owp, wp)
  505. else
  506. Result := slices_are_equal(other, wp, owp)
  507. end
  508. end
  509. end
  510. is_equal (other: like Current): BOOLEAN
  511. local
  512. wp, owp: INTEGER
  513. do
  514. if Current = other then
  515. Result := True
  516. elseif lower = other.lower and then upper = other.upper then
  517. wp := wrap_point
  518. owp := other.wrap_point
  519. if wp < owp then
  520. Result := other.slices_are_equal_map(Current, owp, wp)
  521. else
  522. Result := slices_are_equal_map(other, wp, owp)
  523. end
  524. end
  525. end
  526. slice (min, max: INTEGER): like Current
  527. local
  528. storage_min, storage_max: INTEGER
  529. do
  530. create Result.make(lower, lower + max - min)
  531. if max >= min then
  532. storage_min := storage_index(min)
  533. storage_max := storage_index(max)
  534. if storage_max >= storage_min then
  535. Result.storage.slice_copy(0, storage, storage_min, storage_max)
  536. else
  537. Result.storage.slice_copy(0, storage, storage_min, capacity - 1)
  538. Result.storage.slice_copy(capacity - storage_min, storage, 0, storage_max)
  539. end
  540. end
  541. end
  542. new_iterator: ITERATOR[E_]
  543. do
  544. create {ITERATOR_ON_TRAVERSABLE[E_]} Result.make(Current)
  545. end
  546. first: like item
  547. do
  548. Result := storage.item(storage_lower)
  549. end
  550. feature {}
  551. make_space_for_one
  552. -- Make sure `storage' is big enough to hold at least one
  553. -- more element.
  554. local
  555. old_capacity, s_u, wp: INTEGER
  556. do
  557. if capacity < count + 1 then
  558. if capacity = 0 then
  559. capacity := 16
  560. storage := storage.calloc(capacity)
  561. else
  562. wp := wrap_point
  563. s_u := storage_upper
  564. old_capacity := capacity
  565. capacity := 2 * capacity
  566. storage := storage.realloc(old_capacity, capacity)
  567. if s_u < storage_lower then
  568. -- A bubble was created inside the data. Update upper to acknowledge this (preconditions
  569. -- will fail if we don't)
  570. upper := upper + capacity - old_capacity
  571. squeeze_bubble(lower, upper, wp, capacity - old_capacity)
  572. -- Update upper
  573. upper := upper - capacity + old_capacity
  574. end
  575. end
  576. end
  577. next_generation
  578. end
  579. clear_slice (min, max: INTEGER)
  580. require
  581. valid_index(min)
  582. valid_index(max)
  583. local
  584. s_min, s_max: INTEGER
  585. do
  586. if max >= min then
  587. s_min := storage_index(min)
  588. s_max := storage_index(max)
  589. if s_max >= s_min then
  590. storage.clear(s_min, s_max)
  591. else
  592. storage.clear(s_min, capacity - 1)
  593. storage.clear(0, s_max)
  594. end
  595. end
  596. next_generation
  597. end
  598. squeeze_bubble (min, max, pos, length: INTEGER)
  599. require
  600. valid_index(min)
  601. valid_index(max)
  602. pos.in_range(min + 1, max - length)
  603. length > 0
  604. do
  605. if pos - min <= max - pos - length then
  606. move(min, pos - 1, length)
  607. storage_lower := storage_lower + length
  608. if storage_lower >= capacity then
  609. storage_lower := storage_lower - capacity
  610. end
  611. else
  612. move(pos + length, max, -length)
  613. end
  614. next_generation
  615. end
  616. unwrap
  617. local
  618. bottom, top, free, old_bound, overlap: INTEGER; tmp: like storage
  619. do
  620. if is_wrapped then
  621. bottom := wrap_point - lower
  622. top := upper - wrap_point + 1
  623. free := capacity - count
  624. if free >= bottom then
  625. old_bound := upper
  626. upper := upper + bottom
  627. move(lower, old_bound, bottom)
  628. storage_lower := 0
  629. upper := old_bound
  630. elseif free >= top then
  631. old_bound := lower
  632. lower := lower - top
  633. storage_lower := storage_lower - top
  634. move(old_bound, upper, -top)
  635. lower := old_bound
  636. elseif bottom <= top then
  637. overlap := bottom - free
  638. tmp := tmp.calloc(overlap)
  639. tmp.slice_copy(0, storage, storage_lower, storage_lower + overlap - 1)
  640. old_bound := upper
  641. lower := lower + overlap
  642. storage_lower := storage_lower + overlap
  643. upper := upper + bottom
  644. move(lower, old_bound, bottom)
  645. upper := old_bound
  646. storage.slice_copy(0, tmp, 0, overlap - 1)
  647. lower := lower - overlap
  648. storage_lower := 0
  649. else
  650. overlap := top - free
  651. tmp := tmp.calloc(overlap)
  652. tmp.slice_copy(0, storage, storage_upper - overlap + 1, storage_upper)
  653. old_bound := lower
  654. lower := lower - top
  655. storage_lower := storage_lower - top
  656. upper := upper - overlap
  657. move(old_bound, upper, -top)
  658. lower := old_bound
  659. storage.slice_copy(storage_upper + 1, tmp, 0, overlap - 1)
  660. upper := upper + overlap
  661. end
  662. end
  663. next_generation
  664. ensure
  665. not is_wrapped
  666. is_equal(old twin)
  667. end
  668. feature {ANY}
  669. to_external: POINTER
  670. -- Gives C access into the internal `storage' of the ARRAY.
  671. -- Result is pointing the element at index `lower'.
  672. --
  673. -- NOTE: do not free/realloc the Result. Any operation that changes
  674. -- `lower' or `upper' can make this pointer useless (because the
  675. -- array has wrapped or its beginning in the storage has moved),
  676. -- and operations that change `capacity' can make it invalid
  677. -- (because new memory has been allocated and the old memory has
  678. -- been freed)
  679. do
  680. unwrap
  681. Result := storage.to_pointer + storage_lower * storage.element_sizeof
  682. ensure then
  683. not is_wrapped
  684. end
  685. is_wrapped: BOOLEAN
  686. do
  687. Result := storage_lower + count > capacity
  688. ensure
  689. Result = (not is_empty and then storage_lower > storage_upper)
  690. end
  691. feature {RING_ARRAY}
  692. storage_lower: INTEGER
  693. -- Index of `first' in `storage'
  694. -- This would always be 0 for regular arrays.
  695. storage_upper: INTEGER
  696. -- Index of `last' in `storage'
  697. require
  698. not is_empty
  699. do
  700. Result := storage_index(upper)
  701. ensure
  702. in_storage(Result)
  703. end
  704. storage_index (i: INTEGER): INTEGER
  705. -- Index in `storage' corresponding to index `i' in `Current'
  706. require
  707. valid_index(i)
  708. do
  709. Result := i - lower + storage_lower
  710. if Result >= capacity then
  711. Result := Result - capacity
  712. end
  713. ensure
  714. in_storage(Result)
  715. end
  716. in_storage (index: INTEGER): BOOLEAN
  717. do
  718. Result := index.in_range(0, capacity - 1)
  719. ensure
  720. Result = (0 <= index and index < capacity)
  721. end
  722. wrap_point: INTEGER
  723. -- Index in Current (seen as a COLLECTION) such that for any
  724. -- `valid_index'es i and j, if i < wrap_point and j >=
  725. -- wrap_point then storage_index(i) > storage_index(j)
  726. --
  727. -- This can happen because of the circular nature of the
  728. -- array. `wrap_point' is not a `valid_index' if and only if
  729. -- there is no such point (i.e. the array doesn't wrap).
  730. do
  731. Result := capacity + lower - storage_lower
  732. ensure
  733. capacity > 0 implies Result > lower
  734. valid_index(Result) = is_wrapped
  735. end
  736. slices_are_equal (other: like Current; wp, owp: INTEGER): BOOLEAN
  737. require
  738. wp >= owp
  739. lower = other.lower
  740. upper = other.upper
  741. local
  742. oswp: INTEGER
  743. do
  744. if owp > upper then
  745. Result := storage.slice_fast_memcmp(storage_lower, other.storage, other.storage_lower, other.storage_upper)
  746. elseif wp > upper or else wp = owp then
  747. Result := storage.slice_fast_memcmp(storage_lower, other.storage, other.storage_lower, other.capacity - 1) and then storage.slice_fast_memcmp(storage_index(owp), other.storage, 0, other.storage_upper)
  748. else
  749. oswp := other.storage_index(wp)
  750. Result := storage.slice_fast_memcmp(storage_lower, other.storage, other.storage_lower, other.capacity - 1) and then storage.slice_fast_memcmp(storage_index(owp), other.storage, 0, oswp - 1) and then storage.slice_fast_memcmp(0, other.storage, oswp, other.storage_upper)
  751. end
  752. end
  753. slices_are_equal_map (other: like Current; wp, owp: INTEGER): BOOLEAN
  754. require
  755. wp >= owp
  756. lower = other.lower
  757. upper = other.upper
  758. local
  759. oswp: INTEGER
  760. do
  761. if owp > upper then
  762. Result := storage.slice_memcmp(storage_lower, other.storage, other.storage_lower, other.storage_upper)
  763. elseif wp > upper or else wp = owp then
  764. Result := storage.slice_memcmp(storage_lower, other.storage, other.storage_lower, other.capacity - 1) and then storage.slice_memcmp(storage_index(owp), other.storage, 0, other.storage_upper)
  765. else
  766. oswp := other.storage_index(wp)
  767. Result := storage.slice_memcmp(storage_lower, other.storage, other.storage_lower, other.capacity - 1) and then storage.slice_memcmp(storage_index(owp), other.storage, 0, oswp - 1) and then storage.slice_memcmp(0, other.storage, oswp, other.storage_upper)
  768. end
  769. end
  770. feature {} -- Garbage collector tuning (very low-level):
  771. mark_native_arrays
  772. -- For performance reasons, the unused area of `storage' is always left as it is when
  773. -- some elements are removed. No time is lost to clean the released area with a Void
  774. -- or a 0 value. (Look for example the `remove_last' implementation.)
  775. -- Thus, the unused area of `storage' may contains references of actually unreachable
  776. -- objects. The following `mark_native_arrays' actually replace the
  777. -- default behavior (the call is automatic) in order to mark only reachable objects.
  778. local
  779. i: INTEGER
  780. do
  781. if not is_empty then
  782. if is_wrapped then
  783. from
  784. i := capacity - 1
  785. until
  786. i < storage_lower
  787. loop
  788. mark_item(storage, i)
  789. i := i - 1
  790. end
  791. from
  792. i := storage_upper
  793. until
  794. i < 0
  795. loop
  796. mark_item(storage, i)
  797. i := i - 1
  798. end
  799. else
  800. from
  801. i := storage_upper
  802. until
  803. i < storage_lower
  804. loop
  805. mark_item(storage, i)
  806. i := i - 1
  807. end
  808. end
  809. end
  810. end
  811. feature {} -- Implement manifest generic creation (very low-level):
  812. manifest_make (needed_capacity: INTEGER; initial_lower: INTEGER)
  813. -- Manifest creation of a RING_ARRAY `lower' set to `initial_lower'.
  814. do
  815. make(initial_lower, initial_lower + needed_capacity - 1)
  816. end
  817. manifest_put (index: INTEGER; element: like item)
  818. do
  819. storage.put(element, index)
  820. ensure
  821. item(index + lower) = element
  822. end
  823. invariant
  824. is_empty or in_storage(storage_lower)
  825. end -- class RING_ARRAY
  826. --
  827. -- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
  828. --
  829. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  830. -- of this software and associated documentation files (the "Software"), to deal
  831. -- in the Software without restriction, including without limitation the rights
  832. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  833. -- copies of the Software, and to permit persons to whom the Software is
  834. -- furnished to do so, subject to the following conditions:
  835. --
  836. -- The above copyright notice and this permission notice shall be included in
  837. -- all copies or substantial portions of the Software.
  838. --
  839. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  840. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  841. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  842. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  843. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  844. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  845. -- THE SOFTWARE.