#pragma once
#include <type_traits>

namespace utils
{
	/*
	 * Copied from here: https://github.com/microsoft/GSL/blob/e0880931ae5885eb988d1a8a57acf8bc2b8dacda/include/gsl/util#L57
	 */

	template <class F>
	class final_action
	{
	public:
		static_assert(!std::is_reference<F>::value && !std::is_const<F>::value &&
			!std::is_volatile<F>::value,
			"Final_action should store its callable by value");

		explicit final_action(F f) noexcept : f_(std::move(f))
		{
		}

		final_action(final_action&& other) noexcept
			: f_(std::move(other.f_)), invoke_(std::exchange(other.invoke_, false))
		{
		}

		final_action(const final_action&) = delete;
		final_action& operator=(const final_action&) = delete;
		final_action& operator=(final_action&&) = delete;

		~final_action() noexcept
		{
			if (invoke_) f_();
		}

		// Added by momo5502
		void cancel()
		{
			invoke_ = false;
		}

	private:
		F f_;
		bool invoke_{true};
	};

	template <class F>
	final_action<typename std::remove_cv<typename std::remove_reference<F>::type>::type>
	finally(F&& f) noexcept
	{
		return final_action<typename std::remove_cv<typename std::remove_reference<F>::type>::type>(
			std::forward<F>(f));
	}
}