Date: Thu, 2 Apr 2026 17:57:51 +0200
czw., 2 kwi 2026 o 17:03 Jan Schultke <janschultke_at_[hidden]> napisaĆ(a):
>>
>> The problem with a `big_int operator+(big_int lhs, big_int rhs)`
>> signature is that lvalue arguments cause an unnecessary ref-count
>> inc+dec, even for basic arithmetic.
>
>
> You're right. That may have been fine in another library, but does not seem suitable for standardization.
>
>>
>> Another option is to have a possibly-owning big_int_view type, which
>> you'd use like `big_int operator+(big_int_view lhs, big_int_view rhs)`.
>> big_int_view has same layout as big_int, plus an additional "owning"
>> flag. When initialized from an lvalue (big_int or big_int_view) it
>> (shallowly) copies the value without taking ownership. When initialized
>> from an rvalue it copies the value and takes (or inherits) ownership,
>> clearing the source. This saves you the separate const/rv overloads, and
>> avoids the extra indirection of a reference.
>
>
> I feel like the cost of having this whole new view type is higher than just adding a couple of boilerplate overloads.
>
> You also need to consider that operator+ should work if one of the operands is an integer. I think to handle that without avoidable overhead, you actually need operator+ to be a function template. The reason is that for example, __int128 may not fit into big_int without extra allocation, so (big_int + __int128) would require an extra allocation to fit the right side, even though the operation could be performed with only the left allocation involved. I don't think big_int_view can handle the __int128 case in any reasonable way; you cannot do that without ownership.
What if `big_int` stores pointers to diffrent integers? Like in your
case for 32bit system:
```
struct { int size = 8; _atomic_int refs; int64_t data; };
struct { int size = 16; _atomic_int refs; int128_t data; };
struct { int size = i; _atomic_int refs; int_parts
data[i/sizeof(int_parts )]; }; //pseudo code
```
Now we can assume that if size is `8` then somewhere exists `int64_t`
that we can point to.
Then `big_int_view` would look like:
```
class big_int_view{ int size_plus_sign; union { const void* ptr;
int32_t u32; }; };
```
Now it can point to `__int128` as temporary or payload in `big_int`.
Only real concern would be the lifetime of pointers stored in
`big_int_view` as we could easily end up with dangling references.
>>
>> The problem with a `big_int operator+(big_int lhs, big_int rhs)`
>> signature is that lvalue arguments cause an unnecessary ref-count
>> inc+dec, even for basic arithmetic.
>
>
> You're right. That may have been fine in another library, but does not seem suitable for standardization.
>
>>
>> Another option is to have a possibly-owning big_int_view type, which
>> you'd use like `big_int operator+(big_int_view lhs, big_int_view rhs)`.
>> big_int_view has same layout as big_int, plus an additional "owning"
>> flag. When initialized from an lvalue (big_int or big_int_view) it
>> (shallowly) copies the value without taking ownership. When initialized
>> from an rvalue it copies the value and takes (or inherits) ownership,
>> clearing the source. This saves you the separate const/rv overloads, and
>> avoids the extra indirection of a reference.
>
>
> I feel like the cost of having this whole new view type is higher than just adding a couple of boilerplate overloads.
>
> You also need to consider that operator+ should work if one of the operands is an integer. I think to handle that without avoidable overhead, you actually need operator+ to be a function template. The reason is that for example, __int128 may not fit into big_int without extra allocation, so (big_int + __int128) would require an extra allocation to fit the right side, even though the operation could be performed with only the left allocation involved. I don't think big_int_view can handle the __int128 case in any reasonable way; you cannot do that without ownership.
What if `big_int` stores pointers to diffrent integers? Like in your
case for 32bit system:
```
struct { int size = 8; _atomic_int refs; int64_t data; };
struct { int size = 16; _atomic_int refs; int128_t data; };
struct { int size = i; _atomic_int refs; int_parts
data[i/sizeof(int_parts )]; }; //pseudo code
```
Now we can assume that if size is `8` then somewhere exists `int64_t`
that we can point to.
Then `big_int_view` would look like:
```
class big_int_view{ int size_plus_sign; union { const void* ptr;
int32_t u32; }; };
```
Now it can point to `__int128` as temporary or payload in `big_int`.
Only real concern would be the lifetime of pointers stored in
`big_int_view` as we could easily end up with dangling references.
Received on 2026-04-02 15:58:06
