Add C++ concept for PAL
This will not be used unless the C++ standard version is raised to 20. As concepts and C++20 more generally are quite new, this does not do so. Nevertheless, the use of concepts can improve the local development experience as type mismatches are discovered earlier (at template invocation rather than only during expansion).
This commit is contained in:
committed by
Matthew Parkinson
parent
a3d54779c8
commit
3e21ea1f65
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/concept.h"
|
||||
#include "pal_concept.h"
|
||||
#include "pal_consts.h"
|
||||
|
||||
// If simultating OE, then we need the underlying platform
|
||||
@@ -63,7 +65,7 @@ namespace snmalloc
|
||||
/**
|
||||
* Query whether the PAL supports a specific feature.
|
||||
*/
|
||||
template<PalFeatures F, typename PAL = Pal>
|
||||
template<PalFeatures F, SNMALLOC_CONCEPT(ConceptPAL) PAL = Pal>
|
||||
constexpr static bool pal_supports = (PAL::pal_features & F) == F;
|
||||
|
||||
// Used to keep Superslab metadata committed.
|
||||
|
||||
104
src/pal/pal_concept.h
Normal file
104
src/pal/pal_concept.h
Normal file
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cpp_concepts
|
||||
# include "../ds/concept.h"
|
||||
# include "pal_consts.h"
|
||||
|
||||
# include <utility>
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
/**
|
||||
* PALs must advertize the bit vector of their supported features and the
|
||||
* platform's page size. This concept enforces that these are indeed
|
||||
* constants that fit in the desired types. (This is subtly different from
|
||||
* saying that they are the required types; C++ may handle constants without
|
||||
* much regard for their claimed type.)
|
||||
*/
|
||||
template<typename PAL>
|
||||
concept ConceptPAL_static_members = requires()
|
||||
{
|
||||
typename std::integral_constant<uint64_t, PAL::pal_features>;
|
||||
typename std::integral_constant<size_t, PAL::page_size>;
|
||||
};
|
||||
|
||||
/**
|
||||
* PALs expose an error reporting function which takes a const C string.
|
||||
*/
|
||||
template<typename PAL>
|
||||
concept ConceptPAL_error = requires(const char* const str)
|
||||
{
|
||||
{ PAL::error(str) } -> ConceptSame<void>;
|
||||
};
|
||||
|
||||
/**
|
||||
* PALs expose a basic library of memory operations.
|
||||
*/
|
||||
template<typename PAL>
|
||||
concept ConceptPAL_memops = requires(PAL p, void* vp, size_t sz)
|
||||
{
|
||||
{ p.notify_not_using(vp, sz) } noexcept -> ConceptSame<void>;
|
||||
|
||||
/* For reasons unknown, these seem to tickle some bug in MSVC */
|
||||
# if !defined(_MSC_VER)
|
||||
{ p.template notify_using<NoZero>(vp, sz) } noexcept
|
||||
-> ConceptSame<void>;
|
||||
{ p.template notify_using<YesZero>(vp, sz) } noexcept
|
||||
-> ConceptSame<void>;
|
||||
# endif
|
||||
|
||||
{ p.template zero<false>(vp, sz) } noexcept -> ConceptSame<void>;
|
||||
{ p.template zero<true>(vp, sz) } noexcept -> ConceptSame<void>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Absent any feature flags, the PAL must support a crude primitive allocator
|
||||
*/
|
||||
template<typename PAL>
|
||||
concept ConceptPAL_reserve_at_least = requires(PAL p, void* vp, size_t sz)
|
||||
{
|
||||
{ p.reserve_at_least(sz) } noexcept
|
||||
-> ConceptSame<std::pair<void*, size_t>>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Some PALs expose a richer allocator which understands aligned allocations
|
||||
*/
|
||||
template<typename PAL>
|
||||
concept ConceptPAL_reserve_aligned = requires(PAL p, size_t sz)
|
||||
{
|
||||
{ p.template reserve_aligned<false>(sz) } noexcept -> ConceptSame<void*>;
|
||||
{ p.template reserve_aligned<true>(sz) } noexcept -> ConceptSame<void*>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Some PALs can provide memory pressure callbacks.
|
||||
*/
|
||||
template<typename PAL>
|
||||
concept ConceptPAL_mem_low_notify =
|
||||
requires(PAL p, PalNotificationObject* pno)
|
||||
{
|
||||
{ p.expensive_low_memory_check() } -> ConceptSame<bool>;
|
||||
{ p.register_for_low_memory_callback(pno) } -> ConceptSame<void>;
|
||||
};
|
||||
|
||||
/**
|
||||
* PALs ascribe to the conjunction of several concepts. These are broken
|
||||
* out by the shape of the requires() quantifiers required and by any
|
||||
* requisite claimed pal_features. PALs not claiming particular features
|
||||
* are, naturally, not bound by the corresponding concept.
|
||||
*/
|
||||
template<typename PAL>
|
||||
concept ConceptPAL =
|
||||
ConceptPAL_static_members<PAL> &&
|
||||
ConceptPAL_error<PAL> &&
|
||||
ConceptPAL_memops<PAL> &&
|
||||
(!(PAL::pal_features & LowMemoryNotification) ||
|
||||
ConceptPAL_mem_low_notify<PAL>) &&
|
||||
(!!(PAL::pal_features & AlignedAllocation) ||
|
||||
ConceptPAL_reserve_at_least<PAL>) &&
|
||||
(!(PAL::pal_features & AlignedAllocation) ||
|
||||
ConceptPAL_reserve_aligned<PAL>);
|
||||
|
||||
} // namespace snmalloc
|
||||
#endif
|
||||
Reference in New Issue
Block a user