Skip to content

Commit

Permalink
fix: lazy object construct when atomic shared pointers are unsupported
Browse files Browse the repository at this point in the history
  • Loading branch information
alandefreitas committed Oct 10, 2024
1 parent a962db0 commit efe0620
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 9 deletions.
35 changes: 31 additions & 4 deletions include/mrdocs/Dom/Object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down
24 changes: 19 additions & 5 deletions src/lib/Dom/Object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,15 +218,29 @@ LazyObjectImpl::
obj() const
{
#ifdef __cpp_lib_atomic_shared_ptr
auto impl = sp_.load();
if(impl)
std::shared_ptr<ObjectImpl> 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<ObjectImpl> expected = nullptr;
std::shared_ptr<ObjectImpl> 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
}
Expand Down

0 comments on commit efe0620

Please sign in to comment.