// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime // SPDX-License-Identifier: MIT #pragma once #include #include #include #include "oaknut/oaknut_exception.hpp" namespace oaknut { struct Elem; template struct ElemSelector; struct VRegArranged; namespace detail { template struct is_instance_of_ElemSelector : std::false_type {}; template struct is_instance_of_ElemSelector> : std::true_type {}; template constexpr bool is_instance_of_ElemSelector_v = is_instance_of_ElemSelector::value; struct BaseOnlyTag {}; } // namespace detail template struct List { template constexpr explicit List(U... args) : m_base(std::get<0>(std::tie(args...))) { static_assert((std::is_same_v && ...)); static_assert(sizeof...(args) == N); static_assert(std::is_base_of_v || std::is_base_of_v || detail::is_instance_of_ElemSelector_v); if (!verify(std::index_sequence_for{}, args...)) throw OaknutException{ExceptionType::InvalidList}; } constexpr auto operator[](unsigned elem_index) const { using S = decltype(m_base[elem_index]); return List(detail::BaseOnlyTag{}, m_base[elem_index]); } private: template friend class BasicCodeGenerator; template friend struct List; constexpr explicit List(detail::BaseOnlyTag, T base_) : m_base(base_) {} template constexpr bool verify(std::index_sequence, U... args) { if constexpr (std::is_base_of_v) { return (((m_base.index() + indexes) % 32 == static_cast(args.index())) && ...); } else if constexpr (std::is_base_of_v) { return (((m_base.reg_index() + indexes) % 32 == static_cast(args.reg_index()) && m_base.elem_index() == args.elem_index()) && ...); } else { return (((m_base.reg_index() + indexes) % 32 == static_cast(args.reg_index())) && ...); } } T m_base; }; template List(U...) -> List, sizeof...(U)>; } // namespace oaknut