Skip to content

Commit 9d30ea1

Browse files
committed
refactor: lazy object mapping traits
fix #696
1 parent 9daf71f commit 9d30ea1

20 files changed

+1148
-681
lines changed

include/mrdocs/Dom/Object.hpp

+2-72
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
55
//
66
// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com)
7+
// Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com)
78
//
89
// Official repository: https://github.com/cppalliance/mrdocs
910
//
@@ -268,7 +269,7 @@ class MRDOCS_DECL
268269
template <class F>
269270
requires
270271
std::invocable<F, String, Value> &&
271-
detail::isExpected<std::invoke_result_t<F, String, Value>>
272+
mrdocs::detail::isExpected<std::invoke_result_t<F, String, Value>>
272273
Expected<void, typename std::invoke_result_t<F, String, Value>::error_type>
273274
visit(F&& fn) const;
274275

@@ -414,77 +415,6 @@ class MRDOCS_DECL
414415
storage_type entries_;
415416
};
416417

417-
//------------------------------------------------
418-
//
419-
// LazyObjectImpl
420-
//
421-
//------------------------------------------------
422-
423-
/** Abstract lazy object interface.
424-
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`.
437-
438-
The underlying object storage is only
439-
initialized when the first property is
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-
446-
*/
447-
class MRDOCS_DECL
448-
LazyObjectImpl : public ObjectImpl
449-
{
450-
#ifdef __cpp_lib_atomic_shared_ptr
451-
std::atomic<std::shared_ptr<ObjectImpl>> mutable sp_;
452-
#else
453-
std::shared_ptr<ObjectImpl> mutable sp_;
454-
#endif
455-
456-
using impl_type = Object::impl_type;
457-
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-
*/
470-
ObjectImpl& obj() const;
471-
472-
protected:
473-
/** Return the constructed object.
474-
475-
Subclasses override this.
476-
The function is invoked just in time.
477-
*/
478-
virtual Object construct() const = 0;
479-
480-
public:
481-
std::size_t size() const override;
482-
Value get(std::string_view key) const override;
483-
void set(String key, Value value) override;
484-
bool visit(std::function<bool(String, Value)>) const override;
485-
bool exists(std::string_view key) const override;
486-
};
487-
488418
} // dom
489419
} // mrdocs
490420
} // clang

include/mrdocs/Dom/Object.ipp

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ void Object::visit(F&& fn) const
124124
template <class F>
125125
requires
126126
std::invocable<F, String, Value> &&
127-
detail::isExpected<std::invoke_result_t<F, String, Value>>
127+
mrdocs::detail::isExpected<std::invoke_result_t<F, String, Value>>
128128
Expected<void, typename std::invoke_result_t<F, String, Value>::error_type>
129129
Object::visit(F&& fn) const
130130
{

include/mrdocs/Dom/Value.hpp

+69-18
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,36 @@ safeString(dom::Value const& str);
5454

5555
namespace dom {
5656

57+
/** Mapping traits to convert types into dom::Object.
58+
59+
This class should be specialized by any type that needs to be converted
60+
to/from a @ref dom::Object. For example:
61+
62+
@code
63+
template<>
64+
struct MappingTraits<MyStruct> {
65+
template <class IO>
66+
static void map(IO &io, MyStruct const& s)
67+
{
68+
io.map("name", s.name);
69+
io.map("size", s.size);
70+
io.map("age", s.age);
71+
}
72+
};
73+
@endcode
74+
*/
75+
template<class T>
76+
struct ToValue {
77+
// Value operator()(T const& o) const;
78+
};
79+
80+
/// Concept to determine if @ref ToValue is defined for a type T
81+
template <class T>
82+
concept HasToValue = requires(T const& o)
83+
{
84+
{ Value(std::declval<ToValue<T>>()(o)) } -> std::same_as<Value>;
85+
};
86+
5787
/** A variant container for any kind of Dom value.
5888
*/
5989
class MRDOCS_DECL
@@ -90,30 +120,38 @@ class MRDOCS_DECL
90120

91121
template<class F>
92122
requires
93-
function_traits_convertible_to_value<F>
123+
function_traits_convertible_to_value<F> &&
124+
(!HasToValue<F>)
94125
Value(F const& f)
95126
: Value(Function(f))
96127
{}
97128

98-
template<class Boolean>
99-
requires std::is_same_v<Boolean, bool>
129+
template<std::same_as<bool> Boolean>
130+
requires (!HasToValue<Boolean>)
100131
Value(Boolean const& b) noexcept
101132
: kind_(Kind::Boolean)
102133
, b_(b)
103134
{
104135
}
105136

106137
template <std::integral T>
107-
requires (!std::same_as<T, bool> && !std::same_as<T, char>)
138+
requires
139+
(!std::same_as<T, bool>) &&
140+
(!std::same_as<T, char>) &&
141+
(!HasToValue<T>)
108142
Value(T v) noexcept : Value(std::int64_t(v)) {}
109143

110144
template <std::floating_point T>
145+
requires (!HasToValue<T>)
111146
Value(T v) noexcept : Value(std::int64_t(v)) {}
112147

113148
Value(char c) noexcept : Value(std::string_view(&c, 1)) {}
114149

115150
template<class Enum>
116-
requires std::is_enum_v<Enum> && (!std::same_as<Enum, dom::Kind>)
151+
requires
152+
std::is_enum_v<Enum> &&
153+
(!std::same_as<Enum, dom::Kind>) &&
154+
(!HasToValue<Enum>)
117155
Value(Enum v) noexcept
118156
: Value(static_cast<std::underlying_type_t<Enum>>(v))
119157
{}
@@ -131,6 +169,7 @@ class MRDOCS_DECL
131169
}
132170

133171
template <std::convertible_to<String> StringLike>
172+
requires (!HasToValue<StringLike>)
134173
Value(StringLike const& s)
135174
: Value(String(s))
136175
{
@@ -155,6 +194,12 @@ class MRDOCS_DECL
155194
{
156195
}
157196

197+
template <HasToValue T>
198+
Value(T const& t)
199+
: Value(ToValue<T>{}(t))
200+
{
201+
}
202+
158203
Value& operator=(Value const& other);
159204
Value& operator=(Value&& other) noexcept;
160205

@@ -425,29 +470,35 @@ class MRDOCS_DECL
425470
Value const& lhs,
426471
Value const& rhs) noexcept;
427472

473+
/** Compare two values for inequality.
474+
*/
475+
friend
476+
std::strong_ordering
477+
operator<=>(
478+
Value const& lhs,
479+
Value const& rhs) noexcept;
480+
428481
/// @overload
429482
template <std::convertible_to<Value> S>
430-
friend auto operator==(
431-
S const& lhs, Value const& rhs) noexcept
483+
friend
484+
auto
485+
operator<=>(
486+
S const& lhs,
487+
Value const& rhs) noexcept
432488
{
433-
return Value(lhs) == rhs;
489+
return Value(lhs) <=> rhs;
434490
}
435491

436492
/// @overload
437493
template <std::convertible_to<Value> S>
438-
friend auto operator==(
439-
Value const& lhs, S const& rhs) noexcept
440-
{
441-
return lhs == Value(rhs);
442-
}
443-
444-
/** Compare two values for inequality.
445-
*/
446494
friend
447-
std::strong_ordering
495+
auto
448496
operator<=>(
449497
Value const& lhs,
450-
Value const& rhs) noexcept;
498+
S const& rhs) noexcept
499+
{
500+
return lhs <=> Value(rhs);
501+
}
451502

