@ -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 | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
enum class iterator_type_t{ | |||
contiguous_iterator, | |||
non_contiguous_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) { | |||
} | |||
}; |