Files
mruby-mruby/mrbgems/mruby-set
Yukihiro "Matz" Matsumoto b22a8da598 mruby-set: integrate with unified khash.h implementation
Replace custom kset hash table implementation with unified khash.h to
reduce code redundancy and improve maintainability. This change removes
over 300 lines of duplicate hash table code while preserving all Set
functionality.

Key changes:
- Use khash.h DECLARE/DEFINE macros instead of custom kset functions
- Add helper macros for set state checking (empty/uninitialized)
- Implement separate merge and replace operations for set copying
- Update memory size calculation for new khash structure layout
- Fix iterator usage to match new khash API requirements

Benefits:
- 50% memory reduction from optimized khash structure
- Small table optimization with linear search for <= 4 elements
- Improved load factor (87.5% vs 75%) for better memory utilization
- Single unified hash implementation across mruby codebase

All existing Set functionality and APIs are preserved. Tests pass with
no regressions.

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-14 10:53:03 +09:00
..
2022-10-22 08:31:38 +10:00

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, length
  • empty?
  • clear
  • replace(enum)
  • to_a
  • include?(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)
  • hash
  • eql?(o)
  • classify { |o| ... }
  • divide(&func)
  • join(separator = nil)
  • inspect, to_s
  • flatten, 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: