Enable accessing parent ranges. (#529)

This exposes a feature on Ranges to access ranges higher up the
stack of ranges.  This could be useful for applying operations in the
middle of a pipeline like

   object_range.ancestor<SpecialRange>().init(...);

This allows some initialisation to be added to the middle of pipeline
without breaking the current coding pattern.

It also allows for bypassing some ranges

   object_range.ancestor<LargeObjectsRange>().alloc_chunk(...);

Neither are done in this commit, but both will occur in future commits.

Co-authored-by: Nathaniel Wesley Filardo <nfilardo@microsoft.com>
This commit is contained in:
Matthew Parkinson
2022-05-19 21:19:49 +01:00
committed by GitHub
parent c445de8eb4
commit 7ff10c30f1
9 changed files with 82 additions and 17 deletions

View File

@@ -1,13 +1,14 @@
#pragma once
#include "../pal/pal.h"
#include "empty_range.h"
#include "range_helpers.h"
namespace snmalloc
{
template<typename PAL, typename ParentRange = EmptyRange>
class CommitRange
class CommitRange : public ContainsParent<ParentRange>
{
ParentRange parent{};
using ContainsParent<ParentRange>::parent;
public:
/**

View File

@@ -10,9 +10,9 @@ namespace snmalloc
* and protects access with a lock.
*/
template<typename ParentRange = EmptyRange>
class GlobalRange
class GlobalRange : public StaticParent<ParentRange>
{
SNMALLOC_REQUIRE_CONSTINIT static inline ParentRange parent{};
using StaticParent<ParentRange>::parent;
/**
* This is infrequently used code, a spin lock simplifies the code

View File

@@ -189,9 +189,9 @@ namespace snmalloc
SNMALLOC_CONCEPT(ConceptBuddyRangeMeta) Pagemap,
size_t MIN_REFILL_SIZE_BITS = 0,
typename ParentRange = EmptyRange>
class LargeBuddyRange
class LargeBuddyRange : public ContainsParent<ParentRange>
{
ParentRange parent{};
using ContainsParent<ParentRange>::parent;
/**
* Maximum size of a refill

View File

@@ -1,6 +1,7 @@
#pragma once
#include "empty_range.h"
#include "range_helpers.h"
namespace snmalloc
{
@@ -11,9 +12,9 @@ namespace snmalloc
* ParentRange is what the range is logging calls to.
*/
template<size_t RangeName, typename ParentRange = EmptyRange>
class LogRange
class LogRange : public ContainsParent<ParentRange>
{
ParentRange parent{};
using ContainsParent<ParentRange>::parent;
public:
/**

View File

@@ -2,6 +2,7 @@
#include "../pal/pal.h"
#include "empty_range.h"
#include "range_helpers.h"
namespace snmalloc
{
@@ -9,9 +10,9 @@ namespace snmalloc
SNMALLOC_CONCEPT(ConceptBackendMetaRange) Pagemap,
bool CanConsolidate = true,
typename ParentRange = EmptyRange>
class PagemapRegisterRange
class PagemapRegisterRange : public ContainsParent<ParentRange>
{
ParentRange state{};
using ContainsParent<ParentRange>::parent;
public:
/**
@@ -28,7 +29,7 @@ namespace snmalloc
capptr::Chunk<void> alloc_range(size_t size)
{
auto base = state.alloc_range(size);
auto base = parent.alloc_range(size);
if (base != nullptr)
Pagemap::register_range(address_cast(base), size);

View File

@@ -69,4 +69,65 @@ namespace snmalloc
*/
template<typename... Args>
using Pipe = typename PipeImpl<Args...>::result;
/**
* Helper class for allowing a range to be navigated to find an
* ancestor of a specific type. The parent is an instance field.
*/
template<typename Parent>
class ContainsParent
{
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>();
}
}
};
/**
* Helper class for allowing a range to be navigated to find an
* ancestor of a specific type. The parent is a static field.
*/
template<typename Parent>
class StaticParent
{
protected:
SNMALLOC_REQUIRE_CONSTINIT inline static 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

View File

@@ -144,9 +144,9 @@ namespace snmalloc
};
template<typename ParentRange = EmptyRange>
class SmallBuddyRange
class SmallBuddyRange : public ContainsParent<ParentRange>
{
ParentRange parent{};
using ContainsParent<ParentRange>::parent;
static constexpr size_t MIN_BITS =
bits::next_pow2_bits_const(sizeof(FreeChunk));

View File

@@ -1,6 +1,7 @@
#pragma once
#include "empty_range.h"
#include "range_helpers.h"
#include <atomic>
@@ -10,9 +11,9 @@ namespace snmalloc
* Used to measure memory usage.
*/
template<typename ParentRange = EmptyRange>
class StatsRange
class StatsRange : public ContainsParent<ParentRange>
{
ParentRange parent{};
using ContainsParent<ParentRange>::parent;
static inline std::atomic<size_t> current_usage{};
static inline std::atomic<size_t> peak_usage{};

View File

@@ -10,9 +10,9 @@ namespace snmalloc
* the end of the large allocation.
*/
template<typename PAL, size_t RATIO_BITS, typename ParentRange = EmptyRange>
class SubRange
class SubRange : public ContainsParent<ParentRange>
{
ParentRange parent{};
using ContainsParent<ParentRange>::parent;
public:
/**