Since presym is now mandatory, mruby.h includes presym.h so that
MRB_SYM() macros are available everywhere without explicit include.
Remove redundant #include <mruby/presym.h> from all source files.
Co-authored-by: Claude <noreply@anthropic.com>
ROM method tables used static mrb_mt_tbl variables shared
across the process. The next pointer in each wrapper was
mutated by mrb_mt_init_rom(), causing cross-state
contamination when multiple mrb_state instances existed.
Allocate mrb_mt_tbl wrappers per-state via mrb_malloc().
The const mrb_mt_entry[] arrays remain static and shared.
Wrappers are tracked in mrb->rom_mt and freed at mrb_close().
Remove MRB_MT_ROM_TAB macro; add MRB_MT_INIT_ROM macro that
auto-computes size and calls the new mrb_mt_init_rom().
Co-authored-by: Claude <noreply@anthropic.com>
Restore MRB_ARGS_* argument specs and ISO section comments to all
709 ROM method table entries. The aspec is encoded in bits 4-27 of
the flags field; MRB_MT_NOARG is now auto-derived from aspec==0.
Add MRB_MT_ENTRY_PRIVATE() macro for private methods (53 entries)
and MRB_MT_ASPEC() accessor for extracting aspec from flags.
Co-authored-by: Claude <noreply@anthropic.com>
Since ROM table entries are always C functions, have the
MRB_MT_ENTRY() macro set MRB_MT_FUNC automatically. This
simplifies entry definitions across all 32 source files.
Co-authored-by: Claude <noreply@anthropic.com>
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>
Replace the parallel-arrays (struct-of-arrays) ROM method table
layout with an array-of-structs layout where each mrb_mt_entry
bundles its function pointer and symbol key together.
New MRB_MT_ENTRY() and MRB_MT_ROM_TAB() macros simplify ROM table
definitions from a 3-part pattern (SIZE define + anonymous struct +
mrb_mt_tbl) to a 2-part pattern (entries array + mrb_mt_tbl).
Internal mt_* functions in class.c are simplified: single memmove/
memcpy operations replace paired key+value operations.
Co-authored-by: Claude <noreply@anthropic.com>
wrap hash and eql callbacks with mrb_protect_error() to catch exceptions
during khash table rebuild. when an exception occurs (e.g., SystemStackError
from infinite recursion), return a safe default value and store the exception
in mrb->exc for later processing. this prevents memory leaks from orphaned
allocations when exceptions propagate through khash rebuild.
Co-authored-by: Claude <noreply@anthropic.com>
when a Set contains itself (directly or indirectly), computing its hash
would cause infinite recursion leading to SystemStackError. the exception
during khash rebuild leaked memory.
add recursion detection flag to Set#hash that returns 0 for recursive
references, similar to Ruby's behavior.
Co-authored-by: Claude <noreply@anthropic.com>
young objects stored in old Set instances were being freed during GC
because write barriers were missing. added mrb_field_write_barrier_value()
calls after all kset_put() operations. introduced kset_to_rset() macro
using container-of pattern to obtain RSet pointer from embedded kset_t
without adding function parameters.
Co-authored-by: Claude <noreply@anthropic.com>
set_do_flatten allocated temporary kset_t* via kset_init(). when
exceptions were raised during flattening (e.g., from hash function),
temporary kset was never freed. refactored to pass result set directly
and fill in-place. result set object is GC-protected, so exceptions
are handled cleanly without leaks.
Co-authored-by: Claude <noreply@anthropic.com>
kh_is_end() safely checks if an iterator is at the end position,
preventing issues when the hash table is modified during iteration.
replaced direct kset_end() comparisons with kset_is_end() calls
throughout set operations.
Co-authored-by: Claude <noreply@anthropic.com>
The `mrb_obj_as_string()` function can call the `#to_s` method.
String addresses and string lengths obtained outside the `KSET_FOREACH()` loop may become invalid.
set_init was overwriting set->set without freeing the existing khash
table, causing a memory leak when initialize is called multiple times.
Prevent double initialization by raising an exception in set_init,
while allowing replace/dup semantics in set_init_copy by properly
freeing old data before reinitializing.
Co-authored-by: Claude <noreply@anthropic.com>
Rename the constant to better reflect its semantic meaning as an initial
size hint for new Set allocations rather than a hard default value.
Co-authored-by: Claude <noreply@anthropic.com>
Add kh_replace function that uses direct memory copying instead of
element-by-element rehashing for improved performance.
- Add kh_replace_name function with smart handling of different table types
- Optimize kh_copy to use kh_replace instead of element iteration
- Update Set operations to use kh_replace for copying
- Remove redundant kset_copy_replace function
The optimization provides O(1) memory copy vs O(n) hash operations,
handles small tables and hash tables correctly, and avoids infinite
recursion issues with self-referential data structures.
Co-authored-by: Claude <noreply@anthropic.com>
Replace FNV-1a with XOR-based hash algorithm to ensure sets with identical
contents produce the same hash value regardless of insertion order.
The original FNV-1a algorithm was order-dependent, causing Set[1,2,3] and
Set[3,1,2] to have different hash values despite being equal sets. This
became problematic with small table optimization where iteration order
differs from hash table order.
The new algorithm uses commutative XOR operations with golden ratio mixing
to maintain good distribution properties while ensuring hash consistency.
Co-authored-by: Claude <noreply@anthropic.com>
Extract common logic from set_flatten and set_flatten_bang into helper
functions set_has_nested_sets() and set_do_flatten(). This eliminates
~40 lines of duplicated code while maintaining identical functionality
and performance.
Co-authored-by: Claude <noreply@anthropic.com>
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>
Remove the unused mrb_state parameter from KHASH_FOREACH macro to clean
up the API. The parameter was never used in the macro implementation and
only cluttered the call sites.
Changes:
- Update KHASH_FOREACH macro signature: (name, mrb, kh, k) -> (name, kh, k)
- Update documentation and usage examples in khash.h
- Update KSET_FOREACH wrapper macro in mruby-set
- Update 2 direct call sites in mruby-metaprog
- All mruby-set call sites automatically updated via wrapper macro
This is a breaking change but follows the recent API cleanup where we
already modified KHASH_FOREACH signature. The macro now has a cleaner
interface without the unused parameter.
Co-authored-by: Claude <noreply@anthropic.com>
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>
Replace the custom kset hash table implementation with the optimized
khash.h while maintaining identical functionality and memory footprint.
Changes:
- Replace custom kset_t struct with kh_set_val_t typedef
- Use KHASH_DECLARE/DEFINE macros for type-safe hash operations
- Add compatibility layer to preserve existing kset API
- Embed khash struct directly in RSet (same 16-byte footprint)
- Remove duplicate string.h include (provided by khash.h)
Benefits:
- Unified hash implementation across mruby core
- Eliminated ~200 lines of duplicate hash table code
- Automatic benefits from future khash optimizations
- Reduced maintenance burden with single hash implementation
- Identical performance and memory characteristics
The RSet structure maintains the same size through embedded khash
struct, and all Set class functionality remains unchanged.
Co-authored-by: Claude <noreply@anthropic.com>
Updated method definitions in mrbgems/mruby-set/src/set.c to use
mrb_define_method_id and MRB_SYM() for consistency and to leverage
presyms. This includes handling '?' and '!' in method names
with MRB_SYM_Q() and MRB_SYM_B() respectively, and using string
literals for mrb_define_alias.
Co-authored-by: Gemini <gemini@google.com>
Internal C functions now return a status, allowing Ruby methods
to avoid `is_a?(Set)` checks and simplify the logic for handling
different enumerable types.
Co-authored-by: Gemini <gemini@google.com>
Refactored `kset_resize` and `kset_put2` in `mrbgems/mruby-set/src/set.c`
to address a potential memory leak.
The previous implementation of `kset_resize` could lead to objects
referenced only by `old_keys` being garbage collected if a GC cycle
was triggered during calls to `mrb_obj_hash_code()` or `mrb_eql()`
while rehashing. This was because `s->data` was updated to the new,
empty data block before `old_keys` were fully processed.
Changes:
- Introduced a `kset_raw_put` function to encapsulate the common logic
for inserting an element into a set's underlying arrays (keys/flags).
- Modified `kset_resize` to:
- Keep the `old_data` pointer (and thus `old_keys`) valid and reachable
throughout the rehashing process.
- Allocate `new_data` and populate it using `kset_raw_put` for each
element from `old_data`.
- Free `old_data` only after all elements are successfully copied.
- Update the main set structure (`s->data`, `s->n_buckets`, `s->size`)
after the new data is fully prepared.
- Refactored `kset_put2` to use the `kset_raw_put` function, reducing
code duplication.
This ensures that all mrb_value objects remain reachable during GC
cycles that might occur within the rehashing logic, preventing the
memory leak.