diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6bc7f76 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "clang.cflags": [ + "-std=c++17", + "-I${workspaceRoot}/include" + ] +} \ No newline at end of file diff --git a/Makefile b/Makefile index ff986fc..32bf5e0 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CXX= clang++-8 +CXX= clang++-10 CXXFLAGS= --std=c++17 -O0 -pthread -DGP_TESTS -DFUZZ_STRENGTH=500 -pedantic -Werror \ -Wno-unknown-attributes -frtti \ -g -fprofile-instr-generate -fcoverage-mapping \ diff --git a/include/gp/algorithm/move.hpp b/include/gp/algorithm/move.hpp index c50fde4..1184511 100644 --- a/include/gp/algorithm/move.hpp +++ b/include/gp/algorithm/move.hpp @@ -58,11 +58,12 @@ namespace gp{ return nameless_range{out, dest.end()}; } - template - nameless_range move_uninitialized(range_in src, range_out dest) + template + nameless_range::type::associated_iterator> move_uninitialized(range_in&& src, range_out&& dest) { + using T = typename gp::remove_reference::type; if(src.size()>dest.size()) - return nameless_range(dest.begin(), dest.end()); + return nameless_range::type::associated_iterator>(dest.begin(), dest.end()); auto in = src.begin(); auto in_close = src.end(); auto out = dest.begin(); @@ -70,6 +71,6 @@ namespace gp{ { new(&*(out++)) T{gp::move(*(in++))}; } - return nameless_range{out, dest.end()}; + return nameless_range::type::associated_iterator>{out, dest.end()}; } } \ No newline at end of file diff --git a/include/gp/algorithm/tmp_manip.hpp b/include/gp/algorithm/tmp_manip.hpp index cfde14b..b80cc01 100644 --- a/include/gp/algorithm/tmp_manip.hpp +++ b/include/gp/algorithm/tmp_manip.hpp @@ -202,7 +202,7 @@ namespace gp{ typedef std::true_type yes; typedef std::false_type no; - template struct SFINAE{}; + template struct SFINAE{}; template static yes test(SFINAE*); @@ -219,7 +219,7 @@ namespace gp{ typedef std::true_type yes; typedef std::false_type no; - template struct SFINAE{}; + template struct SFINAE{}; template static yes test(SFINAE*); diff --git a/include/gp/allocator/arena.hpp b/include/gp/allocator/arena.hpp index 6fd38cf..118a2bd 100644 --- a/include/gp/allocator/arena.hpp +++ b/include/gp/allocator/arena.hpp @@ -7,7 +7,7 @@ namespace gp{ - template + template class arena{ page_allocator allocator; gp::buffer data; @@ -20,18 +20,20 @@ namespace gp{ ,data(gp::buffer(nullptr,nullptr)) {} - template::value,int>::type> arena(size_t sz) :last(0) ,count(0) ,data(nullptr,nullptr) { - if(sz!=0) + if constexpr (gp::has_allocator_interface::value) { - auto v=allocator.allocate(sz); - if(v!=nullptr) + if(sz!=0) { - data=gp::buffer(reinterpret_cast(v),reinterpret_cast(v)+sz); + auto v=allocator.allocate(sz); + if(v!=nullptr) + { + data=gp::buffer(reinterpret_cast(v),reinterpret_cast(v)+sz); + } } } } diff --git a/include/gp/array.hpp b/include/gp/array.hpp index ce09add..68e84ba 100644 --- a/include/gp/array.hpp +++ b/include/gp/array.hpp @@ -33,7 +33,7 @@ namespace gp{ array(array&& values) { - gp::move_uninitialized( + gp::move_uninitialized( values, *this ); diff --git a/include/gp/buffer.hpp b/include/gp/buffer.hpp index 3ea66f9..44143b2 100644 --- a/include/gp/buffer.hpp +++ b/include/gp/buffer.hpp @@ -81,7 +81,7 @@ namespace gp{ } else { - if(size()*sizeof(T)/sizeof(U)) + if((size()*sizeof(T))%sizeof(U) == 0) { return buffer(reinterpret_cast(&*begin_elem), size()*sizeof(T)/sizeof(U)); } diff --git a/include/gp/pair.hpp b/include/gp/pair.hpp new file mode 100644 index 0000000..397cabb --- /dev/null +++ b/include/gp/pair.hpp @@ -0,0 +1,72 @@ +#pragma once +#include "gp/algorithm/move.hpp" + +namespace gp{ + template + struct pair{ + T1 first; + T2 second; + + pair() : first(), second() {} + + pair(const T1& a, const T2& b) : first(a), second(b) {} + + pair(pair&& v) + : first(gp::move(v.first)) + , second(gp::move(v.second)) + {} + + template + pair(U1&& a, U2&& b) + : first(gp::forward(a)) + , second(gp::forward(b)) + {} + + template + pair(pair&& v) + : first(gp::move(v.first)) + , second(gp::move(v.second)) + {} + + pair& operator=(pair&& v) + { + first = gp::move(v.first); + second = gp::move(v.second); + return *this; + } + + bool operator==(const pair& rhs) { + return first == rhs.first and second == rhs.second; + } + + bool operator!=(const pair& rhs) { + return first != rhs.first or second != rhs.second; + } + + bool operator<=(const pair& rhs) { + if(first > rhs.first) { + return false; + } else if(first == rhs.first) { + return second <= rhs.second; + } + return true; + } + + bool operator>=(const pair& rhs) { + if(first < rhs.first) { + return false; + } else if(first == rhs.first) { + return second >= rhs.second; + } + return true; + } + + bool operator<(const pair& rhs) { + return !(*this >= rhs); + } + + bool operator>(const pair& rhs) { + return !(*this <= rhs); + } + }; +} \ No newline at end of file diff --git a/include/gp/quotient_filter.hpp b/include/gp/quotient_filter.hpp index 9bb35b8..14040ba 100644 --- a/include/gp/quotient_filter.hpp +++ b/include/gp/quotient_filter.hpp @@ -193,6 +193,7 @@ namespace gp { if(slot.r == r) { slot.is_deleted = true; + slot.is_occupied = false; } } skip.next(); diff --git a/include/gp/ring_list.hpp b/include/gp/ring_list.hpp index 37a98e8..62b24b6 100644 --- a/include/gp/ring_list.hpp +++ b/include/gp/ring_list.hpp @@ -95,13 +95,22 @@ namespace gp { , alloc{_alloc} {} + ring_list(allocator& _alloc) + : any_node{nullptr} + , sz{0} + , alloc{_alloc} + {} + template bool insert(Args&&... elem) { allocator& used_allocator = alloc; - void* mem = used_allocator.allocate(sizeof(V)); + void* mem; + [[unlikely]] if( + nullptr == (mem = used_allocator.allocate(sizeof(V))) + ) return false; T* p = new(mem) V(elem...); node* to_insert = nullptr; - if( + [[unlikely]] if( nullptr == (to_insert = reinterpret_cast(used_allocator.allocate(sizeof(node)))) ) return false; to_insert = new(to_insert) node(p); diff --git a/tests.cpp b/tests.cpp index 57d0db5..0f3c615 100644 --- a/tests.cpp +++ b/tests.cpp @@ -8,6 +8,7 @@ #include "bloomfilter.cpp" #include "quotient_filter.cpp" #include "math.cpp" +#include "pair_test.cpp" #include alignas(2048) gp::array static_mapper::store; diff --git a/tests/gp_test.cpp b/tests/gp_test.cpp index 28de90a..be9c6a7 100644 --- a/tests/gp_test.cpp +++ b/tests/gp_test.cpp @@ -3,10 +3,12 @@ #include "gp/array.hpp" #include "gp/indexed_array.hpp" #include "gp/allocator/aggregator.hpp" +#include "gp/allocator/arena.hpp" #include "gp/allocator/buddy.hpp" #include "gp/allocator/dummy.hpp" #include "gp/algorithm/repeat.hpp" #include "gp/algorithm/rotate.hpp" +#include "gp/algorithm/move.hpp" #include "gp/ring_list.hpp" #include #include @@ -415,6 +417,35 @@ struct aggregator_test : public test_scaffold { } auto duration = std::chrono::steady_clock::now() - start; } + void* a = allocator.allocate(8); + gp_config::assertion(allocator.try_reallocate(a, 16) == false, "could reallocate? was it implemented?"); + gp_config::assertion(allocator.deallocate(nullptr) == false, "error, could free an invalid pointer"); + allocator.deallocate(a); + { + gp::ring_list list{allocator}; + list.insert(8); + list.insert(16); + list.insert(32); + } + { + gp::array work_array; + gp::arena<> alloc_work(work_array.begin().data, work_array.size()); + gp::ring_list, false> list{alloc_work}; + gp_config::assertion(list.insert(8) == true, "could allocate in list with good enough allocator"); + gp_config::assertion(list.insert(8) == true, "could allocate in list with good enough allocator"); + gp_config::assertion(list.insert(8) == true, "could allocate in list with good enough allocator"); + } + { + gp::array once_array; + gp::arena<> alloc_once(once_array.begin().data, once_array.size()); + gp::ring_list, false> list{alloc_once}; + gp_config::assertion(list.insert(8) == false, "could allocate in list with insufficient allocator"); + } + { + gp::arena<> alloc_none(nullptr, 0); + gp::ring_list, false> list{alloc_none}; + gp_config::assertion(list.insert(8) == false, "could allocate in list with fake allocator"); + } return res; } }; @@ -531,4 +562,102 @@ struct indexed_array_test : public test_scaffold { } }; -append_test dummy_khxurgsd3(new indexed_array_test{}); \ No newline at end of file +append_test dummy_khxurgsd3(new indexed_array_test{}); + + + +struct move_uninitialized_test : public test_scaffold { + move_uninitialized_test() { + name = __FILE__ ":8"; + } + + struct tester { + size_t* const incremented; + + tester(size_t* ptr) + : incremented(ptr) + {} + + tester(tester&& oth) + : incremented(oth.incremented) + { + ++*incremented; + } + }; + + virtual int run() { + int res = 0; + { + size_t counter; + using src_t = gp::array; + src_t *source = reinterpret_cast(malloc(sizeof(src_t))); + gp::array buffer; + for(auto& a : *source) { + new(&a) tester(&counter); + } + gp::move_uninitialized(*source, buffer.as_buffer().cast()); + free(source); + } + return res; + } +}; + +append_test dummy_hkfyr5f5(new move_uninitialized_test{}); + + + +struct clamp_test : public test_scaffold { + clamp_test() { + name = __FILE__ ":9"; + } + + virtual int run() { + int res = 0; + { + res += gp::clamp(0.0, -1.0, 1.0); + res += gp::clamp(-1.0, 1.0, 0.0); + res += gp::max(-1, -2, 0, -3); + } + return res; + } +}; + +append_test dummy_gsdh25f5(new clamp_test{}); + +struct buffer_test : public test_scaffold { + buffer_test() { + name = __FILE__ ":10"; + } + + virtual int run() { + int res = 0; + { + gp::array data; + gp::array data_e; + gp::buffer handle = data.as_buffer(); + handle[12] = '&'; + gp_config::assertion(*(handle.begin()+12) == '&', "Could not assign to the buffer"); + res += 1; + try { + handle[24] = 16; + res += 1; + handle[-1] = 16; + res += 1; + handle[1024] = 16; + } catch (...) { + res -= 1; + } + res += 1; + try { + auto cast = handle.cast>(); + } catch (...) { + res -= 1; + } + auto cast = handle.template cast>().template cast>(); + gp_config::assertion(false == (data == data_e), "Different arrays should return false here"); + } + return res; + } +}; + +append_test dummy_gs87ytf5f5(new buffer_test{}); diff --git a/tests/pair_test.cpp b/tests/pair_test.cpp new file mode 100644 index 0000000..5548488 --- /dev/null +++ b/tests/pair_test.cpp @@ -0,0 +1,35 @@ +#include "test_scaffold.h" +#include +#include +#include "gp/pair.hpp" + +typedef std::mt19937_64 cheap_rand; + +struct pair_test : public test_scaffold { + uint32_t seed; + + pair_test() { + seed = std::random_device{}(); + name = __FILE__ ":1_seed"; + name += std::to_string(seed); + } + + virtual int run() { + + cheap_rand setter(seed); + + gp::pair v{0, "zero"}; + bool result = true; + + for(int i = 0 ; i < 100; i++) + { + auto a = setter(); + v = gp::pair(a, std::to_string(a)); + result = gp::pair(a, std::to_string(a)) == v ? result : false; + } + + return !result; + } +}; + +append_test dummy_rsly21r43(new pair_test{}); \ No newline at end of file diff --git a/tests/quotient_filter.cpp b/tests/quotient_filter.cpp index d816b13..e90a4c0 100644 --- a/tests/quotient_filter.cpp +++ b/tests/quotient_filter.cpp @@ -124,4 +124,70 @@ struct qfilter3_test : public test_scaffold { } }; -append_test dummy_kjdflu3(new qfilter3_test{}); \ No newline at end of file +append_test dummy_kjdflu3(new qfilter3_test{}); + +struct qfilter4_test : public test_scaffold { + + qfilter4_test() { + } + + virtual int run() { + gp::quotient_filter<> test_filter; + + for(int a = 0 ; a < 10000; a++) + { + test_filter.set_hash(a); + } + + for(int a = 0 ; a < 10000; a++) + { + test_filter.remove_hash(a); + } + + for(int a = 0 ; a < 10000; a++) + { + gp_config::assertion(!test_filter.test_hash(a), "everything should have been removed"); + } + + for(int a = 0 ; a < 10000; a++) + { + test_filter.set_hash(a); + } + + for(int a = 0 ; a < 10000; a++) + { + gp_config::assertion(test_filter.test_hash(a), "everything should have been set"); + } + + return 0; + } +}; + +append_test dummy_kj54ghu3(new qfilter4_test{}); + +struct qfilter5_test : public test_scaffold { + + qfilter5_test() { + } + + virtual int run() { + gp::quotient_filter test_filter; + + for(int a = 0 ; a < 65536; a++) + { + test_filter.set_hash(a); + } + + int res = 1; + + try { + test_filter.set_hash(123456); + } catch(gp::runtime_error e) { + res = 0; + } + + return res; + } +}; + +append_test dummy_k65421u3(new qfilter5_test{}); \ No newline at end of file