1 /*!
2  * \file
3  * \brief outliving_reference_t and related stuff.
4  *
5  * \note
6  * This code is borrowed from cpp_util_3 project
7  * (https://bitbucket.org/sobjectizerteam/cpp_util-3.0)
8  *
9  * \since
10  * v.5.5.19
11  */
12 
13 #pragma once
14 
15 #include <so_5/compiler_features.hpp>
16 
17 #include <memory>
18 
19 namespace so_5 {
20 
21 /*!
22  * \brief Helper class for indication of long-lived reference via its type.
23  *
24  * Sometimes it is necessary to store a reference to an object that lives
25  * longer that a reference holder. For example:
26  * \code
27 	class config {...};
28 	class config_consumer {
29 		config & cfg_;
30 	public :
31 		config_consumer(config & cfg) : cfg_(cfg) {...}
32 		...
33 	};
34 
35 	void f() {
36 		config cfg = load_config(); // cfg outlives all other objects in f().
37 		config_consumer consumer(cfg); // It is safe to store a reference
38 			// for all lifetime of consumer object.
39 		...
40 	}
41  * \endcode
42  *
43  * The problem there is: when we see <tt>consumer::consumer(cfg)</tt> we can
44  * say is it safe to pass a reference to short-lived object to it or not.
45  * Helper class outliving_reference_t can be used as indicator that
46  * <tt>consumer::consumer</tt> expects a reference to long-lived object:
47  * \code
48 	class config_consumer {
49 		so_5::outliving_reference_t<config> cfg_;
50 	public :
51 		config_consumer(so_5::outliving_reference_t<config> cfg)
52 			: cfg_(cfg)
53 		{...}
54 		...
55 	};
56 
57 	void f() {
58 		config cfg = load_config();
59 		// An explicit sign that cfg will outlive consumer object.
60 		config_consumer consumer(so_5::outliving_mutable(cfg));
61 		...
62 	}
63  * \endcode
64  *
65  * If it is necessary to store a const reference to long-lived object
66  * then outliving_reference_t<const T> and outliving_const() should be used:
67  * \code
68 	class data_processor {
69 		so_5::outliving_reference_t<const config> cfg_;
70 	public :
71 		data_processor(so_5::outliving_reference_t<const config> cfg)
72 			: cfg_(cfg)
73 		{...}
74 		...
75 	};
76 
77 	void f() {
78 		config cfg = load_config();
79 		config_consumer consumer(so_5::outliving_mutable(cfg));
80 		data_processor processor(so_5::outliving_const(cfg));
81 		...
82 	}
83  * \endcode
84  *
85  * \attention
86  * outliving_reference_t has no copy operator! It is CopyConstructible,
87  * but not CopyAssingable class.
88  *
89  * \tparam T type for reference.
90  *
91  * \since
92  * v.5.5.19
93  */
94 template< typename T >
95 class outliving_reference_t
96 {
97 	T * m_ptr;
98 
99 public :
100 	using type = T;
101 
outliving_reference_t(T & r)102 	explicit outliving_reference_t(T & r) noexcept : m_ptr(std::addressof(r)) {}
103 
104 	outliving_reference_t(T &&) = delete;
outliving_reference_t(outliving_reference_t const & o)105 	outliving_reference_t(outliving_reference_t const & o) noexcept
106 		: m_ptr(std::addressof(o.get()))
107 		{}
108 
109 	template<typename U>
outliving_reference_t(outliving_reference_t<U> const & o)110 	outliving_reference_t(outliving_reference_t<U> const & o) noexcept
111 		: m_ptr(std::addressof(o.get()))
112 		{}
113 
114 	outliving_reference_t & operator=(outliving_reference_t const &o) = delete;
115 
operator T&() const116 	operator T&() const noexcept { return this->get(); }
117 
get() const118 	T & get() const noexcept { return *m_ptr; }
119 };
120 
121 /*!
122  * \brief Make outliving_reference wrapper for mutable reference.
123  *
124  * \sa outliving_reference_t
125  *
126  * \since
127  * v.5.5.19
128  */
129 template< typename T >
130 outliving_reference_t< T >
outliving_mutable(T & r)131 outliving_mutable( T & r ) { return outliving_reference_t<T>(r); }
132 
133 /*!
134  * \brief Make outliving_reference wrapper for const reference.
135  *
136  * \sa outliving_reference_t
137  *
138  * \since
139  * v.5.5.19
140  */
141 template< typename T >
142 outliving_reference_t< const T >
outliving_const(T const & r)143 outliving_const( T const & r ) { return outliving_reference_t<const T>(r); }
144 
145 /*!
146  * \brief Make outliving_reference wrapper for const reference.
147  *
148  * \sa outliving_reference_t
149  *
150  * \since
151  * v.5.5.22
152  */
153 template< typename T >
154 outliving_reference_t< const T >
outliving_const(outliving_reference_t<T> r)155 outliving_const( outliving_reference_t<T> r ) { return outliving_reference_t<const T>(r.get()); }
156 
157 } /* namespace so_5 */
158 
159