#ifndef BORROW_CHECKER_HPP_INCLUDED #define BORROW_CHECKER_HPP_INCLUDED #include #include #include namespace detail { template 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 struct borrow_lambda_invoker { Object& object; Expression& expression; template auto call_lambda(int, const Lambda& l) -> decltype(l(object, ref(expression))) { return l(object, ref(expression)); } template auto call_lambda(short, const Lambda& l) -> decltype(l({}, ref(expression))) { return l({}, ref(expression)); } template 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 struct destructive_move_holder { std::aligned_storage_t storage; bool should_destroy; template destructive_move_holder(Args&&... args) : should_destroy(true) { ::new(&storage) T(std::forward(args)...); } template destructive_move_holder(std::initializer_list 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(mem); } T&& move() { should_destroy = false; return std::move(get()); } }; template struct destructive_move_lambda_invoker { destructive_move_holder holder; template destructive_move_lambda_invoker(Args&&... args) : holder(std::forward(args)...) {} template destructive_move_lambda_invoker(std::initializer_list list) : holder(std::move(list)) {} template void operator=(const Lambda& lambda) { lambda(holder, holder.get()); } }; } template using ref = detail::ref; template using mut_ref = detail::ref; template ref borrow(const T& obj) { return ref(obj); } template mut_ref mut_borrow(T& obj) { return mut_ref(obj); } #define _borrow_lambda_invoker(Obj, ...) \ detail::borrow_lambda_invoker, \ const std::remove_reference_t>{Obj, __VA_ARGS__} #define _mut_borrow_lambda_invoker(Obj, ...) \ detail::borrow_lambda_invoker, \ std::remove_reference_t>{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{__VA_ARGS__} \ = [&]([[gnu::unused]] auto& _holder_##Name, auto& Name) #define destructive_move(Name) \ _holder_##Name.move() #endif // BORROW_CHECKER_HPP_INCLUDED