Add indirect range (#562)

* Add indirect range

The ranges currently either completely own the parent range, or it is
a static and thus completely shared.

The indirect range allows sharing without it being global.

Co-authored-by: Nathaniel Filardo <nfilardo@microsoft.com>
This commit is contained in:
Matthew Parkinson
2022-09-21 11:15:44 +01:00
committed by GitHub
parent fb85216386
commit 591dc4c77f
3 changed files with 86 additions and 0 deletions

View File

@@ -5,6 +5,7 @@
#include "defaultpagemapentry.h"
#include "empty_range.h"
#include "globalrange.h"
#include "indirectrange.h"
#include "largebuddyrange.h"
#include "logrange.h"
#include "pagemap.h"

View File

@@ -0,0 +1,54 @@
#pragma once
#include "../ds/ds.h"
#include "empty_range.h"
namespace snmalloc
{
/**
* Stores a references to the parent range so that it can be shared
* without `static` scope.
*
* This could be used to allow multiple allocators on a single region of
* memory.
*/
struct IndirectRange
{
template<typename ParentRange = EmptyRange<>>
class Type : public RefParent<ParentRange>
{
using RefParent<ParentRange>::parent;
public:
static constexpr bool Aligned = ParentRange::Aligned;
static_assert(
ParentRange::ConcurrencySafe,
"IndirectRange requires a concurrency safe parent.");
static constexpr bool ConcurrencySafe = true;
using ChunkBounds = typename ParentRange::ChunkBounds;
constexpr Type() = default;
CapPtr<void, ChunkBounds> alloc_range(size_t size)
{
return parent->alloc_range(size);
}
void dealloc_range(CapPtr<void, ChunkBounds> base, size_t size)
{
parent->dealloc_range(base, size);
}
/**
* Points the parent reference to the given range.
*/
void set_parent(ParentRange* p)
{
parent = p;
}
};
};
} // namespace snmalloc

View File

@@ -130,4 +130,35 @@ namespace snmalloc
}
};
/**
* Helper class for allowing a range to be navigated to find an
* ancestor of a specific type. The parent is a pointer to a range;
* this allows the parent to be shared.
*/
template<typename Parent>
class RefParent
{
protected:
Parent* parent{};
public:
/**
* Returns the outermost Ancestor with the correct type.
*
* Fails to compile if no such ancestor exists.
*/
template<typename Anc>
Anc* ancestor()
{
if constexpr (std::is_same_v<Anc, Parent>)
{
return parent;
}
else
{
return parent->template ancestor<Anc>();
}
}
};
} // namespace snmalloc