You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/CryCommon/UnalignedBlit.h

142 lines
6.0 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Generic unaligned memory access helpers.
#pragma once
#include <stddef.h>
#include <type_traits>
namespace Detail
{
template<typename RealType, typename BlittedElement>
struct Blitter
{
static_assert(std::is_trivial<BlittedElement>::value, "Blittable elements should be trivial (ie, integral types)");
static_assert((std::alignment_of<BlittedElement>::value < std::alignment_of<RealType>::value), "Blittable memory has sufficient alignment, do not use unaligned store or load");
static_assert(sizeof(RealType) > sizeof(BlittedElement), "Blittable element is larger than real type");
static_assert((sizeof(RealType) % sizeof(BlittedElement)) == 0, "Blitted element has the wrong size for the real type");
typedef std::integral_constant<size_t, sizeof(RealType) / sizeof(BlittedElement)> NumElements;
static void BlitLoad(const BlittedElement* pSource, RealType& target)
{
BlittedElement* pTarget = alias_cast<BlittedElement*>(&target);
for (size_t i = 0; i < NumElements::value; ++i, ++pSource, ++pTarget)
{
* pTarget = *pSource;
}
}
static void BlitStore(const RealType& source, BlittedElement* pTarget)
{
const BlittedElement* pSource = alias_cast<const BlittedElement*>(&source);
for (size_t i = 0; i < NumElements::value; ++i, ++pSource, ++pTarget)
{
* pTarget = *pSource;
}
}
};
}
// Load RealType from unaligned memory using some blittable type.
// The source memory must be suitably aligned for accessing BlittedElement.
// If no memory alignment can be guaranteed, use char for BlittedElement.
template<typename RealType, typename BlittedElement>
inline void LoadUnaligned(const BlittedElement* pMemory, RealType& value,
typename std::enable_if<(std::alignment_of<RealType>::value > std::alignment_of<BlittedElement>::value)>::type* = nullptr)
{
Detail::Blitter<RealType, BlittedElement>::BlitLoad(pMemory, value);
}
// Load RealType from aligned memory (fallback overload).
// This is used if there is no reason to call the blitter, because sufficient alignment is guaranteed by BlittedElement.
template<typename RealType, typename BlittedElement>
inline void LoadUnaligned(const BlittedElement* pMemory, RealType& value,
typename std::enable_if<(std::alignment_of<RealType>::value <= std::alignment_of<BlittedElement>::value)>::type* = nullptr)
{
value = *alias_cast<RealType*>(pMemory);
}
// Store to unaligned memory using some blittable type.
// The target memory must be suitably aligned for accessing BlittedElement.
// If no memory alignment can be guaranteed, use char for BlittedElement.
template<typename RealType, typename BlittedElement>
inline void StoreUnaligned(BlittedElement* pMemory, const RealType& value,
typename std::enable_if<(std::alignment_of<RealType>::value > std::alignment_of<BlittedElement>::value)>::type* = nullptr)
{
Detail::Blitter<RealType, BlittedElement>::BlitStore(value, pMemory);
}
// Store to aligned memory (fallback overload).
// This is used if there is no reason to call the blitter, because sufficient alignment is guaranteed by BlittedElement.
template<typename RealType, typename BlittedElement>
inline void StoreUnaligned(BlittedElement* pMemory, const RealType& value,
typename std::enable_if<(std::alignment_of<RealType>::value <= std::alignment_of<BlittedElement>::value)>::type* = nullptr)
{
*alias_cast<RealType*>(pMemory) = value;
}
// Pads the given pointer to the next possible aligned location for RealType
// Use this to ensure RealType can be referenced in some buffer of BlittedElement's, without using LoadUnaligned/StoreUnaligned
template<typename RealType, typename BlittedElement>
inline BlittedElement* AlignPointer(BlittedElement* pMemory,
typename std::enable_if<(std::alignment_of<RealType>::value % std::alignment_of<BlittedElement>::value) == 0>::type* = nullptr)
{
const size_t align = std::alignment_of<RealType>::value;
const size_t mask = align - 1;
const size_t address = reinterpret_cast<size_t>(pMemory);
const size_t offset = (align - (address & mask)) & mask;
return pMemory + (offset / sizeof(BlittedElement));
}
// Pads the given address to the next possible aligned location for RealType
// Use this to ensure RealType can be referenced inside memory, without using LoadUnaligned/StoreUnaligned
template<typename RealType>
inline size_t AlignAddress(size_t address)
{
return reinterpret_cast<size_t>(AlignPointer<RealType>(reinterpret_cast<char*>(address)));
}
// Provides aligned storage for T, optionally aligned at a specific boundary (default being the native alignment of T)
// The specified T is not initialized automatically, use of placement new/delete is the user's responsibility
template<typename T, size_t Align = std::alignment_of<T>::value>
struct SUninitialized
{
typedef typename std::aligned_storage<sizeof(T), Align>::type Storage;
Storage storage;
void DefaultConstruct()
{
new(static_cast<void*>(&storage))T();
}
void CopyConstruct(const T& value)
{
new(static_cast<void*>(&storage))T(value);
}
void MoveConstruct(T&& value)
{
new(static_cast<void*>(&storage))T(std::move(value));
}
void Destruct()
{
alias_cast<T*>(&storage)->~T();
}
operator T& ()
{
return *alias_cast<T*>(&storage);
}
};