From efe0620914f1d1d943e3ba65052230fd6db56ebf Mon Sep 17 00:00:00 2001 From: alandefreitas Date: Thu, 10 Oct 2024 16:15:29 -0300 Subject: [PATCH] fix: lazy object construct when atomic shared pointers are unsupported --- include/mrdocs/Dom/Object.hpp | 35 +++++++++++++++++++++++++++++++---- src/lib/Dom/Object.cpp | 24 +++++++++++++++++++----- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/include/mrdocs/Dom/Object.hpp b/include/mrdocs/Dom/Object.hpp index 3e4713664..1c9081ec9 100644 --- a/include/mrdocs/Dom/Object.hpp +++ b/include/mrdocs/Dom/Object.hpp @@ -420,14 +420,29 @@ class MRDOCS_DECL // //------------------------------------------------ -/** A lazy Object implementation. +/** Abstract lazy object interface. - This implementation is used to construct an - Object on demand. + This interface is used to define objects + that are constructed on demand. + + The subclass must override the `construct` + function to return the constructed object. + It will typically also store whatever + data is necessary to construct this object. + + When any of the object properties are accessed + for the first time, the object is constructed. + This can happen via any of the public functions, + such as `get`, `set`, `size`, `exists`, or `visit`. The underlying object storage is only initialized when the first property is - set or accessed. + set or accessed. In practice, it means + the object is never initialized if it's + not used in a template. + + When the object is initialized, the + */ class MRDOCS_DECL LazyObjectImpl : public ObjectImpl @@ -440,6 +455,18 @@ class MRDOCS_DECL using impl_type = Object::impl_type; + /* Return the constructed object. + + This function is invoked by all public + functions that access the object properties. + + When invoked for the first time, the object + is constructed and stored in the shared + pointer. + + Further invocations return a reference + to the existing value in the shared pointer. + */ ObjectImpl& obj() const; protected: diff --git a/src/lib/Dom/Object.cpp b/src/lib/Dom/Object.cpp index c34c0d19d..1c39cadbd 100644 --- a/src/lib/Dom/Object.cpp +++ b/src/lib/Dom/Object.cpp @@ -218,15 +218,29 @@ LazyObjectImpl:: obj() const { #ifdef __cpp_lib_atomic_shared_ptr - auto impl = sp_.load(); - if(impl) + std::shared_ptr impl = sp_.load(); + if (impl) + { + // Already initialized return *impl; - impl_type expected = nullptr; - if(sp_.compare_exchange_strong( - expected, construct().impl())) + } + + // Fetch the shared pointer from the factory + std::shared_ptr expected = nullptr; + std::shared_ptr desired = construct().impl(); + MRDOCS_ASSERT(desired); + if (sp_.compare_exchange_strong(expected, std::move(desired))) + { return *sp_.load(); + } return *expected; #else + if (sp_) + { + return *sp_; + } + sp_ = construct().impl(); + MRDOCS_ASSERT(sp_); return *sp_; #endif }