Skip to content

Commit

Permalink
add size parameter (closes #6)
Browse files Browse the repository at this point in the history
  • Loading branch information
KRM7 committed Feb 23, 2024
1 parent fcc8c20 commit 54b7e6f
Show file tree
Hide file tree
Showing 3 changed files with 348 additions and 337 deletions.
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,40 @@
A constexpr `unique_ptr` implementation in C++20 with small object optimization.

```cpp
small_unique_ptr<Base> p = make_unique_small<Derived>();
smp::small_unique_ptr<Base> p = smp::make_unique_small<Derived>();
```

Objects created with `make_unique_small<T>` are allocated on the stack if:

- Their size is not greater than the size of the internal stack buffer
- Their required alignment is not greater than 64
- Their alignment is not greater than the alignment of the stack buffer
- Their move constructor is `noexcept`

The size of the stack buffer is architecture dependent, but on 64 bit architectures it will
generally be:
The size of the stack buffer depends on the architecture and the overall size of the
`small_unique_ptr` object, but the default values on 64 bit architectures will typically be:

- 48 for polymorphic types
- 56 for polymorphic types that implement a virtual `small_unique_ptr_move` method
- `sizeof(T)` for non-polymophic types, with an upper limit of 56
- 56 for array types
- 56 for array types (rounded down to a multiple of the element size)

The overall size of a `small_unique_ptr<T>` object is:
The overall size of a `small_unique_ptr<T, Size>` object for a polymorphic type is:

- 64 if `T` may be allocated in the stack buffer
- `Size` if `T` may be allocated in the stack buffer (64 by default)
- `sizeof(T*)` otherwise

The interface matches `std::unique_ptr<T>`, except for:
The interface matches `std::unique_ptr`, except for:

- There is no `Deleter` template parameter or any of the associated methods
- There is a `Size` template parameter that specifies the (maximum) size of the `small_unique_ptr` object
- Constructors from pointers are not provided except for the nullptr constructor
- `release()` is not implemented
- `T` can't be an incomplete type
- There are a couple of extra methods for checking where objects are allocated

Everything is constexpr, but the stack buffer is not used in constant evaluated contexts,
so any constexpr usage is subject to the same transient allocation requirements that a constexpr
`std::unique_ptr<T>` would be.
`std::unique_ptr` would be.

--------------------------------------------------------------------------------------------------

Expand All @@ -59,15 +60,15 @@ public:

template<typename F>
requires(!std::is_same_v<F, move_only_function> && std::is_invocable_r_v<Ret, F&, Args...>)
constexpr move_only_function(F f) noexcept(noexcept(make_unique_small<Impl<F>>(std::move(f)))) :
fptr_(make_unique_small<Impl<F>>(std::move(f)))
constexpr move_only_function(F f) noexcept(noexcept(smp::make_unique_small<Impl<F>>(std::move(f)))) :
fptr_(smp::make_unique_small<Impl<F>>(std::move(f)))
{}

template<typename F>
requires(!std::is_same_v<F, move_only_function> && std::is_invocable_r_v<Ret, F&, Args...>)
constexpr move_only_function& operator=(F f) noexcept(noexcept(make_unique_small<Impl<F>>(std::move(f))))
constexpr move_only_function& operator=(F f) noexcept(noexcept(smp::make_unique_small<Impl<F>>(std::move(f))))
{
fptr_ = make_unique_small<Impl<F>>(std::move(f));
fptr_ = smp::make_unique_small<Impl<F>>(std::move(f));
return *this;
}

Expand Down Expand Up @@ -114,7 +115,7 @@ private:
Callable func_;
};

small_unique_ptr<ImplBase> fptr_ = nullptr;
smp::small_unique_ptr<ImplBase> fptr_ = nullptr;
};
```
</details>
Loading

0 comments on commit 54b7e6f

Please sign in to comment.