style(*): add comments and attribute specifiers

This commit is contained in:
2022-12-29 21:55:02 +08:00
parent b75cb30f4f
commit 9368a49806
15 changed files with 916 additions and 268 deletions

View File

@ -10,8 +10,17 @@ NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Memory)
/** Check if an alignment is an integer power of 2. */
FORCEINLINE constexpr bool IsValidAlignment(size_t Alignment) { return !(Alignment & (Alignment - 1)); }
/**
* Aligns a value to the nearest higher multiple of 'Alignment', which must be a power of 2.
*
* @param InValue - The value to align.
* @param Alignment - The alignment value, must be a power of 2.
*
* @return The value aligned up to the specified alignment.
*/
template <typename T> requires (CIntegral<T> || CPointer<T>)
FORCEINLINE constexpr T Align(T InValue, size_t Alignment)
{
@ -19,6 +28,14 @@ FORCEINLINE constexpr T Align(T InValue, size_t Alignment)
return (T)(((uint64)(InValue) + static_cast<uint64>(Alignment) - 1) & ~(static_cast<uint64>(Alignment) - 1));
}
/**
* Aligns a value to the nearest lower multiple of 'Alignment', which must be a power of 2.
*
* @param InValue - The value to align.
* @param Alignment - The alignment value, must be a power of 2.
*
* @return The value aligned down to the specified alignment.
*/
template <typename T> requires (CIntegral<T> || CPointer<T>)
FORCEINLINE constexpr T AlignDown(T InValue, size_t Alignment)
{
@ -26,13 +43,28 @@ FORCEINLINE constexpr T AlignDown(T InValue, size_t Alignment)
return (T)((uint64)(InValue) & ~(static_cast<uint64>(Alignment) - 1));
}
/**
* Aligns a value to the nearest higher multiple of 'Alignment'.
*
* @param InValue - The value to align.
* @param Alignment - The alignment value, can be any arbitrary value.
*
* @return The value aligned up to the specified alignment.
*/
template <typename T> requires (CIntegral<T> || CPointer<T>)
FORCEINLINE constexpr T AlignArbitrary(T InValue, size_t Alignment)
{
checkf(IsValidAlignment(Alignment), TEXT("The alignment value must be an integer power of 2."));
return (T)((((uint64)(InValue) + static_cast<uint64>(Alignment) - 1) / static_cast<uint64>(Alignment)) * static_cast<uint64>(Alignment));
}
/**
* Checks if a pointer is aligned to the specified alignment.
*
* @param InValue - The value to align.
* @param Alignment - The alignment value, must be a power of 2.
*
* @return true if the pointer is aligned to the specified alignment, false otherwise.
*/
template <typename T> requires (CIntegral<T> || CPointer<T>)
FORCEINLINE constexpr bool IsAligned(T InValue, size_t Alignment)
{

View File

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "CoreTypes.h"
#include "TypeTraits/TypeTraits.h"
@ -13,100 +13,280 @@ NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Memory)
/**
* Default allocator alignment.
* Blocks >= 16 bytes will be 16-byte-aligned, Blocks < 16 will be 8-byte aligned. If the allocator does
* not support allocation alignment, the alignment will be ignored.
*/
inline constexpr size_t DefaultAlignment = 0;
/**
* Minimum allocator alignment.
*/
inline constexpr size_t MinimumAlignment = 8;
#ifdef __cpp_lib_hardware_interference_size
inline constexpr size_t DestructiveInterference = std::hardware_destructive_interference_size;
/**
* Minimum offset between two objects to avoid false sharing.
*
* struct FTwoCacheLiner { // occupies two cache lines
* alignas(DestructiveInterference) TAtomic<uint64> X;
* alignas(DestructiveInterference) TAtomic<uint64> Y;
* };
*
*/
inline constexpr size_t DestructiveInterference = std::hardware_destructive_interference_size;
/**
* Maximum size of contiguous memory to promote true sharing.
*
* struct alignas(ConstructiveInterference) FOneCacheLiner { // occupies one cache line
* TAtomic<uint64> X;
* TAtomic<uint64> Y;
* };
*
*/
inline constexpr size_t ConstructiveInterference = std::hardware_constructive_interference_size;
#else
/**
* Minimum offset between two objects to avoid false sharing.
*
* struct FTwoCacheLiner { // occupies two cache lines
* alignas(DestructiveInterference) TAtomic<uint64> X;
* alignas(DestructiveInterference) TAtomic<uint64> Y;
* };
*
*/
inline constexpr size_t DestructiveInterference = 64;
/**
* Maximum size of contiguous memory to promote true sharing.
*
* struct alignas(ConstructiveInterference) FOneCacheLiner { // occupies one cache line
* TAtomic<uint64> X;
* TAtomic<uint64> Y;
* };
*
*/
inline constexpr size_t ConstructiveInterference = 64;
#endif
/**
* Copies 'Count' bytes from the buffer pointed to by 'Source' to the buffer pointed to by 'Destination'.
* The buffers may overlap, copying takes place as if the characters were copied to a temporary character
* array and then the characters were copied from the array to 'Destination'.
*
* @param Destination - The pointer to the memory location to copy to.
* @param Source - The pointer to the memory location to copy from.
* @param Count - The number of bytes to copy.
*
* @return Destination
*/
FORCEINLINE void* Memmove(void* Destination, const void* Source, size_t Count)
{
return std::memmove(Destination, Source, Count);
}
/**
* Reinterprets the buffers pointed to by 'BufferLHS' and 'BufferRHS' as arrays of unsigned char and
* compares the first 'Count' characters of these arrays. The comparison is done lexicographically.
* The sign of the result is the sign of the difference between the values of the first pair of bytes
* (both interpreted as unsigned char) that differ in the objects being compared.
*
* @param BufferLHS - The pointers to the memory buffers to compare.
* @param BufferRHS - The pointers to the memory buffers to compare.
* @param Count - The number of bytes to examine.
*
* @return Negative value if the first differing byte in 'BufferLHS' is less than the corresponding byte in 'BufferRHS'.
* 0 if all 'Count' bytes of 'BufferLHS' and 'BufferRHS' are equal.
* Positive value if the first differing byte in 'BufferLHS' is greater than the corresponding byte in 'BufferRHS'.
*/
FORCEINLINE int32 Memcmp(const void* BufferLHS, const void* BufferRHS, size_t Count)
{
return std::memcmp(BufferLHS, BufferRHS, Count);
}
FORCEINLINE void Memset(void* Destination, uint8 ValueToSet, size_t Count)
/**
* Copies 'ValueToSet' into each of the first 'Count' characters of the buffer pointed to by 'Destination'.
*
* @param Destination - The pointer to the buffer to fill.
* @param ValueToSet - The fill byte.
* @param Count - The number of bytes to fill.
*
* @return Destination
*/
FORCEINLINE void* Memset(void* Destination, uint8 ValueToSet, size_t Count)
{
std::memset(Destination, ValueToSet, Count);
return std::memset(Destination, ValueToSet, Count);
}
/**
* Copies 0 into each of the first 'Count' characters of the buffer pointed to by 'Destination'.
*
* @param Destination - The pointer to the buffer to fill.
* @param Count - The number of bytes to fill.
*
* @return Destination
*/
FORCEINLINE void* Memzero(void* Destination, size_t Count)
{
return std::memset(Destination, 0, Count);
}
/**
* Copies 'Count' bytes from the buffer pointed to by 'Source' to the buffer pointed to by 'Destination'.
* If the buffers overlap, the behavior is undefined.
*
* @param Destination - The pointer to the memory location to copy to.
* @param Source - The pointer to the memory location to copy from.
* @param Count - The number of bytes to copy.
*
* @return Destination
*/
FORCEINLINE void* Memcpy(void* Destination, const void* Source, size_t Count)
{
return std::memcpy(Destination, Source, Count);
}
template <typename T>
/**
* Copies the object referenced to by 'Source' to the object referenced to by 'Destination'.
* The objects may overlap, copying takes place as if the characters were copied to a temporary character
* array and then the characters were copied from the array to 'Destination'.
*
* @param Destination - The reference to the object to copy to.
* @param Source - The reference to the object to copy from.
*/
template <typename T> requires (!CPointer<T>)
FORCEINLINE void Memmove(T& Destination, const T& Source)
{
static_assert(!CPointer<T>, "For pointers use the three parameters function");
Memmove(&Destination, &Source, sizeof(T));
}
template <typename T>
/**
* Reinterprets the objects referenced to by 'BufferLHS' and 'BufferRHS' as arrays of unsigned char and
* compares the all characters of these arrays. The comparison is done lexicographically.
* The sign of the result is the sign of the difference between the values of the first pair of bytes
* (both interpreted as unsigned char) that differ in the objects being compared.
*
* @param BufferLHS - The reference to the object to compare.
* @param BufferRHS - The reference to the object to compare.
*
* @return Negative value if the first differing byte in 'BufferLHS' is less than the corresponding byte in 'BufferRHS'.
* 0 if all bytes of 'BufferLHS' and 'BufferRHS' are equal.
* Positive value if the first differing byte in 'BufferLHS' is greater than the corresponding byte in 'BufferRHS'.
*/
template <typename T> requires (!CPointer<T>)
FORCEINLINE int32 Memcmp(const T& BufferLHS, const T& BufferRHS)
{
static_assert(!CPointer<T>, "For pointers use the three parameters function");
return Memcmp(&BufferLHS, &BufferRHS, sizeof(T));
}
template <typename T>
FORCEINLINE void Memset(T& Source, uint8 ValueToSet)
/**
* Copies 'ValueToSet' into each of the all characters of the object referenced to by 'Destination'.
*
* @param Destination - The reference to the object to fill.
* @param ValueToSet - The fill byte.
*/
template <typename T> requires (!CPointer<T>)
FORCEINLINE void Memset(T& Destination, uint8 ValueToSet)
{
static_assert(!CPointer<T>, "For pointers use the three parameters function");
Memset(&Source, ValueToSet, sizeof(T));
Memset(&Destination, ValueToSet, sizeof(T));
}
template <typename T>
FORCEINLINE void Memzero(T& Source)
/**
* Copies 0 into each of the all characters of the object referenced to by 'Destination'.
*
* @param Destination - The reference to the object to fill.
* @param ValueToSet - The fill byte.
*/
template <typename T> requires (!CPointer<T>)
FORCEINLINE void Memzero(T& Destination)
{
static_assert(!CPointer<T>, "For pointers use the two parameters function");
Memzero(&Source, sizeof(T));
Memzero(&Destination, sizeof(T));
}
template <typename T>
/**
* Copies the object referenced to by 'Source' to the object referenced to by 'Destination'.
* If the objects overlap, the behavior is undefined.
*
* @param Destination - The reference to the object to copy to.
* @param Source - The reference to the object to copy from.
*/
template <typename T> requires (!CPointer<T>)
FORCEINLINE void Memcpy(T& Destination, const T& Source)
{
static_assert(!CPointer<T>, "For pointers use the three parameters function");
Memcpy(&Destination, &Source, sizeof(T));
}
FORCEINLINE void* SystemMalloc(size_t Count)
/** Fallback to std::malloc(). */
NODISCARD FORCEINLINE void* SystemMalloc(size_t Count)
{
return std::malloc(Count);
}
FORCEINLINE void* SystemRealloc(void* Ptr, size_t Count)
/** Fallback to std::realloc(). */
NODISCARD FORCEINLINE void* SystemRealloc(void* Ptr, size_t Count)
{
return std::realloc(Ptr, Count);
}
/** Fallback to std::free(). */
FORCEINLINE void SystemFree(void* Ptr)
{
std::free(Ptr);
}
REDCRAFTUTILITY_API void* Malloc(size_t Count, size_t Alignment = DefaultAlignment);
REDCRAFTUTILITY_API void* Realloc(void* Ptr, size_t Count, size_t Alignment = DefaultAlignment);
/**
* Allocates 'Count' bytes of uninitialized storage with 'Alignment'.
*
* @param Count - The number of bytes to allocate.
* @param Alignment - The alignment value, must be a power of 2.
*
* @return The non-null pointer to the beginning of newly allocated memory. To avoid a memory leak,
* the returned pointer must be deallocated with Free() or Realloc().
*
* @see DefaultAlignment
*/
NODISCARD REDCRAFTUTILITY_API void* Malloc(size_t Count, size_t Alignment = DefaultAlignment);
/**
* Reallocates the given area of memory. It must be previously allocated by Malloc() or Realloc().
*
* @param Ptr - The pointer to the memory area to be reallocated.
* @param Count - The number of bytes to allocate.
* @param Alignment - The alignment value, must be a power of 2.
*
* @return The non-null pointer to the beginning of newly allocated memory. To avoid a memory leak,
* the returned pointer must be deallocated with Free() or Realloc().
*
* @see DefaultAlignment
*/
NODISCARD REDCRAFTUTILITY_API void* Realloc(void* Ptr, size_t Count, size_t Alignment = DefaultAlignment);
/**
* Deallocates the space previously allocated by Malloc() or Realloc().
* If 'Ptr' is a nullptr, the function does nothing.
*
* @param Ptr - The pointer to the memory to deallocate.
*/
REDCRAFTUTILITY_API void Free(void* Ptr);
REDCRAFTUTILITY_API size_t QuantizeSize(size_t Count, size_t Alignment = DefaultAlignment);
/**
* For some allocators this will return the actual size that should be requested to eliminate
* internal fragmentation. The return value will always be >= 'Count'. This can be used to grow
* and shrink containers to optimal sizes.
* This call is always fast and threadsafe with no locking.
*
* @param Count - The number of bytes to allocate.
* @param Alignment - The alignment value, must be a power of 2.
*
* @return The optimized new size.
*/
NODISCARD REDCRAFTUTILITY_API size_t QuantizeSize(size_t Count, size_t Alignment = DefaultAlignment);
NAMESPACE_END(Memory)
@ -117,8 +297,8 @@ NAMESPACE_REDCRAFT_END
#pragma warning(disable : 28251)
// The global overload operators new/delete do not cross .dll boundaries, and the macros should be placed in the .cpp of each module.
#define REPLACEMENT_OPERATOR_NEW_AND_DELETE \
void* operator new(std::size_t Count) { return NAMESPACE_REDCRAFT::Memory::Malloc(Count); } \
void* operator new(std::size_t Count, std::align_val_t Alignment) { return NAMESPACE_REDCRAFT::Memory::Malloc(Count, static_cast<NAMESPACE_REDCRAFT::size_t>(Alignment)); } \
void operator delete(void* Ptr) noexcept { NAMESPACE_REDCRAFT::Memory::Free(Ptr); } \
void operator delete(void* Ptr, std::align_val_t Alignment) noexcept { NAMESPACE_REDCRAFT::Memory::Free(Ptr); }
#define REPLACEMENT_OPERATOR_NEW_AND_DELETE \
NODISCARD void* operator new(std::size_t Count) { return NAMESPACE_REDCRAFT::Memory::Malloc(Count); } \
NODISCARD void* operator new(std::size_t Count, std::align_val_t Alignment) { return NAMESPACE_REDCRAFT::Memory::Malloc(Count, static_cast<NAMESPACE_REDCRAFT::size_t>(Alignment)); } \
void operator delete(void* Ptr) noexcept { NAMESPACE_REDCRAFT::Memory::Free(Ptr); } \
void operator delete(void* Ptr, std::align_val_t Alignment) noexcept { NAMESPACE_REDCRAFT::Memory::Free(Ptr); }

