1#pragma once
2
3#include <mutex>
4#include <memory>
5
6
7/** Allow to store and read-only usage of an object in several threads,
8 * and to atomically replace an object in another thread.
9 * The replacement is atomic and reading threads can work with different versions of an object.
10 *
11 * Usage:
12 * MultiVersion<T> x;
13 * - on data update:
14 * x.set(new value);
15 * - on read-only usage:
16 * {
17 * MultiVersion<T>::Version current_version = x.get();
18 * // use *current_version
19 * } // now we finish own current version; if the version is outdated and no one else is using it - it will be destroyed.
20 *
21 * All methods are thread-safe.
22 */
23template <typename T>
24class MultiVersion
25{
26public:
27 /// Version of object for usage. shared_ptr manage lifetime of version.
28 using Version = std::shared_ptr<const T>;
29
30 /// Default initialization - by nullptr.
31 MultiVersion() = default;
32
33 MultiVersion(std::unique_ptr<const T> && value)
34 {
35 set(std::move(value));
36 }
37
38 /// Obtain current version for read-only usage. Returns shared_ptr, that manages lifetime of version.
39 Version get() const
40 {
41 /// NOTE: is it possible to lock-free replace of shared_ptr?
42 std::lock_guard lock(mutex);
43 return current_version;
44 }
45
46 /// Update an object with new version.
47 void set(std::unique_ptr<const T> && value)
48 {
49 std::lock_guard lock(mutex);
50 current_version = std::move(value);
51 }
52
53private:
54 Version current_version;
55 mutable std::mutex mutex;
56};
57