Skip to content

Commit 8ef3ffa

Browse files
committed
feat(lib): optional references
Support Optional for references and replace usages of Optional with reference wrappers in the codebase.
1 parent 948e269 commit 8ef3ffa

File tree

7 files changed

+463
-39
lines changed

7 files changed

+463
-39
lines changed

include/mrdocs/ADT/Optional.hpp

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ inline constexpr bool isOptionalV = false;
5252

5353
template<typename T>
5454
inline constexpr bool isOptionalV<Optional<T>> = true;
55+
56+
template<typename T>
57+
inline constexpr bool isOptionalV<Optional<T&>> = true;
5558
}
5659

5760
/** A compact optional that automatically uses nullable_traits<T> when
@@ -632,6 +635,298 @@ concept isDerivedFromOptional = requires(T const& t) {
632635

633636
} // namespace detail
634637

638+
639+
namespace detail {
640+
#if defined(__cpp_lib_reference_from_temporary)
641+
using std::reference_constructs_from_temporary_v;
642+
using std::reference_converts_from_temporary_v;
643+
#else
644+
template<class To, class From>
645+
concept reference_converts_from_temporary_v =
646+
std::is_reference_v<To> &&
647+
(
648+
(!std::is_reference_v<From> &&
649+
std::is_convertible_v<std::remove_cvref_t<From>*,
650+
std::remove_cvref_t<To>*>)
651+
||
652+
(std::is_lvalue_reference_v<To> &&
653+
std::is_const_v<std::remove_reference_t<To>> &&
654+
std::is_convertible_v<From, const std::remove_cvref_t<To>&&> &&
655+
!std::is_convertible_v<From, std::remove_cvref_t<To>&>)
656+
);
657+
658+
template <class To, class From>
659+
inline constexpr bool reference_constructs_from_temporary_v
660+
= reference_converts_from_temporary_v<To, From>;
661+
#endif
662+
} // detail
663+
664+
template <class T>
665+
class Optional<T&> {
666+
T* p_ = nullptr;
667+
668+
template <class U>
669+
static constexpr bool ok_bind_v
670+
= std::is_constructible_v<T&, U>
671+
&& !detail::reference_constructs_from_temporary_v<T&, U>;
672+
673+
public:
674+
using value_type = T;
675+
676+
constexpr
677+
Optional() noexcept = default;
678+
679+
constexpr
680+
Optional(Optional const&) noexcept = default;
681+
682+
constexpr
683+
Optional(Optional&&) noexcept = default;
684+
685+
constexpr
686+
Optional(std::nullopt_t) noexcept
687+
: Optional() {}
688+
689+
template <class U>
690+
requires(
691+
!std::is_same_v<std::remove_cvref_t<U>, Optional> &&
692+
!std::is_same_v<std::remove_cvref_t<U>, std::in_place_t> &&
693+
ok_bind_v<U>)
694+
constexpr
695+
explicit(!std::is_convertible_v<U, T&>)
696+
Optional(U&& u)
697+
noexcept(std::is_nothrow_constructible_v<T&, U>)
698+
{
699+
T& r(static_cast<U&&>(u));
700+
p_ = std::addressof(r);
701+
}
702+
703+
template <class U>
704+
requires ok_bind_v<U&>
705+
constexpr
706+
explicit(!std::is_convertible_v<U&, T&>)
707+
Optional(Optional<U>& rhs)
708+
noexcept(std::is_nothrow_constructible_v<T&, U&>)
709+
{
710+
if (rhs)
711+
{
712+
p_ = std::addressof(*rhs);
713+
}
714+
}
715+
716+
template <class U>
717+
requires ok_bind_v<U const&>
718+
constexpr
719+
explicit(!std::is_convertible_v<U const&, T&>)
720+
Optional(Optional<U> const& rhs)
721+
noexcept(std::is_nothrow_constructible_v<T&, U const&>)
722+
{
723+
if (rhs)
724+
{
725+
p_ = std::addressof(*rhs);
726+
}
727+
}
728+
729+
template <class U>
730+
requires ok_bind_v<U&>
731+
constexpr
732+
Optional(std::optional<U>& o)
733+
noexcept(std::is_nothrow_constructible_v<T&, U&>)
734+
{
735+
if (o)
736+
{
737+
p_ = std::addressof(*o);
738+
}
739+
}
740+
741+
template <class U>
742+
requires ok_bind_v<U const&>
743+
constexpr
744+
Optional(std::optional<U> const& o)
745+
noexcept(std::is_nothrow_constructible_v<T&, U const&>)
746+
{
747+
if (o)
748+
{
749+
p_ = std::addressof(*o);
750+
}
751+
}
752+
753+
constexpr Optional&
754+
operator=(Optional const&) noexcept = default;
755+
756+
constexpr Optional&
757+
operator=(Optional&&) noexcept = default;
758+
759+
constexpr Optional&
760+
operator=(std::nullopt_t) noexcept
761+
{
762+
p_ = nullptr;
763+
return *this;
764+
}
765+
766+
template <class U>
767+
requires ok_bind_v<U>
768+
constexpr Optional&
769+
operator=(U&& u)
770+
noexcept(std::is_nothrow_constructible_v<T&, U>)
771+
{
772+
T& r(static_cast<U&&>(u));
773+
p_ = std::addressof(r);
774+
return *this;
775+
}
776+
777+
template <class U>
778+
requires ok_bind_v<U&>
779+
constexpr
780+
Optional&
781+
operator=(Optional<U>& rhs)
782+
noexcept(std::is_nothrow_constructible_v<T&, U&>)
783+
{
784+
p_ = rhs ? std::addressof(*rhs) : nullptr;
785+
return *this;
786+
}
787+
788+
template <class U>
789+
requires ok_bind_v<U const&>
790+
constexpr
791+
Optional&
792+
operator=(Optional<U> const& rhs)
793+
noexcept(std::is_nothrow_constructible_v<T&, U const&>)
794+
{
795+
p_ = rhs ? std::addressof(*rhs) : nullptr;
796+
return *this;
797+
}
798+
799+
template <class U>
800+
requires ok_bind_v<U>
801+
constexpr
802+
Optional&
803+
operator=(Optional<U>&& rhs)
804+
noexcept(std::is_nothrow_constructible_v<T&, U>)
805+
{
806+
p_ = rhs ? std::addressof(*rhs) : nullptr;
807+
return *this;
808+
}
809+
810+
template <class U>
811+
requires ok_bind_v<U>
812+
constexpr
813+
value_type&
814+
emplace(U&& u)
815+
noexcept(std::is_nothrow_constructible_v<T&, U>)
816+
{
817+
T& r(static_cast<U&&>(u));
818+
p_ = std::addressof(r);
819+
return *p_;
820+
}
821+
822+
static
823+
constexpr
824+
bool
825+
is_inlined() noexcept
826+
{
827+
return true;
828+
}
829+
830+
constexpr
831+
bool
832+
has_value() const noexcept
833+
{
834+
return p_ != nullptr;
835+
}
836+
837+
constexpr
838+
explicit
839+
operator bool() const noexcept
840+
{
841+
return has_value();
842+
}
843+
844+
constexpr
845+
void
846+
reset() noexcept
847+
{
848+
p_ = nullptr;
849+
}
850+
851+
constexpr
852+
value_type*
853+
operator->() noexcept
854+
{
855+
MRDOCS_ASSERT(has_value());
856+
return p_;
857+
}
858+
859+
constexpr
860+
value_type const*
861+
operator->() const noexcept
862+
{
863+
MRDOCS_ASSERT(has_value());
864+
return p_;
865+
}
866+
867+
constexpr
868+
value_type&
869+
operator*() noexcept
870+
{
871+
MRDOCS_ASSERT(has_value());
872+
return *p_;
873+
}
874+
875+
constexpr
876+
value_type const&
877+
operator*() const noexcept
878+
{
879+
MRDOCS_ASSERT(has_value());
880+
return *p_;
881+
}
882+
883+
constexpr
884+
value_type&
885+
value() & noexcept
886+
{
887+
MRDOCS_ASSERT(has_value());
888+
return *p_;
889+
}
890+
891+
constexpr
892+
value_type const&
893+
value() const& noexcept
894+
{
895+
MRDOCS_ASSERT(has_value());
896+
return *p_;
897+
}
898+
899+
constexpr
900+
value_type&
901+
value() && noexcept
902+
{
903+
MRDOCS_ASSERT(has_value());
904+
return *p_;
905+
}
906+
907+
constexpr
908+
value_type const&
909+
value() const&& noexcept
910+
{
911+
MRDOCS_ASSERT(has_value());
912+
return *p_;
913+
}
914+
915+
constexpr void
916+
swap(Optional& other) noexcept
917+
{
918+
using std::swap;
919+
swap(p_, other.p_);
920+
}
921+
};
922+
923+
template <class T>
924+
constexpr void
925+
swap(Optional<T&>& a, Optional<T&>& b) noexcept
926+
{
927+
a.swap(b);
928+
}
929+
635930
/** Compares two Optional values for equality.
636931
Returns true if both are engaged and their contained values are equal, or both are disengaged.
637932
@return `true` if both optionals are engaged and equal, or both are disengaged; otherwise, `false`.
@@ -893,6 +1188,7 @@ operator<=>(Optional<T> const& x, U const& v)
8931188
{
8941189
return bool(x) ? *x <=> v : std::strong_ordering::less;
8951190
}
1191+
8961192
} // namespace clang::mrdocs
8971193

8981194
#endif

include/mrdocs/Metadata/Info/InfoBase.hpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,22 @@ namespace clang::mrdocs {
3131
*/
3232
struct MRDOCS_VISIBLE Info
3333
{
34+
/** The unqualified name.
35+
*/
36+
std::string Name;
37+
3438
/** The source location information.
3539
*/
3640
SourceInfo Loc;
3741

38-
/** The unique identifier for this symbol.
39-
*/
40-
SymbolID id;
41-
42-
/** The unqualified name.
43-
*/
44-
std::string Name;
45-
4642
/** Kind of declaration.
4743
*/
4844
InfoKind Kind = InfoKind::None;
4945

46+
/** The unique identifier for this symbol.
47+
*/
48+
SymbolID id;
49+
5050
/** Declaration access.
5151
5252
Class members use:
@@ -152,8 +152,8 @@ struct MRDOCS_VISIBLE Info
152152
Info(
153153
InfoKind const kind,
154154
SymbolID const& ID) noexcept
155-
: id(ID)
156-
, Kind(kind)
155+
: Kind(kind)
156+
, id(ID)
157157
{
158158
}
159159
};

include/mrdocs/Metadata/Type.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,16 +118,16 @@ operator==(
118118

119119
/** Return the inner type.
120120
121-
The inner type is the type which is modified
122-
by a specifier (e.g. "int" in "pointer to int".
121+
The inner type is the type that is modified
122+
by a specifier (e.g. "int" in "pointer to int").
123123
*/
124124
MRDOCS_DECL
125-
Optional<std::reference_wrapper<Polymorphic<TypeInfo> const>>
125+
Optional<Polymorphic<TypeInfo> const&>
126126
innerType(TypeInfo const& TI) noexcept;
127127

128128
/// @copydoc innerType(TypeInfo const&)
129129
MRDOCS_DECL
130-
Optional<std::reference_wrapper<Polymorphic<TypeInfo>>>
130+
Optional<Polymorphic<TypeInfo>&>
131131
innerType(TypeInfo& TI) noexcept;
132132

133133
/// @copydoc innerType(TypeInfo const&)

src/lib/AST/ParseRef.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,15 +1550,15 @@ class RefParser
15501550
// For instance, in "int (*)[3][6]", we have a pointer to an
15511551
// array of 3 arrays of 6 ints.
15521552
std::size_t curSuffixLevel = suffixLevel;
1553-
while (curSuffixLevel > 0 && inner && !inner->get().valueless_after_move())
1553+
while (curSuffixLevel > 0 && inner && !inner->valueless_after_move())
15541554
{
1555-
auto& ref = inner->get();
1555+
auto& ref = *inner;
15561556
inner = innerType(*ref);
15571557
--curSuffixLevel;
15581558
}
15591559
char const* parenStart = ptr_;
15601560
if (!parseArrayOrFunctionDeclaratorSuffix<declarator_type>(
1561-
inner ? inner->get() : dest))
1561+
inner ? *inner : dest))
15621562
{
15631563
setError(parenStart, "expected declarator");
15641564
ptr_ = start;

0 commit comments

Comments
 (0)