/* * Copyright (c) 2018-2020 Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "sf_common.hpp" #include "sf_out.hpp" #include "cmif/sf_cmif_pointer_and_size.hpp" #include "sf_buffer_tags.hpp" namespace ams::sf { enum class BufferTransferMode { MapAlias, Pointer, AutoSelect, }; namespace impl { /* Buffer utilities. */ struct BufferBaseTag{}; template constexpr inline u32 BufferTransferModeAttributes = [] { if constexpr (TransferMode == BufferTransferMode::MapAlias) { return SfBufferAttr_HipcMapAlias; } else if constexpr (TransferMode == BufferTransferMode::Pointer) { return SfBufferAttr_HipcPointer; } else if constexpr(TransferMode == BufferTransferMode::AutoSelect) { return SfBufferAttr_HipcAutoSelect; } else { static_assert(TransferMode != TransferMode, "Invalid BufferTransferMode"); } }(); } template constexpr inline bool IsLargeData = std::is_base_of::value; template constexpr inline bool IsLargeData> = IsLargeData; template constexpr inline size_t LargeDataSize = sizeof(T); template constexpr inline size_t LargeDataSize> = sizeof(T); template constexpr inline BufferTransferMode PreferredTransferMode = [] { constexpr bool prefers_map_alias = std::is_base_of::value; constexpr bool prefers_pointer = std::is_base_of::value; constexpr bool prefers_auto_select = std::is_base_of::value; if constexpr (prefers_map_alias) { static_assert(!prefers_pointer && !prefers_auto_select, "Type T must only prefer one transfer mode."); return BufferTransferMode::MapAlias; } else if constexpr (prefers_pointer) { static_assert(!prefers_map_alias && !prefers_auto_select, "Type T must only prefer one transfer mode."); return BufferTransferMode::Pointer; } else if constexpr (prefers_auto_select) { static_assert(!prefers_map_alias && !prefers_pointer, "Type T must only prefer one transfer mode."); return BufferTransferMode::AutoSelect; } else if constexpr (IsLargeData) { return BufferTransferMode::Pointer; } else { return BufferTransferMode::MapAlias; } }(); template constexpr inline BufferTransferMode PreferredTransferMode> = PreferredTransferMode; namespace impl { class BufferBase : public BufferBaseTag { public: static constexpr u32 AdditionalAttributes = 0; private: const cmif::PointerAndSize pas; protected: constexpr uintptr_t GetAddressImpl() const { return this->pas.GetAddress(); } template constexpr inline size_t GetSizeImpl() const { return this->pas.GetSize() / sizeof(Entry); } public: constexpr BufferBase() : pas() { /* ... */ } constexpr BufferBase(const cmif::PointerAndSize &_pas) : pas(_pas) { /* ... */ } constexpr BufferBase(uintptr_t ptr, size_t sz) : pas(ptr, sz) { /* ... */ } }; class InBufferBase : public BufferBase { public: using BaseType = BufferBase; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | SfBufferAttr_In; public: constexpr InBufferBase() : BaseType() { /* ... */ } constexpr InBufferBase(const cmif::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ } constexpr InBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } constexpr InBufferBase(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } constexpr InBufferBase(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } }; class OutBufferBase : public BufferBase { public: using BaseType = BufferBase; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | SfBufferAttr_Out; public: constexpr OutBufferBase() : BaseType() { /* ... */ } constexpr OutBufferBase(const cmif::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ } constexpr OutBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } constexpr OutBufferBase(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } constexpr OutBufferBase(u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } }; template class InBufferImpl : public InBufferBase { public: using BaseType = InBufferBase; static constexpr BufferTransferMode TransferMode = TMode; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | ExtraAttributes; public: constexpr InBufferImpl() : BaseType() { /* ... */ } constexpr InBufferImpl(const cmif::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ } constexpr InBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } constexpr InBufferImpl(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } constexpr InBufferImpl(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } constexpr const u8 *GetPointer() const { return reinterpret_cast(this->GetAddressImpl()); } constexpr size_t GetSize() const { return this->GetSizeImpl(); } }; template class OutBufferImpl : public OutBufferBase { public: using BaseType = OutBufferBase; static constexpr BufferTransferMode TransferMode = TMode; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | ExtraAttributes; public: constexpr OutBufferImpl() : BaseType() { /* ... */ } constexpr OutBufferImpl(const cmif::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ } constexpr OutBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } constexpr OutBufferImpl(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } constexpr OutBufferImpl(u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } constexpr u8 *GetPointer() const { return reinterpret_cast(this->GetAddressImpl()); } constexpr size_t GetSize() const { return this->GetSizeImpl(); } }; template> struct InArrayImpl : public InBufferBase { public: using BaseType = InBufferBase; static constexpr BufferTransferMode TransferMode = TMode; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes; public: constexpr InArrayImpl() : BaseType() { /* ... */ } constexpr InArrayImpl(const cmif::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ } constexpr InArrayImpl(const T *ptr, size_t num_elements) : BaseType(reinterpret_cast(ptr), num_elements * sizeof(T)) { /* ... */ } constexpr const T *GetPointer() const { return reinterpret_cast(this->GetAddressImpl()); } constexpr size_t GetSize() const { return this->GetSizeImpl(); } constexpr const T &operator[](size_t i) const { return this->GetPointer()[i]; } constexpr explicit operator Span() const { return {this->GetPointer(), static_cast(this->GetSize())}; } constexpr Span ToSpan() const { return {this->GetPointer(), static_cast(this->GetSize())}; } }; template> struct OutArrayImpl : public OutBufferBase { public: using BaseType = OutBufferBase; static constexpr BufferTransferMode TransferMode = TMode; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes; public: constexpr OutArrayImpl() : BaseType() { /* ... */ } constexpr OutArrayImpl(const cmif::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ } constexpr OutArrayImpl(T *ptr, size_t num_elements) : BaseType(reinterpret_cast(ptr), num_elements * sizeof(T)) { /* ... */ } constexpr T *GetPointer() const { return reinterpret_cast(this->GetAddressImpl()); } constexpr size_t GetSize() const { return this->GetSizeImpl(); } constexpr T &operator[](size_t i) const { return this->GetPointer()[i]; } constexpr explicit operator Span() const { return {this->GetPointer(), static_cast(this->GetSize())}; } constexpr Span ToSpan() const { return {this->GetPointer(), static_cast(this->GetSize())}; } }; } /* Buffer Types. */ using InBuffer = typename impl::InBufferImpl; using InMapAliasBuffer = typename impl::InBufferImpl; using InPointerBuffer = typename impl::InBufferImpl; using InAutoSelectBuffer = typename impl::InBufferImpl; using InNonSecureBuffer = typename impl::InBufferImpl; using InNonDeviceBuffer = typename impl::InBufferImpl; using InNonSecureAutoSelectBuffer = typename impl::InBufferImpl; using OutBuffer = typename impl::OutBufferImpl; using OutMapAliasBuffer = typename impl::OutBufferImpl; using OutPointerBuffer = typename impl::OutBufferImpl; using OutAutoSelectBuffer = typename impl::OutBufferImpl; using OutNonSecureBuffer = typename impl::OutBufferImpl; using OutNonDeviceBuffer = typename impl::OutBufferImpl; using OutNonSecureAutoSelectBuffer = typename impl::OutBufferImpl; template using InArray = typename impl::InArrayImpl; template using InMapAliasArray = typename impl::InArrayImpl; template using InPointerArray = typename impl::InArrayImpl; template using InAutoSelectArray = typename impl::InArrayImpl; template using OutArray = typename impl::OutArrayImpl; template using OutMapAliasArray = typename impl::OutArrayImpl; template using OutPointerArray = typename impl::OutArrayImpl; template using OutAutoSelectArray = typename impl::OutArrayImpl; /* Attribute serialization structs. */ template constexpr inline bool IsBuffer = [] { const bool is_buffer = std::is_base_of::value; const bool is_large_data = IsLargeData; static_assert(!(is_buffer && is_large_data), "Invalid sf::IsBuffer state"); return is_buffer || is_large_data; }(); template constexpr inline u32 BufferAttributes = [] { static_assert(IsBuffer, "BufferAttributes requires IsBuffer"); if constexpr (std::is_base_of::value) { return impl::BufferTransferModeAttributes | T::AdditionalAttributes; } else if constexpr (IsLargeData) { u32 attr = SfBufferAttr_FixedSize | impl::BufferTransferModeAttributes>; if constexpr (std::is_base_of::value) { attr |= SfBufferAttr_Out; } else { attr |= SfBufferAttr_In; } return attr; } else { static_assert(!std::is_same::value, "Invalid BufferAttributes"); } }(); }