Skip to content

Commit

Permalink
Overhaul function calls and usage
Browse files Browse the repository at this point in the history
- add noexcept to some of the core function calls
- type usage for both trampolines and yields can now be fully tracked, at the expense of more template instantiations when using both
- exceptions should be less prone to explosion in C versions, but will break in C++ code (the trampolines need to be modified for usertype calls to avoid this problem, specifically)
  • Loading branch information
ThePhD committed Dec 18, 2020
1 parent 561c90a commit d39330e
Show file tree
Hide file tree
Showing 20 changed files with 915 additions and 620 deletions.
2 changes: 1 addition & 1 deletion docs/source/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ functions and argument passing

All arguments are forwarded. Unlike :doc:`get/set/operator[] on sol::state<api/state>` or :doc:`sol::table<api/table>`, value semantics are not used here. It is forwarding reference semantics, which do not copy/move unless it is specifically done by the receiving functions / specifically done by the user.

You can change this behavior by defining ``SOL_FUNCTION_CALL_VALUE_SEMANTICS``, as defined in the :doc:`safety configuration page<safety>`.
You can change this behavior by defining ``SOL_FUNCTION_CALL_VALUE_SEMANTICS``, as defined in the :doc:`safety configuration page<safety>`. You can also change it for specific types using the ``sol::is_value_semantic_for_function<T>`` template and _partially specializing_ it to make either ``std::true_type``, ``std::false_type``, or equivalent ``true``/``false`` functionality.

.. note::

Expand Down
81 changes: 40 additions & 41 deletions include/sol/ebco.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,39 +31,40 @@ namespace sol { namespace detail {

template <typename T, std::size_t tag = 0, typename = void>
struct ebco {
T value_;
T m_value;

ebco() = default;
ebco(const ebco&) = default;
ebco(ebco&&) = default;
ebco& operator=(const ebco&) = default;
ebco& operator=(ebco&&) = default;
ebco(const T& v) : value_(v) {};
ebco(T&& v) : value_(std::move(v)) {};
ebco& operator=(const T& v) {
value_ = v;
ebco(const T& v) noexcept(std::is_nothrow_copy_constructible_v<T>) : m_value(v) {};
ebco(T&& v) noexcept(std::is_nothrow_move_constructible_v<T>) : m_value(std::move(v)) {};
ebco& operator=(const T& v) noexcept(std::is_nothrow_copy_assignable_v<T>) {
m_value = v;
return *this;
}
ebco& operator=(T&& v) {
value_ = std::move(v);
ebco& operator=(T&& v) noexcept(std::is_nothrow_move_assignable_v<T>) {
m_value = std::move(v);
return *this;
};
template <typename Arg, typename... Args,
typename = std::enable_if_t<!std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>,
ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T>>>
ebco(Arg&& arg, Args&&... args) : value_(std::forward<Arg>(arg), std::forward<Args>(args)...) {
ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T> && (sizeof...(Args) > 0 || !std::is_convertible_v<Arg, T>)>>
ebco(Arg&& arg, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Arg, Args...>)
: m_value(std::forward<Arg>(arg), std::forward<Args>(args)...) {
}

T& value() & {
return value_;
T& value() & noexcept {
return m_value;
}

T const& value() const& {
return value_;
T const& value() const& noexcept {
return m_value;
}

T&& value() && {
return std::move(value_);
T&& value() && noexcept {
return std::move(m_value);
}
};

Expand All @@ -72,56 +73,58 @@ namespace sol { namespace detail {
ebco() = default;
ebco(const ebco&) = default;
ebco(ebco&&) = default;
ebco(const T& v) : T(v) {};
ebco(T&& v) : T(std::move(v)) {};
ebco(const T& v) noexcept(std::is_nothrow_copy_constructible_v<T>) : T(v) {};
ebco(T&& v) noexcept(std::is_nothrow_move_constructible_v<T>) : T(std::move(v)) {};
template <typename Arg, typename... Args,
typename = std::enable_if_t<!std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>,
ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T>>>
ebco(Arg&& arg, Args&&... args) : T(std::forward<Arg>(arg), std::forward<Args>(args)...) {
ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T> && (sizeof...(Args) > 0 || !std::is_convertible_v<Arg, T>)>>
ebco(Arg&& arg, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Arg, Args...>) : T(std::forward<Arg>(arg), std::forward<Args>(args)...) {
}

ebco& operator=(const ebco&) = default;
ebco& operator=(ebco&&) = default;
ebco& operator=(const T& v) {
ebco& operator=(const T& v) noexcept(std::is_nothrow_copy_assignable_v<T>) {
static_cast<T&>(*this) = v;
return *this;
}
ebco& operator=(T&& v) {
ebco& operator=(T&& v) noexcept(std::is_nothrow_move_assignable_v<T>) {
static_cast<T&>(*this) = std::move(v);
return *this;
};

T& value() & {
T& value() & noexcept {
return static_cast<T&>(*this);
}

T const& value() const& {
T const& value() const& noexcept {
return static_cast<T const&>(*this);
}

T&& value() && {
T&& value() && noexcept {
return std::move(static_cast<T&>(*this));
}
};

template <typename T, std::size_t tag>
struct ebco<T&, tag> {
T& ref;
private:
T* m_ref;

public:
ebco() = default;
ebco(const ebco&) = default;
ebco(ebco&&) = default;
ebco(T& v) : ref(v) {};
ebco(T& v) noexcept : m_ref(std::addressof(v)) {};

ebco& operator=(const ebco&) = default;
ebco& operator=(ebco&&) = default;
ebco& operator=(T& v) {
ref = v;
ebco& operator=(T& v) noexcept {
m_ref = std::addressof(v);
return *this;
}

T& value() const {
return const_cast<ebco<T&, tag>&>(*this).ref;
T& value() const noexcept {
return *(const_cast<ebco<T&, tag>&>(*this).m_ref);
}
};

Expand All @@ -130,26 +133,22 @@ namespace sol { namespace detail {
T&& ref;

ebco() = default;
ebco(const ebco&) = default;
ebco(const ebco&) = delete;
ebco(ebco&&) = default;
ebco(T&& v) : ref(v) {};
ebco(T&& v) noexcept : ref(v) {};

ebco& operator=(const ebco&) = default;
ebco& operator=(ebco&&) = default;
ebco& operator=(T&& v) {
ref = std::move(v);
return *this;
}
ebco& operator=(const ebco&) = delete;
ebco& operator=(ebco&&) = delete;

T& value() & {
T& value() & noexcept {
return ref;
}

const T& value() const& {
const T& value() const& noexcept {
return ref;
}

T&& value() && {
T&& value() && noexcept {
return std::move(ref);
}
};
Expand Down
Loading

0 comments on commit d39330e

Please sign in to comment.