|
|
@@ -0,0 +1,180 @@ |
|
|
#ifndef BORROW_CHECKER_HPP_INCLUDED |
|
|
#define BORROW_CHECKER_HPP_INCLUDED |
|
|
|
|
|
#include <initializer_list> |
|
|
#include <new> |
|
|
#include <type_traits> |
|
|
|
|
|
namespace detail |
|
|
{ |
|
|
template <typename T> |
|
|
class ref |
|
|
{ |
|
|
public: |
|
|
explicit ref(T& obj) |
|
|
: ptr_(&obj) {} |
|
|
|
|
|
T& operator*() const noexcept |
|
|
{ |
|
|
return *ptr_; |
|
|
} |
|
|
|
|
|
T* operator->() const noexcept |
|
|
{ |
|
|
return ptr_; |
|
|
} |
|
|
|
|
|
private: |
|
|
T* ptr_; |
|
|
}; |
|
|
|
|
|
template <typename Object, typename Expression> |
|
|
struct borrow_lambda_invoker |
|
|
{ |
|
|
Object& object; |
|
|
Expression& expression; |
|
|
|
|
|
template <typename Lambda> |
|
|
auto call_lambda(int, const Lambda& l) |
|
|
-> decltype(l(object, ref<Expression>(expression))) |
|
|
{ |
|
|
return l(object, ref<Expression>(expression)); |
|
|
} |
|
|
|
|
|
template <typename Lambda> |
|
|
auto call_lambda(short, const Lambda& l) |
|
|
-> decltype(l({}, ref<Expression>(expression))) |
|
|
{ |
|
|
return l({}, ref<Expression>(expression)); |
|
|
} |
|
|
|
|
|
template <typename Lambda> |
|
|
void operator=(const Lambda& l) |
|
|
{ |
|
|
call_lambda(0, l); |
|
|
} |
|
|
}; |
|
|
|
|
|
struct error_variable_borrowed_as_mutable |
|
|
{ |
|
|
error_variable_borrowed_as_mutable(const error_variable_borrowed_as_mutable&) = delete; |
|
|
}; |
|
|
|
|
|
template <typename T> |
|
|
struct destructive_move_holder |
|
|
{ |
|
|
std::aligned_storage_t<sizeof(T), alignof(T)> storage; |
|
|
bool should_destroy; |
|
|
|
|
|
template <typename ... Args> |
|
|
destructive_move_holder(Args&&... args) |
|
|
: should_destroy(true) |
|
|
{ |
|
|
::new(&storage) T(std::forward<Args>(args)...); |
|
|
} |
|
|
|
|
|
template <typename U> |
|
|
destructive_move_holder(std::initializer_list<U> list) |
|
|
: should_destroy(true) |
|
|
{ |
|
|
::new(&storage) T(std::move(list)); |
|
|
} |
|
|
|
|
|
destructive_move_holder(const destructive_move_holder&) = delete; |
|
|
destructive_move_holder& operator=(const destructive_move_holder&) = delete; |
|
|
|
|
|
~destructive_move_holder() |
|
|
{ |
|
|
if (should_destroy) |
|
|
get().~T(); |
|
|
} |
|
|
|
|
|
T& get() |
|
|
{ |
|
|
void* mem = &storage; |
|
|
return *static_cast<T*>(mem); |
|
|
} |
|
|
|
|
|
T&& move() |
|
|
{ |
|
|
should_destroy = false; |
|
|
return std::move(get()); |
|
|
} |
|
|
}; |
|
|
|
|
|
template <typename T> |
|
|
struct destructive_move_lambda_invoker |
|
|
{ |
|
|
destructive_move_holder<T> holder; |
|
|
|
|
|
template <typename ... Args> |
|
|
destructive_move_lambda_invoker(Args&&... args) |
|
|
: holder(std::forward<Args>(args)...) {} |
|
|
|
|
|
template <typename U> |
|
|
destructive_move_lambda_invoker(std::initializer_list<U> list) |
|
|
: holder(std::move(list)) {} |
|
|
|
|
|
template <typename Lambda> |
|
|
void operator=(const Lambda& lambda) |
|
|
{ |
|
|
lambda(holder, holder.get()); |
|
|
} |
|
|
}; |
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
using ref = detail::ref<const T>; |
|
|
|
|
|
template <typename T> |
|
|
using mut_ref = detail::ref<T>; |
|
|
|
|
|
template <typename T> |
|
|
ref<T> borrow(const T& obj) |
|
|
{ |
|
|
return ref<T>(obj); |
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
mut_ref<T> mut_borrow(T& obj) |
|
|
{ |
|
|
return mut_ref<T>(obj); |
|
|
} |
|
|
|
|
|
#define _borrow_lambda_invoker(Obj, ...) \ |
|
|
detail::borrow_lambda_invoker<std::remove_reference_t<decltype(Obj)>, \ |
|
|
const std::remove_reference_t<decltype(__VA_ARGS__)>>{Obj, __VA_ARGS__} |
|
|
|
|
|
|
|
|
#define _mut_borrow_lambda_invoker(Obj, ...) \ |
|
|
detail::borrow_lambda_invoker<std::remove_reference_t<decltype(Obj)>, \ |
|
|
std::remove_reference_t<decltype(__VA_ARGS__)>>{Obj, __VA_ARGS__} |
|
|
|
|
|
#define _borrow_lambda(Name, Obj) \ |
|
|
[&]([[gnu::unused]] const auto& Obj, const auto& Name) |
|
|
|
|
|
#define _mut_borrow_lambda(Name, Obj) \ |
|
|
[&]([[gnu::unused]] const detail::error_variable_borrowed_as_mutable& Obj, const auto& Name) |
|
|
|
|
|
#define _borrow(Name, Obj, ...) \ |
|
|
_borrow_lambda_invoker(Obj, __VA_ARGS__) = _borrow_lambda(Name, Obj) |
|
|
|
|
|
#define _mut_borrow(Name, Obj, ...) \ |
|
|
_mut_borrow_lambda_invoker(Obj, __VA_ARGS__) = _mut_borrow_lambda(Name, Obj) |
|
|
|
|
|
#define borrow_var(Name, Obj) _borrow(Name, Obj, Obj) |
|
|
#define borrow_expr(Name, Obj, ...) _borrow(Name, Obj, __VA_ARGS__) |
|
|
#define borrow_elem(Name, Obj, I) _borrow(Name, Obj, Obj[I]) |
|
|
|
|
|
#define mut_borrow_var(Name, Obj) _mut_borrow(Name, Obj, Obj) |
|
|
#define mut_borrow_expr(Name, Obj, ...) _mut_borrow(Name, Obj, __VA_ARGS__) |
|
|
#define mut_borrow_elem(Name, Obj, I) _mut_borrow(Name, Obj, Obj[I]) |
|
|
|
|
|
#define destructive_moveable(Type, Name, ...) \ |
|
|
detail::destructive_move_lambda_invoker<Type>{__VA_ARGS__} \ |
|
|
= [&]([[gnu::unused]] auto& _holder_##Name, auto& Name) |
|
|
|
|
|
#define destructive_move(Name) \ |
|
|
_holder_##Name.move() |
|
|
|
|
|
#endif // BORROW_CHECKER_HPP_INCLUDED |