Skip to content
Merged

Dev #366

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
aa80647
More CMake updates.
cfis Dec 21, 2025
7442f93
Getting ready for 4.8.0 release.
cfis Dec 21, 2025
29637fd
Update docs generation and documentation.
cfis Dec 21, 2025
68661a0
More documentation work.
cfis Dec 22, 2025
5018e52
Set const for wrapped values.
cfis Dec 22, 2025
f93e2f1
Fix ambiguity with max macro on windows.
cfis Dec 22, 2025
94f6b66
Force type cast default values so code compiles.
cfis Dec 22, 2025
11b872c
Updated changelog
cfis Dec 22, 2025
7bd007d
Ditch the idea of std::shared_ptr as a wrapper class and just expose …
cfis Dec 27, 2025
95228f3
Fix a compilation error due to other changes.
cfis Dec 27, 2025
2e2a0b2
Formatting.
cfis Dec 27, 2025
5b43731
Better handling of Bignum conversion to C/C++ types.
cfis Dec 27, 2025
a639031
Add significantly more penalty for converting integral types to float…
cfis Dec 27, 2025
81944b7
Put back in all tests.
cfis Dec 28, 2025
e3a4ed7
Protect call to ruby.
cfis Dec 28, 2025
5e6acb9
Improve block handling and add Arg#setBlock() which is the equivalent…
cfis Dec 28, 2025
573c9c1
I don't remember why I returned exact here, let's return none instead…
cfis Dec 28, 2025
1bb83fb
Short circuit the loop since we know we won't use this native.
cfis Dec 28, 2025
899b73a
Add back missing tests.
cfis Dec 29, 2025
73c5c63
Introduce new Rice::Reference class so that method overloading can wo…
cfis Dec 29, 2025
b6d1b68
References only work with fundamental types and strings.
cfis Dec 29, 2025
395b985
Fix test failure.
cfis Dec 29, 2025
622cd4b
Change Reference Ruby api from #get to #value.
cfis Dec 29, 2025
30d7d3e
Documentation updates.
cfis Dec 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
# Changelog

## 4.8.0 (2025-11-28)
The release focuses on compilation times and library sizes. Compilation times are approximately 2x faster than version 4.7 and a bit faster than 4.6. Library sizes are about 30% smaller.

However, these updates required some breaking changes, which include:
## 4.8.0 (2025-12-29)
This release focuses on making Rice easier to use:

* Compilation times are approximately 2x faster than version 4.7
* Compiled library sizes are about 30% smaller
* Improved keyword argument support
* Improved method override support
* Improved CMake support
* Improved rbs generation support
* Improved api documentation generation support
* Expanded and improved documentation
* Enum values can now be compared against their underlying type (e.g., `Season::Red == 0`)
* STL containers now support `==` and `eql?` for equality comparison
* Automatic creation of `std::shared_ptr<T>` Ruby classes
* Support for C++ references in callbacks
* Array class now supports random iterators
* Fixed Ruby detection for Homebrew installations on macOS
* Added support for references to fundamental types

However, these changes did require some breaking changes, which include:

* `Return().isBuffer()` is replaced by `ReturnBuffer()`
* `Arg("").isBuffer()` is replaced by `ArgBuffer("")`
* `Function().noGVL()` is replaced by `NoGvL()`

See the pointer documentation for information on how to use them.
* `is_convertible` methods must now return a `double` instead of a `Convertible` enum

## 4.7.1 (2025-10-28)
Updates:
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.26)
project(rice LANGUAGES CXX)

# Put actual target definitions in a separate file so the root stays tiny.
include(${CMAKE_CURRENT_SOURCE_DIR}/rice.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/Rice.cmake)

# Default behavior:
# - If you're working on Rice directly (top-level), build tests by default (good for Visual Studio).
Expand Down
10 changes: 10 additions & 0 deletions Rice.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
add_library(Rice INTERFACE)
add_library(Rice::Rice ALIAS Rice)

target_include_directories(Rice INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)

