Replace binary search with linear scan in mt_get(), mt_put(), mt_del(), mt_chain_has(), and mrb_mt_foreach(). The method cache makes repeated lookups O(1), so linear scan on cache misses is acceptable. This removes the sorting requirement, allowing ROM entry arrays to be declared const. On embedded systems, const static data resides in flash/ROM instead of RAM, saving ~8.4KB for ~700 method entries on 32-bit MCUs. Co-authored-by: Claude <noreply@anthropic.com>
mruby-set
mruby-set provides a Set class for mruby, offering a collection of unordered, unique elements. It's useful when you need to store a group of items and quickly check for membership, or perform set operations like union, intersection, and difference.
Installation
To use mruby-set in your mruby project, add the following to your build_config.rb:
conf.gem "#{MRUBY_ROOT}/mrbgems/mruby-set"
Or, if you have it as a separate gem:
conf.gem :github => "mruby/mruby-set"
Usage and Examples
Creating a Set
You can create a set from an array or by using the Set.[] shorthand:
require 'set' # Not strictly necessary in mruby if compiled in
set1 = Set.new([1, 2, 3])
#=> Set[1, 2, 3]
set2 = Set[3, 4, 5]
#=> Set[3, 4, 5]
Adding and Deleting Elements
s = Set.new
s.add(10) #=> Set[10]
s << 20 #=> Set[10, 20]
s.add?(30) #=> Set[10, 20, 30]
s.add?(20) #=> nil (20 is already in the set)
s.delete(10) #=> Set[20, 30]
s.delete?(5) #=> nil (5 was not in the set)
s.delete?(20) #=> Set[30]
Set Operations
mruby-set supports common set operations:
Union (|, +, union): Returns a new set containing all elements from both sets.
set_a = Set[1, 2, 3]
set_b = Set[3, 4, 5]
set_a | set_b #=> Set[1, 2, 3, 4, 5]
set_a + set_b #=> Set[1, 2, 3, 4, 5]
Intersection (&, intersection): Returns a new set containing elements common to both sets.
set_a = Set[1, 2, 3]
set_b = Set[3, 4, 5]
set_a & set_b #=> Set[3]
Difference (-, difference): Returns a new set containing elements from the first set that are not in the second set.
set_a = Set[1, 2, 3]
set_b = Set[3, 4, 5]
set_a - set_b #=> Set[1, 2]
Exclusive OR (^): Returns a new set containing elements that are in one or the other of the sets, but not in both.
set_a = Set[1, 2, 3]
set_b = Set[3, 4, 5]
set_a ^ set_b #=> Set[1, 2, 4, 5]
Querying the Set
Checking for inclusion (include?, member?, ===):
s = Set["apple", "banana", "cherry"]
s.include?("banana") #=> true
s.member?("grape") #=> false
Checking size (size, length):
s = Set[10, 20, 30]
s.size #=> 3
Checking if empty (empty?):
Set.new.empty? #=> true
Set[1].empty? #=> false
Subset and Superset (subset?, superset?, <, <=, >, >=):
set_main = Set[1, 2, 3, 4]
sub = Set[2, 3]
super_set = Set[1, 2, 3, 4, 5]
sub.subset?(set_main) #=> true
set_main.superset?(sub) #=> true
set_main < super_set #=> true (proper subset)
super_set > set_main #=> true (proper superset)
Set[1,2].proper_subset?(Set[1,2,3]) #=> true
Set[1,2,3].proper_superset?(Set[1,2]) #=> true
Disjoint (disjoint?): Returns true if the set has no elements in common with the given set.
Set[1, 2].disjoint?(Set[3, 4]) #=> true
Set[1, 2].disjoint?(Set[2, 3]) #=> false
Intersect (intersect?): Returns true if the set has any elements in common with the given set.
Set[1, 2].intersect?(Set[2, 3]) #=> true
Set[1, 2].intersect?(Set[3, 4]) #=> false
Other Useful Methods
Convert to Array (to_a):
s = Set["a", "b", "c"]
s.to_a #=> ["a", "b", "c"] (order may vary)
Iterating (each):
s = Set[1, 2, 3]
s.each { |x| puts x * 10 }
# Output:
# 10
# 20
# 30
Map/Collect (map!, collect!): Modifies the set by applying the block to each element.
s = Set[1, 2, 3]
s.map! { |x| x * x } #=> Set[1, 4, 9]
Select/Filter (select!, filter!): Keeps elements for which the block returns true.
s = Set[1, 2, 3, 4, 5]
s.select! { |x| x.even? } #=> Set[2, 4]
Reject (reject!): Deletes elements for which the block returns true.
s = Set[1, 2, 3, 4, 5]
s.reject! { |x| x.odd? } #=> Set[2, 4]
Clear (clear): Removes all elements from the set.
s = Set[1, 2, 3]
s.clear #=> Set[]
Replace (replace): Replaces the contents of the set with the contents of the given enumerable.
s = Set[1, 2, 3]
s.replace([4, 5]) #=> Set[4, 5]
Flatten (flatten, flatten!): Returns a new set that is a copy of the set, flattening any nested sets. flatten! modifies the set in place.
s = Set[1, Set[2, 3], 4]
s.flatten #=> Set[1, 2, 3, 4]
Method Overview
Here's a list of commonly used methods available in mruby-set:
Set.[](*ary)initialize(enum = nil, &block)size,lengthempty?clearreplace(enum)to_ainclude?(o),member?(o),===superset?(set),>=proper_superset?(set),>subset?(set),<=proper_subset?(set),<intersect?(set)disjoint?(set)each(&block)add(o),<<(o)add?(o)delete(o)delete?(o)delete_if { |o| ... }keep_if { |o| ... }collect! { |o| ... },map! { |o| ... }reject! { |o| ... }select! { |o| ... },filter! { |o| ... }merge(enum)subtract(enum)|(enum),+(enum),union(enum)-(enum),difference(enum)&(enum),intersection(enum)^(enum)==(other)hasheql?(o)classify { |o| ... }divide(&func)join(separator = nil)inspect,to_sflatten,flatten!
Limitations
These methods are not implemented yet:
- freeze
- to_set
- divide(Set#divide with 2 arity block is not implemented.)
License
Under the MIT License:
- see LICENSE file