Skip to content

Commit

Permalink
Merge pull request #26 from archonitelabs/allocator-requirements
Browse files Browse the repository at this point in the history
allocator concept requirements
  • Loading branch information
jxy-s authored Jul 11, 2024
2 parents 11f033f + 864d4cf commit 52dd6a2
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 7 deletions.
16 changes: 16 additions & 0 deletions radiant/Memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 <typename T>
RAD_INLINE_VAR constexpr bool AllocatorRequires =
(IsNoThrowDtor<T> && //
IsNoThrowCopyCtor<T> && IsNoThrowCopyAssign<T> && //
IsNoThrowMoveCtor<T> && IsNoThrowMoveAssign<T> &&
noexcept(DeclVal<T>().Free(nullptr)) &&
noexcept(DeclVal<T>().FreeBytes(nullptr)));

} // namespace rad
4 changes: 2 additions & 2 deletions radiant/Result.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,8 @@ class RAD_NODISCARD Result final : private detail::ResultStorage<T, E>
using typename StorageType::OkType;
using typename StorageType::ErrType;

RAD_S_ASSERT_NOTHROW_MOVE((IsNoThrowMoveCtor<T> && IsNoThrowMoveAssign<T> &&
IsNoThrowMoveCtor<E> && IsNoThrowMoveAssign<E>));
RAD_S_ASSERT_NOTHROW_MOVE_T(T);
RAD_S_ASSERT_NOTHROW_MOVE_T(E);

constexpr Result() noexcept
: StorageType(ResultEmptyTag)
Expand Down
6 changes: 6 additions & 0 deletions radiant/SharedPtr.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ class PtrBlock final : public PtrBlockBase
using ValueType = T;
using PairType = EmptyOptimizedPair<AllocatorType, ValueType>;

RAD_S_ASSERT_ALLOCATOR_REQUIRES_T(TAlloc);

template <typename... TArgs>
PtrBlock(const AllocatorType& alloc, TArgs&&... args) noexcept(
noexcept(PairType(alloc, Forward<TArgs>(args)...)))
Expand Down Expand Up @@ -956,6 +958,8 @@ SharedPtr<T> AllocateShared(const TAlloc& alloc, TArgs&&... args) //
noexcept(noexcept(detail::AllocateSharedImpl::AllocateShared<T, TAlloc>(
alloc, Forward<TArgs>(args)...)))
{
RAD_S_ASSERT_ALLOCATOR_REQUIRES_T(TAlloc);

return detail::AllocateSharedImpl::AllocateShared<T, TAlloc>(
alloc,
Forward<TArgs>(args)...);
Expand All @@ -972,6 +976,8 @@ template <typename T, typename TAlloc RAD_ALLOCATOR_EQ(T), typename... TArgs>
SharedPtr<T> MakeShared(TArgs&&... args) noexcept(
noexcept(AllocateShared<T>(DeclVal<TAlloc&>(), Forward<TArgs>(args)...)))
{
RAD_S_ASSERT_ALLOCATOR_REQUIRES_T(TAlloc);

TAlloc alloc;
return AllocateShared<T>(alloc, Forward<TArgs>(args)...);
}
Expand Down
24 changes: 21 additions & 3 deletions radiant/TotallyRad.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<T>&& IsNoThrowMoveAssign<T>, \
RAD_S_ASSERTMSG(IsNoThrowMoveCtor<x>&& IsNoThrowMoveAssign<x>, \
"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<x>, "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
Expand Down
2 changes: 1 addition & 1 deletion radiant/TypeWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class TypeWrapper<T, false>

using Type = T;

RAD_S_ASSERT_NOTHROW_MOVE((IsNoThrowMoveCtor<T> && IsNoThrowMoveAssign<T>));
RAD_S_ASSERT_NOTHROW_MOVE_T(T);

template <typename U = T, EnIf<IsDefaultCtor<U>, int> = 0>
constexpr TypeWrapper() noexcept(IsNoThrowDefaultCtor<T>)
Expand Down
2 changes: 1 addition & 1 deletion radiant/Vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class Vector final
using OtherType = Vector<T, OtherTAllocator, OtherTInlineCount>;

RAD_S_ASSERT_NOTHROW_MOVE_T(T);
RAD_S_ASSERT_NOTHROW_MOVE_T(TAllocator);
RAD_S_ASSERT_ALLOCATOR_REQUIRES_T(TAllocator);

~Vector()
{
Expand Down

0 comments on commit 52dd6a2

Please sign in to comment.