This documentation is automatically generated by online-judge-tools/verification-helper
require "benchmark"
require "../../src/datastructure/sset/red_black_tree"
require "../../src/datastructure/sset/treap"
require "../../src/datastructure/sset/bucket"
private def add(type : T.class, x, label, values) forall T
x.report(label) do
set = T.new
values.each { |x| set.add x }
end
end
private def add_delete(type : T.class, x, label, values) forall T
x.report(label) do
set = T.new
values.each { |x| set.add x }
values.each { |x| set.delete x }
end
end
private def each(type : T.class, x, label, n) forall T
set = T.new 0...n
x.report(label) do
s = 0i64
set.each { |x| s += x }
end
end
private def includes?(type : T.class, x, label, n) forall T
set = T.new (0...n).step(by: 2)
x.report(label) do
(0...n).each { |x| set.includes?(x) }
end
end
private def add_includes?(type : T.class, x, label, values, n) forall T
x.report(label) do
set = T.new
values.each { |x| set << x }
(0...n).each { |x| set.includes?(x) }
end
end
private def ge(type : T.class, x, label, n) forall T
set = T.new (0...n).step(by: 2)
x.report(label) do
(0...n).each { |x| set.ge(x) }
end
end
R = Random.new(42)
values5 = (0...10**5).to_a.shuffle(R)
values6 = (0...10**6).to_a.shuffle(R)
{% begin %}
{% hash = {
"SSet::RedBlackTree" => "RBT",
"SSet::Treap" => "Treap",
"SSet::Bucket(Int32, 1, 170, 0)" => "Bucket( 1, false)",
"SSet::Bucket(Int32, 30, 170, 0)" => "Bucket(30, false)",
"SSet::Bucket(Int32, 60, 170, 0)" => "Bucket(60, false)",
"SSet::Bucket(Int32, 90, 170, 0)" => "Bucket(90, false)",
"SSet::Bucket(Int32, 1, 170, 1)" => "Bucket( 1, true)",
"SSet::Bucket(Int32, 30, 170, 1)" => "Bucket(30, true)",
"SSet::Bucket(Int32, 60, 170, 1)" => "Bucket(60, true)",
"SSet::Bucket(Int32, 90, 170, 1)" => "Bucket(90, true)",
} %}
puts "#add (1e5 times)"
Benchmark.ips do |x|
{% for type, label in hash %} add({{type.id}}, x, {{label}}, values5); {% end %}
end
puts "\n#add and #delete (1e5 times)"
Benchmark.ips do |x|
{% for type, label in hash %} add_delete({{type.id}}, x, {{label}}, values5); {% end %}
end
puts "\n#add (1e6 times)"
Benchmark.ips do |x|
{% for type, label in hash %} add({{type.id}}, x, {{label}}, values6); {% end %}
end
puts "\n#add (1e6 times) and #delete (1e6 times)"
Benchmark.ips do |x|
{% for type, label in hash %} add_delete({{type.id}}, x, {{label}}, values6); {% end %}
end
puts "\n#add (1e6 times) and #includes? (1e6 times)"
Benchmark.ips do |x|
{% for type, label in hash %} add_includes?({{type.id}}, x, {{label}}, values6, 10**6); {% end %}
end
puts "\n#each (1e6 elements)"
Benchmark.ips do |x|
{% for type, label in hash %} each({{type.id}}, x, {{label}}, 10**6); {% end %}
end
puts "\n#includes? (1e6 times with 5e5 elements)"
Benchmark.ips do |x|
{% for type, label in hash %} includes?({{type.id}}, x, {{label}}, 10**6); {% end %}
end
puts "\n#ge (1e6 times with 5e5 elements)"
Benchmark.ips do |x|
{% for type, label in hash %} ge({{type.id}}, x, {{label}}, 10**6); {% end %}
end
{% end %}
require "benchmark"
# require "../../src/datastructure/sset/red_black_tree"
# require "../binary_tree"
module TreeNode(T)
abstract def key : T
abstract def left
abstract def right
abstract def parent
def node?
true
end
def nil_node?
false
end
def key? : T?
key
end
def key! : T
key
end
def min_node : self
x = self
while x.left.node?
x = x.left
end
x
end
def max_node : self
x = self
while x.right.node?
x = x.right
end
x
end
def succ : self
if right.node?
return right.min_node
end
x, y = self, parent
while y.node? && x != y.left
x = y
y = y.parent
end
y
end
def pred : self
if left.node?
return left.max_node
end
x, y = self, parent
while y.node? && x != y.right
x = y
y = y.parent
end
y
end
def to_s(io : IO)
io << '[' << key << ']'
end
def inspect(io : IO)
to_s(io)
end
end
module TreeNilNode(T)
def node?
false
end
def nil_node?
true
end
def key? : T?
nil
end
def key!
raise NilAssertionError.new
end
def to_s(io : IO)
io << "NilNode"
end
def inspect(io : IO)
to_s(io)
end
end
module BinaryTree(T, Node, NilNode)
class EmptyError < Exception
def initialize(message = "Empty RedBlackTree")
super(message)
end
end
include Enumerable(T)
include Iterable(T)
abstract def root
abstract def size : Int32
abstract def add?(key : T) : Bool
abstract def delete(key : T) : Bool
def empty? : Bool
root.nil_node?
end
def clear : self
@root = NilNode.new
@size = 0
self
end
def add(key : T) : self
add?(key)
self
end
def <<(key : T) : self
add(key)
end
def rotate_left(x : Node) : Nil
raise "x.right is nil!" if x.right.nil_node?
y = x.right
x.right = y.left
y.left.parent = x if y.left.node?
y.parent = x.parent
if x.parent.nil_node?
@root = y
else
if x == x.parent.left
x.parent.left = y
else
x.parent.right = y
end
end
y.left = x
x.parent = y
end
def rotate_right(x : Node) : Nil
raise "x.left is nil!" if x.left.nil_node?
y = x.left
x.left = y.right
y.right.parent = x if y.right.node?
y.parent = x.parent
if x.parent.nil_node?
@root = y
else
if x == x.parent.left
x.parent.left = y
else
x.parent.right = y
end
end
y.right = x
x.parent = y
end
def min_node : Node
root.min_node
end
def max_node : Node
root.max_node
end
def min? : T?
min_node.key?
end
def min : T
min? || raise EmptyError.new
end
def max? : T?
max_node.key?
end
def max : T
max? || raise EmptyError.new
end
private class InorderWalkIterator(T, Node)
include Iterator(T)
def initialize(@node : Node)
end
def next
if @node.nil_node?
stop
else
@node.key.tap { @node = @node.succ }
end
end
end
def each(node : Node = min_node, &block) : Nil
while node.node?
yield node.key
node = node.succ
end
end
def each(node : Node = min_node)
InorderWalkIterator(T, Node).new(node)
end
private class ReverseInorderWalkIterator(T, Node)
include Iterator(T)
def initialize(@node : Node)
end
def next
if @node.nil_node?
stop
else
@node.key.tap { @node = @node.pred }
end
end
end
def reverse_each(node : Node = max_node, &block) : Nil
while node.node?
yield node.key
node = node.pred
end
end
def reverse_each(node : Node = max_node)
ReverseInorderWalkIterator(T, Node).new(node)
end
def includes?(key : T) : Bool
x = root
loop do
return false if x.nil_node?
cmp = key <=> x.key
return true if cmp == 0
x = cmp < 0 ? x.left : x.right
end
end
def search(key : T, x : Node = root) : Node
while x.node?
cmp = key <=> x.key
break if cmp == 0
x = cmp < 0 ? x.left : x.right
end
x
end
def le_node(key : T, x : Node = root) : Node
loop do
cmp = key <=> x.key
y = cmp < 0 ? x.left : x.right
if y.nil_node?
return cmp < 0 ? x.pred : x
end
x = y
end
end
def lt_node(key : T, x : Node = root) : Node
loop do
cmp = key <=> x.key
y = cmp <= 0 ? x.left : x.right
if y.nil_node?
return cmp <= 0 ? x.pred : x
end
x = y
end
end
def ge_node(key : T, x : Node = root) : Node
loop do
cmp = key <=> x.key
y = cmp <= 0 ? x.left : x.right
if y.nil_node?
return cmp <= 0 ? x : x.succ
end
x = y
end
end
def gt_node(key : T, x : Node = root) : Node
loop do
cmp = key <=> x.key
y = cmp < 0 ? x.left : x.right
if y.nil_node?
return cmp < 0 ? x : x.succ
end
x = y
end
end
{% for method in [:le, :lt, :ge, :gt] %}
def {{method.id}}(key : T) : T?
{{method.id}}_node(key).key?
end
def {{method.id}}!(key : T) : T
{{method.id}}_node(key).key!
end
{% end %}
end
# Copied with modifications from: https://github.com/crystal-lang/crystal/blob/1.1.1/samples/red_black_tree.cr
class SSet::RedBlackTree(T)
class Node(T)
enum Color
Red
Black
end
include TreeNode(T)
property key : T, color : Color
property! left : Node(T), right : Node(T), parent : Node(T)
def initialize(@key : T, @color : Color = :red)
@left = @right = @parent = NilNode(T).new
end
def black?
color.black?
end
def red?
color.red?
end
def split(split_key : T) : {Node(T), Node(T)}
if nil_node?
{NilNode(T).new, NilNode(T).new}
elsif split_key < key
l, r = left.split(split_key)
self.left = r
r.parent = self
{l, self}
else
l, r = right.split(split_key)
self.right = l
l.parent = self
{self, r}
end
end
end
class NilNode(T) < Node(T)
include TreeNilNode(T)
def initialize
@key = uninitialized T
@left = @right = @parent = self
end
end
include BinaryTree(T, Node(T), NilNode(T))
getter root : Node(T), size : Int32 = 0
def initialize
@root = NilNode(T).new
end
def initialize(enumerable : Enumerable(T))
initialize
enumerable.each { |x| self << x }
end
protected def initialize(@root : Node(T))
end
private def insert_node(x : Node(T)) : Nil
insert_helper(x)
x.color = :red
while x != root && x.parent.red?
if x.parent == x.parent.parent.left
y = x.parent.parent.right
if !y.nil_node? && y.red?
x.parent.color = :black
y.color = :black
x.parent.parent.color = :red
x = x.parent.parent
else
if x == x.parent.right
x = x.parent
left_rotate(x)
end
x.parent.color = :black
x.parent.parent.color = :red
right_rotate(x.parent.parent)
end
else
y = x.parent.parent.left
if !y.nil_node? && y.red?
x.parent.color = :black
y.color = :black
x.parent.parent.color = :red
x = x.parent.parent
else
if x == x.parent.left
x = x.parent
right_rotate(x)
end
x.parent.color = :black
x.parent.parent.color = :red
left_rotate(x.parent.parent)
end
end
end
root.color = :black
end
private def delete_node(z : Node(T)) : Nil
y = (z.left.nil_node? || z.right.nil_node?) ? z : z.succ
x = y.left.nil_node? ? y.right : y.left
x.parent = y.parent
if y.parent.nil_node?
@root = x
else
if y == y.parent.left
y.parent.left = x
else
y.parent.right = x
end
end
z.key = y.key if y != z
if y.black?
delete_fixup(x)
end
@size -= 1
y
end
def add?(key : T) : Bool
return false if includes?(key)
insert_node(Node.new(key))
true
end
def delete(key : T) : Bool
node = search(key)
return false if node.nil_node?
delete_node(node)
true
end
def split(key : T) : {self, self}
l, r = root.split(key)
l.parent = NilNode(T).new
r.parent = NilNode(T).new
{RedBlackTree(T).new(l), RedBlackTree(T).new(r)}
end
def black_height(x : Node = root)
height = 0
until x.nil_node?
x = x.left
height += 1 if x.nil_node? || x.black?
end
height
end
def to_s(io : IO) : Nil
io << "SSet::RedBlackTree{"
each_with_index do |x, i|
io << ", " if i > 0
io << x
end
io << '}'
end
def inspect(io : IO) : Nil
to_s(io)
end
private def left_rotate(x : Node)
raise "x.right is nil!" if x.right.nil_node?
y = x.right
x.right = y.left
y.left.parent = x if !y.left.nil_node?
y.parent = x.parent
if x.parent.nil_node?
@root = y
else
if x == x.parent.left
x.parent.left = y
else
x.parent.right = y
end
end
y.left = x
x.parent = y
end
private def right_rotate(x : Node)
raise "x.left is nil!" if x.left.nil_node?
y = x.left
x.left = y.right
y.right.parent = x if !y.right.nil_node?
y.parent = x.parent
if x.parent.nil_node?
@root = y
else
if x == x.parent.left
x.parent.left = y
else
x.parent.right = y
end
end
y.right = x
x.parent = y
end
private def insert_helper(z : Node)
y = NilNode(T).new
x = root
while !x.nil_node?
y = x
x = (z.key < x.key) ? x.left : x.right
end
z.parent = y
if y.nil_node?
@root = z
else
z.key < y.key ? y.left = z : y.right = z
end
@size += 1
end
private def delete_fixup(x : Node)
while x != root && x.black?
if x == x.parent.left
w = x.parent.right
if w.red?
w.color = :black
x.parent.color = :red
left_rotate(x.parent)
w = x.parent.right
end
if w.left.black? && w.right.black?
w.color = :red
x = x.parent
else
if w.right.black?
w.left.color = :black
w.color = :red
right_rotate(w)
w = x.parent.right
end
w.color = x.parent.color
x.parent.color = :black
w.right.color = :black
left_rotate(x.parent)
x = root
end
else
w = x.parent.left
if w.red?
w.color = :black
x.parent.color = :red
right_rotate(x.parent)
w = x.parent.left
end
if w.right.black? && w.left.black?
w.color = :red
x = x.parent
else
if w.left.black?
w.right.color = :black
w.color = :red
left_rotate(w)
w = x.parent.left
end
w.color = x.parent.color
x.parent.color = :black
w.left.color = :black
right_rotate(x.parent)
x = root
end
end
end
x.color = :black
end
end
# require "../../src/datastructure/sset/treap"
# require "../binary_tree"
class SSet::Treap(T)
class Node(T)
include TreeNode(T)
getter key : T, priority : Int32
property! left : Node(T), right : Node(T), parent : Node(T)
def initialize(@key : T, @priority : Int32)
@left = @right = @parent = NilNode(T).new
end
def split(split_key : T) : {Node(T), Node(T)}
if nil_node?
{NilNode(T).new, NilNode(T).new}
elsif split_key < key
l, r = left.split(split_key)
self.left = r
r.parent = self
{l, self}
else
l, r = right.split(split_key)
self.right = l
l.parent = self
{self, r}
end
end
def to_s(io : IO)
io << '[' << key << ']'
end
end
class NilNode(T) < Node(T)
include TreeNilNode(T)
def initialize
@key = uninitialized T
@left = @right = @parent = self
end
end
include BinaryTree(T, Node(T), NilNode(T))
getter root : Node(T), size : Int32 = 0
def initialize
@root = NilNode(T).new
end
def initialize(enumerable : Enumerable(T))
initialize
enumerable.each { |x| self << x }
end
protected def initialize(@root : Node(T))
end
private def add_node(node : Node) : Bool
if empty?
@root = node
@size += 1
return true
end
u, prev = root, NilNode(T).new
while u.node?
cmp = node.key <=> u.key
return false if cmp == 0
u, prev = cmp < 0 ? u.left : u.right, u
end
if node.key < prev.key
prev.left = node
else
prev.right = node
end
node.parent = prev
@size += 1
true
end
private def bubble_up(u : Node) : Nil
raise "u is nil node" unless u.node?
while u.parent.node? && u.parent.priority > u.priority
if u.parent.right == u
rotate_left(u.parent)
else
rotate_right(u.parent)
end
end
@root = u if u.parent.nil_node?
end
def add?(key : T) : Bool
u = Node.new(key, rand(Int32))
add_node(u).tap do |f|
bubble_up(u) if f
end
end
private def trickle_down(u : Node(T))
loop do
l, r = u.left.node?, u.right.node?
break unless l || r
if !l
rotate_left(u)
elsif !r
rotate_right(u)
elsif u.left.priority < u.right.priority
rotate_right(u)
else
rotate_left(u)
end
@root = u.parent if root == u
end
end
def delete(key : T) : Bool
u = search(key)
return false if u.nil_node?
trickle_down(u)
if u.parent.left == u
u.parent.left = NilNode(T).new
else
u.parent.right = NilNode(T).new
end
@size -= 1
if size == 0
@root = NilNode(T).new
end
true
end
def split(key : T) : {self, self}
l, r = root.split(key)
l.parent = NilNode(T).new
r.parent = NilNode(T).new
{Treap(T).new(l), Treap(T).new(r)}
end
def to_s(io : IO) : Nil
io << "SSet::Treap{"
each_with_index do |x, i|
io << ", " if i > 0
io << x
end
io << '}'
end
def inspect(io : IO) : Nil
to_s(io)
end
end
# require "../../src/datastructure/sset/bucket"
# reference: https://github.com/tatyam-prime/SortedSet/blob/main/SortedSet.py
class SSet::Bucket(T, BUCKET_RATIO, REBUILD_RATIO, BSEARCH)
include Enumerable(T)
include Iterable(T)
include Indexable(T)
getter size = 0
@buckets = [] of Array(T)
def initialize
end
def initialize(a : Enumerable(T))
build a.to_a.sort!.uniq!
end
private def build(a : Array(T)) : Nil
@size = a.size
bucket_size = Math.sqrt(size / BUCKET_RATIO).ceil.to_i
@buckets = Array.new(bucket_size) { |i| a[size * i // bucket_size...size * (i + 1) // bucket_size] }
end
private def build
build to_a
end
def empty? : Bool
@size == 0
end
def clear
@size = 0
@buckets.clear
end
def min? : T?
empty? ? nil : @buckets.first.first
end
def min : T
min? || raise EmptyError.new
end
def max? : T?
empty? ? nil : @buckets.last.last
end
def max : T
max? || raise EmptyError.new
end
def each(&) : Nil
@buckets.each do |bucket|
bucket.each do |object|
yield object
end
end
end
private class ItemIterator(T)
include Iterator(T)
def initialize(@buckets : Array(Array(T)))
@i, @j = 0, 0
end
def next
if @buckets.size == @i
stop
else
@buckets[@i][@j].tap do
@j += 1
@i, @j = @i + 1, 0 if @buckets[@i].size == @j
end
end
end
end
def each
ItemIterator(T).new(@buckets)
end
def reverse_each(&) : Nil
@buckets.reverse_each do |bucket|
bucket.reverse_each do |object|
yield object
end
end
end
private def find_bucket(object : T)
{% if BSEARCH > 0 %}
@buckets.bsearch { |bucket| object <= bucket.last } || @buckets.last
{% else %}
@buckets.find(@buckets.last) { |bucket| object <= bucket.last }
{% end %}
end
def includes?(object : T) : Bool
false if empty?
find_bucket(object).bsearch { |x| x >= object } == object
end
def unsafe_fetch(index : Int) : T
@buckets.each do |bucket|
return bucket.unsafe_fetch(index) if index < bucket.size
index -= bucket.size
end
raise "Bug"
end
def add?(object : T) : Bool
if size == 0
@buckets = [[object]]
@size = 1
return true
end
a = find_bucket(object)
i = a.bsearch_index { |x| x >= object }
return false if i && a[i] == object
i ? a.insert(i, object) : a.push(object)
@size += 1
build if a.size > @buckets.size * REBUILD_RATIO
true
end
def add(object : T) : self
add?(object)
self
end
def <<(object : T) : self
add(object)
end
def concat(elems) : self
elems.each { |object| add(object) }
self
end
def delete(object : T) : Bool
return false if empty?
a = find_bucket(object)
i = a.bsearch_index { |x| x >= object }
return false if i.nil? || a[i] != object
a.delete_at(i)
@size -= 1
build if a.empty?
true
end
def count(object : T) : Int32
includes?(object) ? 1 : 0
end
def index(object : T) : Int32?
offset = 0
@buckets.each do |bucket|
if bucket.last >= object
i = bucket.bsearch_index { |x| x >= object }.not_nil!
return offset + i if bucket[i] == object
end
end
end
def index_left(object : T) : Int32
@buckets.reduce(0) do |offset, bucket|
if bucket.last >= object
return offset + bucket.bsearch_index { |x| x >= object }.not_nil!
end
offset + bucket.size
end
end
def index_right(object : T) : Int32?
@buckets.reduce(0) do |offset, bucket|
if bucket.last > object
return offset + bucket.bsearch_index { |x| x > object }.not_nil!
end
offset + bucket.size
end
end
def le(object : T) : T?
@buckets.reverse_each do |bucket|
if bucket.first <= object
i = bucket.bsearch_index { |x| x > object } || bucket.size
return bucket[i - 1]
end
end
end
def lt(object : T) : T?
@buckets.reverse_each do |bucket|
if bucket.first < object
i = bucket.bsearch_index { |x| x >= object } || bucket.size
return bucket[i - 1]
end
end
end
def ge(object : T) : T?
{% if BSEARCH > 0 %}
@buckets.bsearch { |bucket| bucket.last >= object }.try do |bucket|
bucket.bsearch { |x| x >= object }.not_nil!
end
{% else %}
@buckets.each do |bucket|
if bucket.last >= object
return bucket.bsearch { |x| x >= object }.not_nil!
end
end
{% end %}
end
def gt(object : T) : T?
@buckets.each do |bucket|
if bucket.last > object
return bucket.bsearch { |x| x > object }.not_nil!
end
end
end
{% for method in [:le, :lt, :ge, :gt] %}
def {{method.id}}!(object : T) : T
{{method.id}}(object).not_nil!
end
{% end %}
{% for op in [:&, :|, :^, :+, :-] %}
def {{op.id}}(other : Enumerable(T)) : self
SSet::Bucket(T, BUCKET_RATIO, REBUILD_RATIO, BSEARCH).new (self.to_set {{op.id}} other.to_set)
end
{% end %}
def to_a : Array(T)
@buckets.each_with_object(Array(T).new size) do |bucket, a|
a.concat bucket
end
end
def to_s(io : IO) : Nil
io << "SSet::Bucket{"
join(", ", io)
io << "}"
end
def inspect(io : IO) : Nil
@buckets.inspect(io)
end
end
private def add(type : T.class, x, label, values) forall T
x.report(label) do
set = T.new
values.each { |x| set.add x }
end
end
private def add_delete(type : T.class, x, label, values) forall T
x.report(label) do
set = T.new
values.each { |x| set.add x }
values.each { |x| set.delete x }
end
end
private def each(type : T.class, x, label, n) forall T
set = T.new 0...n
x.report(label) do
s = 0i64
set.each { |x| s += x }
end
end
private def includes?(type : T.class, x, label, n) forall T
set = T.new (0...n).step(by: 2)
x.report(label) do
(0...n).each { |x| set.includes?(x) }
end
end
private def add_includes?(type : T.class, x, label, values, n) forall T
x.report(label) do
set = T.new
values.each { |x| set << x }
(0...n).each { |x| set.includes?(x) }
end
end
private def ge(type : T.class, x, label, n) forall T
set = T.new (0...n).step(by: 2)
x.report(label) do
(0...n).each { |x| set.ge(x) }
end
end
R = Random.new(42)
values5 = (0...10**5).to_a.shuffle(R)
values6 = (0...10**6).to_a.shuffle(R)
{% begin %}
{% hash = {
"SSet::RedBlackTree" => "RBT",
"SSet::Treap" => "Treap",
"SSet::Bucket(Int32, 1, 170, 0)" => "Bucket( 1, false)",
"SSet::Bucket(Int32, 30, 170, 0)" => "Bucket(30, false)",
"SSet::Bucket(Int32, 60, 170, 0)" => "Bucket(60, false)",
"SSet::Bucket(Int32, 90, 170, 0)" => "Bucket(90, false)",
"SSet::Bucket(Int32, 1, 170, 1)" => "Bucket( 1, true)",
"SSet::Bucket(Int32, 30, 170, 1)" => "Bucket(30, true)",
"SSet::Bucket(Int32, 60, 170, 1)" => "Bucket(60, true)",
"SSet::Bucket(Int32, 90, 170, 1)" => "Bucket(90, true)",
} %}
puts "#add (1e5 times)"
Benchmark.ips do |x|
{% for type, label in hash %} add({{type.id}}, x, {{label}}, values5); {% end %}
end
puts "\n#add and #delete (1e5 times)"
Benchmark.ips do |x|
{% for type, label in hash %} add_delete({{type.id}}, x, {{label}}, values5); {% end %}
end
puts "\n#add (1e6 times)"
Benchmark.ips do |x|
{% for type, label in hash %} add({{type.id}}, x, {{label}}, values6); {% end %}
end
puts "\n#add (1e6 times) and #delete (1e6 times)"
Benchmark.ips do |x|
{% for type, label in hash %} add_delete({{type.id}}, x, {{label}}, values6); {% end %}
end
puts "\n#add (1e6 times) and #includes? (1e6 times)"
Benchmark.ips do |x|
{% for type, label in hash %} add_includes?({{type.id}}, x, {{label}}, values6, 10**6); {% end %}
end
puts "\n#each (1e6 elements)"
Benchmark.ips do |x|
{% for type, label in hash %} each({{type.id}}, x, {{label}}, 10**6); {% end %}
end
puts "\n#includes? (1e6 times with 5e5 elements)"
Benchmark.ips do |x|
{% for type, label in hash %} includes?({{type.id}}, x, {{label}}, 10**6); {% end %}
end
puts "\n#ge (1e6 times with 5e5 elements)"
Benchmark.ips do |x|
{% for type, label in hash %} ge({{type.id}}, x, {{label}}, 10**6); {% end %}
end
{% end %}