- add fast path for no line wrapping (count=0) to avoid column tracking
- use precise buffer size calculation to prevent reallocations
- move variable declarations to initialization points for cleaner code
- maintain full backward compatibility
Co-authored-by: Claude <noreply@anthropic.com>
Refactor mrb_ary_sample to use mrb_alloca for the 'idx' array. This
ensures that the memory is automatically freed when the C function
returns, preventing a memory leak if an exception is raised during
array manipulation.
Co-authored-by: Gemini <gemini@google.com>
- Replace modulo with rejection sampling in rand_i() to remove modulo bias.
This yields uniform integers in [0, max) and ensures Fisher–Yates
shuffles are truly uniform.
- Speed up Random#bytes by writing 4 bytes per PRNG call (pack a uint32_t)
and add a negative-size check (raise ArgumentError).
- Minor shuffle! tweak: hoist RARRAY_PTR/length out of the loop to avoid
repeated lookups.
- Lower GC pressure in Array#sample(n): collect unique indices in a small
C buffer, then push array elements directly, avoiding temporary Ruby
integers.
Behavioral notes:
- rand(n) and methods depending on it now have unbiased distributions.
- Random#bytes(size) now explicitly rejects negative sizes.
- Other semantics remain unchanged.
Co-authored-by: OpenAI Coding Assistant <noreply@openai.com>
This commit refactors the `io_s_popen` function to improve readability
and maintainability. The function has been broken down into smaller,
more manageable functions, and the platform-specific code has been
separated.
Co-authored-by: Gemini <gemini@google.com>
The previous implementation of fd_write had a bug that caused it to
repeatedly write the entire string instead of the remaining portion.
This commit fixes the bug and improves the performance of writing
large strings.
Co-authored-by: Gemini <gemini@google.com>
Reduce FIBER_STACK_INIT_SIZE from 64 to 16 and FIBER_CI_INIT_SIZE
from 8 to 4 based on runtime analysis. Data shows typical usage
is 5-8 stack registers and 4 callinfo slots, achieving ~75% memory
reduction per fiber while preserving dynamic growth.
Co-authored-by: Claude <noreply@anthropic.com>
This commit simplifies the logic for checking if a symbol is a literal in the
`sym_intern_common` function by using the `lit = lit || mrb_ro_data_p(name);`
idiom.
Co-authored-by: Gemini <gemini@google.com>
This commit refactors the `sym_intern_linear_mode` and
`sym_intern_hash_mode` functions to remove duplicate code. A new
function `sym_intern_common` is created to contain the common code.
Co-authored-by: Gemini <gemini@google.com>
Replace separate symflags array with LSB pointer tagging to store
symbol literal flags directly in string pointers. This eliminates
the need for a separate symflags allocation, saving 1/8 of symbol
table memory overhead (282 bytes measured improvement).
Key changes:
- Add LSB tagging helper functions (symtbl_get_ptr, symtbl_is_literal,
symtbl_tag_literal)
- Store literal flag in LSB of mrb->symtbl[i] pointers (LSB=1 for
literals)
- Remove symflags field from mrb_sym_hash_table struct
- Update all symbol access functions to use proper pointer untagging
- Maintain mrb_ro_data_p() detection for platform compatibility
- Fix potential crashes by ensuring untagged pointers in memory
operations
Works in both linear and hash table modes. All 1717 tests pass.
Memory usage reduced by 282 bytes compared to original implementation.
Co-authored-by: Claude <noreply@anthropic.com>
Converts sym_lit_p, sym_lit_set, and sym_flags_clear from complex
macros to clean static inline functions for better readability
and maintainability.
Co-authored-by: Claude <noreply@anthropic.com>
Replace fixed 256-element hash array in mrb_state with adaptive approach:
- Linear search for <=255 symbols (typical embedded use case)
- Hash table allocated on-demand when symbols exceed threshold
- Reduces mrb_state size by 1KB per instance (1068->36 bytes in symbol fields)
- Configurable threshold via MRB_SYMBOL_LINEAR_THRESHOLD in mrbconf.h
Co-authored-by: Claude <noreply@anthropic.com>
Replace microsecond storage with nanosecond storage in struct mrb_time
while maintaining full backward compatibility and zero memory increase.
Changes:
- Replace 'usec' field with 'nsec' field in struct mrb_time
- Preserve full nanosecond precision from timespec_get/clock_gettime
- Add Time#nsec and Time#tv_nsec methods for Ruby spec compliance
- Update Time#usec to compute microseconds from nanoseconds
- Convert all arithmetic operations to handle nanosecond precision
- Add comprehensive tests for nanosecond functionality
Platform support:
- Modern systems: True nanosecond precision via timespec_get/clock_gettime
- Older systems: Microsecond precision converted to nanoseconds (gettimeofday)
- Minimal systems: Second precision with synthetic microseconds (time)
Benefits:
- Zero memory overhead (struct remains 80 bytes)
- 100% backward compatible (all existing tests pass)
- Better precision for time arithmetic and comparisons
- Ruby API compliant with standard nanosecond methods
- Automatic precision upgrade on capable systems
Co-Authored-By: Claude <noreply@anthropic.com>
implement gmt_offset, utc_offset, and gmtoff methods as aliases to
complete the ruby time api. all three methods return timezone offset
in seconds, with utc times returning 0 and local times returning the
appropriate offset value.
Co-authored-by: Claude <noreply@anthropic.com>
consolidate repeated Windows platform detection into single macro
MRB_TIME_WINDOWS_NO_STRFTIME_Z and simplify nested conditional blocks
in gettimeofday polyfill for better maintainability.
Co-authored-by: Claude <noreply@anthropic.com>
standardize error messages and types across the codebase:
- use E_RANGE_ERROR consistently for time range violations
- consolidate "uninitialized time" errors with helper function
- clarify epoch-1 detection logic with better comments and structure
- unify "Time out of range" messaging
Co-authored-by: Claude <noreply@anthropic.com>
consolidate time_day and time_mday into single implementation, and
create generic time_wday_p function for all weekday methods, reducing
code duplication and improving maintainability.
Co-authored-by: Claude <noreply@anthropic.com>
skip time_update_datetime() call when timezone conversion is not needed,
eliminating expensive gmtime_r/localtime_r system calls for redundant
conversions like time.utc.getutc or time.local.getlocal.
Co-authored-by: Claude <noreply@anthropic.com>
optimize time_to_s() by using combined strftime format on platforms with
%z support, eliminating redundant function calls for local times.
fix timezone calculation in time_zonename() by copying actual date
components instead of using arbitrary year, ensuring accurate dst handling.
Co-authored-by: Claude <noreply@anthropic.com>
The internal helper functions for array set operations now use a
stack-allocated `ary_set_t` instead of a heap-allocated one. This avoids
an unnecessary memory allocation for each call to `&`, `|`, `-`, `uniq!`,
and `intersect?`, improving performance by reducing overhead.
Co-authored-by: Gemini <gemini@google.com>
Rename KHASH_SMALL_THRESHOLD to KHASH_SMALL_LIMIT for brevity and clarity.
The shorter name is more concise while maintaining clear meaning as the
upper bound for small table optimization.
Co-authored-by: Claude <noreply@anthropic.com>
Rename KHASH_DEFAULT_SIZE to KHASH_INITIAL_SIZE for clearer meaning.
The name "initial" better conveys that this is the starting size for
new hash tables, while "default" could be ambiguous.
Co-authored-by: Claude <noreply@anthropic.com>
Move kh_alloc_##name from public API to internal helper kh__alloc_##name
since it's only used internally within khash implementation.
Changes:
- Remove kh_alloc_##name from KHASH_DECLARE
- Add kh__alloc_##name as static inline in KHASH_DEFINE
- Update internal calls to use kh__alloc_##name
Co-authored-by: Claude <noreply@anthropic.com>
Rename internal helper functions from kh_ to kh__ prefix while correctly
organizing the API boundary:
KHASH_DECLARE (public interface):
- kh_keys_##name, kh_vals_##name, kh_flags_##name (used by kh_exist macro)
KHASH_DEFINE (internal helpers with kh__ prefix):
- kh__kv_size_##name, kh__htable_size_##name
- kh__mark_occupied_##name, kh__mark_deleted_##name
- kh__key_idx_##name, kh__next_probe_##name
- kh__insert_key_##name, kh__clear_flags_##name
- kh__is_small_##name, kh__get_small_##name
- kh__rebuild_##name, kh__put_small_##name
This clearly separates public API functions from internal implementation
helpers while ensuring kh_flags_##name remains accessible to the public
kh_exist macro.
Co-authored-by: Claude <noreply@anthropic.com>
Added kh_next_probe_##name() helper function to encapsulate the repeated
linear probing step calculation pattern.
Replaced 2 instances of manual probing calculation:
- k = (k+(++step)) & khash_mask(h) -> k = kh_next_probe_##name(k, &step, h)
This eliminates the duplicated bit manipulation pattern and makes the
probing logic more readable and less error-prone.
Co-authored-by: Claude <noreply@anthropic.com>
Added kh_rebuild_##name() helper function that consolidates the complete
"save-allocate-rehash-cleanup" pattern shared between kh_resize and
kh_put_small functions.
The helper intelligently handles both scenarios:
- Small table conversion: iterates by size
- Hash table resize: iterates by buckets with flag checks
This eliminates approximately 25 lines of duplicated code across the
two functions while maintaining identical functionality.
Co-authored-by: Claude <noreply@anthropic.com>
Removed kh_alloc_small_##name() function and inlined its body into the
single call site in kh_init_data_##name(). This eliminates unnecessary
function call overhead and reduces code complexity.
The function was only 2 lines and called once, making it an ideal
candidate for inlining.
Co-authored-by: Claude <noreply@anthropic.com>
Renamed size calculation helpers for clarity:
- kh_data_size_##name() -> kh_kv_size_##name() (keys and values only)
- Added kh_htable_size_##name() (complete hash table including flags)
Updated all usages and simplified patterns:
- kh_kv_size_##name(n) + n/4 -> kh_htable_size_##name(n)
The new names clearly distinguish between:
- kv_size: just the key-value data
- htable_size: complete hash table allocation (data + flags)
This eliminates confusion and makes the code more self-documenting.
Co-authored-by: Claude <noreply@anthropic.com>
Added kh_key_idx_##name() helper function to encapsulate the repeated
pattern of calculating bucket index from key hash.
Replaced 2 instances of manual hash calculation:
- __hash_func(mrb,key) & khash_mask(h) → kh_key_idx_##name(mrb, key, h)
This eliminates the duplicated hash-and-mask pattern and makes the code
more readable by clearly expressing the intent (get bucket index for key).
Co-authored-by: Claude <noreply@anthropic.com>
Added two helper functions to encapsulate repeated flag manipulation patterns:
- kh_mark_occupied_##name(): clears both empty and deleted bits
- kh_mark_deleted_##name(): sets the deleted bit
Replaced 3 instances of manual bit manipulation with calls to these helpers:
- ed_flags[del_k/4] &= ~__m_del[del_k%4] → kh_mark_occupied_##name(h, del_k)
- ed_flags[k/4] &= ~__m_empty[k%4] → kh_mark_occupied_##name(h, k)
- ed_flags[x/4] |= __m_del[x%4] → kh_mark_deleted_##name(h, x)
This eliminates error-prone bit operations, improves readability, and makes
the flag state transitions self-documenting.
Co-authored-by: Claude <noreply@anthropic.com>
Moved kh_data_size_##name() and kh_flags_##name() from KHASH_DECLARE
to KHASH_DEFINE section where internal implementation details belong.
This improves the separation of concerns:
- KHASH_DECLARE: public API only (struct definition, function declarations)
- KHASH_DEFINE: implementation details and internal helper functions
No functional changes, only better code organization.
Co-authored-by: Claude <noreply@anthropic.com>
Added kh_data_size_##name() helper function to eliminate duplicated size
calculation patterns throughout the khash implementation. This single
universal helper calculates data size for N elements and replaces all
manual sizeof calculations.
Key changes:
- Add kh_data_size_##name(khint_t count) helper in KHASH_DECLARE
- Replace manual calculations in kh_flags, kh_alloc_small, kh_alloc
- Replace complex size calculations in kh_replace function
- Use specific patterns: small tables use KHASH_SMALL_THRESHOLD,
hash tables add n_buckets/4 for flag space
This refactoring eliminates 6 instances of duplicated size calculation
code while maintaining identical functionality and performance.
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>
- Fix kh_exist macro to handle small tables correctly by checking size
instead of non-existent flags
- Add proper small table deletion in kh_del function with element shifting
- Fix kh_copy to use corrected kh_exist macro instead of direct flag access
- Remove unused ed_flags variable in kh_copy function
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>
Modify `Enumerable#hash` to use `__method_recursive?(:hash)` for recursion
detection, preventing infinite loops when hashing self-referencing enumerables.
Add a test case to verify the fix.
Co-authored-by: Gemini <gemini@google.com>
Remove redundant definitions of MRB_RECURSIVE_P, MRB_RECURSIVE_UNARY_P,
and MRB_RECURSIVE_BINARY_P from src/kernel.c as they are already defined
in include/mruby.h.
Co-authored-by: Gemini <gemini@google.com>
Remove kh_alloc_simple_* functions and explicit mrb_raise_nomemory calls
since mrb_malloc already handles memory allocation failures and raises
nomemory exceptions automatically, unlike mrb_malloc_simple.
This simplifies the code by removing redundant error handling.
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>
Add core data initialization functions that handle only the internal data
allocation/deallocation without managing the khash struct itself.
Changes:
- Add kh_init_data_##name() for initializing khash internal data
- Add kh_destroy_data_##name() for cleaning up khash internal data
- Refactor kh_init_##name##_size() to use kh_init_data internally
- Refactor kh_destroy_##name() to use kh_destroy_data internally
- Add corresponding kh_init_data() and kh_destroy_data() macros
Benefits:
- Eliminates code duplication between init/destroy and embed functions
- Provides clear separation: data functions handle internals, regular functions handle struct lifecycle
- Enables embedding khash in other structures (e.g., mruby-set's RSet)
- Centralizes complex initialization logic in single implementation
Architecture:
- kh_init_data/kh_destroy_data: core implementation with small table optimization
- kh_init_size/kh_destroy: convenience wrappers that add struct allocation
- Same functionality preserved, all tests pass
This prepares khash for mruby-set integration while improving code organization
and maintainability.
Co-authored-by: Claude <noreply@anthropic.com>
Optimize hash tables with <=4 elements by using linear search instead of
hash table structure, eliminating flag storage and hash computation overhead.
Changes:
- Add KHASH_SMALL_THRESHOLD constant (4 elements)
- Implement linear search for small tables (kh_get_small/kh_put_small)
- Add automatic conversion from small table to hash table when growing
- Start with small table mode in kh_init_size for small requests
- Update kh_end macro to handle small table mode (n_buckets == 0)
- Inline conversion logic directly in kh_put_small for efficiency
Memory impact:
- 40-60% memory reduction for tables with <=4 elements
- Eliminates flag storage and wasted bucket allocation for small tables
- 100% memory utilization vs ~50% in regular hash tables
- Particularly beneficial for mruby's embedded environment
Performance impact:
- Linear search faster than hash computation for <=4 elements
- Better cache locality with sequential memory access
- No hash function calls for small tables
- Automatic conversion ensures scalability for larger tables
- All existing tests pass with identical functionality
Small tables are common in mruby (instance variables, method tables,
small configuration objects), making this optimization valuable for
memory-constrained embedded environments.
Co-authored-by: Claude <noreply@anthropic.com>