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 self.uppercase_chars set = Set.new set.set_bits!(2475880041677272402379145216) set.entropy=91 return set end def self.lowercase_chars set = Set.new set.set_bits!(10633823807823001954701781295154855936) set.entropy=123 return set end def self.letter_chars set = Set.new set.set_bits!(10633823810298881996379053697534001152) set.entropy=123 return set end def self.digit_chars set = Set.new set.set_bits!(287948901175001088) set.entropy=58 return set end def self.parse_chars set = Set.new set.set_bits!(159507359650170349735020301117175103487) set.entropy=127 return set end def replace(ent) ent = ent.to_set @mode = ent.mode @entropy = ent.entropy @bits = ent.to_i self end def add_parse_chars! # add! [0..47, 58..64, 91..96, 123..126] add! Set.parse_chars self end def add_parse_chars return Set.parse_chars | self end def add_digit_chars! add! Set.digit_chars self end def add_digit_chars return Set.digit_chars | self end def add_uppercase_chars! add! Set.uppercase_chars self end def add_uppercase_chars return Set.uppercase_chars | self end def add_lowercase_chars! add! Set.lowercase_chars self end def add_lowercase_chars return Set.lowercase_chars | self end def add_letter_chars return Set.letter_chars | self end def add_letter_chars! add! Set.letter_chars self end def add_opposing_case! aa = Set.lowercase_chars bb = Set.uppercase_chars ka = aa & self # subset lower case kb = bb & self # subset upper case @bits |= ka.to_i >> 32 @bits |= kb.to_i << 32 self.entropy = 32 + kb.recalculate_entropy! if self.entropy <= 123 self end def add_opposing_case dup.add_opposing_case! end def to_set return self 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 # 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.replace(self) return 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 add(items) dup.add!(items) 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(int = true) rtn = [] each_member do |num| rtn.push int ? num : num.chr end rtn end def to_ra(int=true, th=3) raise "Threshold too low" unless th >= 2 rtn = [] cnt = 0 last = -100 flag = false th -= 1 each_member do |num| # byebug unless int rtn.push int ? num : num.chr if ((last+1)==num) # byebug if cnt.nil? cnt += 1 flag = cnt >= th elsif flag save = rtn.pop tmp = rtn.pop(cnt+1) range = (tmp.first)..(tmp.last) rtn.push range rtn.push save cnt = 0 last = -100 flag = false else cnt = 0 end last = num end #byebug if flag # convert final range tmp = rtn.pop(cnt+1) range = (tmp.first)..(tmp.last) rtn.push range 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 # new behavior ... single element returns true/false # multi element ... returns subset def [](*pset) idx = nil if pset.count==1 # check for single instance inst[5], inst['t'] if pset.first.kind_of? Integer idx = pset.first elsif pset.first.kind_of? String if pset.first.length == 1 idx = pset.first.ord end end end unless idx.nil? raise "Negative indexes are illegal for Set" if idx < 0 self.entropy = idx+1 y = @bits & (1< 0 return false end return pset.to_set & self end def []=(*pset,value) # pset goes in the box, value after '=' pset = pset.to_set state = value ? true : false if state replace pset | self # add elements to set else replace self - pset # remove elements from set end return state # this gets ignored, but to be safe, do what the previous version did 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 # :array :array_chars :string :set def rand(elm_count, format = :set) raise "rand minimum count too low" if elm_count < 1 ary = self.to_a ary.shuffle! ary = ary[0..(elm_count-1)] case format when :array return ary when :array_chars rtn = [] ary.each do |elm| rtn.push elm.chr end return rtn when :string rtn = [] ary.each do |elm| rtn.push elm.chr end return rtn.join "" else # :set return ary.to_set end 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