From 864d4cf84e8c283a98e8d7a6bf4499950b49a867 Mon Sep 17 00:00:00 2001 From: Johnny Shaw Date: Tue, 9 Jul 2024 11:22:03 -0600 Subject: [PATCH] allocator concept requirements --- radiant/Memory.h | 16 ++++++++++++++++ radiant/Result.h | 4 ++-- radiant/SharedPtr.h | 6 ++++++ radiant/TotallyRad.h | 24 +++++++++++++++++++++--- radiant/TypeWrapper.h | 2 +- radiant/Vector.h | 2 +- 6 files changed, 47 insertions(+), 7 deletions(-) diff --git a/radiant/Memory.h b/radiant/Memory.h index d0562b0..e82a5a3 100644 --- a/radiant/Memory.h +++ b/radiant/Memory.h @@ -15,6 +15,7 @@ #pragma once #include "radiant/TotallyRad.h" +#include "radiant/TypeTraits.h" // // Users of Radiant may define their own default allocator. Radiant itself @@ -123,4 +124,19 @@ class Allocator }; #endif +// +// Radiant allocator concept requires: +// - Destruction does not throw. +// - Copying does not throw. +// - Moving does not throw. +// - Freeing memory does not throw. +// +template +RAD_INLINE_VAR constexpr bool AllocatorRequires = + (IsNoThrowDtor && // + IsNoThrowCopyCtor && IsNoThrowCopyAssign && // + IsNoThrowMoveCtor && IsNoThrowMoveAssign && + noexcept(DeclVal().Free(nullptr)) && + noexcept(DeclVal().FreeBytes(nullptr))); + } // namespace rad diff --git a/radiant/Result.h b/radiant/Result.h index 87d0066..62ad158 100644 --- a/radiant/Result.h +++ b/radiant/Result.h @@ -326,8 +326,8 @@ class RAD_NODISCARD Result final : private detail::ResultStorage using typename StorageType::OkType; using typename StorageType::ErrType; - RAD_S_ASSERT_NOTHROW_MOVE((IsNoThrowMoveCtor && IsNoThrowMoveAssign && - IsNoThrowMoveCtor && IsNoThrowMoveAssign)); + RAD_S_ASSERT_NOTHROW_MOVE_T(T); + RAD_S_ASSERT_NOTHROW_MOVE_T(E); constexpr Result() noexcept : StorageType(ResultEmptyTag) diff --git a/radiant/SharedPtr.h b/radiant/SharedPtr.h index c85ace9..029dfb3 100644 --- a/radiant/SharedPtr.h +++ b/radiant/SharedPtr.h @@ -180,6 +180,8 @@ class PtrBlock final : public PtrBlockBase using ValueType = T; using PairType = EmptyOptimizedPair; + RAD_S_ASSERT_ALLOCATOR_REQUIRES_T(TAlloc); + template PtrBlock(const AllocatorType& alloc, TArgs&&... args) noexcept( noexcept(PairType(alloc, Forward(args)...))) @@ -956,6 +958,8 @@ SharedPtr AllocateShared(const TAlloc& alloc, TArgs&&... args) // noexcept(noexcept(detail::AllocateSharedImpl::AllocateShared( alloc, Forward(args)...))) { + RAD_S_ASSERT_ALLOCATOR_REQUIRES_T(TAlloc); + return detail::AllocateSharedImpl::AllocateShared( alloc, Forward(args)...); @@ -972,6 +976,8 @@ template SharedPtr MakeShared(TArgs&&... args) noexcept( noexcept(AllocateShared(DeclVal(), Forward(args)...))) { + RAD_S_ASSERT_ALLOCATOR_REQUIRES_T(TAlloc); + TAlloc alloc; return AllocateShared(alloc, Forward(args)...); } diff --git a/radiant/TotallyRad.h b/radiant/TotallyRad.h index 78fcd6b..8180005 100644 --- a/radiant/TotallyRad.h +++ b/radiant/TotallyRad.h @@ -270,7 +270,7 @@ inline bool DoAssert(const char* Assertion, const char* File, int Line) #endif // -// Enables assertions the move operations do not throw exceptions. +// Enables assertions that move operations do not throw exceptions. // // Core Guideline: A throwing move violates most people’s reasonable // assumptions. A non-throwing move will be used more efficiently by @@ -282,15 +282,33 @@ inline bool DoAssert(const char* Assertion, const char* File, int Line) #if RAD_ENABLE_NOTHROW_MOVE_ASSERTIONS #define RAD_S_ASSERT_NOTHROW_MOVE(x) \ RAD_S_ASSERTMSG(x, "move operations should not throw") - #define RAD_S_ASSERT_NOTHROW_MOVE_T(x) \ - RAD_S_ASSERTMSG(IsNoThrowMoveCtor&& IsNoThrowMoveAssign, \ + RAD_S_ASSERTMSG(IsNoThrowMoveCtor&& IsNoThrowMoveAssign, \ "move operations should not throw") #else #define RAD_S_ASSERT_NOTHROW_MOVE(x) RAD_S_ASSERT(true) #define RAD_S_ASSERT_NOTHROW_MOVE_T(x) RAD_S_ASSERT(true) #endif +// +// Enables assertions that allocators meet the Radiant allocator concept +// requirements. +// +// See: rad::AllocatorRequires +// +#ifndef RAD_ENABLE_ALLOCATOR_REQUIRES_ASSERTIONS +#define RAD_ENABLE_ALLOCATOR_REQUIRES_ASSERTIONS 1 +#endif +#if RAD_ENABLE_ALLOCATOR_REQUIRES_ASSERTIONS +#define RAD_S_ASSERT_ALLOCATOR_REQUIRES(x) \ + RAD_S_ASSERTMSG(x, "allocator requirements not met") +#define RAD_S_ASSERT_ALLOCATOR_REQUIRES_T(x) \ + RAD_S_ASSERTMSG(AllocatorRequires, "allocator requirements not met") +#else +#define RAD_S_ASSERT_ALLOCATOR_REQUIRES(x) RAD_S_ASSERT(true) +#define RAD_S_ASSERT_ALLOCATOR_REQUIRES_T(x) RAD_S_ASSERT(true) +#endif + #define RAD_NOT_COPYABLE(x) \ x(x const&) = delete; \ x& operator=(x const&) = delete diff --git a/radiant/TypeWrapper.h b/radiant/TypeWrapper.h index b9ed7d1..2b7dfdb 100644 --- a/radiant/TypeWrapper.h +++ b/radiant/TypeWrapper.h @@ -33,7 +33,7 @@ class TypeWrapper using Type = T; - RAD_S_ASSERT_NOTHROW_MOVE((IsNoThrowMoveCtor && IsNoThrowMoveAssign)); + RAD_S_ASSERT_NOTHROW_MOVE_T(T); template , int> = 0> constexpr TypeWrapper() noexcept(IsNoThrowDefaultCtor) diff --git a/radiant/Vector.h b/radiant/Vector.h index cd59555..5a8201c 100644 --- a/radiant/Vector.h +++ b/radiant/Vector.h @@ -47,7 +47,7 @@ class Vector final using OtherType = Vector; RAD_S_ASSERT_NOTHROW_MOVE_T(T); - RAD_S_ASSERT_NOTHROW_MOVE_T(TAllocator); + RAD_S_ASSERT_ALLOCATOR_REQUIRES_T(TAllocator); ~Vector() {