# Need C++17 or higher
target_compile_features(Rice INTERFACE cxx_std_17)
90 changes: 45 additions & 45 deletions docs/architecture/overload_resolution.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct Convertible
{
static constexpr double Exact = 1.0; // Perfect type match
static constexpr double None = 0.0; // Cannot convert
static constexpr double IntToFloat = 0.9; // Penalty for int to float conversion
static constexpr double IntToFloat = 0.5; // Penalty for int to float conversion
static constexpr double SignedToUnsigned = 0.5;// Penalty for signed to unsigned (can't represent negatives)
static constexpr double FloatToInt = 0.5; // Penalty for float to int conversion
static constexpr double ConstMismatch = 0.99; // Penalty for const mismatch
Expand All @@ -26,28 +26,28 @@ struct Convertible

Ruby numeric types have precision defined in terms of bits:

| Ruby Type | Precision Bits | Notes |
|-----------|----------------|-------|
| Integer (Fixnum/Bignum) | 63 | Same as C++ long long |
| Float | 53 | Same as C++ double mantissa |
| Ruby Type | Precision Bits | Notes |
|-------------------------|-----------------|-----------------------------|
| Integer (Fixnum/Bignum) | 63 | Same as C++ long long |
| Float | 53 | Same as C++ double mantissa |

C++ types use `std::numeric_limits<T>::digits`:

| C++ Type | Precision Bits |
|----------|----------------|
| char | 7 |
| signed char | 7 |
| unsigned char | 8 |
| short | 15 |
| unsigned short | 16 |
| int | 31 |
| unsigned int | 32 |
| long | 31 or 63* |
| unsigned long | 32 or 64* |
| long long | 63 |
| unsigned long long | 64 |
| float | 24 (mantissa) |
| double | 53 (mantissa) |
| C++ Type | Precision Bits |
|--------------------|----------------|
| char | 7 |
| signed char | 7 |
| unsigned char | 8 |
| short | 15 |
| unsigned short | 16 |
| int | 31 |
| unsigned int | 32 |
| long | 31 or 63* |
| unsigned long | 32 or 64* |
| long long | 63 |
| unsigned long long | 64 |
| float | 24 (mantissa) |
| double | 53 (mantissa) |

\* Platform dependent

Expand Down Expand Up @@ -81,10 +81,10 @@ Score = 0.508 * 0.5 = 0.254

This ensures signed types are preferred over unsigned types. For example, given overloads `foo(int)` and `foo(unsigned int)`:

| Overload | Score | Calculation |
|----------|-------|-------------|
| foo(int) | 0.49 | 31/63 |
| foo(unsigned int) | 0.25 | 32/63 × 0.5 |
| Overload | Score | Calculation |
|-------------------|--------|-------------|
| foo(int) | 0.49 | 31/63 |
| foo(unsigned int) | 0.25 | 32/63 × 0.5 |

Result: `foo(int)` is selected.

Expand All @@ -96,24 +96,24 @@ When converting a Ruby Integer to a C++ float type, the score combines precision

```
Score = precisionScore * IntToFloat
= precisionScore * 0.9
= precisionScore * 0.5
```

Example: Ruby Integer (63 bits) to C++ double (53 bits)
```
precisionScore = min(63, 53) / 63 = 53/63 = 0.841
Score = 0.841 * 0.9 = 0.757
Score = 0.841 * 0.5 = 0.42
```

Example: Ruby Integer (63 bits) to C++ float (24 bits)
```
precisionScore = min(63, 24) / 63 = 24/63 = 0.381
Score = 0.381 * 0.9 = 0.343
Score = 0.381 * 0.5 = 0.19
```

### Float to Integer

When converting a Ruby Float to a C++ integer type, a larger penalty is applied because the fractional part is lost:
When converting a Ruby Float to a C++ integer type, a penalty is applied because the fractional part is lost:

```
Score = precisionScore * FloatToInt
Expand All @@ -136,29 +136,29 @@ Score = 1.0 * 0.5 = 0.5

The following table shows conversion scores for all Ruby-to-C++ type combinations, with the underlying calculations.

| C++ Type | Bits | True | False | Nil | String | Integer | Float |
|--------------------|:----:|:----:|:-----:|:---:|:------:|:-------:|:-----:|
| bool | - | 1.0 | 1.0 | 1.0 | | | |
| char | 7 | | | | 1.0 | 0.11 = 7/63 | 0.07 = 7/53×0.5 |
| signed char | 7 | | | | 1.0 | 0.11 = 7/63 | 0.07 = 7/53×0.5 |
| unsigned char | 8 | | | | 1.0 | 0.06 = 8/63×0.5 | 0.08 = 8/53×0.5 |
| short | 15 | | | | | 0.24 = 15/63 | 0.14 = 15/53×0.5 |
| C++ Type | Bits | True | False | Nil | String | Integer | Float |
|--------------------|:----:|:----:|:-----:|:---:|:------:|:----------------:|:----------------:|
| bool | - | 1.0 | 1.0 | 1.0 | | | |
| char | 7 | | | | 1.0 | 0.11 = 7/63 | 0.07 = 7/53×0.5 |
| signed char | 7 | | | | 1.0 | 0.11 = 7/63 | 0.07 = 7/53×0.5 |
| unsigned char | 8 | | | | 1.0 | 0.06 = 8/63×0.5 | 0.08 = 8/53×0.5 |
| short | 15 | | | | | 0.24 = 15/63 | 0.14 = 15/53×0.5 |
| unsigned short | 16 | | | | | 0.13 = 16/63×0.5 | 0.15 = 16/53×0.5 |
| int | 31 | | | | | 0.49 = 31/63 | 0.29 = 31/53×0.5 |
| int | 31 | | | | | 0.49 = 31/63 | 0.29 = 31/53×0.5 |
| unsigned int | 32 | | | | | 0.25 = 32/63×0.5 | 0.30 = 32/53×0.5 |
| long* | 31 | | | | | 0.49 = 31/63 | 0.29 = 31/53×0.5 |
| long* | 31 | | | | | 0.49 = 31/63 | 0.29 = 31/53×0.5 |
| unsigned long* | 32 | | | | | 0.25 = 32/63×0.5 | 0.30 = 32/53×0.5 |
| long long | 63 | | | | | 1.0 = 63/63 | 0.50 = 1.0×0.5 |
| unsigned long long | 64 | | | | | 0.50 = 1.0×0.5 | 0.50 = 1.0×0.5 |
| float | 24 | | | | | 0.34 = 24/63×0.9 | 0.45 = 24/53 |
| double | 53 | | | | | 0.76 = 53/63×0.9 | 1.0 = 53/53 |
| long long | 63 | | | | | 1.0 = 63/63 | 0.50 = 1.0×0.5 |
| unsigned long long | 64 | | | | | 0.50 = 1.0×0.5 | 0.50 = 1.0×0.5 |
| float | 24 | | | | | 0.19 = 24/63×0.5 | 0.45 = 24/53 |
| double | 53 | | | | | 0.42 = 53/63×0.5 | 1.0 = 53/53 |

\* `long` is platform-dependent. On 64-bit systems: `long` = 63 bits, `unsigned long` = 64 bits.

**Score formulas:**
- **Integer → signed integer**: `targetBits / 63` (narrowing) or `1.0` (widening)
- **Integer → unsigned integer**: `(targetBits / 63) × 0.5` (SignedToUnsigned penalty)
- **Integer → float**: `min(targetBits, 63) / 63 × 0.9` (IntToFloat penalty)
- **Integer → float**: `min(targetBits, 63) / 63 × 0.5` (IntToFloat penalty)
- **Float → integer**: `min(targetBits, 53) / 53 × 0.5` (FloatToInt penalty)
- **Float → float**: `targetBits / 53` (narrowing) or `1.0` (widening)

Expand Down Expand Up @@ -219,7 +219,7 @@ Called with Ruby Integer `foo(42)`:
| Overload | Parameter Score | Final Score |
|----------|-----------------|-------------|
| foo(int) | 1.0 (exact) | 1.0 |
| foo(double) | 0.9 (int to float) | 0.9 |
| foo(double) | 0.42 (int to float) | 0.42 |

Result: `foo(int)` is selected.

Expand Down Expand Up @@ -288,15 +288,15 @@ Called with `qux(1, 2.0)` (Integer, Float):
| Overload | Scores | Min Score | Final |
|----------|--------|-----------|-------|
| qux(int, double) | 1.0, 1.0 | 1.0 | 1.0 |
| qux(double, int) | 0.9, 0.5 | 0.5 | 0.5 |
| qux(double, int) | 0.42, 0.5 | 0.42 | 0.42 |

Result: `qux(int, double)` is selected.

Called with `qux(1.0, 2)` (Float, Integer):

| Overload | Scores | Min Score | Final |
|----------|--------|-----------|-------|
| qux(int, double) | 0.5, 0.9 | 0.5 | 0.5 |
| qux(int, double) | 0.5, 0.42 | 0.42 | 0.42 |
| qux(double, int) | 1.0, 1.0 | 1.0 | 1.0 |

Result: `qux(double, int)` is selected.
Expand Down
Loading