require "setfu/version" class Set attr_reader :entropy def entropy=(ent) # entropy only gets bigger, just like the universe! @entropy = ent unless @entropy > ent end def mode return @mode end def initialize(data=nil) @bits = 0 @entropy = 0 add!(data) unless data.nil? self end def zap! @bits = 0 @entropy = 0 self end def recalculate_entropy! @entropy = 0 bits = @bits num = 1 << 8192 while(bits > num) @entropy += 8192 bits >>= 8192 end num = 1 << 256 while(bits > num) @entropy += 256 bits >>= 256 end num = 1 << 16 while(bits > num) @entropy += 16 bits >>= 16 end while(bits > 0) @entropy += 1 bits >>= 1 end #@entropy += 1 @entropy end def add_parse_chars! add! [0..47, 58..64, 91..96, 123..126] self end # this only works on integer ... String, Array, Range does not implement: &, |, ^ def coerce(other) #puts "TESTING ... coerce called!" return [self, other] # does not seem to get called ... end def dup rtn = Set.new rtn.set_bits!(@bits) rtn end def ^(item) rtn = self.dup if(item.class==Set) rtn.set_bits!(rtn.to_i ^ item.to_i) else rtn = Set.new(item) rtn.set_bits!(@bits ^ rtn.to_i) end rtn end def |(item) rtn = self.dup if(item.class==Set) rtn.set_bits!(rtn.to_i | item.to_i) self.entropy=item.entropy else rtn = Set.new(item) rtn.set_bits!(@bits | rtn.to_i) end rtn end def &(item) rtn = self.dup if(item.class==Set) rtn.set_bits!(rtn.to_i & item.to_i) else rtn = Set.new(item) rtn.set_bits!(@bits & rtn.to_i) end rtn end def -(item) rtn = Set.new rtn.entropy = self.entropy a = self.to_i if(item.class==Set) b = item.to_i rtn.entropy = item.entropy else b = Set.new(item) rtn.entropy = b.entropy b = b.to_i end c = a & b d = c ^ a rtn.set_bits!(d) rtn end def **(item) # intersection test set_item = Set.new(item) return false if (self & set_item).empty? return true end # comparison operators: def ==(item) if(item.class==Set) rtn = item.to_i == self.to_i else rtn = Set.new(item).to_i == self.to_i end rtn end def !=(item) if(item.class==Set) rtn = item.to_i != self.to_i else rtn = Set.new(item).to_i != self.to_i end rtn end def set_case(mode=:mode_equal) @mode = mode self end def ===(item) # self ... when clause ... # item ... case clause ... case(item) # Note: coerce does not work in this context ... md = item.to_set.mode || @mode case md when :mode_intersection return item ** self when :mode_sub return item <= self when :mode_proper return item < self when :mode_super return self <= item when :mode_superproper return self < item else return self == item end end def <=(item) si = Set.new item return si.include?(self) end def <(item) si = Set.new item return false if (si == self) # not a 'proper' subset return si.include?(self) end def add!(items) if(items.class==Set) @bits |= items.to_i entropy = items.entropy elsif(items.class==Range) f=items.first.ord l=items.last.ord f,l = l,f if f>l t = (l-f)+1 t = (1 << t)-1 @bits |= t << f self.entropy = l+1 elsif(items.respond_to? :each_char) items.each_char do |item| @bits |= 1 << item.ord self.entropy = item.ord+1 end elsif(items.respond_to? :each) items.each do |item| add! item end else #assume number raise "negative numbers are not allowed" if items < 0 pos = 1 << items @bits |= pos self.entropy = items+1 end self end def empty? @bits == 0 end def include?(items) if(items.class==Set) return (@bits & items.to_i) == items.to_i elsif(items.class==Range) f=items.first.ord l=items.last.ord f,l = l,f if f>l t = (l-f)+1 t = (1 << t)-1 t = t << f return (@bits & t) == t elsif(items.respond_to? :each_char) items.each_char do |item| t = 1 << item.ord return false if 0 == (t & @bits) end elsif(items.respond_to? :each) items.each do |item| return false if false==include?(item) end else #assume number t = 1 << items.abs return false if 0 == (t & @bits) end return true end def each_member bits = @bits pos = 0 while bits > 0 yield pos if ((bits & 1) == 1) pos += 1 bits >>= 1 end self end def to_i return @bits end def count cnt = 0 each_member do |toss| cnt += 1 end cnt end def to_s rtn = "" each_member do |ch| rtn += ch.chr end rtn end def to_a rtn = [] each_member do |num| rtn.push num end rtn end def set_bits!(bits) raise "negative numbers are not allowed" if bits.to_i < 0 @bits = bits.to_i end def ~@() rtn = dup mask = (1 << @entropy) - 1 rtn.set_bits!(mask ^ @bits) rtn end def [](pos) idx = pos.ord if pos.class==String idx = pos.to_i raise "Negative indexes are illegal for Set" if idx < 0 self.entropy = idx+1 y = @bits & (1< 0 false end def []=(pos,value) idx = pos.ord if pos.class==String idx = pos.to_i raise "Negative indexes are illegal for Set" if idx < 0 state = value ? true : false self.entropy = idx+1 if state # set bit @bits |= 1 << idx else # clear bit mask = 1 << idx @bits |= mask @bits ^= mask end return state end def min return nil if empty? range = (self.entropy)..(0) while((range.first - range.last) >= 2) do mid = ((range.first - range.last) >> 1) + range.last top = (range.first)..(mid) bot = (mid)..(range.last) range = self ** bot ? bot : top end #byebug return range.last if (self[range.last]) range.first end def max #look from left #byebug return nil if empty? range = (self.entropy)..(0) while((range.first - range.last) >= 2) do mid = ((range.first - range.last) >> 1) + range.last top = (range.first)..(mid) bot = (mid)..(range.last) range = self ** top ? top : bot end #byebug return range.first if (self[range.first]) range.last end end # end Set module SetFuMixinBinaryAndOperator def &(item) a = Set.new(self) b = Set.new(item) return a & b end end module SetFuMixinBinaryOrOperator def |(item) a = Set.new(self) b = Set.new(item) return a | b end end module SetFuMixinBinaryXorOperator def ^(item) a = Set.new(self) b = Set.new(item) return a ^ b end end module SetFuMixinBinaryIntersectionOperator def **(item) # intersection test a = Set.new(self) b = Set.new(item) return a ** b end end module SetFuMixinToSetMethod def to_set rtn = Set.new(self) # byebug return rtn end end module SetFuMixinTrippleEqualsOperator alias_method :old_triple_equal4Set, :=== def ===(item) return old_triple_equal4Set(item) unless (item.class==Set) return self.to_set === item end end module SetFuMixinBinarySubtractOperator def -(item) a = Set.new(self) b = Set.new(item) return a - b end end module SetFuMixinBinarySubsetOperator def <=(item) a = Set.new(self) b = Set.new(item) return a <= b end end module SetFuMixinBinaryProperOperator def <(item) a = Set.new(self) b = Set.new(item) return a < b end end class String alias_method :old_string_lt4set, :< alias_method :old_string_lte4set, :<= include SetFuMixinBinaryAndOperator include SetFuMixinBinaryOrOperator include SetFuMixinBinaryXorOperator include SetFuMixinBinaryIntersectionOperator include SetFuMixinToSetMethod include SetFuMixinTrippleEqualsOperator include SetFuMixinBinarySubtractOperator def <=(item) return old_string_lte4set(item) if (item.class==String) a = Set.new(self) b = Set.new(item) return a <= b end def <(item) return old_string_lt4set(item) if (item.class==String) a = Set.new(self) b = Set.new(item) return a < b end end class Array alias_method :old_subtract_method4set, :- alias_method :old_and_method4set, :& alias_method :old_or_method4set, :| include SetFuMixinBinaryXorOperator include SetFuMixinBinaryIntersectionOperator include SetFuMixinToSetMethod include SetFuMixinTrippleEqualsOperator include SetFuMixinBinarySubsetOperator include SetFuMixinBinaryProperOperator def -(item) return old_subtract_method4set(item) if (item.class==Array) a = Set.new(self) b = Set.new(item) return a - b end def &(item) return old_and_method4set(item) if (item.class==Array) a = Set.new(self) b = Set.new(item) return a & b end def |(item) return old_or_method4set(item) if (item.class==Array) a = Set.new(self) b = Set.new(item) return a | b end end class Range include SetFuMixinBinaryAndOperator include SetFuMixinBinaryOrOperator include SetFuMixinBinaryXorOperator include SetFuMixinBinaryIntersectionOperator include SetFuMixinToSetMethod include SetFuMixinTrippleEqualsOperator include SetFuMixinBinarySubtractOperator include SetFuMixinBinarySubsetOperator include SetFuMixinBinaryProperOperator end