/*
* Copyright (c) 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
#include
#include
#include
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(false, "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 m_pas;
protected:
constexpr uintptr_t GetAddressImpl() const {
return m_pas.GetAddress();
}
template
constexpr inline size_t GetSizeImpl() const {
return m_pas.GetSize() / sizeof(Entry);
}
public:
constexpr BufferBase() : m_pas() { /* ... */ }
constexpr BufferBase(const cmif::PointerAndSize &pas) : m_pas(pas) { /* ... */ }
constexpr BufferBase(uintptr_t ptr, size_t sz) : m_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) { /* ... */ }
InBufferBase(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ }
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) { /* ... */ }
OutBufferBase(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ }
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) { /* ... */ }
InBufferImpl(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ }
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) { /* ... */ }
OutBufferImpl(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ }
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) { /* ... */ }
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(), this->GetSize()};
}
constexpr Span ToSpan() const {
return {this->GetPointer(), 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) { /* ... */ }
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(), this->GetSize()};
}
constexpr Span ToSpan() const {
return {this->GetPointer(), 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");
}
}();
}