From 498ce9d57957fa46956a18a5c19e7cccb5b5a357 Mon Sep 17 00:00:00 2001
From: Nicolas Pope <nwpope@utu.fi>
Date: Sun, 5 Jul 2020 09:45:04 +0300
Subject: [PATCH] Add a transactional class

---
 components/common/cpp/include/ftl/threads.hpp |  2 +
 .../common/cpp/include/ftl/transactional.hpp  | 42 +++++++++++++++++++
 2 files changed, 44 insertions(+)
 create mode 100644 components/common/cpp/include/ftl/transactional.hpp

diff --git a/components/common/cpp/include/ftl/threads.hpp b/components/common/cpp/include/ftl/threads.hpp
index 6dc002359..03536e2ff 100644
--- a/components/common/cpp/include/ftl/threads.hpp
+++ b/components/common/cpp/include/ftl/threads.hpp
@@ -31,6 +31,8 @@
 #define SHARED_LOCK(M,L) std::shared_lock<std::remove_reference<decltype(M)>::type> L(M);
 #endif  // DEBUG_MUTEX
 
+#define SHARED_LOCK_TYPE(M) std::shared_lock<M>
+
 namespace ftl {
 	extern ctpl::thread_pool pool;
 }
diff --git a/components/common/cpp/include/ftl/transactional.hpp b/components/common/cpp/include/ftl/transactional.hpp
new file mode 100644
index 000000000..7c1553ac5
--- /dev/null
+++ b/components/common/cpp/include/ftl/transactional.hpp
@@ -0,0 +1,42 @@
+#ifndef _FTL_TRANSACTIONAL_HPP_
+#define _FTL_TRANSACTIONAL_HPP_
+
+#include <ftl/threads.hpp>
+
+namespace ftl {
+
+/**
+ * Use RAII style transactional objects with shared locking. This wraps an
+ * object with a lock and provides a release notification mechanism to allow
+ * completion code.
+ */
+template <typename T>
+class Transactional {
+	static_assert(std::is_pointer<T>::value, "Transactional type must be a pointer");
+
+	public:
+	Transactional(T obj, SHARED_MUTEX &mtx) : ref_(obj), mtx_(mtx), lock_(mtx_) {}
+	Transactional(T obj, SHARED_MUTEX &mtx, const std::function<void(T)> &complete) : ref_(obj), mtx_(mtx), lock_(mtx_), completed_(complete) {}
+	Transactional(const Transactional &)=delete;
+	Transactional()=delete;
+	~Transactional() {
+		lock_.unlock();
+		if (completed_) completed_(ref_);
+	}
+
+	Transactional &operator=(const Transactional &)=delete;
+
+	T operator->() { return ref_; }
+
+	const T operator->() const { return ref_; }
+
+	private:
+	T ref_;
+	SHARED_MUTEX &mtx_;
+	SHARED_LOCK_TYPE(SHARED_MUTEX) lock_;
+	std::function<void(T)> completed_;
+};
+
+}
+
+#endif
-- 
GitLab