Added a sequential queue
This changes the slab lists to use a sequential queue. They were previously stored in a stack. This commit also tidies up some incomplete refactoring from the initial snmalloc2 work.
This commit is contained in:
committed by
Matthew Parkinson
parent
dbb7965507
commit
8ac2adc4e5
@@ -1,93 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "address.h"
|
||||
#include "defines.h"
|
||||
#include "ptrwrap.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
/**
|
||||
* TODO Rewrite for actual use, no longer Cyclic or doubly linked.
|
||||
*
|
||||
* Special class for cyclic doubly linked non-empty linked list
|
||||
*
|
||||
* This code assumes there is always one element in the list. The client
|
||||
* must ensure there is a sentinal element.
|
||||
*/
|
||||
template<template<typename> typename Ptr = Pointer>
|
||||
class CDLLNode
|
||||
{
|
||||
Ptr<CDLLNode> next{nullptr};
|
||||
|
||||
constexpr void set_next(Ptr<CDLLNode> c)
|
||||
{
|
||||
next = c;
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Single element cyclic list. This is the empty case.
|
||||
*/
|
||||
constexpr CDLLNode()
|
||||
{
|
||||
this->set_next(nullptr);
|
||||
}
|
||||
|
||||
SNMALLOC_FAST_PATH bool is_empty()
|
||||
{
|
||||
return next == nullptr;
|
||||
}
|
||||
|
||||
SNMALLOC_FAST_PATH Ptr<CDLLNode> get_next()
|
||||
{
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Single element cyclic list. This is the uninitialised case.
|
||||
*
|
||||
* This entry should never be accessed and is only used to make
|
||||
* a fake metaslab.
|
||||
*/
|
||||
constexpr CDLLNode(bool) {}
|
||||
|
||||
SNMALLOC_FAST_PATH Ptr<CDLLNode> pop()
|
||||
{
|
||||
SNMALLOC_ASSERT(!this->is_empty());
|
||||
auto result = get_next();
|
||||
set_next(result->get_next());
|
||||
return result;
|
||||
}
|
||||
|
||||
SNMALLOC_FAST_PATH void insert(Ptr<CDLLNode> item)
|
||||
{
|
||||
debug_check();
|
||||
item->set_next(this->get_next());
|
||||
set_next(item);
|
||||
debug_check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the lists invariants
|
||||
* x->next->prev = x
|
||||
* for all x in the list.
|
||||
*/
|
||||
void debug_check()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// Ptr<CDLLNode> item = this->get_next();
|
||||
// auto p = Ptr<CDLLNode>(this);
|
||||
|
||||
// do
|
||||
// {
|
||||
// SNMALLOC_ASSERT(item->prev == p);
|
||||
// p = item;
|
||||
// item = item->get_next();
|
||||
// } while (item != Ptr<CDLLNode>(this));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // namespace snmalloc
|
||||
105
src/ds/seqqueue.h
Normal file
105
src/ds/seqqueue.h
Normal file
@@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
#include "address.h"
|
||||
#include "defines.h"
|
||||
#include "ptrwrap.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
/**
|
||||
* Simple sequential queue of T.
|
||||
*
|
||||
* Linked using the T::next field.
|
||||
*/
|
||||
template<typename T>
|
||||
class SeqQueue
|
||||
{
|
||||
static_assert(
|
||||
std::is_same<decltype(T::next), T*>::value,
|
||||
"T->next must be a queue pointer to T");
|
||||
T* head{nullptr};
|
||||
T** end{&head};
|
||||
|
||||
public:
|
||||
/**
|
||||
* Empty queue
|
||||
*/
|
||||
constexpr SeqQueue() = default;
|
||||
|
||||
/**
|
||||
* Check for empty
|
||||
*/
|
||||
SNMALLOC_FAST_PATH bool is_empty()
|
||||
{
|
||||
SNMALLOC_ASSERT(end != nullptr);
|
||||
return &head == end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an element from the queue
|
||||
*
|
||||
* Assumes queue is non-empty
|
||||
*/
|
||||
SNMALLOC_FAST_PATH T* pop()
|
||||
{
|
||||
SNMALLOC_ASSERT(!this->is_empty());
|
||||
auto result = head;
|
||||
if (&(head->next) == end)
|
||||
end = &head;
|
||||
else
|
||||
head = head->next;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter
|
||||
*
|
||||
* Removes all elements that f returns true for.
|
||||
* If f returns true, then filter is not allowed to look at the
|
||||
* object again, and f is responsible for its lifetime.
|
||||
*/
|
||||
template<typename Fn>
|
||||
SNMALLOC_FAST_PATH void filter(Fn&& f)
|
||||
{
|
||||
T** prev = &head;
|
||||
// Check for empty case.
|
||||
if (prev == end)
|
||||
return;
|
||||
|
||||
while (true)
|
||||
{
|
||||
T* curr = *prev;
|
||||
// Note must read curr->next before calling `f` as `f` is allowed to
|
||||
// mutate that field.
|
||||
T* next = curr->next;
|
||||
if (f(curr))
|
||||
{
|
||||
// Remove element;
|
||||
*prev = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep element
|
||||
prev = &(curr->next);
|
||||
}
|
||||
|
||||
if (&(curr->next) == end)
|
||||
break;
|
||||
}
|
||||
|
||||
end = prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an element to the queue.
|
||||
*/
|
||||
SNMALLOC_FAST_PATH void insert(T* item)
|
||||
{
|
||||
*end = item;
|
||||
end = &(item->next);
|
||||
}
|
||||
};
|
||||
} // namespace snmalloc
|
||||
Reference in New Issue
Block a user