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