/src/lib/storage/set.e

http://github.com/tybor/Liberty · Specman e · 497 lines · 385 code · 37 blank · 75 comment · 14 complexity · 55bc22865b721fc3431e4d65608404f7 MD5 · raw file

  1. -- This file is part of a Liberty Eiffel library.
  2. -- See the full copyright at the end.
  3. --
  4. deferred class SET[E_]
  5. --
  6. -- Definition of a mathematical set of objects. All common operations on mathematical sets are available.
  7. --
  8. -- Well known implementations are HASHED_SET and AVL_SET.
  9. --
  10. inherit
  11. TRAVERSABLE[E_]
  12. redefine is_equal, copy
  13. end
  14. insert
  15. SAFE_EQUAL[E_]
  16. undefine out_in_tagged_out_memory
  17. redefine is_equal, copy
  18. end
  19. feature {ANY} -- Counting:
  20. is_empty: BOOLEAN
  21. -- Is the set empty?
  22. do
  23. Result := count = 0
  24. end
  25. feature {ANY} -- Adding and removing:
  26. add (e: like item)
  27. -- Add new item `e' to the set. The mathematical definition of adding in a set is followed, i.e. the
  28. -- element `e' is added only and only if it is not yet present in the set.
  29. -- As this `add' feature is actually using `is_equal', you may consider to use `fast_add' for expanded
  30. -- objects as well while trying to get the very best performances.
  31. require
  32. e /= Void
  33. deferred
  34. ensure
  35. added: has(e)
  36. not_in_then_added: not old has(e) implies count = old count + 1
  37. in_then_not_added: old has(e) implies count = old count
  38. end
  39. fast_add (e: like item)
  40. -- Same job as `add', but uses basic `=' for comparison.
  41. require
  42. e /= Void
  43. deferred
  44. ensure
  45. added: has(e)
  46. not_in_then_added: not old has(e) implies count = old count + 1
  47. in_then_not_added: old has(e) implies count = old count
  48. end
  49. remove (e: like item)
  50. -- Remove item `e' from the set: the mathematical definition of
  51. -- removing from a set is followed.
  52. require
  53. e /= Void
  54. deferred
  55. ensure
  56. removed: not has(e)
  57. not_in_not_removed: not old has(e) implies count = old count
  58. in_then_removed: old has(e) implies count = old count - 1
  59. end
  60. fast_remove (e: like item)
  61. -- Same job as `remove', but uses basic `=' for comparison.
  62. require
  63. e /= Void
  64. deferred
  65. ensure
  66. removed: not has(e)
  67. not_in_not_removed: not old has(e) implies count = old count
  68. in_then_removed: old has(e) implies count = old count - 1
  69. end
  70. clear_count
  71. -- Empty the current set (`is_empty' is True after that call). If possible, the actual implementation
  72. -- is supposed to keep its internal storage area in order to refill `Current' in an efficient way.
  73. -- See also `clear_count_and_capacity' to select the most appropriate.
  74. deferred
  75. ensure
  76. is_empty: count = 0
  77. end
  78. clear_count_and_capacity
  79. -- Empty the current set (`is_empty' is True after that call). If possible, the actual implementation
  80. -- is supposed to release its internal storage area for this memory to be used by other objects.
  81. -- See also `clear_count' to select the most appropriate.
  82. deferred
  83. ensure
  84. is_empty: count = 0
  85. end
  86. feature {ANY} -- Looking and searching:
  87. has (e: like item): BOOLEAN
  88. -- Is element `e' in the set?
  89. -- As this query is actually using `is_equal', you may consider to use `fast_has' for expanded
  90. -- objects as well while trying to get the very best performances.
  91. require
  92. e /= Void
  93. deferred
  94. ensure
  95. Result implies not is_empty
  96. end
  97. fast_has (e: like item): BOOLEAN
  98. -- Is element `e' actually stored in the set?
  99. -- Warning: this query is using basic `=' for comparison. See also `has' when dealing with reference
  100. -- types.
  101. require
  102. e /= Void
  103. deferred
  104. ensure
  105. Result implies e = reference_at(e)
  106. end
  107. reference_at (e: like item): like item
  108. -- Non Void when `e' is in the set. In such a situation, `Result' is the object which is actually
  109. -- stored in the `Current' set (see ensure assertion).
  110. require
  111. e /= Void
  112. elements_are_not_expanded: Result = Void
  113. deferred
  114. ensure
  115. has(e) implies Result.is_equal(e)
  116. end
  117. feature {ANY} -- To provide iterating facilities:
  118. lower: INTEGER 1
  119. upper: INTEGER
  120. do
  121. Result := count
  122. ensure
  123. Result = count
  124. end
  125. item (index: INTEGER): E_
  126. -- Item at the corresponding index `i'.
  127. --
  128. -- See also `lower', `upper', `valid_index'.
  129. --
  130. -- SETs are intrinsically unordered, so there is no guarantee that `item'(i) after performing an `add'
  131. -- or `remove' operation is related in any way to `item'(i) before that operation.
  132. deferred
  133. ensure
  134. has(Result)
  135. end
  136. first: E_
  137. do
  138. Result := item(lower)
  139. end
  140. last: E_
  141. do
  142. Result := item(upper)
  143. end
  144. new_iterator: ITERATOR[E_]
  145. do
  146. create {ITERATOR_ON_SET[E_]} Result.make(Current)
  147. end
  148. feature {ANY} -- Mathematical operations:
  149. union (other: like Current)
  150. -- Make the union of the `Current' set with `other'.
  151. require
  152. other /= Void
  153. local
  154. i: INTEGER; e: like item
  155. do
  156. from
  157. i := 1
  158. until
  159. i > other.count
  160. loop
  161. e := other.item(i)
  162. if not has(e) then
  163. add(e)
  164. end
  165. i := i + 1
  166. end
  167. ensure
  168. count <= old count + other.count
  169. end
  170. fast_union (other: like Current)
  171. -- Make the union of the `Current' set with `other'.
  172. require
  173. other /= Void
  174. local
  175. i: INTEGER; e: like item
  176. do
  177. from
  178. i := 1
  179. until
  180. i > other.count
  181. loop
  182. e := other.item(i)
  183. if not fast_has(e) then
  184. fast_add(e)
  185. end
  186. i := i + 1
  187. end
  188. ensure
  189. count <= old count + other.count
  190. end
  191. infix "+" (other: like Current): like Current
  192. -- Return the union of the `Current' set with `other'.
  193. require
  194. other /= Void
  195. do
  196. Result := twin
  197. Result.union(other)
  198. ensure
  199. Result.count <= count + other.count
  200. Current.is_subset_of(Result) and then other.is_subset_of(Result)
  201. end
  202. intersection (other: like Current)
  203. -- Make the intersection of the `Current' set with `other'.
  204. require
  205. other /= Void
  206. local
  207. i: INTEGER; e: like item
  208. do
  209. from
  210. i := upper
  211. until
  212. i < lower
  213. loop
  214. e := item(i)
  215. if not other.has(e) then
  216. remove(e)
  217. end
  218. i := i - 1
  219. end
  220. ensure
  221. count <= other.count.min(old count)
  222. end
  223. fast_intersection (other: like Current)
  224. -- Make the intersection of the `Current' set with `other'.
  225. require
  226. other /= Void
  227. local
  228. i: INTEGER; e: like item
  229. do
  230. from
  231. i := upper
  232. until
  233. i < lower
  234. loop
  235. e := item(i)
  236. if not other.fast_has(e) then
  237. fast_remove(e)
  238. end
  239. i := i - 1
  240. end
  241. ensure
  242. count <= other.count.min(old count)
  243. end
  244. infix "^" (other: like Current): like Current
  245. -- Return the intersection of the `Current' set with `other'.
  246. require
  247. other /= Void
  248. do
  249. Result := twin
  250. Result.intersection(other)
  251. ensure
  252. Result.count <= other.count.min(count)
  253. Result.is_subset_of(Current) and then Result.is_subset_of(other)
  254. end
  255. minus (other: like Current)
  256. -- Make the set `Current' - `other'.
  257. require
  258. other /= Void
  259. local
  260. i: INTEGER
  261. do
  262. if other = Current then
  263. clear_count
  264. else
  265. from
  266. i := 1
  267. until
  268. i > other.count
  269. loop
  270. remove(other.item(i))
  271. i := i + 1
  272. end
  273. end
  274. ensure
  275. count <= old count
  276. end
  277. fast_minus (other: like Current)
  278. -- Make the set `Current' - `other'.
  279. require
  280. other /= Void
  281. local
  282. i: INTEGER
  283. do
  284. if other = Current then
  285. clear_count
  286. else
  287. from
  288. i := 1
  289. until
  290. i > other.count
  291. loop
  292. fast_remove(other.item(i))
  293. i := i + 1
  294. end
  295. end
  296. ensure
  297. count <= old count
  298. end
  299. infix "-" (other: like Current): like Current
  300. -- Return the set `Current' - `other'.
  301. require
  302. other /= Void
  303. do
  304. Result := twin
  305. Result.minus(other)
  306. ensure
  307. Result.count <= count
  308. Result.is_subset_of(Current)
  309. end
  310. feature {ANY} -- Comparison:
  311. is_subset_of (other: like Current): BOOLEAN
  312. -- Is the `Current' set a subset of `other'?
  313. require
  314. other /= Void
  315. local
  316. i: INTEGER
  317. do
  318. if Current = other then
  319. Result := True
  320. elseif count <= other.count then
  321. from
  322. Result := True
  323. i := 1
  324. until
  325. not Result or else i > count
  326. loop
  327. Result := other.has(item(i))
  328. i := i + 1
  329. end
  330. end
  331. ensure
  332. Result implies count <= other.count
  333. end
  334. is_disjoint_from (other: like Current): BOOLEAN
  335. -- Is the `Current' set disjoint from `other' ?
  336. require
  337. other /= Void
  338. local
  339. i: INTEGER
  340. do
  341. if Current /= other then
  342. Result := True
  343. i := 1
  344. if count <= other.count then
  345. from
  346. until
  347. not Result or else i > count
  348. loop
  349. Result := not other.has(item(i))
  350. i := i + 1
  351. end
  352. else
  353. from
  354. until
  355. not Result or else i > other.count
  356. loop
  357. Result := not has(other.item(i))
  358. i := i + 1
  359. end
  360. end
  361. end
  362. ensure
  363. Result = (Current ^ other).is_empty
  364. end
  365. is_equal (other: like Current): BOOLEAN
  366. -- Is the `Current' set equal to `other'?
  367. local
  368. i: INTEGER
  369. do
  370. if Current = other then
  371. Result := True
  372. elseif count = other.count then
  373. from
  374. Result := True
  375. i := 1
  376. until
  377. not Result or else i > count
  378. loop
  379. Result := other.has(item(i))
  380. i := i + 1
  381. end
  382. end
  383. ensure then
  384. double_inclusion: Result = (is_subset_of(other) and other.is_subset_of(Current))
  385. end
  386. feature {ANY}
  387. copy (other: like Current)
  388. -- Copy 'other' into the current set
  389. local
  390. i: INTEGER
  391. do
  392. -- Note: this naive implementation is OK because node
  393. -- recycling is implemented.
  394. from
  395. make
  396. i := 1
  397. until
  398. i > other.count
  399. loop
  400. add(other.item(i))
  401. i := i + 1
  402. end
  403. end
  404. from_collection (model: TRAVERSABLE[like item])
  405. -- Add all items of `model'.
  406. require
  407. model /= Void
  408. local
  409. i, up: INTEGER
  410. do
  411. from
  412. make
  413. up := model.upper
  414. i := model.lower
  415. until
  416. i > up
  417. loop
  418. add(model.item(i))
  419. i := i + 1
  420. end
  421. end
  422. feature {}
  423. make
  424. -- Creation of an empty SET.
  425. deferred
  426. ensure
  427. is_empty
  428. end
  429. feature {} -- Implement manifest generic creation:
  430. manifest_make (needed_capacity: INTEGER)
  431. -- Manifest creation of a SET.
  432. do
  433. make
  434. end
  435. manifest_put (index: INTEGER; element: like item)
  436. do
  437. add(element)
  438. end
  439. manifest_semicolon_check: BOOLEAN False
  440. end -- class SET
  441. --
  442. -- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
  443. --
  444. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  445. -- of this software and associated documentation files (the "Software"), to deal
  446. -- in the Software without restriction, including without limitation the rights
  447. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  448. -- copies of the Software, and to permit persons to whom the Software is
  449. -- furnished to do so, subject to the following conditions:
  450. --
  451. -- The above copyright notice and this permission notice shall be included in
  452. -- all copies or substantial portions of the Software.
  453. --
  454. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  455. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  456. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  457. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  458. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  459. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  460. -- THE SOFTWARE.