/src/lib/storage/low_level/fixed_array.e

http://github.com/tybor/Liberty · Specman e · 713 lines · 556 code · 51 blank · 106 comment · 27 complexity · 153f0ef8859532a3f17847eac54071b0 MD5 · raw file

  1. -- This file is part of a Liberty Eiffel library.
  2. -- See the full copyright at the end.
  3. --
  4. expanded class FIXED_ARRAY[E_]
  5. insert
  6. SAFE_EQUAL[E_]
  7. TRAVERSABLE[E_]
  8. creation {ANY}
  9. default_create
  10. feature {FIXED_ARRAY}
  11. elements: NATIVE_ARRAY[E_]
  12. capacity: INTEGER
  13. -- The number of slots this array holds
  14. feature {FIXED_ARRAY}
  15. do_calloc (c: like capacity) is
  16. require
  17. c >= 0
  18. do
  19. elements := elements.calloc(c)
  20. capacity := c
  21. ensure
  22. capacity = c
  23. end
  24. do_realloc (e: like elements; c: like capacity) is
  25. require
  26. c >= 0
  27. do
  28. elements := e.realloc(capacity, c)
  29. capacity := c
  30. ensure
  31. capacity = c
  32. end
  33. feature {ANY} -- Basic features:
  34. element_sizeof: INTEGER is
  35. -- The size in number of bytes for type `E_'.
  36. do
  37. Result := elements.element_sizeof
  38. end
  39. calloc (nb_elements: INTEGER): like Current is
  40. -- Allocate a new array of `nb_elements' of type `E_'.
  41. -- The new array is initialized with default values.
  42. require
  43. nb_elements > 0
  44. do
  45. Result.do_calloc(nb_elements)
  46. ensure
  47. Result.capacity = nb_elements
  48. Result.all_default
  49. end
  50. item (index: INTEGER): E_ is
  51. -- To read an `item'.
  52. -- Assume that `calloc' is already done and that `index' is the range [0 .. `capacity'-1].
  53. require
  54. index >= 0 and then index < capacity
  55. do
  56. Result := elements.item(index)
  57. end
  58. put (element: E_; index: INTEGER) is
  59. -- To write an item.
  60. -- Assume that `calloc' is already done and that `index'
  61. -- is the range [0 .. `capacity'-1].
  62. require
  63. index >= 0 and then index < capacity
  64. do
  65. elements.put(element, index)
  66. ensure
  67. item(index) = element
  68. end
  69. lower: INTEGER is 0
  70. upper: INTEGER is
  71. do
  72. Result := capacity - 1
  73. end
  74. count: INTEGER is
  75. do
  76. Result := capacity
  77. end
  78. feature {ANY}
  79. realloc (new_nb_elts: INTEGER): like Current is
  80. -- Assume Current is a valid NATIVE_ARRAY in range
  81. -- [0 .. `capacity'-1]. Allocate a bigger new array in
  82. -- range [0 .. `new_nb_elts'-1].
  83. -- Old range is copied in the new allocated array.
  84. -- New items are initialized with default values.
  85. require
  86. new_nb_elts > capacity
  87. do
  88. Result.do_realloc(elements, new_nb_elts)
  89. ensure
  90. Result.capacity = new_nb_elts
  91. end
  92. feature {ANY} -- Comparison:
  93. memcmp (other: like Current): BOOLEAN is
  94. -- True if all elements in range [0 .. `capacity'-1] are identical using `is_equal'.
  95. -- See also `fast_memcmp'.
  96. require
  97. other.capacity = capacity
  98. local
  99. i: INTEGER
  100. do
  101. from
  102. i := capacity - 1
  103. until
  104. i < 0 or else not safe_equal(item(i), other.item(i))
  105. loop
  106. i := i - 1
  107. end
  108. Result := i < 0
  109. end
  110. slice_memcmp (at: INTEGER; other: like Current; other_low, other_up: INTEGER): BOOLEAN is
  111. -- True if all elements in range [`at' .. `at' + `other_up' - `other_low'] are identical
  112. -- to the elements in range [`other_low' .. `other_up'] of `other' using
  113. -- `is_equal'. Assume `Current' and `other' are big enough.
  114. -- See also `slice_fast_memcmp'.
  115. require
  116. at >= 0
  117. other_low >= 0
  118. other_up >= other_low - 1
  119. other_up < other.capacity
  120. local
  121. i: INTEGER
  122. do
  123. from
  124. i := other_up - other_low
  125. until
  126. i < 0 or else not safe_equal(item(at + i), other.item(other_low + i))
  127. loop
  128. i := i - 1
  129. end
  130. Result := i < 0
  131. end
  132. fast_memcmp (other: like Current): BOOLEAN is
  133. -- Same jobs as `memcmp' but uses infix "=" instead of `is_equal'.
  134. require
  135. other.capacity = capacity
  136. local
  137. i: INTEGER
  138. do
  139. from
  140. i := capacity - 1
  141. until
  142. i < 0 or else item(i) /= other.item(i)
  143. loop
  144. i := i - 1
  145. end
  146. Result := i < 0
  147. end
  148. slice_fast_memcmp (at: INTEGER; other: like Current; other_low, other_up: INTEGER): BOOLEAN is
  149. -- Same jobs as `slice_memcmp' but uses infix "=" instead of `is_equal'.
  150. require
  151. at >= 0
  152. other_low >= 0
  153. other_up >= other_low - 1
  154. other_up < other.capacity
  155. local
  156. i: INTEGER
  157. do
  158. from
  159. i := other_up - other_low
  160. until
  161. i < 0 or else item(at + i) /= other.item(other_low + i)
  162. loop
  163. i := i - 1
  164. end
  165. Result := i < 0
  166. end
  167. deep_memcmp (other: like Current; nb_elements: INTEGER): BOOLEAN is
  168. -- Same jobs as `memcmp' but uses `is_deep_equal' instead of `is_equal'.
  169. local
  170. i: INTEGER; e1, e2: like item
  171. do
  172. from
  173. i := nb_elements - 1
  174. Result := True
  175. until
  176. not Result or else i < 0
  177. loop
  178. e1 := item(i)
  179. e2 := other.item(i)
  180. if e1 = e2 then
  181. elseif e1 /= Void then
  182. if e2 /= Void then
  183. Result := e1.is_deep_equal(e2)
  184. else
  185. Result := False
  186. end
  187. else
  188. Result := False
  189. end
  190. i := i - 1
  191. end
  192. end
  193. slice_deep_memcmp (at: INTEGER; other: like Current; other_low, other_up: INTEGER): BOOLEAN is
  194. -- Same jobs as `slice_memcmp' but uses `is_deep_equal' instead of `is_equal'.
  195. require
  196. at >= 0
  197. other_low >= 0
  198. other_up >= other_low - 1
  199. other_up < other.capacity
  200. local
  201. i: INTEGER; e1, e2: like item
  202. do
  203. from
  204. i := other_up - other_low
  205. Result := True
  206. until
  207. not Result or else i < 0
  208. loop
  209. e1 := item(i)
  210. e2 := other.item(i)
  211. if e1 = e2 then
  212. elseif e1 /= Void then
  213. if e2 /= Void then
  214. Result := e1.is_deep_equal(e2)
  215. else
  216. Result := False
  217. end
  218. else
  219. Result := False
  220. end
  221. i := i - 1
  222. end
  223. end
  224. feature {ANY} -- Searching:
  225. first_index_of (element: like item): INTEGER is
  226. -- Using `is_equal' for comparison, gives the index of the first occurrence of `element' at or after
  227. -- `0'. Answer `-1' when the search fail.
  228. -- See also `fast_index_of', `reverse_index_of'.
  229. do
  230. Result := index_of(element, 0)
  231. ensure
  232. Result.in_range(-1, capacity - 1)
  233. Result /= -1 implies safe_equal(element, item(Result))
  234. end
  235. index_of (element: like item; start_index: INTEGER): INTEGER is
  236. -- Using `is_equal' for comparison, gives the index of the first occurrence of `element' at or after
  237. -- `start_index'. Answer `-1' when the search fail.
  238. -- See also `fast_index_of', `reverse_index_of'.
  239. require
  240. start_index >= 0
  241. start_index < capacity
  242. do
  243. from
  244. Result := start_index
  245. until
  246. Result >= capacity or else safe_equal(element, item(Result))
  247. loop
  248. Result := Result + 1
  249. end
  250. if Result >= capacity then
  251. Result := -1
  252. end
  253. ensure
  254. Result.in_range(-1, capacity - 1)
  255. Result /= -1 implies safe_equal(element, item(Result))
  256. end
  257. reverse_index_of (element: like item): INTEGER is
  258. -- Using `is_equal' for comparison, gives the index of the first occurrence of `element' at or before
  259. -- `capacity'-1. Search is done in reverse direction, which means from `up' down to the
  260. -- `0'. Answer `-1' when the search fail.
  261. -- See also `fast_reverse_index_of', `index_of'.
  262. do
  263. from
  264. Result := capacity - 1
  265. until
  266. Result < 0 or else safe_equal(element, item(Result))
  267. loop
  268. Result := Result - 1
  269. end
  270. ensure
  271. Result.in_range(-1, capacity - 1)
  272. Result /= -1 implies safe_equal(element, item(Result))
  273. end
  274. fast_first_index_of (element: like item): INTEGER is
  275. -- Using basic `=' for comparison, gives the index of the first occurrence of `element' at or after
  276. -- `0'. Answer `-1' when the search fail.
  277. -- See also `fast_index_of', `reverse_index_of'.
  278. do
  279. Result := fast_index_of(element, 0)
  280. ensure
  281. Result.in_range(-1, capacity - 1)
  282. Result /= -1 implies element = item(Result)
  283. end
  284. fast_index_of (element: like item; start_index: INTEGER): INTEGER is
  285. -- Using basic `=' for comparison, gives the index of the first occurrence of `element' at or after
  286. -- `start_index'. Answer `-1' when the search fail.
  287. -- See also `index_of', `reverse_index_of'.
  288. require
  289. start_index >= 0
  290. start_index < capacity
  291. do
  292. from
  293. Result := start_index
  294. until
  295. Result >= capacity or else element = item(Result)
  296. loop
  297. Result := Result + 1
  298. end
  299. if Result >= capacity then
  300. Result := -1
  301. end
  302. ensure
  303. Result.in_range(start_index, capacity - 1)
  304. Result /= -1 implies element = item(Result)
  305. end
  306. fast_reverse_index_of (element: like item): INTEGER is
  307. -- Using basic `=' for comparison, gives the index of the first occurrence of `element' at or before
  308. -- `capacity'-1. Search is done in reverse direction, which means from `up' down to the
  309. -- `0'. Answer `-1' when the search fail.
  310. -- See also `reverse_index_of', `index_of'.
  311. do
  312. from
  313. Result := capacity - 1
  314. until
  315. Result < 0 or else element = item(Result)
  316. loop
  317. Result := Result - 1
  318. end
  319. ensure
  320. Result.in_range(-1, capacity - 1)
  321. Result /= -1 implies element = item(Result)
  322. end
  323. has (element: like item): BOOLEAN is
  324. -- Look for `element' using `is_equal' for comparison.
  325. -- Also consider `fast_has' to choose the most appropriate.
  326. local
  327. i: INTEGER
  328. do
  329. from
  330. i := capacity - 1
  331. until
  332. Result or else i < 0
  333. loop
  334. Result := safe_equal(element, item(i))
  335. i := i - 1
  336. end
  337. end
  338. fast_has (element: like item): BOOLEAN is
  339. -- Look for `element' using basic `=' for comparison.
  340. -- Also consider `has' to choose the most appropriate.
  341. local
  342. i: INTEGER
  343. do
  344. from
  345. i := capacity - 1
  346. until
  347. Result or else i < 0
  348. loop
  349. Result := element = item(i)
  350. i := i - 1
  351. end
  352. end
  353. feature {ANY} -- Removing:
  354. remove_first is
  355. -- Move range [1 .. `capacity'-1] by 1 position left.
  356. require
  357. capacity > 0
  358. do
  359. remove(0)
  360. end
  361. remove (index: INTEGER) is
  362. -- Move range [`index' + 1 .. `capacity' - 1] by 1 position left.
  363. -- The last element is set to the default value.
  364. require
  365. index >= 0
  366. index < capacity
  367. local
  368. i: INTEGER; e: E_
  369. do
  370. from
  371. i := index
  372. until
  373. i = capacity - 1
  374. loop
  375. put(item(i + 1), i)
  376. i := i + 1
  377. end
  378. put(e, i)
  379. end
  380. feature {ANY} -- Replacing:
  381. replace_all (old_value, new_value: like item) is
  382. -- Replace all occurrences of the element `old_value' by `new_value' using `is_equal' for comparison.
  383. -- See also `fast_replace_all' to choose the apropriate one.
  384. local
  385. i: INTEGER
  386. do
  387. from
  388. i := capacity - 1
  389. until
  390. i < 0
  391. loop
  392. if safe_equal(old_value, item(i)) then
  393. put(new_value, i)
  394. end
  395. i := i - 1
  396. end
  397. end
  398. fast_replace_all (old_value, new_value: like item) is
  399. -- Replace all occurrences of the element `old_value' by `new_value'
  400. -- using basic `=' for comparison.
  401. -- See also `replace_all' to choose the apropriate one.
  402. local
  403. i: INTEGER
  404. do
  405. from
  406. i := capacity - 1
  407. until
  408. i < 0
  409. loop
  410. if old_value = item(i) then
  411. put(new_value, i)
  412. end
  413. i := i - 1
  414. end
  415. end
  416. feature {ANY} -- Adding:
  417. copy_at (at: INTEGER; src: like Current) is
  418. -- Copy range [0 .. `src.capacity - 1'] of `src' to range [`at' .. `at + src.capacity - 1'] of `Current'.
  419. -- No subscript checking.
  420. require
  421. at >= 0
  422. src.capacity >= 0
  423. at + src.capacity <= capacity
  424. do
  425. slice_copy(at, src, 0, src.capacity-1)
  426. end
  427. slice_copy (at: INTEGER; src: like Current; src_min, src_max: INTEGER) is
  428. -- Copy range [`src_min' .. `src_max'] of `src' to range [`at' .. `at + src_max - src_min'] of `Current'.
  429. -- No subscript checking.
  430. --*** NATIVE_ARRAY[CHARACTER/INTEGER_8] are modified byte per byte. Efficiency should be improved here.
  431. require
  432. at >= 0
  433. src_max >= src_min - 1
  434. at + src_max - src_min < capacity
  435. useful_work: src /= Current or at /= src_min
  436. do
  437. elements.slice_copy(at, src.elements, src_min, src_max)
  438. end
  439. feature {ANY} -- Other:
  440. set_all_with (v: like item) is
  441. -- Set all elements in range [0 .. `capacity'-1] with value `v'.
  442. do
  443. set_slice_with(v, 0, capacity - 1)
  444. end
  445. set_slice_with (v: like item; low, up: INTEGER) is
  446. -- Set all elements in range [`low' .. `up'] with value `v'.
  447. require
  448. low >= 0
  449. up >= low - 1
  450. up < capacity
  451. local
  452. i: INTEGER
  453. do
  454. from
  455. i := low
  456. until
  457. i > up
  458. loop
  459. put(v, i)
  460. i := i + 1
  461. end
  462. end
  463. clear_all is
  464. -- Set all elements in range [0 .. `capacity'-1] with the default value.
  465. local
  466. e: E_
  467. do
  468. set_all_with(e)
  469. ensure
  470. all_default
  471. end
  472. clear_slice (low, up: INTEGER) is
  473. -- Set all elements in range [`low' .. `up'] with the default value.
  474. require
  475. low >= 0
  476. up >= low - 1
  477. up < capacity
  478. local
  479. e: E_
  480. do
  481. set_slice_with(e, low, up)
  482. end
  483. copy_from (src: like Current) is
  484. require
  485. src.capacity = capacity
  486. do
  487. copy_at(0, src)
  488. end
  489. deep_twin_from: like Current is
  490. -- To implement `deep_twin'. Allocate a new array of `capacity' initialized with `deep_twin'.
  491. local
  492. i: INTEGER; element: like item
  493. do
  494. if capacity > 0 then
  495. from
  496. Result := calloc(capacity)
  497. i := capacity - 1
  498. until
  499. i < 0
  500. loop
  501. element := item(i)
  502. if element /= Void then
  503. element := element.deep_twin
  504. end
  505. Result.put(element, i)
  506. i := i - 1
  507. end
  508. end
  509. end
  510. move (low, up, offset: INTEGER) is
  511. -- Move range [`low' .. `up'] by `offset' positions.
  512. -- Freed positions are not initialized to default values.
  513. require
  514. low >= 0
  515. up >= low
  516. low + offset >= 0
  517. up + offset < capacity
  518. local
  519. i: INTEGER
  520. do
  521. if offset = 0 then
  522. elseif offset < 0 then
  523. from
  524. i := low
  525. until
  526. i > up
  527. loop
  528. put(item(i), i + offset)
  529. i := i + 1
  530. end
  531. else
  532. from
  533. i := up
  534. until
  535. i < low
  536. loop
  537. put(item(i), i + offset)
  538. i := i - 1
  539. end
  540. end
  541. end
  542. occurrences (element: like item): INTEGER is
  543. -- Number of occurrences of `element' in range [0 .. `capacity'-1] using `is_equal' for comparison.
  544. -- See also `fast_occurrences' to chose the apropriate one.
  545. do
  546. Result := slice_occurrences(element, 0, capacity - 1)
  547. end
  548. slice_occurrences (element: like item; low, up: INTEGER): INTEGER is
  549. -- Number of occurrences of `element' in range [`low' .. `up'] using `is_equal' for comparison.
  550. -- See also `slice_fast_occurrences' to chose the apropriate one.
  551. require
  552. low >= 0
  553. up >= low - 1
  554. up < capacity
  555. local
  556. i: INTEGER
  557. do
  558. from
  559. i := low
  560. until
  561. i > up
  562. loop
  563. if safe_equal(element, item(i)) then
  564. Result := Result + 1
  565. end
  566. i := i + 1
  567. end
  568. end
  569. fast_occurrences (element: like item): INTEGER is
  570. -- Number of occurrences of `element' in range [0 .. `capacity'-1] using basic "=" for comparison.
  571. -- See also `occurrences' to chose the apropriate one.
  572. do
  573. Result := slice_fast_occurrences(element, 0, capacity - 1)
  574. end
  575. slice_fast_occurrences (element: like item; low, up: INTEGER): INTEGER is
  576. -- Number of occurrences of `element' in range [`low' .. `up']
  577. -- using basic "=" for comparison.
  578. -- See also `slice_occurrences' to chose the apropriate one.
  579. require
  580. low >= 0
  581. up >= low - 1
  582. up < capacity
  583. local
  584. i: INTEGER
  585. do
  586. from
  587. i := low
  588. until
  589. i > up
  590. loop
  591. if element = item(i) then
  592. Result := Result + 1
  593. end
  594. i := i + 1
  595. end
  596. end
  597. all_default: BOOLEAN is
  598. -- Do all items in range [0 .. `capacity'-1] have their type's default value?
  599. -- Note: for non Void items, the test is performed with the `is_default' predicate.
  600. do
  601. Result := slice_default(0, capacity - 1)
  602. end
  603. slice_default (low, up: INTEGER): BOOLEAN is
  604. -- Do all items in range [`low' .. `up'] have their type's default value?
  605. -- Note: for non Void items, the test is performed with the `is_default' predicate.
  606. require
  607. low >= 0
  608. up >= low - 1
  609. up < capacity
  610. local
  611. i: INTEGER; v: like item
  612. do
  613. from
  614. Result := True
  615. i := low
  616. until
  617. i > up or else not Result
  618. loop
  619. v := item(i)
  620. if v /= Void then
  621. Result := v.is_default
  622. end
  623. i := i + 1
  624. end
  625. end
  626. feature {ANY} -- Interfacing with other languages:
  627. to_external: POINTER is
  628. -- Gives access to the C pointer on the area of storage.
  629. do
  630. Result := elements.to_pointer
  631. end
  632. from_pointer (pointer: POINTER; nb_elements: INTEGER): like Current is
  633. -- Convert `pointer' into Current type.
  634. do
  635. elements := elements.from_pointer(pointer)
  636. capacity := nb_elements
  637. ensure
  638. Result.capacity = nb_elements
  639. end
  640. invariant
  641. capacity >= 0
  642. end
  643. --
  644. -- Copyright (c) 2009 by all the people cited in the AUTHORS file.
  645. --
  646. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  647. -- of this software and associated documentation files (the "Software"), to deal
  648. -- in the Software without restriction, including without limitation the rights
  649. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  650. -- copies of the Software, and to permit persons to whom the Software is
  651. -- furnished to do so, subject to the following conditions:
  652. --
  653. -- The above copyright notice and this permission notice shall be included in
  654. -- all copies or substantial portions of the Software.
  655. --
  656. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  657. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  658. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  659. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  660. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  661. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  662. -- THE SOFTWARE.