@@ -793,6 +793,82 @@ auto transform(const std::optional<OptionalElement> &value,
793793 }
794794 return std::nullopt ;
795795}
796+
797+ // / A little wrapper that either wraps a `T &&` or a `const T &`.
798+ // / It allows you to defer the optimal decision about how to
799+ // / forward the value to runtime.
800+ template <class T >
801+ class maybe_movable_ref {
802+ // / Actually a T&& if movable is true.
803+ const T &ref;
804+ bool movable;
805+
806+ public:
807+ // The maybe_movable_ref wrapper itself is, basically, either an
808+ // r-value reference or an l-value reference. It is therefore
809+ // move-only so that code working with it has to properly
810+ // forward it around.
811+ maybe_movable_ref (maybe_movable_ref &&other) = default ;
812+ maybe_movable_ref &operator =(maybe_movable_ref &&other) = default ;
813+
814+ maybe_movable_ref (const maybe_movable_ref &other) = delete ;
815+ maybe_movable_ref &operator =(const maybe_movable_ref &other) = delete ;
816+
817+ // / Allow the wrapper to be statically constructed from an r-value
818+ // / reference in the movable state.
819+ maybe_movable_ref (T &&ref) : ref(ref), movable(true ) {}
820+
821+ // / Allow the wrapper to be statically constructed from a
822+ // / const l-value reference in the non-movable state.
823+ maybe_movable_ref (const T &ref) : ref(ref), movable(false ) {}
824+
825+ // / Don't allow the wrapper to be statically constructed from
826+ // / a non-const l-value reference without passing a flag
827+ // / dynamically.
828+ maybe_movable_ref (T &ref) = delete ;
829+
830+ // / The fully-general constructor.
831+ maybe_movable_ref (T &ref, bool movable) : ref(ref), movable(movable) {}
832+
833+ // / Check dynamically whether the reference is movable.
834+ bool isMovable () const {
835+ return movable;
836+ }
837+
838+ // / Construct a T from the wrapped reference.
839+ T construct () && {
840+ if (isMovable ()) {
841+ return T (move ());
842+ } else {
843+ return T (ref);
844+ }
845+ }
846+
847+ // / Get access to the value, conservatively returning a const
848+ // / reference.
849+ const T &get () const {
850+ return ref;
851+ }
852+
853+ // / Get access to the value, dynamically aserting that it is movable.
854+ T &get_mutable () const {
855+ assert (isMovable ());
856+ return const_cast <T&>(ref);
857+ }
858+
859+ // / Return an r-value reference to the value, dynamically asserting
860+ // / that it is movable.
861+ T &&move() {
862+ assert (isMovable ());
863+ return static_cast <T&&>(const_cast <T&>(ref));
864+ }
865+ };
866+
867+ template <class T >
868+ maybe_movable_ref<T> move_if (T &ref, bool movable) {
869+ return maybe_movable_ref<T>(ref, movable);
870+ }
871+
796872} // end namespace swift
797873
798874#endif // SWIFT_BASIC_STLEXTRAS_H
0 commit comments