| @ -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) { | |||
| } | |||
| }; | |||