View File

@ -11,6 +11,12 @@ NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Memory)
/**
* Default constructs a range of items in memory.
*
* @param Address - The address of the first memory location to construct at.
* @param Count - The number of elements to construct.
*/
template <CDefaultConstructible ElementType>
FORCEINLINE void DefaultConstruct(void* Address, size_t Count = 1)
{
@ -25,6 +31,13 @@ FORCEINLINE void DefaultConstruct(void* Address, size_t Count = 1)
}
}
/**
* Constructs a range of items into memory from a set of arguments. The arguments come from an another array.
*
* @param Destination - The memory location to start copying into.
* @param Source - A pointer to the first argument to pass to the constructor.
* @param Count - The number of elements to copy.
*/
template <typename DestinationElementType, typename SourceElementType = DestinationElementType>
requires (CConstructibleFrom<DestinationElementType, const SourceElementType&>)
FORCEINLINE void Construct(void* Destination, const SourceElementType* Source, size_t Count = 1)
@ -45,6 +58,13 @@ FORCEINLINE void Construct(void* Destination, const SourceElementType* Source, s
}
}
/**
* Copy constructs a range of items into memory.
*
* @param Destination - The memory location to start copying into.
* @param Source - A pointer to the first item to copy from.
* @param Count - The number of elements to copy.
*/
template <CCopyConstructible ElementType>
FORCEINLINE void CopyConstruct(void* Destination, const ElementType* Source, size_t Count = 1)
{
@ -64,6 +84,13 @@ FORCEINLINE void CopyConstruct(void* Destination, const ElementType* Source, siz
}
}
/**
* Move constructs a range of items into memory.
*
* @param Destination - The memory location to start moving into.
* @param Source - A pointer to the first item to move from.
* @param Count - The number of elements to move.
*/
template <CMoveConstructible ElementType>
FORCEINLINE void MoveConstruct(void* Destination, ElementType* Source, size_t Count = 1)
{
@ -83,6 +110,13 @@ FORCEINLINE void MoveConstruct(void* Destination, ElementType* Source, size_t Co
}
}
/**
* Copy assigns a range of items.
*
* @param Destination - The memory location to start assigning to.
* @param Source - A pointer to the first item to assign.
* @param Count - The number of elements to assign.
*/
template <CCopyAssignable ElementType>
FORCEINLINE void CopyAssign(ElementType* Destination, const ElementType* Source, size_t Count = 1)
{
@ -102,6 +136,13 @@ FORCEINLINE void CopyAssign(ElementType* Destination, const ElementType* Source,
}
}
/**
* Move assigns a range of items.
*
* @param Destination - The memory location to start assigning to.
* @param Source - A pointer to the first item to assign.
* @param Count - The number of elements to assign.
*/
template <CMoveAssignable ElementType>
FORCEINLINE void MoveAssign(ElementType* Destination, ElementType* Source, size_t Count = 1)
{
@ -121,6 +162,12 @@ FORCEINLINE void MoveAssign(ElementType* Destination, ElementType* Source, size_
}
}
/**
* Destructs a range of items in memory.
*
* @param Elements - A pointer to the first item to destruct.
* @param Count - The number of elements to destruct.
*/
template <CDestructible ElementType>
FORCEINLINE void Destruct(ElementType* Element, size_t Count = 1)
{