#!/usr/bin/env ruby

require 'benchmark/ips'
require 'set'

class Set
  def fast_intersect(enum)
    n = self.class.new
    if enum.is_a?(Set)
      # if enum.size > size
      #   each { |o| n.add(o) if enum.include?(o) }
      # else
        enum.each { |o| n.add(o) if include?(o) }
      # end
    else
      do_with_enum(enum) { |o| n.add(o) if include?(o) }
    end
    n
  end

  def fastest_intersect(enum)
    n = self.class.new
    if enum.is_a?(Set)
      if enum.size > size
        each { |o| n.add(o) if enum.include?(o) }
      else
        enum.each { |o| n.add(o) if include?(o) }
      end
    else
      do_with_enum(enum) { |o| n.add(o) if include?(o) }
    end
    n
  end
end

n_values1 = 100
size_2_percentage = 0.8
overlap_percentage = 0.5

n_values2 = (n_values1 * size_2_percentage).to_i
overlap = (n_values2 * overlap_percentage).to_i

a1 = (0...n_values1).to_a
a2 = ((n_values1 - overlap)...(n_values1 - overlap + n_values2)).to_a
s1 = Set.new(a1)
s2 = Set.new(a2)
ss1 = SortedSet.new(a1)
ss2 = SortedSet.new(a2)

puts s1.size
puts s2.size
puts((s1 & s2).size)

method_groups = {
  Set_Set: {
    old: -> { s2 & s1 },
    fast: -> { s2.fast_intersect s1 },
    fastest: -> { s2.fastest_intersect s1 },
  },
  Set_SortedSet: {
    old: -> { s2 & ss1 },
    fast: -> { s2.fast_intersect ss1 },
    fastest: -> { s2.fastest_intersect ss1 },
  },
  SortedSet_Set: {
    old: -> { ss2 & s1 },
    fast: -> { ss2.fast_intersect s1 },
    fastest: -> { ss2.fastest_intersect s1 },
  },
  SortedSet_SortedSet: {
    old: -> { ss2 & ss1 },
    fast: -> { ss2.fast_intersect ss1 },
    fastest: -> { ss2.fastest_intersect ss1 },
  },
  Set_Array: {
    old: -> { s2 & a1 },
    fastest: -> { s2.fast_intersect a1 },
  },
}

method_groups.each do |group_name, group|
  puts '*' * 80
  puts group_name
  puts '*' * 80
  Benchmark.ips do |bm|
    group.each do |name, method|
      bm.report(name, &method)
    end

    bm.compare!
  end
end
