diff --git a/Makefile b/Makefile index 26a90d9..8a5515d 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ CXX= clang++-8 -CXXFLAGS= --std=c++17 -g -fprofile-instr-generate -fcoverage-mapping -pthread +CXXFLAGS= --std=c++17 -g -O0 -fprofile-instr-generate -fcoverage-mapping -pthread all: tests tests: bin/tests LLVM_PROFILE_FILE="./bin/tests.profraw" ./bin/tests @llvm-profdata merge -sparse ./bin/tests.profraw -o ./bin/tests.profdata - @llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata include/*.hpp include/gp/*.hpp include/gp/algorithm/*.hpp - @llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata include/*.hpp include/gp/*.hpp include/gp/algorithm/*.hpp | tail -n 1 | tr -s " " | sed -e 's/ /,/g' -- | awk -F "," '{print $$9}' | sed -e 's/^/Untested lines: /g' + @llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata include/*.hpp include/gp/*.hpp include/gp/algorithm/*.hpp include/gp/allocator/*.hpp + @llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata include/*.hpp include/gp/*.hpp include/gp/algorithm/*.hpp include/gp/allocator/*.hpp | tail -n 1 | tr -s " " | sed -e 's/ /,/g' -- | awk -F "," '{print $$9}' | sed -e 's/^/Untested lines: /g' bin/tests: tests.cpp $(wildcard tests/*.cpp) $(wildcard include/*.hpp) ./tests/test_scaffold.h @mkdir -p $(@D) diff --git a/include/gp/arena.hpp b/include/gp/allocator/arena.hpp similarity index 74% rename from include/gp/arena.hpp rename to include/gp/allocator/arena.hpp index 9133441..6fd38cf 100644 --- a/include/gp/arena.hpp +++ b/include/gp/allocator/arena.hpp @@ -10,17 +10,17 @@ namespace gp{ template class arena{ page_allocator allocator; - fel::buffer data; + gp::buffer data; size_t last; size_t count; public: arena() :last(0) ,count(0) - ,data(fel::buffer(nullptr,nullptr)) + ,data(gp::buffer(nullptr,nullptr)) {} - template::value,int>::type> + template::value,int>::type> arena(size_t sz) :last(0) ,count(0) @@ -31,7 +31,7 @@ namespace gp{ auto v=allocator.allocate(sz); if(v!=nullptr) { - data=fel::buffer(reinterpret_cast(v),reinterpret_cast(v)+sz); + data=gp::buffer(reinterpret_cast(v),reinterpret_cast(v)+sz); } } } @@ -66,6 +66,10 @@ namespace gp{ } } + constexpr bool try_reallocate(void*, size_t) { + return false; + } + bool deallocate(void* ptr) { if(data.contains((char*)ptr)) @@ -86,7 +90,7 @@ namespace gp{ ~arena() { - if constexpr(fel::has_allocator_interface::value) + if constexpr(gp::has_allocator_interface::value) { allocator.deallocate(&data[0]); } diff --git a/include/gp/allocator/buddy.hpp b/include/gp/allocator/buddy.hpp new file mode 100644 index 0000000..c9c819f --- /dev/null +++ b/include/gp/allocator/buddy.hpp @@ -0,0 +1,211 @@ +#pragma once +#include "gp_config.hpp" +#include "gp/buffer.hpp" +#include "gp/array.hpp" +#include "gp/integer_math.hpp" +#include +#include + + + +namespace gp{ + template + 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 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 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 + 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 + 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 + 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(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(v) % align) ==0) + { + data=gp::buffer(reinterpret_cast(v),reinterpret_cast(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(index*depth_to_size(depth) + + reinterpret_cast(&*data.begin())); + } + + bool deallocate(void* ptr) + { + if(data.contains((char*)ptr)) + { + return true; + } + return false; + } + + ~buddy() + { + if constexpr(gp::has_allocator_interface::value) + { + allocator.deallocate(&data[0]); + } + } + }; +} \ No newline at end of file diff --git a/include/gp/allocator/dummy.hpp b/include/gp/allocator/dummy.hpp new file mode 100644 index 0000000..75680e7 --- /dev/null +++ b/include/gp/allocator/dummy.hpp @@ -0,0 +1,20 @@ +#pragma once +#include + +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; + } + }; +} \ No newline at end of file diff --git a/include/gp/array.hpp b/include/gp/array.hpp index bf50b02..4cc3bce 100644 --- a/include/gp/array.hpp +++ b/include/gp/array.hpp @@ -7,8 +7,8 @@ namespace gp{ class array{ T ary[sz]; public: - using associated_iterator = typename buffer::associated_iterator; - using associated_const_iterator = typename buffer::associated_iterator; + using associated_iterator = pointer_iterator; + using associated_const_iterator = pointer_iterator; array() = default; @@ -27,14 +27,24 @@ namespace gp{ return sz; } - constexpr associated_iterator begin() const + constexpr associated_iterator begin() { - return gp::buffer{(T*)ary, (T*)ary+sz}.begin(); + return associated_iterator(&ary[0]); } - constexpr associated_iterator end() const + constexpr associated_iterator end() { - return gp::buffer{(T*)ary, (T*)ary+sz}.end(); + return associated_iterator(&ary[sz]); + } + + constexpr associated_const_iterator cbegin() const + { + return ary; + } + + constexpr associated_const_iterator cend() const + { + return ary+sz; } constexpr bool operator==(const array& oth) const diff --git a/include/gp/buffer.hpp b/include/gp/buffer.hpp index 6c8345f..d6d328c 100644 --- a/include/gp/buffer.hpp +++ b/include/gp/buffer.hpp @@ -12,100 +12,11 @@ namespace gp{ template class buffer final{ public: - struct buffer_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 buffer_iterator(const buffer_iterator& oth) - : data{oth.data} - {} - - constexpr buffer_iterator(T* ptr) - : data{ptr} - {} - - constexpr operator T&() - { - return *data; - } - - constexpr T& operator*(){ - return *data; - } - - constexpr buffer_iterator operator++() - { - return buffer_iterator{++data}; - } - - constexpr buffer_iterator operator++(int) - { - return buffer_iterator{data++}; - } - - constexpr buffer_iterator operator--() - { - return buffer_iterator{--data}; - } - - constexpr buffer_iterator operator--(int) - { - return buffer_iterator{data--}; - } - - constexpr buffer_iterator operator+(const std::size_t offset) - { - return buffer_iterator{data+offset}; - } - - constexpr buffer_iterator operator+(const int offset) - { - return buffer_iterator{data+offset}; - } - - constexpr buffer_iterator operator-(const std::size_t offset) - { - return buffer_iterator{data-offset}; - } - - constexpr buffer_iterator operator-(const int offset) - { - return buffer_iterator{data-offset}; - } - - constexpr difference_type operator-(const buffer_iterator& oth) const - { - return (T*)data-(T*)oth.data; - } - - constexpr bool operator==(const buffer_iterator& oth) - { - return data==oth.data; - } - - constexpr bool operator!=(buffer_iterator& oth) - { - return data!=oth.data; - } - - constexpr bool before_or_equal(const buffer_iterator& oth) - { - return reinterpret_cast(data) <= reinterpret_cast(oth.data); - } - - constexpr bool operator<=(const buffer_iterator& oth) - { - return before_or_equal(oth); - } - }; private: - buffer_iterator begin_elem; - buffer_iterator end_elem; + pointer_iterator begin_elem; + pointer_iterator end_elem; public: - using associated_iterator = buffer_iterator; + using associated_iterator = pointer_iterator; constexpr buffer(T* beg_ptr, T* end_ptr) : begin_elem{beg_ptr} @@ -117,7 +28,7 @@ namespace gp{ , end_elem{beg_ptr+sz} {} - constexpr typename buffer_iterator::difference_type size() const + constexpr typename pointer_iterator::difference_type size() const { return end_elem - begin_elem; } @@ -137,7 +48,7 @@ namespace gp{ return *(begin_elem+offset); } - optional at(std::size_t offset) + optional> at(std::size_t offset) { auto elem = begin()+offset; if(!contains(elem)) @@ -147,7 +58,7 @@ namespace gp{ return elem; } - constexpr bool contains(buffer_iterator ptr) + constexpr bool contains(pointer_iterator ptr) { return ptr.data < end_elem.data diff --git a/include/gp/flat_tree.hpp b/include/gp/flat_tree.hpp new file mode 100644 index 0000000..0e3632e --- /dev/null +++ b/include/gp/flat_tree.hpp @@ -0,0 +1,10 @@ +#pragma one +#include +#include +#include + +template +class flat_tree { + gp::array data_; + +}; diff --git a/include/gp/integer_math.hpp b/include/gp/integer_math.hpp new file mode 100644 index 0000000..fd460de --- /dev/null +++ b/include/gp/integer_math.hpp @@ -0,0 +1,68 @@ +#pragma once +#include +#include + +namespace gp { + namespace math { + + template + size_t log2(word_t v); + + /** + Sean Eron Anderson + seander@cs.stanford.edu + **/ + template<> + constexpr size_t log2(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 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 + constexpr size_t msb(word_t v); + + template<> + constexpr size_t msb(uint32_t v) + { + return log2(v); + } + template<> + constexpr size_t msb(uint64_t v) + { + return log2(v); + } + } +} diff --git a/include/gp/iterator.hpp b/include/gp/iterator.hpp index e37fca7..9e2dc49 100644 --- a/include/gp/iterator.hpp +++ b/include/gp/iterator.hpp @@ -1,7 +1,100 @@ #pragma once +#include +#include enum class iterator_type_t{ contiguous_iterator, non_contiguous_iterator, lazy_iterator +}; + +template +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(data) <= reinterpret_cast(oth.data); + } + + constexpr bool operator<=(const pointer_iterator& oth) + { + return before_or_equal(oth); + } }; \ No newline at end of file diff --git a/include/gp/subtree_iterator.hpp b/include/gp/subtree_iterator.hpp new file mode 100644 index 0000000..d2b432b --- /dev/null +++ b/include/gp/subtree_iterator.hpp @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include + +template +struct subtree_iterator final +{ + gp::buffer target; + size_t idx; +public: + subtree_iterator() + : target{} + , idx{0} + {} + + subtree_iterator(gp::buffer data, size_t itr_idx) + : target{data} + , idx{itr_idx} + {} + + template + void climb_traversal(func& traverser) { + + } +}; \ No newline at end of file diff --git a/include/rc6_generic.hpp b/include/rc6_generic.hpp index fd4ab47..38825a1 100644 --- a/include/rc6_generic.hpp +++ b/include/rc6_generic.hpp @@ -1,55 +1,10 @@ #pragma once #include #include +#include #include #include -template -size_t lg(word_t v); - - -/** -Sean Eron Anderson -seander@cs.stanford.edu -**/ -template<> -constexpr size_t lg(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 lg(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 @@ -132,6 +87,7 @@ public: {} constexpr block_type encrypt(block_type plaintext) { + using namespace gp::math; auto& A = plaintext[0]; auto& B = plaintext[1]; auto& C = plaintext[2]; @@ -144,8 +100,8 @@ public: for(size_t i = 0; i < r; ++i) { - auto u = r_l( D * ( 2 * D + 1 ), lg(word_size)); - auto t = r_l( B * ( 2 * B + 1 ), lg(word_size)); + auto u = r_l( D * ( 2 * D + 1 ), msb(word_size)); + auto t = r_l( B * ( 2 * B + 1 ), msb(word_size)); A = r_l((A ^ t), u % word_size) + *(it++); C = r_l((C ^ u), t % word_size) + *(it++); std::rotate(plaintext.begin(), plaintext.begin()+1, plaintext.end()); @@ -158,6 +114,7 @@ public: } constexpr block_type decrypt(block_type plaintext) { + using namespace gp::math; auto& A = plaintext[0]; auto& B = plaintext[1]; auto& C = plaintext[2]; @@ -170,8 +127,8 @@ public: for(size_t i = 0; i < r; ++i) { std::rotate(plaintext.begin(), plaintext.end()-1, plaintext.end()); - auto u = r_l( D * ( 2 * D + 1 ), lg(word_size)); - auto t = r_l( B * ( 2 * B + 1 ), lg(word_size)); + auto u = r_l( D * ( 2 * D + 1 ), msb(word_size)); + auto t = r_l( B * ( 2 * B + 1 ), msb(word_size)); C = r_r( (C - *(it++)) , t % word_size) ^ u ; A = r_r( (A - *(it++)) , u % word_size) ^ t ; } diff --git a/tests.cpp b/tests.cpp index 83a6e8c..88a244f 100644 --- a/tests.cpp +++ b/tests.cpp @@ -15,16 +15,19 @@ int main() { ++runned; int value; - try{ + //try{ value = test->run(); if(value) { std::cout << std::dec << test->name << " failed with "<< value << std::endl; } - } catch (...) { + /*} catch (gp::runtime_error err) { + std::cout << test->name << " failed with an exception: " << err.what() << std::endl; + value = -1; + //} catch (...) { std::cout << test->name << " failed with an exception" << std::endl; value = -1; - } + }*/ failed += (value != 0); } std::cout << std::dec << "Runned "< #include +#include #include #include #include @@ -75,4 +78,36 @@ struct optional_test : public test_scaffold { } }; -append_test dummy_mlyusisd3(new optional_test{}); \ No newline at end of file +append_test dummy_mlyusisd3(new optional_test{}); + + +struct buddy_test : public test_scaffold { + buddy_test() { + name = __FILE__ ":3"; + } + + gp::array store; + + virtual int run() { + int res = 0; + { + gp::buddy(4096)> bud{&*store.begin(), store.size()}; + std::set ptr_set; + for(int i = 0; i < 4096 / 8; i++) + { + void* v = bud.allocate(8); + if(v == nullptr) throw gp::runtime_error("allocation failed"); + ptr_set.insert(v); + } + std::cout << ptr_set.size() << "//" << ptr_set.count(nullptr); + if(ptr_set.count(nullptr)!=0 || ptr_set.size()!=(4096/8)) throw gp::runtime_error("some allocations failed"); + res++; + res += nullptr == bud.allocate(8); + if(nullptr != bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected"); + ++res; + } + return res; + } +}; + +append_test dummy_654sisd3(new buddy_test{}); \ No newline at end of file