Convert kset_copy_merge and kset_copy_replace from macros to static functions for better maintainability and debugging. Benefits: - Better debugging: can set breakpoints and step through code - Improved type safety: proper function parameter checking - Cleaner code: no macro expansion bloat at call sites - Better error messages: meaningful function names in stack traces - Easier maintenance: functions are simpler to modify than complex macros The operations are substantial enough (memory allocation, loops with GC management) that function call overhead is negligible compared to the actual work performed. 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