summaryrefslogtreecommitdiff
path: root/AK
diff options
context:
space:
mode:
authorAli Mohammad Pur <ali.mpfard@gmail.com>2021-05-09 08:24:22 +0430
committerLinus Groh <mail@linusgroh.de>2021-05-11 14:09:17 +0100
commit02de813950fc7c6858f645f39e38c7aeee5058fe (patch)
tree8db12f37e5a2f5b3e896b7d1409fe7f7d69193e1 /AK
parent4fdbac236d8adf042837850930c0be46df6c457f (diff)
downloadserenity-02de813950fc7c6858f645f39e38c7aeee5058fe.zip
AK: Add a Tuple implementation
Please don't use this outside of metaprogramming needs, *please*.
Diffstat (limited to 'AK')
-rw-r--r--AK/Tuple.h218
1 files changed, 218 insertions, 0 deletions
diff --git a/AK/Tuple.h b/AK/Tuple.h
new file mode 100644
index 0000000000..99fdd916da
--- /dev/null
+++ b/AK/Tuple.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/StdLibExtras.h>
+#include <AK/TypeList.h>
+
+namespace AK::Detail {
+
+template<typename... Ts>
+struct Tuple {
+};
+
+template<typename T>
+struct Tuple<T> {
+ Tuple(T&& value) requires(!IsSame<T&&, const T&>)
+ : value(forward<T>(value))
+ {
+ }
+
+ Tuple(const T& value)
+ : value(value)
+ {
+ }
+
+ template<typename U>
+ U& get()
+ {
+ static_assert(IsSame<T, U>, "Invalid tuple access");
+ return value;
+ }
+
+ template<typename U>
+ const U& get() const
+ {
+ return const_cast<Tuple<T>&>(*this).get<U>();
+ }
+
+ template<typename U, unsigned index>
+ U& get_with_index()
+ {
+ static_assert(IsSame<T, U> && index == 0, "Invalid tuple access");
+ return value;
+ }
+
+ template<typename U, unsigned index>
+ const U& get_with_index() const
+ {
+ return const_cast<Tuple<T>&>(*this).get_with_index<U, index>();
+ }
+
+private:
+ T value;
+};
+
+template<typename T, typename... TRest>
+struct Tuple<T, TRest...> : Tuple<TRest...> {
+ Tuple(T&& first, TRest&&... rest)
+ : Tuple<TRest...>(forward<TRest>(rest)...)
+ , value(forward<T>(first))
+ {
+ }
+
+ Tuple(const T& first, const TRest&... rest)
+ : Tuple<TRest...>(rest...)
+ , value(first)
+ {
+ }
+
+ template<typename U>
+ U& get()
+ {
+ if constexpr (IsSame<T, U>)
+ return value;
+ else
+ return Tuple<TRest...>::template get<U>();
+ }
+
+ template<typename U>
+ const U& get() const
+ {
+ return const_cast<Tuple<T, TRest...>&>(*this).get<U>();
+ }
+
+ template<typename U, unsigned index>
+ U& get_with_index()
+ {
+ if constexpr (IsSame<T, U> && index == 0)
+ return value;
+ else
+ return Tuple<TRest...>::template get_with_index<U, index - 1>();
+ }
+
+ template<typename U, unsigned index>
+ const U& get_with_index() const
+ {
+ return const_cast<Tuple<T, TRest...>&>(*this).get_with_index<U, index>();
+ }
+
+private:
+ T value;
+};
+
+}
+
+namespace AK {
+
+template<typename... Ts>
+struct Tuple : Detail::Tuple<Ts...> {
+ using Types = TypeList<Ts...>;
+ using Detail::Tuple<Ts...>::Tuple;
+ using Indices = MakeIndexSequence<sizeof...(Ts)>;
+
+ Tuple(Tuple&& other)
+ : Tuple(move(other), Indices())
+ {
+ }
+
+ Tuple(const Tuple& other)
+ : Tuple(other, Indices())
+ {
+ }
+
+ Tuple& operator=(Tuple&& other)
+ {
+ set(move(other), Indices());
+ return *this;
+ }
+
+ Tuple& operator=(const Tuple& other)
+ {
+ set(other, Indices());
+ return *this;
+ }
+
+ template<typename T>
+ auto& get()
+ {
+ return Detail::Tuple<Ts...>::template get<T>();
+ }
+
+ template<unsigned index>
+ auto& get()
+ {
+ return Detail::Tuple<Ts...>::template get_with_index<typename Types::template Type<index>, index>();
+ }
+
+ template<typename T>
+ auto& get() const
+ {
+ return Detail::Tuple<Ts...>::template get<T>();
+ }
+
+ template<unsigned index>
+ auto& get() const
+ {
+ return Detail::Tuple<Ts...>::template get_with_index<typename Types::template Type<index>, index>();
+ }
+
+ template<typename F>
+ auto apply_as_args(F&& f)
+ {
+ return apply_as_args(forward<F>(f), Indices());
+ }
+
+ template<typename F>
+ auto apply_as_args(F&& f) const
+ {
+ return apply_as_args(forward<F>(f), Indices());
+ }
+
+ static constexpr auto size() { return sizeof...(Ts); }
+
+private:
+ template<unsigned... Is>
+ Tuple(Tuple&& other, IndexSequence<Is...>)
+ : Detail::Tuple<Ts...>(move(other.get<Is>())...)
+ {
+ }
+
+ template<unsigned... Is>
+ Tuple(const Tuple& other, IndexSequence<Is...>)
+ : Detail::Tuple<Ts...>(other.get<Is>()...)
+ {
+ }
+
+ template<unsigned... Is>
+ void set(Tuple&& other, IndexSequence<Is...>)
+ {
+ ((get<Is>() = move(other.get<Is>())), ...);
+ }
+
+ template<unsigned... Is>
+ void set(const Tuple& other, IndexSequence<Is...>)
+ {
+ ((get<Is>() = other.get<Is>()), ...);
+ }
+
+ template<typename F, unsigned... Is>
+ auto apply_as_args(F&& f, IndexSequence<Is...>)
+ {
+ return forward<F>(f)(get<Is>()...);
+ }
+
+ template<typename F, unsigned... Is>
+ auto apply_as_args(F&& f, IndexSequence<Is...>) const
+ {
+ return forward<F>(f)(get<Is>()...);
+ }
+};
+
+}
+
+using AK::Tuple;