summaryrefslogtreecommitdiff
path: root/tiger-compiler/lib/misc/variant.hh
diff options
context:
space:
mode:
authorMartial Simon <msimon_fr@hotmail.com>2025-09-15 01:07:58 +0200
committerMartial Simon <msimon_fr@hotmail.com>2025-09-15 01:07:58 +0200
commit967be9e750221ab2ab783f95df79bb26d290a45e (patch)
tree6802900a5e975f9f68b169f0f503f040056d6952 /tiger-compiler/lib/misc/variant.hh
add: added projectsHEADmain
Diffstat (limited to 'tiger-compiler/lib/misc/variant.hh')
-rw-r--r--tiger-compiler/lib/misc/variant.hh111
1 files changed, 111 insertions, 0 deletions
diff --git a/tiger-compiler/lib/misc/variant.hh b/tiger-compiler/lib/misc/variant.hh
new file mode 100644
index 0000000..71a8c1a
--- /dev/null
+++ b/tiger-compiler/lib/misc/variant.hh
@@ -0,0 +1,111 @@
+/**
+ ** \file misc/variant.hh
+ ** \brief Interface of misc::variant.
+ **
+ ** misc::variant is a wrapper over std::variant that adds
+ ** conversion operators to the original standard variant class.
+ ** misc::variant is used just like std::variant, and you
+ ** won't be disturbed when using it.
+ **/
+
+#pragma once
+
+#include <variant>
+
+namespace misc
+{
+ // Defining some concepts sepecific to variants:
+
+ // Type T can be converted into another type in Ts,
+ // used to set the variant's value.
+ template <typename T, typename... Ts>
+ concept ContainsTypeSet =
+ std::disjunction<std::is_convertible<T, Ts>...>::value;
+
+ // A type in Ts can be converted into T, used to get the variant's value.
+ template <typename T, typename... Ts>
+ concept ContainsTypeGet =
+ std::disjunction<std::is_convertible<Ts, T>...>::value;
+
+ /// Type V is a visitor on each Ts.
+ template <typename V, typename... Ts>
+ concept Visits = std::conjunction<std::is_invocable<V, Ts>...>::value;
+
+ /// A wrapper over std::variant supporting conversion operators.
+ ///
+ /// Constraints:
+ /// - No type may be const-qualified.
+ /// - Each type must be unique.
+ /// - The first type must be default constructible.
+ ///
+ /// Proper declaration form:
+ /// misc::variant<T, T1, ..., Tn>
+
+ template <typename T, typename... Ts>
+ class variant : public std::variant<T, Ts...>
+ {
+ public:
+ /// The type of this variant.
+ using self_type = variant<T, Ts...>;
+ /// Super type.
+
+ using super_type = std::variant<T, Ts...>;
+
+ /// Constructors.
+ /// \{
+ variant() = default;
+
+ template <typename U>
+ requires ContainsTypeSet<U, T, Ts...>
+ variant(const U& rhs);
+ /// \}
+
+ template <typename U>
+ requires ContainsTypeSet<U, T, Ts...>
+ self_type& operator=(const U&);
+
+ /// \brief Convert this variant to a value of type \a U.
+ ///
+ /// This conversion relies on std::get. In particular, if the
+ /// conversion fails, a std::bad_variant_access exception is thrown.
+ template <typename U>
+ requires ContainsTypeGet<U, T, Ts...>
+ operator U&();
+
+ /// Likewise, const version.
+ template <typename U>
+ requires ContainsTypeGet<U, T, Ts...>
+ operator const U&() const;
+
+ /** \brief Visit variants of this class.
+ ** std::visit does not handle classes inheriting from std::variant, hence
+ ** these wrappers.
+ ** \{ */
+ template <typename V>
+ requires Visits<V, T, Ts...>
+ auto visit(V&& visitor) const;
+
+ template <typename V, class... Variants>
+ static auto visit(V&& visitor, Variants&&... vars);
+ /** \} */
+ };
+
+ // Here add variadic template recursion on std::get
+ template <typename T, typename... Ts>
+ std::ostream& operator<<(std::ostream& os, const variant<T, Ts...>& obj);
+
+ class PrintVisitor
+ {
+ public:
+ PrintVisitor(std::ostream& os)
+ : os_(os)
+ {}
+
+ template <typename T> std::ostream& operator()(const T& value) const;
+
+ private:
+ std::ostream& os_;
+ };
+} // namespace misc
+
+#include <misc/variant.hxx>