mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-04 07:21:14 -03:00
maybe_t: make maybe_t<T> trivially copyable if T is
When passing a value of type maybe_t<size_t>, clangd complains:
Parameter 'cursor' is passed by value and only copied once; consider
moving it to avoid unnecessary copies (fix available)
We get this warning because maybe_t<size_t> is not trivially copyable
because it has a user-defined destructor and copy-constructor. Let's remove
them if the contained type is trivially copyable, to avoid such warnings.
No functional change.
This commit is contained in:
52
src/maybe.h
52
src/maybe.h
@@ -7,10 +7,11 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace maybe_detail {
|
namespace maybe_detail {
|
||||||
// Template magic to make maybe_t<T> copyable iff T is copyable.
|
// Template magic to make maybe_t<T> (trivially) copyable iff T is.
|
||||||
// maybe_impl_t is the "too aggressive" implementation: it is always copyable.
|
|
||||||
|
// This is an unsafe implementation: it is always trivially copyable.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct maybe_impl_t {
|
struct maybe_impl_trivially_copyable_t {
|
||||||
alignas(T) char storage[sizeof(T)];
|
alignas(T) char storage[sizeof(T)];
|
||||||
bool filled = false;
|
bool filled = false;
|
||||||
|
|
||||||
@@ -38,11 +39,13 @@ struct maybe_impl_t {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe_impl_t() = default;
|
maybe_impl_trivially_copyable_t() = default;
|
||||||
|
|
||||||
// Move construction/assignment from a T.
|
// Move construction/assignment from a T.
|
||||||
explicit maybe_impl_t(T &&v) : filled(true) { new (storage) T(std::forward<T>(v)); }
|
explicit maybe_impl_trivially_copyable_t(T &&v) : filled(true) {
|
||||||
maybe_impl_t &operator=(T &&v) {
|
new (storage) T(std::forward<T>(v));
|
||||||
|
}
|
||||||
|
maybe_impl_trivially_copyable_t &operator=(T &&v) {
|
||||||
if (filled) {
|
if (filled) {
|
||||||
value() = std::move(v);
|
value() = std::move(v);
|
||||||
} else {
|
} else {
|
||||||
@@ -53,8 +56,8 @@ struct maybe_impl_t {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy construction/assignment from a T.
|
// Copy construction/assignment from a T.
|
||||||
explicit maybe_impl_t(const T &v) : filled(true) { new (storage) T(v); }
|
explicit maybe_impl_trivially_copyable_t(const T &v) : filled(true) { new (storage) T(v); }
|
||||||
maybe_impl_t &operator=(const T &v) {
|
maybe_impl_trivially_copyable_t &operator=(const T &v) {
|
||||||
if (filled) {
|
if (filled) {
|
||||||
value() = v;
|
value() = v;
|
||||||
} else {
|
} else {
|
||||||
@@ -63,14 +66,26 @@ struct maybe_impl_t {
|
|||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Move construction/assignment from a maybe_impl.
|
// This is an unsafe implementation: it is always copyable.
|
||||||
maybe_impl_t(maybe_impl_t &&v) : filled(v.filled) {
|
template <typename T>
|
||||||
|
struct maybe_impl_not_trivially_copyable_t : public maybe_impl_trivially_copyable_t<T> {
|
||||||
|
using base_t = maybe_impl_trivially_copyable_t<T>;
|
||||||
|
using base_t::maybe_impl_trivially_copyable_t;
|
||||||
|
using base_t::operator=;
|
||||||
|
using base_t::filled;
|
||||||
|
using base_t::reset;
|
||||||
|
using base_t::storage;
|
||||||
|
|
||||||
|
// Move construction/assignment from another instance.
|
||||||
|
maybe_impl_not_trivially_copyable_t(maybe_impl_not_trivially_copyable_t &&v) {
|
||||||
|
filled = v.filled;
|
||||||
if (filled) {
|
if (filled) {
|
||||||
new (storage) T(std::move(v.value()));
|
new (storage) T(std::move(v.value()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maybe_impl_t &operator=(maybe_impl_t &&v) {
|
maybe_impl_not_trivially_copyable_t &operator=(maybe_impl_not_trivially_copyable_t &&v) {
|
||||||
if (!v.filled) {
|
if (!v.filled) {
|
||||||
reset();
|
reset();
|
||||||
} else {
|
} else {
|
||||||
@@ -79,13 +94,14 @@ struct maybe_impl_t {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy construction/assignment from a maybe_impl.
|
// Copy construction/assignment from another instance.
|
||||||
maybe_impl_t(const maybe_impl_t &v) : filled(v.filled) {
|
maybe_impl_not_trivially_copyable_t(const maybe_impl_not_trivially_copyable_t &v) : base_t() {
|
||||||
|
filled = v.filled;
|
||||||
if (v.filled) {
|
if (v.filled) {
|
||||||
new (storage) T(v.value());
|
new (storage) T(v.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maybe_impl_t &operator=(const maybe_impl_t &v) {
|
maybe_impl_not_trivially_copyable_t &operator=(const maybe_impl_not_trivially_copyable_t &v) {
|
||||||
if (&v == this) return *this;
|
if (&v == this) return *this;
|
||||||
if (!v.filled) {
|
if (!v.filled) {
|
||||||
reset();
|
reset();
|
||||||
@@ -95,7 +111,7 @@ struct maybe_impl_t {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
~maybe_impl_t() { reset(); }
|
~maybe_impl_not_trivially_copyable_t() { reset(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct copyable_t {};
|
struct copyable_t {};
|
||||||
@@ -128,7 +144,11 @@ inline constexpr none_t none() { return none_t::none; }
|
|||||||
// This is a value-type class that stores a value of T in aligned storage.
|
// This is a value-type class that stores a value of T in aligned storage.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class maybe_t : private maybe_detail::conditionally_copyable_t<T> {
|
class maybe_t : private maybe_detail::conditionally_copyable_t<T> {
|
||||||
maybe_detail::maybe_impl_t<T> impl_;
|
using maybe_impl_t =
|
||||||
|
typename std::conditional<std::is_trivially_copyable<T>::value,
|
||||||
|
maybe_detail::maybe_impl_trivially_copyable_t<T>,
|
||||||
|
maybe_detail::maybe_impl_not_trivially_copyable_t<T>>::type;
|
||||||
|
maybe_impl_t impl_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// return whether the receiver contains a value.
|
// return whether the receiver contains a value.
|
||||||
|
|||||||
Reference in New Issue
Block a user