Skip to content

Commit

Permalink
refactor: unify dom lazy array classes
Browse files Browse the repository at this point in the history
The DomCorpus uses multiple classes that represented lazy arrays. This commit simplifies the dom by unifying all of these array implementations.
  • Loading branch information
alandefreitas committed Oct 29, 2024
1 parent 3f24987 commit aa5f95a
Show file tree
Hide file tree
Showing 8 changed files with 450 additions and 390 deletions.
10 changes: 8 additions & 2 deletions include/mrdocs/Metadata/DomCorpus.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,17 @@ class MRDOCS_DECL

/** Returns the Corpus associated with the Dom.
*/
Corpus const& operator*() const;
Corpus const& operator*() const
{
return getCorpus();
}

/** Returns the Corpus associated with the Dom.
*/
Corpus const* operator->() const;
Corpus const* operator->() const
{
return &getCorpus();
}

/** Construct a lazy Dom object representing the specified symbol.
Expand Down
27 changes: 20 additions & 7 deletions include/mrdocs/Metadata/Scope.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,29 @@ namespace mrdocs {
class are the symbols and functions declared
in the class.
The Lookups are the symbols that are accessible
from the scope of the Info. For instance, the
Lookups["foo"] of a namespace are the symbols
declared as "foo" in the namespace.
This Info class can be used as a base class
for other Info classes, such as NamespaceInfo,
ClassInfo, that represent scopes. This class
can also be used with composition, such as in
@ref Interface to represent different scopes of
the same class (such as member and static overloads).
*/
struct ScopeInfo
{
/** The members of this scope.
*/
std::vector<SymbolID> Members;

/** The lookup table for this scope.
*/
std::unordered_map<std::string,
/** The members of this scope.
*/
std::vector<SymbolID> Members;

/** The lookup table for this scope.
*/
std::unordered_map<
std::string,
std::vector<SymbolID>> Lookups;
};

Expand Down
27 changes: 27 additions & 0 deletions include/mrdocs/Metadata/Source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ MRDOCS_DECL
std::string_view
toString(FileKind kind);

namespace dom {
template <>
struct ToValue<FileKind>
{
std::string_view
operator()(FileKind id) const;
};
}

struct MRDOCS_DECL
Location
{
Expand Down Expand Up @@ -76,6 +85,15 @@ struct MRDOCS_DECL
}
};

namespace dom {
template <>
struct ToValue<Location>
{
dom::Object
operator()(Location const& loc) const;
};
}

struct LocationEmptyPredicate
{
constexpr bool operator()(
Expand Down Expand Up @@ -113,6 +131,15 @@ struct MRDOCS_DECL
SourceInfo() = default;
};

namespace dom {
template <>
struct ToValue<SourceInfo>
{
dom::Object
operator()(SourceInfo const& info) const;
};
}

} // mrdocs
} // clang

Expand Down
170 changes: 170 additions & 0 deletions src/lib/Dom/LazyArray.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Copyright (c) 2024 Alan de Freitas ([email protected])
//
// Official repository: https://github.com/cppalliance/mrdocs
//

#ifndef MRDOCS_LIB_DOM_LAZY_ARRAY_HPP
#define MRDOCS_LIB_DOM_LAZY_ARRAY_HPP

#include "mrdocs/Dom.hpp"
#include "mrdocs/Platform.hpp"
#include "mrdocs/Support/Error.hpp"
#include <string_view>
#include <ranges>

