Skip to content

Commit 5fa2ff4

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 73796cb commit 5fa2ff4

File tree

4 files changed

+463
-366
lines changed

4 files changed

+463
-366
lines changed

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

0 commit comments

Comments
 (0)