@ -0,0 +1,211 @@ | |||||
#pragma once | |||||
#include "gp_config.hpp" | |||||
#include "gp/buffer.hpp" | |||||
#include "gp/array.hpp" | |||||
#include "gp/integer_math.hpp" | |||||
#include <type_traits> | |||||
#include <gp/algorithm/tmp_manip.hpp> | |||||
namespace gp{ | |||||
template<typename page_allocator, size_t max_msb = 24, size_t align = 8> | |||||
class buddy{ | |||||
struct twig { | |||||
bool used : 1; | |||||
bool used_children : 1; | |||||
twig(uint8_t src) { | |||||
used = 1 & src; | |||||
used_children = 2 & src; | |||||
} | |||||
operator uint8_t() { | |||||
return used + 2 * used_children; | |||||
} | |||||
}; | |||||
struct bundle { | |||||
uint8_t a : 2; | |||||
uint8_t b : 2; | |||||
uint8_t c : 2; | |||||
uint8_t d : 2; | |||||
}; | |||||
page_allocator allocator; | |||||
gp::buffer<char> data; | |||||
static constexpr size_t max_depth = max_msb - gp::math::msb(align); | |||||
static constexpr size_t required_twigs = (1 << (max_depth + 1)) - 1; | |||||
/** | |||||
* ((max allocatable size - min allocatable size) ** 2 - 1) / 4 twigs in a bundle | |||||
**/ | |||||
static constexpr size_t span_size = required_twigs / 4 + (required_twigs % 4 != 0); | |||||
gp::array<bundle, span_size> stack; | |||||
twig get_twig(size_t idx) { | |||||
auto far = idx / 4; | |||||
auto local = idx % 4; | |||||
auto& group = stack[far]; | |||||
switch(local) { | |||||
case 0: | |||||
return group.a; | |||||
case 1: | |||||
return group.b; | |||||
case 2: | |||||
return group.c; | |||||
case 3: | |||||
return group.d; | |||||
} | |||||
} | |||||
void set_twig(size_t idx, twig v) { | |||||
auto far = idx / 4; | |||||
auto local = idx % 4; | |||||
auto& group = stack[far]; | |||||
switch(local) { | |||||
case 0: | |||||
group.a = v; | |||||
return; | |||||
case 1: | |||||
group.b = v; | |||||
return; | |||||
case 2: | |||||
group.c = v; | |||||
return; | |||||
case 3: | |||||
group.d = v; | |||||
return; | |||||
} | |||||
} | |||||
constexpr size_t size_to_depth(size_t sz) { | |||||
auto pow2 = gp::math::msb(sz); | |||||
return gp::max(max_depth ,max_msb - pow2 - (0 != sz % (1 << pow2))); | |||||
} | |||||
constexpr size_t depth_to_size(size_t depth) { | |||||
return 1 << (max_depth - depth + gp::math::msb(align)); | |||||
} | |||||
size_t get_left(size_t index) { | |||||
return ((index + 1) << 1) - 1; | |||||
} | |||||
size_t get_right(size_t index) { | |||||
return ((index + 1) << 1); | |||||
} | |||||
template<typename function> | |||||
void all_under(size_t index, function func) { | |||||
size_t left = get_left(index); | |||||
size_t right = get_right(index); | |||||
all_under(left, func); | |||||
all_under(right, func); | |||||
func(left); | |||||
func(right); | |||||
} | |||||
template<typename function> | |||||
void all_over(size_t index, function func) { | |||||
size_t parent = ((index + 1) >> 1) - 1; | |||||
func(parent); | |||||
if(parent != 0) | |||||
all_over(parent, func); | |||||
} | |||||
template<typename function> | |||||
bool is_any_child(size_t index, function func) { | |||||
size_t left = get_left(index); | |||||
size_t right = get_right(index); | |||||
if(func(left)) return true; | |||||
if(func(right)) return true; | |||||
if(any_child(left, func)) return true; | |||||
if(any_child(right, func)) return true; | |||||
return false; | |||||
} | |||||
static constexpr size_t no_twig = -1; | |||||
size_t find_free_twig(size_t depth, size_t root = 0, size_t explored = 0) { | |||||
if(depth == explored) { | |||||
auto v = get_twig(root); | |||||
if(v.used || v.used_children) | |||||
{ | |||||
return no_twig; | |||||
} else { | |||||
return root; | |||||
} | |||||
} else { | |||||
++explored; | |||||
auto ret = find_free_twig(depth, get_right(root), explored); | |||||
if(ret != no_twig) | |||||
{ | |||||
return ret; | |||||
} | |||||
ret = find_free_twig(depth, get_left(root), explored); | |||||
if(ret != no_twig) | |||||
{ | |||||
return ret; | |||||
} | |||||
} | |||||
return no_twig; | |||||
} | |||||
public: | |||||
buddy() | |||||
: data(gp::buffer<char>(nullptr,nullptr)) | |||||
{} | |||||
buddy(size_t sz) | |||||
: data(nullptr,nullptr) | |||||
{ | |||||
if(sz!=0 && (sz & (sz - 1)) == 0) | |||||
{ | |||||
auto v=allocator.allocate(sz); | |||||
if(v!=nullptr && (static_cast<intptr_t>(v) % align) ==0) | |||||
{ | |||||
data=gp::buffer<char>(reinterpret_cast<char*>(v),reinterpret_cast<char*>(v)+sz); | |||||
} | |||||
} | |||||
} | |||||
buddy(char* pos,size_t sz) | |||||
: data(pos,pos+sz) | |||||
{ | |||||
} | |||||
void* allocate(size_t sz) | |||||
{ | |||||
auto depth = size_to_depth(sz); | |||||
auto index = find_free_twig(depth); | |||||
if(index == no_twig) | |||||
{ | |||||
return nullptr; | |||||
} | |||||
all_over(index, [&](size_t idx){ | |||||
auto t = get_twig(idx); | |||||
t.used_children = true; | |||||
set_twig(idx, t); | |||||
}); | |||||
auto t = get_twig(index); | |||||
t.used = true; | |||||
set_twig(index, t); | |||||
return reinterpret_cast<void*>(index*depth_to_size(depth) | |||||
+ reinterpret_cast<intptr_t>(&*data.begin())); | |||||
} | |||||
bool deallocate(void* ptr) | |||||
{ | |||||
if(data.contains((char*)ptr)) | |||||
{ | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
~buddy() | |||||
{ | |||||
if constexpr(gp::has_allocator_interface<page_allocator>::value) | |||||
{ | |||||
allocator.deallocate(&data[0]); | |||||
} | |||||
} | |||||
}; | |||||
} |
@ -0,0 +1,20 @@ | |||||
#pragma once | |||||
#include <stddef.h> | |||||
namespace gp { | |||||
struct dummy_allocator{ | |||||
void* allocator(size_t) | |||||
{ | |||||
return nullptr; | |||||
} | |||||
bool deallocate(void*) | |||||
{ | |||||
return false; | |||||
} | |||||
constexpr bool try_reallocate(void*, size_t) { | |||||
return false; | |||||
} | |||||
}; | |||||
} |
@ -0,0 +1,10 @@ | |||||
#pragma one | |||||
#include <gp/array.hpp> | |||||
#include <gp/iterator.hpp> | |||||
#include <gp/integer_math.hpp> | |||||
template<typename T, size_t depth> | |||||
class flat_tree { | |||||
gp::array<T, ((1 << depth) << 1) & 1> data_; | |||||
}; |
@ -0,0 +1,68 @@ | |||||
#pragma once | |||||
#include <stdint.h> | |||||
#include <stddef.h> | |||||
namespace gp { | |||||
namespace math { | |||||
template<typename word_t> | |||||
size_t log2(word_t v); | |||||
/** | |||||
Sean Eron Anderson | |||||
seander@cs.stanford.edu | |||||
**/ | |||||
template<> | |||||
constexpr size_t log2<uint32_t>(uint32_t v) | |||||
{ | |||||
constexpr int MultiplyDeBruijnBitPosition[32] = | |||||
{ | |||||
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, | |||||
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 | |||||
}; | |||||
v |= v >> 1; | |||||
v |= v >> 2; | |||||
v |= v >> 4; | |||||
v |= v >> 8; | |||||
v |= v >> 16; | |||||
return MultiplyDeBruijnBitPosition[(uint32_t)(v * 0x07C4ACDDU) >> 27]; | |||||
} | |||||
template<> | |||||
constexpr size_t log2<uint64_t>(uint64_t v) | |||||
{ | |||||
constexpr int MultiplyDeBruijnBitPosition[64] = | |||||
{ | |||||
0, 58, 1, 59, 47, 53, 2, 60, 39, 48, 27, 54, 33, 42, 3, 61, | |||||
51, 37, 40, 49, 18, 28, 20, 55, 30, 34, 11, 43, 14, 22, 4, 62, | |||||
57, 46, 52, 38, 26, 32, 41, 50, 36, 17, 19, 29, 10, 13, 21, 56, | |||||
45, 25, 31, 35, 16, 9, 12, 44, 24, 15, 8, 23, 7, 6, 5, 63 | |||||
}; | |||||
v |= v >> 1; | |||||
v |= v >> 2; | |||||
v |= v >> 4; | |||||
v |= v >> 8; | |||||
v |= v >> 16; | |||||
v |= v >> 32; | |||||
return MultiplyDeBruijnBitPosition[(uint64_t)(v * 0x03f6eaf2cd271461) >> 58]; | |||||
} | |||||
template<typename word_t> | |||||
constexpr size_t msb(word_t v); | |||||
template<> | |||||
constexpr size_t msb<uint32_t>(uint32_t v) | |||||
{ | |||||
return log2(v); | |||||
} | |||||
template<> | |||||
constexpr size_t msb<uint64_t>(uint64_t v) | |||||
{ | |||||
return log2(v); | |||||
} | |||||
} | |||||
} |
@ -1,7 +1,100 @@ | |||||
#pragma once | #pragma once | ||||
#include <stddef.h> | |||||
#include <stdint.h> | |||||
enum class iterator_type_t{ | enum class iterator_type_t{ | ||||
contiguous_iterator, | contiguous_iterator, | ||||
non_contiguous_iterator, | non_contiguous_iterator, | ||||
lazy_iterator | lazy_iterator | ||||
}; | |||||
template<typename T> | |||||
struct pointer_iterator final | |||||
{ | |||||
T* data; | |||||
typedef T value_type; | |||||
typedef std::size_t difference_type; | |||||
static constexpr iterator_type_t iterator_type = iterator_type_t::contiguous_iterator; | |||||
constexpr pointer_iterator(const pointer_iterator& oth) | |||||
: data{oth.data} | |||||
{} | |||||
constexpr pointer_iterator(T* ptr) | |||||
: data{ptr} | |||||
{} | |||||
constexpr operator T&() | |||||
{ | |||||
return *data; | |||||
} | |||||
constexpr T& operator*(){ | |||||
return *data; | |||||
} | |||||
constexpr pointer_iterator operator++() | |||||
{ | |||||
return pointer_iterator{++data}; | |||||
} | |||||
constexpr pointer_iterator operator++(int) | |||||
{ | |||||
return pointer_iterator{data++}; | |||||
} | |||||
constexpr pointer_iterator operator--() | |||||
{ | |||||
return pointer_iterator{--data}; | |||||
} | |||||
constexpr pointer_iterator operator--(int) | |||||
{ | |||||
return pointer_iterator{data--}; | |||||
} | |||||
constexpr pointer_iterator operator+(const std::size_t offset) | |||||
{ | |||||
return pointer_iterator{data+offset}; | |||||
} | |||||
constexpr pointer_iterator operator+(const int offset) | |||||
{ | |||||
return pointer_iterator{data+offset}; | |||||
} | |||||
constexpr pointer_iterator operator-(const std::size_t offset) | |||||
{ | |||||
return pointer_iterator{data-offset}; | |||||
} | |||||
constexpr pointer_iterator operator-(const int offset) | |||||
{ | |||||
return pointer_iterator{data-offset}; | |||||
} | |||||
constexpr difference_type operator-(const pointer_iterator& oth) const | |||||
{ | |||||
return (T*)data-(T*)oth.data; | |||||
} | |||||
constexpr bool operator==(const pointer_iterator& oth) | |||||
{ | |||||
return data==oth.data; | |||||
} | |||||
constexpr bool operator!=(pointer_iterator& oth) | |||||
{ | |||||
return data!=oth.data; | |||||
} | |||||
constexpr bool before_or_equal(const pointer_iterator& oth) | |||||
{ | |||||
return reinterpret_cast<std::intptr_t>(data) <= reinterpret_cast<std::intptr_t>(oth.data); | |||||
} | |||||
constexpr bool operator<=(const pointer_iterator& oth) | |||||
{ | |||||
return before_or_equal(oth); | |||||
} | |||||
}; | }; |
@ -0,0 +1,26 @@ | |||||
#pragma once | |||||
#include <stddef.h> | |||||
#include <stdint.h> | |||||
#include <gp/buffer.hpp> | |||||
template<typename T> | |||||
struct subtree_iterator final | |||||
{ | |||||
gp::buffer<T> target; | |||||
size_t idx; | |||||
public: | |||||
subtree_iterator() | |||||
: target{} | |||||
, idx{0} | |||||
{} | |||||
subtree_iterator(gp::buffer<T> data, size_t itr_idx) | |||||
: target{data} | |||||
, idx{itr_idx} | |||||
{} | |||||
template<typename func> | |||||
void climb_traversal(func& traverser) { | |||||
} | |||||
}; |