/* * 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 #include namespace Detail { template struct Blitter { static_assert(std::is_trivial::value, "Blittable elements should be trivial (ie, integral types)"); static_assert((std::alignment_of::value < std::alignment_of::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 NumElements; static void BlitLoad(const BlittedElement* pSource, RealType& target) { BlittedElement* pTarget = alias_cast(&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(&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 inline void LoadUnaligned(const BlittedElement* pMemory, RealType& value, typename std::enable_if<(std::alignment_of::value > std::alignment_of::value)>::type* = nullptr) { Detail::Blitter::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 inline void LoadUnaligned(const BlittedElement* pMemory, RealType& value, typename std::enable_if<(std::alignment_of::value <= std::alignment_of::value)>::type* = nullptr) { value = *alias_cast(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 inline void StoreUnaligned(BlittedElement* pMemory, const RealType& value, typename std::enable_if<(std::alignment_of::value > std::alignment_of::value)>::type* = nullptr) { Detail::Blitter::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 inline void StoreUnaligned(BlittedElement* pMemory, const RealType& value, typename std::enable_if<(std::alignment_of::value <= std::alignment_of::value)>::type* = nullptr) { *alias_cast(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 inline BlittedElement* AlignPointer(BlittedElement* pMemory, typename std::enable_if<(std::alignment_of::value % std::alignment_of::value) == 0>::type* = nullptr) { const size_t align = std::alignment_of::value; const size_t mask = align - 1; const size_t address = reinterpret_cast(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 inline size_t AlignAddress(size_t address) { return reinterpret_cast(AlignPointer(reinterpret_cast(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::value> struct SUninitialized { typedef typename std::aligned_storage::type Storage; Storage storage; void DefaultConstruct() { new(static_cast(&storage))T(); } void CopyConstruct(const T& value) { new(static_cast(&storage))T(value); } void MoveConstruct(T&& value) { new(static_cast(&storage))T(std::move(value)); } void Destruct() { alias_cast(&storage)->~T(); } operator T& () { return *alias_cast(&storage); } };