452503
/** Add or concatenate two values.
453504
*/

include/mrdocs/Metadata/DomMetadata.hpp renamed to include/mrdocs/Metadata/DomCorpus.hpp

+12-6
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
//
66
// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com)
77
// Copyright (c) 2023 Krystian Stasiowski (sdkrystian@gmail.com)
8+
// Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com)
89
//
910
// Official repository: https://github.com/cppalliance/mrdocs
1011
//
1112

12-
#ifndef MRDOCS_API_DOM_DOMMETADATA_HPP
13-
#define MRDOCS_API_DOM_DOMMETADATA_HPP
13+
#ifndef MRDOCS_API_DOM_DOMCORPUS_HPP
14+
#define MRDOCS_API_DOM_DOMCORPUS_HPP
1415

1516
#include <mrdocs/Platform.hpp>
1617
#include <mrdocs/Corpus.hpp>
@@ -24,9 +25,14 @@ namespace mrdocs {
2425

2526
/** Front-end factory for producing Dom nodes.
2627
27-
A @ref Generator subclasses this object and
28-
then uses it to create the Dom nodes used for
29-
rendering in template engines.
28+
This class keeps a reference to the @ref Corpus
29+
of extracted metadata, and provides a mechanism
30+
for constructing DOM nodes representing the metadata.
31+
32+
A @ref Generator subclasses this object
33+
(e.g. @ref AdocCorpus and @ref HTMLCorpus),
34+
then uses it to create the Dom nodes used
35+
as input for rendering template engines.
3036
*/
3137
class MRDOCS_DECL
3238
DomCorpus
@@ -62,7 +68,7 @@ class MRDOCS_DECL
6268
*/
6369
Corpus const* operator->() const;
6470

65-
/** Construct a Dom object representing the given symbol.
71+
/** Construct a lazy Dom object representing the specified symbol.
6672
6773
This function is called internally when a `dom::Object`
6874
representing a symbol needs to be constructed because

include/mrdocs/Metadata/Symbols.hpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ namespace mrdocs {
3131
*/
3232
class SymbolID
3333
{
34+
std::uint8_t data_[20]{};
35+
3436
public:
3537
static const SymbolID invalid;
3638
static const SymbolID global;
@@ -120,9 +122,6 @@ class SymbolID
120122
*/
121123
bool operator==(
122124
const SymbolID& other) const noexcept = default;
123-
124-
private:
125-
value_type data_[20]{};
126125
};
127126

128127
/** The invalid Symbol ID.

include/mrdocs/mrdocs.natvis

-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@
109109

110110
<Type Name="clang::mrdocs::dom::Object">
111111
<Intrinsic Name="as_default" Expression="dynamic_cast&lt;DefaultObjectImpl*&gt;(impl_._Ptr)"/>
112-
<Intrinsic Name="as_lazy" Expression="dynamic_cast&lt;LazyObjectImpl*&gt;(impl_._Ptr)"/>
113112
<Intrinsic Name="as_overlay" Expression="dynamic_cast&lt;OverlayObjectImpl*&gt;(impl_._Ptr)"/>
114113
<Intrinsic Name="as_hbs_helper" Expression="dynamic_cast&lt;HbsHelperObjectImpl*&gt;(impl_._Ptr)"/>
115114
<DisplayString>[ dom::Object ]</DisplayString>

0 commit comments

Comments
 (0)