Changed Lazy<T> to take a lambda-function in its constructor. This avoids the need for sub-classing.

This commit is contained in:
LoRd_MuldeR 2017-11-04 21:10:32 +01:00
parent e3f5f0a801
commit 3b6051393d
5 changed files with 25 additions and 27 deletions

View File

@ -65,10 +65,9 @@ $(function() {
<div class="header">
<div class="summary">
<a href="#pub-methods">Public Member Functions</a> &#124;
<a href="#pro-methods">Protected Member Functions</a> &#124;
<a href="../../da/d44/class_m_utils_1_1_lazy-members.html">List of all members</a> </div>
<div class="headertitle">
<div class="title">MUtils::Lazy&lt; T &gt; Class Template Reference<span class="mlabels"><span class="mlabel">abstract</span></span></div> </div>
<div class="title">MUtils::Lazy&lt; T &gt; Class Template Reference</div> </div>
</div><!--header-->
<div class="contents">
@ -79,23 +78,20 @@ $(function() {
<table class="memberdecls">
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-methods"></a>
Public Member Functions</h2></td></tr>
<tr class="memitem:a7dc7baa7d7ac31c644965be2ccc4d8cd"><td class="memItemLeft" align="right" valign="top"><a id="a7dc7baa7d7ac31c644965be2ccc4d8cd"></a>
&#160;</td><td class="memItemRight" valign="bottom"><b>Lazy</b> (std::function&lt; T *(void)&gt; &amp;&amp;initializer)</td></tr>
<tr class="separator:a7dc7baa7d7ac31c644965be2ccc4d8cd"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a86cf7d344a38ea09d37d27acd8993f45"><td class="memItemLeft" align="right" valign="top"><a id="a86cf7d344a38ea09d37d27acd8993f45"></a>
T &amp;&#160;</td><td class="memItemRight" valign="bottom"><b>operator*</b> (void)</td></tr>
<tr class="separator:a86cf7d344a38ea09d37d27acd8993f45"><td class="memSeparator" colspan="2">&#160;</td></tr>
</table><table class="memberdecls">
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pro-methods"></a>
Protected Member Functions</h2></td></tr>
<tr class="memitem:a03f52adf0e421b20298f2f7578e3375f"><td class="memItemLeft" align="right" valign="top"><a id="a03f52adf0e421b20298f2f7578e3375f"></a>
virtual T *&#160;</td><td class="memItemRight" valign="bottom"><b>create</b> ()=0</td></tr>
<tr class="separator:a03f52adf0e421b20298f2f7578e3375f"><td class="memSeparator" colspan="2">&#160;</td></tr>
</table>
<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
<div class="textblock"><h3>template&lt;typename T&gt;<br />
class MUtils::Lazy&lt; T &gt;</h3>
<p><a class="el" href="../../d0/dce/class_m_utils_1_1_lazy.html" title="Lazy initialization template class. ">Lazy</a> initialization template class. </p>
<p>In order to create your own "lazy" initializer, inherit from the <code><a class="el" href="../../d0/dce/class_m_utils_1_1_lazy.html" title="Lazy initialization template class. ">Lazy</a>&lt;T&gt;</code> class an implement the <a class="el" href="../../d2/dad/_hash_8h.html#a330b73d6927d6cd95892712f9396f40e" title="Create instance of a hash function. ">create()</a> function. The lazy-initialized value can be obtained from a <code><a class="el" href="../../d0/dce/class_m_utils_1_1_lazy.html" title="Lazy initialization template class. ">Lazy</a>&lt;T&gt;</code> instance by using the <code>operator*()</code>. Initialization of the value happens when the <code>operator*()</code> is called for the very first time, by invoking the concrete <a class="el" href="../../d2/dad/_hash_8h.html#a330b73d6927d6cd95892712f9396f40e" title="Create instance of a hash function. ">create()</a> function. The return value of <a class="el" href="../../d2/dad/_hash_8h.html#a330b73d6927d6cd95892712f9396f40e" title="Create instance of a hash function. ">create()</a> is then stored internally, so that any subsequent call to the <code>operator*()</code> immediately returns the previously created value.</p>
<p><b>Note on thread-saftey:</b> This class is thread-safe in the sense that all calls to <code>operator*()</code> on the same <code><a class="el" href="../../d0/dce/class_m_utils_1_1_lazy.html" title="Lazy initialization template class. ">Lazy</a>&lt;T&gt;</code> instance, regardless from which thread, are guaranteed to return the exactly same value/object. Still, if the value has <em>not</em> been initialized yet <b>and</b> if multiple threads happen to call <code>operator*()</code> at the same time, then the concrete <a class="el" href="../../d2/dad/_hash_8h.html#a330b73d6927d6cd95892712f9396f40e" title="Create instance of a hash function. ">create()</a> function <em>may</em> be invoked more than once (concurrently and by different threads). In that case, all but one return value of <a class="el" href="../../d2/dad/_hash_8h.html#a330b73d6927d6cd95892712f9396f40e" title="Create instance of a hash function. ">create()</a> are discarded, and all threads eventually receive the same value/object. </p>
<p>The lazy-initialized value of type T can be obtained from a <code><a class="el" href="../../d0/dce/class_m_utils_1_1_lazy.html" title="Lazy initialization template class. ">Lazy</a>&lt;T&gt;</code> instance by using the <code>operator*()</code>. Initialization of the value happens when the <code>operator*()</code> is called for the very first time, by invoking the <code>initializer</code> lambda-function that was passed to the constructor. The return value of the <code>initializer</code> lambda-function is then stored internally, so that any subsequent call to the <code>operator*()</code> <em>immediately</em> returns the previously created value.</p>
<p><b>Note on thread-saftey:</b> This class is thread-safe in the sense that all calls to <code>operator*()</code> on the same <code><a class="el" href="../../d0/dce/class_m_utils_1_1_lazy.html" title="Lazy initialization template class. ">Lazy</a>&lt;T&gt;</code> instance, regardless from which thread, are guaranteed to return the exactly same value/object. Still, if the value has <em>not</em> been initialized yet <b>and</b> if multiple threads happen to call <code>operator*()</code> at the same time, then the <code>initializer</code> lambda-function <em>may</em> be invoked more than once (concurrently and by different threads). In that case, all but one return value of the <code>initializer</code> lambda-function are discarded, and all threads eventually obtain the same value/object. </p>
</div><hr/>The documentation for this class was generated from the following file:<ul>
<li>include/MUtils/<a class="el" href="../../d8/d4d/_lazy_8h_source.html">Lazy.h</a></li>
</ul>

View File

@ -75,8 +75,8 @@ $(function() {
<a href="#details">More...</a></p>
<div class="textblock"><code>#include &lt;<a class="el" href="../../d5/d3b/_global_8h_source.html">MUtils/Global.h</a>&gt;</code><br />
<code>#include &lt;MUtils/Exception.h&gt;</code><br />
<code>#include &lt;QScopedPointer&gt;</code><br />
<code>#include &lt;QAtomicPointer&gt;</code><br />
<code>#include &lt;functional&gt;</code><br />
</div>
<p><a href="../../d8/d4d/_lazy_8h_source.html">Go to the source code of this file.</a></p>
<table class="memberdecls">

File diff suppressed because one or more lines are too long

View File

@ -70,7 +70,7 @@ $(function() {
<p>This is the complete list of members for <a class="el" href="../../d0/dce/class_m_utils_1_1_lazy.html">MUtils::Lazy&lt; T &gt;</a>, including all inherited members.</p>
<table class="directory">
<tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>create</b>()=0 (defined in <a class="el" href="../../d0/dce/class_m_utils_1_1_lazy.html">MUtils::Lazy&lt; T &gt;</a>)</td><td class="entry"><a class="el" href="../../d0/dce/class_m_utils_1_1_lazy.html">MUtils::Lazy&lt; T &gt;</a></td><td class="entry"><span class="mlabel">protected</span><span class="mlabel">pure virtual</span></td></tr>
<tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>Lazy</b>(std::function&lt; T *(void)&gt; &amp;&amp;initializer) (defined in <a class="el" href="../../d0/dce/class_m_utils_1_1_lazy.html">MUtils::Lazy&lt; T &gt;</a>)</td><td class="entry"><a class="el" href="../../d0/dce/class_m_utils_1_1_lazy.html">MUtils::Lazy&lt; T &gt;</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
<tr bgcolor="#f0f0f0"><td class="entry"><b>operator*</b>(void) (defined in <a class="el" href="../../d0/dce/class_m_utils_1_1_lazy.html">MUtils::Lazy&lt; T &gt;</a>)</td><td class="entry"><a class="el" href="../../d0/dce/class_m_utils_1_1_lazy.html">MUtils::Lazy&lt; T &gt;</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
</table></div><!-- contents -->
<!-- start footer part -->

View File

@ -31,44 +31,46 @@
#include <MUtils/Exception.h>
//Qt
#include <QScopedPointer>
#include <QAtomicPointer>
//CRT
#include <functional>
namespace MUtils
{
/**
* \brief Lazy initialization template class
*
* In order to create your own "lazy" initializer, inherit from the `Lazy<T>` class an implement the create() function. The lazy-initialized value can be obtained from a `Lazy<T>` instance by using the `operator*()`. Initialization of the value happens when the `operator*()` is called for the very first time, by invoking the concrete create() function. The return value of create() is then stored internally, so that any subsequent call to the `operator*()` immediately returns the previously created value.
* The lazy-initialized value of type T can be obtained from a `Lazy<T>` instance by using the `operator*()`. Initialization of the value happens when the `operator*()` is called for the very first time, by invoking the `initializer` lambda-function that was passed to the constructor. The return value of the `initializer` lambda-function is then stored internally, so that any subsequent call to the `operator*()` *immediately* returns the previously created value.
*
* **Note on thread-saftey:** This class is thread-safe in the sense that all calls to `operator*()` on the same `Lazy<T>` instance, regardless from which thread, are guaranteed to return the exactly same value/object. Still, if the value has *not* been initialized yet **and** if multiple threads happen to call `operator*()` at the same time, then the concrete create() function *may* be invoked more than once (concurrently and by different threads). In that case, all but one return value of create() are discarded, and all threads eventually receive the same value/object.
* **Note on thread-saftey:** This class is thread-safe in the sense that all calls to `operator*()` on the same `Lazy<T>` instance, regardless from which thread, are guaranteed to return the exactly same value/object. Still, if the value has *not* been initialized yet **and** if multiple threads happen to call `operator*()` at the same time, then the `initializer` lambda-function *may* be invoked more than once (concurrently and by different threads). In that case, all but one return value of the `initializer` lambda-function are discarded, and all threads eventually obtain the same value/object.
*/
template<typename T> class Lazy
{
public:
Lazy(std::function<T*(void)> &&initializer) : m_initializer(initializer) { }
T& operator*(void)
{
while (!m_data)
while (!m_value)
{
if (T *const initializer = create())
if (T *const value = m_initializer())
{
if (!m_data.testAndSetOrdered(NULL, initializer))
if (!m_value.testAndSetOrdered(NULL, value))
{
delete initializer;
delete value; /*too late*/
}
}
else
{
MUTILS_THROW("Initializer function returned NULL!");
MUTILS_THROW("Initializer returned NULL!");
}
}
return *m_data;
return *m_value;
}
protected:
virtual T *create() = 0;
private:
QAtomicPointer<T> m_data;
QAtomicPointer<T> m_value;
const std::function<T*(void)> m_initializer;
};
}