Skip to content

Commit aa5f95a

Browse files
committed
refactor: unify dom lazy array classes
The DomCorpus uses multiple classes that represented lazy arrays. This commit simplifies the dom by unifying all of these array implementations.
1 parent 3f24987 commit aa5f95a

File tree

8 files changed

+450
-390
lines changed

8 files changed

+450
-390
lines changed

include/mrdocs/Metadata/DomCorpus.hpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,17 @@ class MRDOCS_DECL
6262

6363
/** Returns the Corpus associated with the Dom.
6464
*/
65-
Corpus const& operator*() const;
65+
Corpus const& operator*() const
66+
{
67+
return getCorpus();
68+
}
6669

6770
/** Returns the Corpus associated with the Dom.
6871
*/
69-
Corpus const* operator->() const;
72+
Corpus const* operator->() const
73+
{
74+
return &getCorpus();
75+
}
7076

7177
/** Construct a lazy Dom object representing the specified symbol.
7278

include/mrdocs/Metadata/Scope.hpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,29 @@ namespace mrdocs {
2929
class are the symbols and functions declared
3030
in the class.
3131
32+
The Lookups are the symbols that are accessible
33+
from the scope of the Info. For instance, the
34+
Lookups["foo"] of a namespace are the symbols
35+
declared as "foo" in the namespace.
36+
37+
This Info class can be used as a base class
38+
for other Info classes, such as NamespaceInfo,
39+
ClassInfo, that represent scopes. This class
40+
can also be used with composition, such as in
41+
@ref Interface to represent different scopes of
42+
the same class (such as member and static overloads).
43+
3244
*/
3345
struct ScopeInfo
3446
{
35-
/** The members of this scope.
36-
*/
37-
std::vector<SymbolID> Members;
38-
39-
/** The lookup table for this scope.
40-
*/
41-
std::unordered_map<std::string,
47+
/** The members of this scope.
48+
*/
49+
std::vector<SymbolID> Members;
50+
51+
/** The lookup table for this scope.
52+
*/
53+
std::unordered_map<
54+
std::string,
4255
std::vector<SymbolID>> Lookups;
4356
};
4457

include/mrdocs/Metadata/Source.hpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ MRDOCS_DECL
3636
std::string_view
3737
toString(FileKind kind);
3838

39+
namespace dom {
40+
template <>
41+
struct ToValue<FileKind>
42+
{
43+
std::string_view
44+
operator()(FileKind id) const;
45+
};
46+
}
47+
3948
struct MRDOCS_DECL
4049
Location
4150
{
@@ -76,6 +85,15 @@ struct MRDOCS_DECL
7685
}
7786
};
7887

88+
namespace dom {
89+
template <>
90+
struct ToValue<Location>
91+
{
92+
dom::Object
93+
operator()(Location const& loc) const;
94+
};
95+
}
96+
7997
struct LocationEmptyPredicate
8098
{
8199
constexpr bool operator()(
@@ -113,6 +131,15 @@ struct MRDOCS_DECL
113131
SourceInfo() = default;
114132
};
115133

134+
namespace dom {
135+
template <>
136+
struct ToValue<SourceInfo>
137+
{
138+
dom::Object
139+
operator()(SourceInfo const& info) const;
140+
};
141+
}
142+
116143
} // mrdocs
117144
} // clang
118145

