Skip to content

Commit da81e09

Browse files
committed
fix: lazy object construct when atomic shared pointers are unsupported
1 parent a962db0 commit da81e09

File tree

2 files changed

+50
-9
lines changed

2 files changed

+50
-9
lines changed

include/mrdocs/Dom/Object.hpp

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -420,14 +420,29 @@ class MRDOCS_DECL
420420
//
421421
//------------------------------------------------
422422

423-
/** A lazy Object implementation.
423+
/** Abstract lazy object interface.
424424
425-
This implementation is used to construct an
426-
Object on demand.
425+
This interface is used to define objects
426+
that are constructed on demand.
427+
428+
The subclass must override the `construct`
429+
function to return the constructed object.
430+
It will typically also store whatever
431+
data is necessary to construct this object.
432+
433+
When any of the object properties are accessed
434+
for the first time, the object is constructed.
435+
This can happen via any of the public functions,
436+
such as `get`, `set`, `size`, `exists`, or `visit`.
427437
428438
The underlying object storage is only
429439
initialized when the first property is
430-
set or accessed.
440+
set or accessed. In practice, it means
441+
the object is never initialized if it's
442+
not used in a template.
443+
444+
When the object is initialized, the
445+
431446
*/
432447
class MRDOCS_DECL
433448
LazyObjectImpl : public ObjectImpl
@@ -440,6 +455,18 @@ class MRDOCS_DECL
440455

441456
using impl_type = Object::impl_type;
442457

458+
/* Return the constructed object.
459+
460+
This function is invoked by all public
461+
functions that access the object properties.
462+
463+
When invoked for the first time, the object
464+
is constructed and stored in the shared
465+
pointer.
466+
467+
Further invocations return a reference
468+
to the existing value in the shared pointer.
469+
*/
443470
ObjectImpl& obj() const;
444471

445472
protected:

src/lib/Dom/Object.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,15 +218,29 @@ LazyObjectImpl::
218218
obj() const
219219
{
220220
#ifdef __cpp_lib_atomic_shared_ptr
221-
auto impl = sp_.load();
222-
if(impl)
221+
std::shared_ptr<ObjectImpl> impl = sp_.load();
222+
if (impl)
223+
{
224+
// Already initialized
223225
return *impl;
224-
impl_type expected = nullptr;
225-
if(sp_.compare_exchange_strong(
226-
expected, construct().impl()))
226+
}
227+
228+
// Fetch the shared pointer from the factory
229+
std::shared_ptr<ObjectImpl> expected = nullptr;
230+
std::shared_ptr<ObjectImpl> desired = construct().impl();
231+
MRDOCS_ASSERT(desired);
232+
if (sp_.compare_exchange_strong(expected, std::move(desired)))
233+
{
227234
return *sp_.load();
235+
}
228236
return *expected;
229237
#else
238+
if (sp_)
239+
{
240+
return *sp_;
241+
}
242+
sp_ = construct().impl();
243+
MRDOCS_ASSERT(sp_);
230244
return *sp_;
231245
#endif
232246
}

0 commit comments

Comments
 (0)