namespace clang {
namespace mrdocs {
namespace dom {

namespace detail {
struct noop {
template <class T>
auto operator()(T&& t) const
{
return t;
}
};

struct no_size_tag {};
}

/** Lazy array implementation
This array type is used to define a dom::Array
whose members are evaluated on demand
as they are accessed.
Each member can goes through a transform
function before being returned as a Value so
that all types can be converted to dom::Value.
The underlying representation of the array is
a range from where the elements are extracted.
Elements in this range should be convertible
to dom::Value.
This class is typically useful for
implementing arrays that are expensive
and have recursive dependencies, as these
recursive dependencies can also be deferred.
Unlike a LazyObjectImpl, which contains an
overlay object, this implementation is
read-only. The `set` and `emplace_back`
methods are not implemented.
*/
template <std::ranges::random_access_range R, class F = detail::noop>
requires
std::invocable<F, std::ranges::range_value_t<R>> &&
std::constructible_from<Value, std::invoke_result_t<F, std::ranges::range_value_t<R>>>
class LazyArrayImpl : public ArrayImpl
{
using const_iterator_t = decltype(std::ranges::cbegin(std::declval<R&>()));
using const_sentinel_t = decltype(std::ranges::cend(std::declval<R&>()));
using size_type = std::conditional_t<
std::ranges::sized_range<R>,
std::ranges::range_size_t<R>,
detail::no_size_tag>;

const_iterator_t begin_;
const_sentinel_t end_;
[[no_unique_address]] size_type size_;
[[no_unique_address]] F transform_;

public:
explicit
LazyArrayImpl(R const& arr)
: begin_(std::ranges::begin(arr))
, end_(std::ranges::end(arr))
{
if constexpr (std::ranges::sized_range<R>)
{
size_ = std::ranges::size(arr);
}
}

explicit
LazyArrayImpl(R const& arr, F transform)
: begin_(std::ranges::begin(arr))
, end_(std::ranges::end(arr))
, transform_(std::move(transform))
{
if constexpr (std::ranges::sized_range<R>)
{
size_ = std::ranges::size(arr);
}
}

~LazyArrayImpl() override = default;

/// @copydoc ObjectImpl::type_key
char const*
type_key() const noexcept override
{
return "LazyArray";
}

std::size_t size() const noexcept override
{
if constexpr (std::ranges::sized_range<R>)
{
return size_;
}
else
{
return std::ranges::distance(begin_, end_);
}
}

dom::Value get(std::size_t i) const override
{
if (i >= size())
{
return {};
}
auto it = begin_;
std::ranges::advance(it, i);
if constexpr (std::is_same_v<F, detail::noop>)
{
return Value(*it);
}
else
{
return Value(transform_(*it));
}
}
};

/** Return a new dom::Array based on a lazy array implementation.
*/
template <std::ranges::random_access_range T>
requires std::constructible_from<Value, std::ranges::range_value_t<T>>
Array
LazyArray(T const& arr)
{
return newArray<LazyArrayImpl<T>>(arr);
}

/** Return a new dom::Array based on a transformed lazy array implementation.
*/
template <std::ranges::random_access_range T, class F>
requires
std::invocable<F, std::ranges::range_value_t<T>> &&
std::constructible_from<Value, std::invoke_result_t<F, std::ranges::range_value_t<T>>>
Array
LazyArray(T const& arr, F transform)
{
return newArray<LazyArrayImpl<T, F>>(arr, std::move(transform));
}

} // dom
} // mrdocs
} // clang

#endif
28 changes: 10 additions & 18 deletions src/lib/Dom/LazyObject.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
// Official repository: https://github.com/cppalliance/mrdocs
//

#ifndef MRDOCS_API_DOM_MAPPING_TRAITS_HPP
#define MRDOCS_API_DOM_MAPPING_TRAITS_HPP
#ifndef MRDOCS_LIB_DOM_LAZY_OBJECT_HPP
#define MRDOCS_LIB_DOM_LAZY_OBJECT_HPP

#include "mrdocs/Dom.hpp"
#include "mrdocs/Platform.hpp"
Expand Down Expand Up @@ -72,27 +72,19 @@ concept HasMappingTraits = requires(detail::ArchetypalIO& io, T const& o)
//
//------------------------------------------------

/** Abstract lazy object interface.
/** Lazy object implementation.
This interface is used to define objects
whose members are evaluated on demand
as they are accessed.
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. In practice, it means
the object is never initialized if it's
not used in a template.
When any of the object properties are accessed,
the object Value is constructed.
In practice, the object never takes any memory
besides the pointer to the underlying object.
The keys and values in the underlying object
should be mapped using the MappingTraits<T> class.
This class is typically useful for
implementing objects that are expensive
Expand Down
Loading

0 comments on commit aa5f95a

Please sign in to comment.