#pragma once

#include <mutex>

namespace utilities::concurrency
{
	template <typename T, typename MutexType = std::mutex>
	class container
	{
	public:
		template <typename R = void, typename F>
		R access(F&& accessor) const
		{
			std::lock_guard<MutexType> _{mutex_};
			return accessor(object_);
		}

		template <typename R = void, typename F>
		R access(F&& accessor)
		{
			std::lock_guard<MutexType> _{mutex_};
			return accessor(object_);
		}

		template <typename R = void, typename F>
		R access_with_lock(F&& accessor) const
		{
			std::unique_lock<MutexType> lock{mutex_};
			return accessor(object_, lock);
		}

		template <typename R = void, typename F>
		R access_with_lock(F&& accessor)
		{
			std::unique_lock<MutexType> lock{mutex_};
			return accessor(object_, lock);
		}

		T& get_raw() { return object_; }
		const T& get_raw() const { return object_; }

	private:
		mutable MutexType mutex_{};
		T object_{};
	};
}