mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:12:43 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			226 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			226 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * 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 &&, T const& >)
 | |
|         : value(forward<T>(value))
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     Tuple(T const& value)
 | |
|         : value(value)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     template<typename U>
 | |
|     U& get()
 | |
|     {
 | |
|         static_assert(IsSame<T, U>, "Invalid tuple access");
 | |
|         return value;
 | |
|     }
 | |
| 
 | |
|     template<typename U>
 | |
|     U const& 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>
 | |
|     U const& 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...> {
 | |
| 
 | |
|     template<typename FirstT, typename... RestT>
 | |
|     Tuple(FirstT&& first, RestT&&... rest)
 | |
|         : Tuple<TRest...>(forward<RestT>(rest)...)
 | |
|         , value(forward<FirstT>(first))
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     Tuple(T&& first, TRest&&... rest)
 | |
|         : Tuple<TRest...>(move(rest)...)
 | |
|         , value(move(first))
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     template<typename U>
 | |
|     U& get()
 | |
|     {
 | |
|         if constexpr (IsSame<T, U>)
 | |
|             return value;
 | |
|         else
 | |
|             return Tuple<TRest...>::template get<U>();
 | |
|     }
 | |
| 
 | |
|     template<typename U>
 | |
|     U const& 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>
 | |
|     U const& 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(Tuple const& other)
 | |
|         : Tuple(other, Indices())
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     Tuple& operator=(Tuple&& other)
 | |
|     {
 | |
|         set(move(other), Indices());
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     Tuple& operator=(Tuple const& 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(Tuple const& 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(Tuple const& 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>()...);
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<class... Args>
 | |
| Tuple(Args... args) -> Tuple<Args...>;
 | |
| 
 | |
| }
 | |
| 
 | |
| #if USING_AK_GLOBALLY
 | |
| using AK::Tuple;
 | |
| #endif
 | 