src/lib/Dom/LazyArray.hpp

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
//
2+
// Licensed under the Apache License v2.0 with LLVM Exceptions.
3+
// See https://llvm.org/LICENSE.txt for license information.
4+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
//
6+
// Copyright (c) 2024 Alan de Freitas ([email protected])
7+
//
8+
// Official repository: https://github.com/cppalliance/mrdocs
9+
//
10+
11+
#ifndef MRDOCS_LIB_DOM_LAZY_ARRAY_HPP
12+
#define MRDOCS_LIB_DOM_LAZY_ARRAY_HPP
13+
14+
#include "mrdocs/Dom.hpp"
15+
#include "mrdocs/Platform.hpp"
16+
#include "mrdocs/Support/Error.hpp"
17+
#include <string_view>
18+
#include <ranges>
19+
20+
namespace clang {
21+
namespace mrdocs {
22+
namespace dom {
23+
24+
namespace detail {
25+
struct noop {
26+
template <class T>
27+
auto operator()(T&& t) const
28+
{
29+
return t;
30+
}
31+
};
32+
33+
struct no_size_tag {};
34+
}
35+
36+
/** Lazy array implementation
37+
38+
This array type is used to define a dom::Array
39+
whose members are evaluated on demand
40+
as they are accessed.
41+
42+
Each member can goes through a transform
43+
function before being returned as a Value so
44+
that all types can be converted to dom::Value.
45+
46+
The underlying representation of the array is
47+
a range from where the elements are extracted.
48+
Elements in this range should be convertible
49+
to dom::Value.
50+
51+
This class is typically useful for
52+
implementing arrays that are expensive
53+
and have recursive dependencies, as these
54+
recursive dependencies can also be deferred.
55+
56+
Unlike a LazyObjectImpl, which contains an
57+
overlay object, this implementation is
58+
read-only. The `set` and `emplace_back`
59+
methods are not implemented.
60+
61+
*/
62+
template <std::ranges::random_access_range R, class F = detail::noop>
63+
requires
64+
std::invocable<F, std::ranges::range_value_t<R>> &&
65+
std::constructible_from<Value, std::invoke_result_t<F, std::ranges::range_value_t<R>>>
66+
class LazyArrayImpl : public ArrayImpl
67+
{
68+
using const_iterator_t = decltype(std::ranges::cbegin(std::declval<R&>()));
69+
using const_sentinel_t = decltype(std::ranges::cend(std::declval<R&>()));
70+
using size_type = std::conditional_t<
71+
std::ranges::sized_range<R>,
72+
std::ranges::range_size_t<R>,
73+
detail::no_size_tag>;
74+
75+
const_iterator_t begin_;
76+
const_sentinel_t end_;
77+
[[no_unique_address]] size_type size_;
78+
[[no_unique_address]] F transform_;
79+
80+
public:
81+
explicit
82+
LazyArrayImpl(R const& arr)
83+
: begin_(std::ranges::begin(arr))
84+
, end_(std::ranges::end(arr))
85+
{
86+
if constexpr (std::ranges::sized_range<R>)
87+
{
88+
size_ = std::ranges::size(arr);
89+
}
90+
}
91+
92+
explicit
93+
LazyArrayImpl(R const& arr, F transform)
94+
: begin_(std::ranges::begin(arr))
95+
, end_(std::ranges::end(arr))
96+
, transform_(std::move(transform))
97+
{
98+
if constexpr (std::ranges::sized_range<R>)
99+
{
100+
size_ = std::ranges::size(arr);
101+
}
102+
}
103+
104+
~LazyArrayImpl() override = default;
105+
106+
/// @copydoc ObjectImpl::type_key
107+
char const*
108+
type_key() const noexcept override
109+
{
110+
return "LazyArray";
111+
}
112+
113+
std::size_t size() const noexcept override
114+
{
115+
if constexpr (std::ranges::sized_range<R>)
116+
{
117+
return size_;
118+
}
119+
else
120+
{
121+
return std::ranges::distance(begin_, end_);
122+
}
123+
}
124+
125+
dom::Value get(std::size_t i) const override
126+
{
127+
if (i >= size())
128+
{
129+
return {};
130+
}
131+
auto it = begin_;
132+
std::ranges::advance(it, i);
133+
if constexpr (std::is_same_v<F, detail::noop>)
134+
{
135+
return Value(*it);
136+
}
137+
else
138+
{
139+
return Value(transform_(*it));
140+
}
141+
}
142+
};
143+
144+
/** Return a new dom::Array based on a lazy array implementation.
145+
*/
146+
template <std::ranges::random_access_range T>
147+
requires std::constructible_from<Value, std::ranges::range_value_t<T>>
148+
Array
149+
LazyArray(T const& arr)
150+
{
151+
return newArray<LazyArrayImpl<T>>(arr);
152+
}
153+
154+
/** Return a new dom::Array based on a transformed lazy array implementation.
155+
*/
156+
template <std::ranges::random_access_range T, class F>
157+
requires
158+
std::invocable<F, std::ranges::range_value_t<T>> &&
159+
std::constructible_from<Value, std::invoke_result_t<F, std::ranges::range_value_t<T>>>
160+
Array
161+
LazyArray(T const& arr, F transform)
162+
{
163+
return newArray<LazyArrayImpl<T, F>>(arr, std::move(transform));
164+
}
165+
166+
} // dom
167+
} // mrdocs
168+
} // clang
169+
170+
#endif

src/lib/Dom/LazyObject.hpp

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
// Official repository: https://github.com/cppalliance/mrdocs
99
//
1010

11-
#ifndef MRDOCS_API_DOM_MAPPING_TRAITS_HPP
12-
#define MRDOCS_API_DOM_MAPPING_TRAITS_HPP
11+
#ifndef MRDOCS_LIB_DOM_LAZY_OBJECT_HPP
12+
#define MRDOCS_LIB_DOM_LAZY_OBJECT_HPP
1313

1414
#include "mrdocs/Dom.hpp"
1515
#include "mrdocs/Platform.hpp"
@@ -72,27 +72,19 @@ concept HasMappingTraits = requires(detail::ArchetypalIO& io, T const& o)
7272
//
7373
//------------------------------------------------
7474

75-
/** Abstract lazy object interface.
75+
/** Lazy object implementation.
7676
7777
This interface is used to define objects
7878
whose members are evaluated on demand
7979
as they are accessed.
8080
81-
The subclass must override the `construct`
82-
function to return the constructed object.
83-
It will typically also store whatever
84-
data is necessary to construct this object.
85-
86-
When any of the object properties are accessed
87-
for the first time, the object is constructed.
88-
This can happen via any of the public functions,
89-
such as `get`, `set`, `size`, `exists`, or `visit`.
90-
91-
The underlying object storage is only
92-
initialized when the first property is
93-
set or accessed. In practice, it means
94-
the object is never initialized if it's
95-
not used in a template.
81+
When any of the object properties are accessed,
82+
the object Value is constructed.
83+
In practice, the object never takes any memory
84+
besides the pointer to the underlying object.
85+
86+
The keys and values in the underlying object
87+
should be mapped using the MappingTraits<T> class.
9688
9789
This class is typically useful for
9890
implementing objects that are expensive

0 commit comments

Comments
 (0)