Change soft-fail to use the config, rather than env
[rbx.git] / stdlib / set.rb
blob3c96ceedbc2a8573a9fae855e896bb2ba45077a7
1 #!/usr/bin/env ruby
2 #--
3 # set.rb - defines the Set class
4 #++
5 # Copyright (c) 2002 Akinori MUSHA <knu@iDaemons.org>
7 # Documentation by Akinori MUSHA and Gavin Sinclair. 
9 # All rights reserved.  You can redistribute and/or modify it under the same
10 # terms as Ruby.
12 #   $Id: set.rb 11980 2007-03-03 16:06:45Z knu $
14 # == Overview 
15
16 # This library provides the Set class, which deals with a collection
17 # of unordered values with no duplicates.  It is a hybrid of Array's
18 # intuitive inter-operation facilities and Hash's fast lookup.  If you
19 # need to keep values ordered, use the SortedSet class.
21 # The method +to_set+ is added to Enumerable for convenience.
23 # See the Set class for an example of usage.
27 # Set implements a collection of unordered values with no duplicates.
28 # This is a hybrid of Array's intuitive inter-operation facilities and
29 # Hash's fast lookup.
31 # Several methods accept any Enumerable object (implementing +each+)
32 # for greater flexibility: new, replace, merge, subtract, |, &, -, ^.
34 # The equality of each couple of elements is determined according to
35 # Object#eql? and Object#hash, since Set uses Hash as storage.
37 # Finally, if you are using class Set, you can also use Enumerable#to_set
38 # for convenience.
40 # == Example
42 #   require 'set'
43 #   s1 = Set.new [1, 2]                   # -> #<Set: {1, 2}>
44 #   s2 = [1, 2].to_set                    # -> #<Set: {1, 2}>
45 #   s1 == s2                              # -> true
46 #   s1.add("foo")                         # -> #<Set: {1, 2, "foo"}>
47 #   s1.merge([2, 6])                      # -> #<Set: {6, 1, 2, "foo"}>
48 #   s1.subset? s2                         # -> false
49 #   s2.subset? s1                         # -> true
51 class Set
52   include Enumerable
54   # Creates a new set containing the given objects.
55   def self.[](*ary)
56     new(ary)
57   end
59   # Creates a new set containing the elements of the given enumerable
60   # object.
61   #
62   # If a block is given, the elements of enum are preprocessed by the
63   # given block.
64   def initialize(enum = nil, &block) # :yields: o
65     @hash ||= Hash.new
67     enum.nil? and return
69     if block
70       enum.each { |o| add(block[o]) }
71     else
72       merge(enum)
73     end
74   end
76   # Copy internal hash.
77   def initialize_copy(orig)
78     @hash = orig.instance_eval{@hash}.dup
79   end
81   # Returns the number of elements.
82   def size
83     @hash.size
84   end
85   alias length size
87   # Returns true if the set contains no elements.
88   def empty?
89     @hash.empty?
90   end
92   # Removes all elements and returns self.
93   def clear
94     @hash.clear
95     self
96   end
98   # Replaces the contents of the set with the contents of the given
99   # enumerable object and returns self.
100   def replace(enum)
101     if enum.class == self.class
102       @hash.replace(enum.instance_eval { @hash })
103     else
104       enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
105       clear
106       enum.each { |o| add(o) }
107     end
109     self
110   end
112   # Converts the set to an array.  The order of elements is uncertain.
113   def to_a
114     @hash.keys
115   end
117   def flatten_merge(set, seen = Set.new)
118     set.each { |e|
119       if e.is_a?(Set)
120         if seen.include?(e_id = e.object_id)
121           raise ArgumentError, "tried to flatten recursive Set"
122         end
124         seen.add(e_id)
125         flatten_merge(e, seen)
126         seen.delete(e_id)
127       else
128         add(e)
129       end
130     }
132     self
133   end
134   protected :flatten_merge
136   # Returns a new set that is a copy of the set, flattening each
137   # containing set recursively.
138   def flatten
139     self.class.new.flatten_merge(self)
140   end
142   # Equivalent to Set#flatten, but replaces the receiver with the
143   # result in place.  Returns nil if no modifications were made.
144   def flatten!
145     if detect { |e| e.is_a?(Set) }
146       replace(flatten())
147     else
148       nil
149     end
150   end
152   # Returns true if the set contains the given object.
153   def include?(o)
154     @hash.include?(o)
155   end
156   alias member? include?
158   # Returns true if the set is a superset of the given set.
159   def superset?(set)
160     set.is_a?(Set) or raise ArgumentError, "value must be a set"
161     return false if size < set.size
162     set.all? { |o| include?(o) }
163   end
165   # Returns true if the set is a proper superset of the given set.
166   def proper_superset?(set)
167     set.is_a?(Set) or raise ArgumentError, "value must be a set"
168     return false if size <= set.size
169     set.all? { |o| include?(o) }
170   end
172   # Returns true if the set is a subset of the given set.
173   def subset?(set)
174     set.is_a?(Set) or raise ArgumentError, "value must be a set"
175     return false if set.size < size
176     all? { |o| set.include?(o) }
177   end
179   # Returns true if the set is a proper subset of the given set.
180   def proper_subset?(set)
181     set.is_a?(Set) or raise ArgumentError, "value must be a set"
182     return false if set.size <= size
183     all? { |o| set.include?(o) }
184   end
186   # Calls the given block once for each element in the set, passing
187   # the element as parameter.
188   def each
189     @hash.each_key { |o| yield(o) }
190     self
191   end
193   # Adds the given object to the set and returns self.  Use +merge+ to
194   # add several elements at once.
195   def add(o)
196     @hash[o] = true
197     self
198   end
199   alias << add
201   # Adds the given object to the set and returns self.  If the
202   # object is already in the set, returns nil.
203   def add?(o)
204     if include?(o)
205       nil
206     else
207       add(o)
208     end
209   end
211   # Deletes the given object from the set and returns self.  Use +subtract+ to
212   # delete several items at once.
213   def delete(o)
214     @hash.delete(o)
215     self
216   end
218   # Deletes the given object from the set and returns self.  If the
219   # object is not in the set, returns nil.
220   def delete?(o)
221     if include?(o)
222       delete(o)
223     else
224       nil
225     end
226   end
228   # Deletes every element of the set for which block evaluates to
229   # true, and returns self.
230   def delete_if
231     @hash.delete_if { |o,| yield(o) }
232     self
233   end
235   # Do collect() destructively.
236   def collect!
237     set = self.class.new
238     each { |o| set << yield(o) }
239     replace(set)
240   end
241   alias map! collect!
243   # Equivalent to Set#delete_if, but returns nil if no changes were
244   # made.
245   def reject!
246     n = size
247     delete_if { |o| yield(o) }
248     size == n ? nil : self
249   end
251   # Merges the elements of the given enumerable object to the set and
252   # returns self.
253   def merge(enum)
254     if enum.is_a?(Set)
255       @hash.update(enum.instance_eval { @hash })
256     else
257       enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
258       enum.each { |o| add(o) }
259     end
261     self
262   end
264   # Deletes every element that appears in the given enumerable object
265   # and returns self.
266   def subtract(enum)
267     enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
268     enum.each { |o| delete(o) }
269     self
270   end
272   # Returns a new set built by merging the set and the elements of the
273   # given enumerable object.
274   def |(enum)
275     enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
276     dup.merge(enum)
277   end
278   alias + |             ##
279   alias union |         ##
281   # Returns a new set built by duplicating the set, removing every
282   # element that appears in the given enumerable object.
283   def -(enum)
284     enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
285     dup.subtract(enum)
286   end
287   alias difference -    ##
289   # Returns a new set containing elements common to the set and the
290   # given enumerable object.
291   def &(enum)
292     enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
293     n = self.class.new
294     enum.each { |o| n.add(o) if include?(o) }
295     n
296   end
297   alias intersection &  ##
299   # Returns a new set containing elements exclusive between the set
300   # and the given enumerable object.  (set ^ enum) is equivalent to
301   # ((set | enum) - (set & enum)).
302   def ^(enum)
303     enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
304     n = Set.new(enum)
305     each { |o| if n.include?(o) then n.delete(o) else n.add(o) end }
306     n
307   end
309   # Returns true if two sets are equal.  The equality of each couple
310   # of elements is defined according to Object#eql?.
311   def ==(set)
312     equal?(set) and return true
314     set.is_a?(Set) && size == set.size or return false
316     hash = @hash.dup
317     set.all? { |o| hash.include?(o) }
318   end
320   def hash      # :nodoc:
321     @hash.hash
322   end
324   def eql?(o)   # :nodoc:
325     return false unless o.is_a?(Set)
326     @hash.eql?(o.instance_eval{@hash})
327   end
329   # Classifies the set by the return value of the given block and
330   # returns a hash of {value => set of elements} pairs.  The block is
331   # called once for each element of the set, passing the element as
332   # parameter.
333   #
334   # e.g.:
335   #
336   #   require 'set'
337   #   files = Set.new(Dir.glob("*.rb"))
338   #   hash = files.classify { |f| File.mtime(f).year }
339   #   p hash    # => {2000=>#<Set: {"a.rb", "b.rb"}>,
340   #             #     2001=>#<Set: {"c.rb", "d.rb", "e.rb"}>,
341   #             #     2002=>#<Set: {"f.rb"}>}
342   def classify # :yields: o
343     h = {}
345     each { |i|
346       x = yield(i)
347       (h[x] ||= self.class.new).add(i)
348     }
350     h
351   end
353   # Divides the set into a set of subsets according to the commonality
354   # defined by the given block.
355   #
356   # If the arity of the block is 2, elements o1 and o2 are in common
357   # if block.call(o1, o2) is true.  Otherwise, elements o1 and o2 are
358   # in common if block.call(o1) == block.call(o2).
359   #
360   # e.g.:
361   #
362   #   require 'set'
363   #   numbers = Set[1, 3, 4, 6, 9, 10, 11]
364   #   set = numbers.divide { |i,j| (i - j).abs == 1 }
365   #   p set     # => #<Set: {#<Set: {1}>,
366   #             #            #<Set: {11, 9, 10}>,
367   #             #            #<Set: {3, 4}>,
368   #             #            #<Set: {6}>}>
369   def divide(&func)
370     if func.arity == 2
371       require 'tsort'
373       class << dig = {}         # :nodoc:
374         include TSort
376         alias tsort_each_node each_key
377         def tsort_each_child(node, &block)
378           fetch(node).each(&block)
379         end
380       end
382       each { |u|
383         dig[u] = a = []
384         each{ |v| func.call(u, v) and a << v }
385       }
387       set = Set.new()
388       dig.each_strongly_connected_component { |css|
389         set.add(self.class.new(css))
390       }
391       set
392     else
393       Set.new(classify(&func).values)
394     end
395   end
397   InspectKey = :__inspect_key__         # :nodoc:
399   # Returns a string containing a human-readable representation of the
400   # set. ("#<Set: {element1, element2, ...}>")
401   def inspect
402     ids = (Thread.current[InspectKey] ||= [])
404     if ids.include?(object_id)
405       return sprintf('#<%s: {...}>', self.class.name)
406     end
408     begin
409       ids << object_id
410       return sprintf('#<%s: {%s}>', self.class, to_a.inspect[1..-2])
411     ensure
412       ids.pop
413     end
414   end
416   def pretty_print(pp)  # :nodoc:
417     pp.text sprintf('#<%s: {', self.class.name)
418     pp.nest(1) {
419       pp.seplist(self) { |o|
420         pp.pp o
421       }
422     }
423     pp.text "}>"
424   end
426   def pretty_print_cycle(pp)    # :nodoc:
427     pp.text sprintf('#<%s: {%s}>', self.class.name, empty? ? '' : '...')
428   end
431 # SortedSet implements a set which elements are sorted in order.  See Set.
432 class SortedSet < Set
433   @@setup = false
435   class << self
436     def [](*ary)        # :nodoc:
437       new(ary)
438     end
440     def setup   # :nodoc:
441       @@setup and return
443       module_eval {
444         # a hack to shut up warning
445         alias old_init initialize
446         remove_method :old_init
447       }
448       begin
449         require 'rbtree'
451         module_eval %{
452           def initialize(*args, &block)
453             @hash = RBTree.new
454             super
455           end
456         }
457       rescue LoadError
458         module_eval %{
459           def initialize(*args, &block)
460             @keys = nil
461             super
462           end
464           def clear
465             @keys = nil
466             super
467           end
469           def replace(enum)
470             @keys = nil
471             super
472           end
474           def add(o)
475             @keys = nil
476             @hash[o] = true
477             self
478           end
479           alias << add
481           def delete(o)
482             @keys = nil
483             @hash.delete(o)
484             self
485           end
487           def delete_if
488             n = @hash.size
489             @hash.delete_if { |o,| yield(o) }
490             @keys = nil if @hash.size != n
491             self
492           end
494           def merge(enum)
495             @keys = nil
496             super
497           end
499           def each
500             to_a.each { |o| yield(o) }
501           end
503           def to_a
504             (@keys = @hash.keys).sort! unless @keys
505             @keys
506           end
507         }
508       end
510       @@setup = true
511     end
512   end
514   def initialize(*args, &block) # :nodoc:
515     SortedSet.setup
516     initialize(*args, &block)
517   end
520 module Enumerable
521   # Makes a set from the enumerable object with given arguments.
522   # Needs to +require "set"+ to use this method.
523   def to_set(klass = Set, *args, &block)
524     klass.new(self, *args, &block)
525   end
528 # =begin
529 # == RestricedSet class
530 # RestricedSet implements a set with restrictions defined by a given
531 # block.
533 # === Super class
534 #     Set
536 # === Class Methods
537 # --- RestricedSet::new(enum = nil) { |o| ... }
538 # --- RestricedSet::new(enum = nil) { |rset, o| ... }
539 #     Creates a new restricted set containing the elements of the given
540 #     enumerable object.  Restrictions are defined by the given block.
542 #     If the block's arity is 2, it is called with the RestrictedSet
543 #     itself and an object to see if the object is allowed to be put in
544 #     the set.
546 #     Otherwise, the block is called with an object to see if the object
547 #     is allowed to be put in the set.
549 # === Instance Methods
550 # --- restriction_proc
551 #     Returns the restriction procedure of the set.
553 # =end
555 # class RestricedSet < Set
556 #   def initialize(*args, &block)
557 #     @proc = block or raise ArgumentError, "missing a block"
559 #     if @proc.arity == 2
560 #       instance_eval %{
561 #       def add(o)
562 #         @hash[o] = true if @proc.call(self, o)
563 #         self
564 #       end
565 #       alias << add
567 #       def add?(o)
568 #         if include?(o) || !@proc.call(self, o)
569 #           nil
570 #         else
571 #           @hash[o] = true
572 #           self
573 #         end
574 #       end
576 #       def replace(enum)
577 #         enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
578 #         clear
579 #         enum.each { |o| add(o) }
581 #         self
582 #       end
584 #       def merge(enum)
585 #         enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
586 #         enum.each { |o| add(o) }
588 #         self
589 #       end
590 #       }
591 #     else
592 #       instance_eval %{
593 #       def add(o)
594 #         if @proc.call(o)
595 #           @hash[o] = true 
596 #         end
597 #         self
598 #       end
599 #       alias << add
601 #       def add?(o)
602 #         if include?(o) || !@proc.call(o)
603 #           nil
604 #         else
605 #           @hash[o] = true
606 #           self
607 #         end
608 #       end
609 #       }
610 #     end
612 #     super(*args)
613 #   end
615 #   def restriction_proc
616 #     @proc
617 #   end
618 # end
620 if $0 == __FILE__
621   eval DATA.read, nil, $0, __LINE__+4
624 __END__
626 require 'test/unit'
628 class TC_Set < Test::Unit::TestCase
629   def test_aref
630     assert_nothing_raised {
631       Set[]
632       Set[nil]
633       Set[1,2,3]
634     }
636     assert_equal(0, Set[].size)
637     assert_equal(1, Set[nil].size)
638     assert_equal(1, Set[[]].size)
639     assert_equal(1, Set[[nil]].size)
641     set = Set[2,4,6,4]
642     assert_equal(Set.new([2,4,6]), set)
643   end
645   def test_s_new
646     assert_nothing_raised {
647       Set.new()
648       Set.new(nil)
649       Set.new([])
650       Set.new([1,2])
651       Set.new('a'..'c')
652       Set.new('XYZ')
653     }
654     assert_raises(ArgumentError) {
655       Set.new(false)
656     }
657     assert_raises(ArgumentError) {
658       Set.new(1)
659     }
660     assert_raises(ArgumentError) {
661       Set.new(1,2)
662     }
664     assert_equal(0, Set.new().size)
665     assert_equal(0, Set.new(nil).size)
666     assert_equal(0, Set.new([]).size)
667     assert_equal(1, Set.new([nil]).size)
669     ary = [2,4,6,4]
670     set = Set.new(ary)
671     ary.clear
672     assert_equal(false, set.empty?)
673     assert_equal(3, set.size)
675     ary = [1,2,3]
677     s = Set.new(ary) { |o| o * 2 }
678     assert_equal([2,4,6], s.sort)
679   end
681   def test_clone
682     set1 = Set.new
683     set2 = set1.clone
684     set1 << 'abc'
685     assert_equal(Set.new, set2)
686   end
688   def test_dup
689     set1 = Set[1,2]
690     set2 = set1.dup
692     assert_not_same(set1, set2)
694     assert_equal(set1, set2)
696     set1.add(3)
698     assert_not_equal(set1, set2)
699   end
701   def test_size
702     assert_equal(0, Set[].size)
703     assert_equal(2, Set[1,2].size)
704     assert_equal(2, Set[1,2,1].size)
705   end
707   def test_empty?
708     assert_equal(true, Set[].empty?)
709     assert_equal(false, Set[1, 2].empty?)
710   end
712   def test_clear
713     set = Set[1,2]
714     ret = set.clear
716     assert_same(set, ret)
717     assert_equal(true, set.empty?)
718   end
720   def test_replace
721     set = Set[1,2]
722     ret = set.replace('a'..'c')
724     assert_same(set, ret)
725     assert_equal(Set['a','b','c'], set)
726   end
728   def test_to_a
729     set = Set[1,2,3,2]
730     ary = set.to_a
732     assert_equal([1,2,3], ary.sort)
733   end
735   def test_flatten
736     # test1
737     set1 = Set[
738       1,
739       Set[
740         5,
741         Set[7,
742           Set[0]
743         ],
744         Set[6,2],
745         1
746       ],
747       3,
748       Set[3,4]
749     ]
751     set2 = set1.flatten
752     set3 = Set.new(0..7)
754     assert_not_same(set2, set1)
755     assert_equal(set3, set2)
757     # test2; destructive
758     orig_set1 = set1
759     set1.flatten!
761     assert_same(orig_set1, set1)
762     assert_equal(set3, set1)
764     # test3; multiple occurrences of a set in an set
765     set1 = Set[1, 2]
766     set2 = Set[set1, Set[set1, 4], 3]
768     assert_nothing_raised {
769       set2.flatten!
770     }
772     assert_equal(Set.new(1..4), set2)
774     # test4; recursion
775     set2 = Set[]
776     set1 = Set[1, set2]
777     set2.add(set1)
779     assert_raises(ArgumentError) {
780       set1.flatten!
781     }
783     # test5; miscellaneous
784     empty = Set[]
785     set =  Set[Set[empty, "a"],Set[empty, "b"]]
787     assert_nothing_raised {
788       set.flatten
789     }
791     set1 = empty.merge(Set["no_more", set])
793     assert_nil(Set.new(0..31).flatten!)
795     x = Set[Set[],Set[1,2]].flatten!
796     y = Set[1,2]
798     assert_equal(x, y)
799   end
801   def test_include?
802     set = Set[1,2,3]
804     assert_equal(true, set.include?(1))
805     assert_equal(true, set.include?(2))
806     assert_equal(true, set.include?(3))
807     assert_equal(false, set.include?(0))
808     assert_equal(false, set.include?(nil))
810     set = Set["1",nil,"2",nil,"0","1",false]
811     assert_equal(true, set.include?(nil))
812     assert_equal(true, set.include?(false))
813     assert_equal(true, set.include?("1"))
814     assert_equal(false, set.include?(0))
815     assert_equal(false, set.include?(true))
816   end
818   def test_superset?
819     set = Set[1,2,3]
821     assert_raises(ArgumentError) {
822       set.superset?()
823     }
825     assert_raises(ArgumentError) {
826       set.superset?(2)
827     }
829     assert_raises(ArgumentError) {
830       set.superset?([2])
831     }
833     assert_equal(true, set.superset?(Set[]))
834     assert_equal(true, set.superset?(Set[1,2]))
835     assert_equal(true, set.superset?(Set[1,2,3]))
836     assert_equal(false, set.superset?(Set[1,2,3,4]))
837     assert_equal(false, set.superset?(Set[1,4]))
839     assert_equal(true, Set[].superset?(Set[]))
840   end
842   def test_proper_superset?
843     set = Set[1,2,3]
845     assert_raises(ArgumentError) {
846       set.proper_superset?()
847     }
849     assert_raises(ArgumentError) {
850       set.proper_superset?(2)
851     }
853     assert_raises(ArgumentError) {
854       set.proper_superset?([2])
855     }
857     assert_equal(true, set.proper_superset?(Set[]))
858     assert_equal(true, set.proper_superset?(Set[1,2]))
859     assert_equal(false, set.proper_superset?(Set[1,2,3]))
860     assert_equal(false, set.proper_superset?(Set[1,2,3,4]))
861     assert_equal(false, set.proper_superset?(Set[1,4]))
863     assert_equal(false, Set[].proper_superset?(Set[]))
864   end
866   def test_subset?
867     set = Set[1,2,3]
869     assert_raises(ArgumentError) {
870       set.subset?()
871     }
873     assert_raises(ArgumentError) {
874       set.subset?(2)
875     }
877     assert_raises(ArgumentError) {
878       set.subset?([2])
879     }
881     assert_equal(true, set.subset?(Set[1,2,3,4]))
882     assert_equal(true, set.subset?(Set[1,2,3]))
883     assert_equal(false, set.subset?(Set[1,2]))
884     assert_equal(false, set.subset?(Set[]))
886     assert_equal(true, Set[].subset?(Set[1]))
887     assert_equal(true, Set[].subset?(Set[]))
888   end
890   def test_proper_subset?
891     set = Set[1,2,3]
893     assert_raises(ArgumentError) {
894       set.proper_subset?()
895     }
897     assert_raises(ArgumentError) {
898       set.proper_subset?(2)
899     }
901     assert_raises(ArgumentError) {
902       set.proper_subset?([2])
903     }
905     assert_equal(true, set.proper_subset?(Set[1,2,3,4]))
906     assert_equal(false, set.proper_subset?(Set[1,2,3]))
907     assert_equal(false, set.proper_subset?(Set[1,2]))
908     assert_equal(false, set.proper_subset?(Set[]))
910     assert_equal(false, Set[].proper_subset?(Set[]))
911   end
913   def test_each
914     ary = [1,3,5,7,10,20]
915     set = Set.new(ary)
917     assert_raises(LocalJumpError) {
918       set.each
919     }
921     assert_nothing_raised {
922       set.each { |o|
923         ary.delete(o) or raise "unexpected element: #{o}"
924       }
926       ary.empty? or raise "forgotten elements: #{ary.join(', ')}"
927     }
928   end
930   def test_add
931     set = Set[1,2,3]
933     ret = set.add(2)
934     assert_same(set, ret)
935     assert_equal(Set[1,2,3], set)
937     ret = set.add?(2)
938     assert_nil(ret)
939     assert_equal(Set[1,2,3], set)
941     ret = set.add(4)
942     assert_same(set, ret)
943     assert_equal(Set[1,2,3,4], set)
945     ret = set.add?(5)
946     assert_same(set, ret)
947     assert_equal(Set[1,2,3,4,5], set)
948   end
950   def test_delete
951     set = Set[1,2,3]
953     ret = set.delete(4)
954     assert_same(set, ret)
955     assert_equal(Set[1,2,3], set)
957     ret = set.delete?(4)
958     assert_nil(ret)
959     assert_equal(Set[1,2,3], set)
961     ret = set.delete(2)
962     assert_equal(set, ret)
963     assert_equal(Set[1,3], set)
965     ret = set.delete?(1)
966     assert_equal(set, ret)
967     assert_equal(Set[3], set)
968   end
970   def test_delete_if
971     set = Set.new(1..10)
972     ret = set.delete_if { |i| i > 10 }
973     assert_same(set, ret)
974     assert_equal(Set.new(1..10), set)
976     set = Set.new(1..10)
977     ret = set.delete_if { |i| i % 3 == 0 }
978     assert_same(set, ret)
979     assert_equal(Set[1,2,4,5,7,8,10], set)
980   end
982   def test_collect!
983     set = Set[1,2,3,'a','b','c',-1..1,2..4]
985     ret = set.collect! { |i|
986       case i
987       when Numeric
988         i * 2
989       when String
990         i.upcase
991       else
992         nil
993       end
994     }
996     assert_same(set, ret)
997     assert_equal(Set[2,4,6,'A','B','C',nil], set)
998   end
1000   def test_reject!
1001     set = Set.new(1..10)
1003     ret = set.reject! { |i| i > 10 }
1004     assert_nil(ret)
1005     assert_equal(Set.new(1..10), set)
1007     ret = set.reject! { |i| i % 3 == 0 }
1008     assert_same(set, ret)
1009     assert_equal(Set[1,2,4,5,7,8,10], set)
1010   end
1012   def test_merge
1013     set = Set[1,2,3]
1015     ret = set.merge([2,4,6])
1016     assert_same(set, ret)
1017     assert_equal(Set[1,2,3,4,6], set)
1018   end
1020   def test_subtract
1021     set = Set[1,2,3]
1023     ret = set.subtract([2,4,6])
1024     assert_same(set, ret)
1025     assert_equal(Set[1,3], set)
1026   end
1028   def test_plus
1029     set = Set[1,2,3]
1031     ret = set + [2,4,6]
1032     assert_not_same(set, ret)
1033     assert_equal(Set[1,2,3,4,6], ret)
1034   end
1036   def test_minus
1037     set = Set[1,2,3]
1039     ret = set - [2,4,6]
1040     assert_not_same(set, ret)
1041     assert_equal(Set[1,3], ret)
1042   end
1044   def test_and
1045     set = Set[1,2,3,4]
1047     ret = set & [2,4,6]
1048     assert_not_same(set, ret)
1049     assert_equal(Set[2,4], ret)
1050   end
1052   def test_xor
1053     set = Set[1,2,3,4]
1054     ret = set ^ [2,4,5,5]
1055     assert_not_same(set, ret)
1056     assert_equal(Set[1,3,5], ret)
1057   end
1059   def test_eq
1060     set1 = Set[2,3,1]
1061     set2 = Set[1,2,3]
1063     assert_equal(set1, set1)
1064     assert_equal(set1, set2)
1065     assert_not_equal(Set[1], [1])
1067     set1 = Class.new(Set)["a", "b"]
1068     set2 = Set["a", "b", set1]
1069     set1 = set1.add(set1.clone)
1071 #    assert_equal(set1, set2)
1072 #    assert_equal(set2, set1)
1073     assert_equal(set2, set2.clone)
1074     assert_equal(set1.clone, set1)
1076     assert_not_equal(Set[Exception.new,nil], Set[Exception.new,Exception.new], "[ruby-dev:26127]")
1077   end
1079   # def test_hash
1080   # end
1082   # def test_eql?
1083   # end
1085   def test_classify
1086     set = Set.new(1..10)
1087     ret = set.classify { |i| i % 3 }
1089     assert_equal(3, ret.size)
1090     assert_instance_of(Hash, ret)
1091     ret.each_value { |value| assert_instance_of(Set, value) }
1092     assert_equal(Set[3,6,9], ret[0])
1093     assert_equal(Set[1,4,7,10], ret[1])
1094     assert_equal(Set[2,5,8], ret[2])
1095   end
1097   def test_divide
1098     set = Set.new(1..10)
1099     ret = set.divide { |i| i % 3 }
1101     assert_equal(3, ret.size)
1102     n = 0
1103     ret.each { |s| n += s.size }
1104     assert_equal(set.size, n)
1105     assert_equal(set, ret.flatten)
1107     set = Set[7,10,5,11,1,3,4,9,0]
1108     ret = set.divide { |a,b| (a - b).abs == 1 }
1110     assert_equal(4, ret.size)
1111     n = 0
1112     ret.each { |s| n += s.size }
1113     assert_equal(set.size, n)
1114     assert_equal(set, ret.flatten)
1115     ret.each { |s|
1116       if s.include?(0)
1117         assert_equal(Set[0,1], s)
1118       elsif s.include?(3)
1119         assert_equal(Set[3,4,5], s)
1120       elsif s.include?(7)
1121         assert_equal(Set[7], s)
1122       elsif s.include?(9)
1123         assert_equal(Set[9,10,11], s)
1124       else
1125         raise "unexpected group: #{s.inspect}"
1126       end
1127     }
1128   end
1130   def test_inspect
1131     set1 = Set[1]
1133     assert_equal('#<Set: {1}>', set1.inspect)
1135     set2 = Set[Set[0], 1, 2, set1]
1136     assert_equal(false, set2.inspect.include?('#<Set: {...}>'))
1138     set1.add(set2)
1139     assert_equal(true, set1.inspect.include?('#<Set: {...}>'))
1140   end
1142   # def test_pretty_print
1143   # end
1145   # def test_pretty_print_cycle
1146   # end
1149 class TC_SortedSet < Test::Unit::TestCase
1150   def test_sortedset
1151     s = SortedSet[4,5,3,1,2]
1153     assert_equal([1,2,3,4,5], s.to_a)
1155     prev = nil
1156     s.each { |o| assert(prev < o) if prev; prev = o }
1157     assert_not_nil(prev)
1159     s.map! { |o| -2 * o }
1161     assert_equal([-10,-8,-6,-4,-2], s.to_a)
1163     prev = nil
1164     s.each { |o| assert(prev < o) if prev; prev = o }
1165     assert_not_nil(prev)
1167     s = SortedSet.new([2,1,3]) { |o| o * -2 }
1168     assert_equal([-6,-4,-2], s.to_a)
1169   end
1172 class TC_Enumerable < Test::Unit::TestCase
1173   def test_to_set
1174     ary = [2,5,4,3,2,1,3]
1176     set = ary.to_set
1177     assert_instance_of(Set, set)
1178     assert_equal([1,2,3,4,5], set.sort)
1180     set = ary.to_set { |o| o * -2 }
1181     assert_instance_of(Set, set)
1182     assert_equal([-10,-8,-6,-4,-2], set.sort)
1184     set = ary.to_set(SortedSet)
1185     assert_instance_of(SortedSet, set)
1186     assert_equal([1,2,3,4,5], set.to_a)
1188     set = ary.to_set(SortedSet) { |o| o * -2 }
1189     assert_instance_of(SortedSet, set)
1190     assert_equal([-10,-8,-6,-4,-2], set.sort)
1191   end
1194 # class TC_RestricedSet < Test::Unit::TestCase
1195 #   def test_s_new
1196 #     assert_raises(ArgumentError) { RestricedSet.new }
1198 #     s = RestricedSet.new([-1,2,3]) { |o| o > 0 }
1199 #     assert_equal([2,3], s.sort)
1200 #   end
1202 #   def test_restriction_proc
1203 #     s = RestricedSet.new([-1,2,3]) { |o| o > 0 }
1205 #     f = s.restriction_proc
1206 #     assert_instance_of(Proc, f)
1207 #     assert(f[1])
1208 #     assert(!f[0])
1209 #   end
1211 #   def test_replace
1212 #     s = RestricedSet.new(-3..3) { |o| o > 0 }
1213 #     assert_equal([1,2,3], s.sort)
1215 #     s.replace([-2,0,3,4,5])
1216 #     assert_equal([3,4,5], s.sort)
1217 #   end
1219 #   def test_merge
1220 #     s = RestricedSet.new { |o| o > 0 }
1221 #     s.merge(-5..5)
1222 #     assert_equal([1,2,3,4,5], s.sort)
1224 #     s.merge([10,-10,-8,8])
1225 #     assert_equal([1,2,3,4,5,8,10], s.sort)
1226 #   end
1227 # end