diff --git a/Makefile b/Makefile index f1a1acb..c3df7ef 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CXX= clang++-10 -CXXFLAGS= --std=c++20 -O0 -g -pthread -DGP_TESTS -DFUZZ_STRENGTH=500 -DNO_BENCH=0 -pedantic \ +CXXFLAGS= --std=c++20 -O0 -g -pthread -DGP_TESTS -DFUZZ_STRENGTH=500 -DNO_BENCH=1 -pedantic \ -fprofile-instr-generate -fcoverage-mapping -Wno-unknown-attributes \ -fsanitize=address -fno-omit-frame-pointer all: tests diff --git a/include/gp/algorithm/cvref.hpp b/include/gp/algorithm/cvref.hpp new file mode 100644 index 0000000..e471830 --- /dev/null +++ b/include/gp/algorithm/cvref.hpp @@ -0,0 +1,11 @@ +#pragma once + +namespace gp{ + template< class T > + struct remove_cvref { + using type = std::remove_cv_t>; + }; + + template< class T > + using remove_cvref_t = typename remove_cvref::type; +} \ No newline at end of file diff --git a/include/gp/algorithm/modifiers.hpp b/include/gp/algorithm/modifiers.hpp index 8fd440c..c2d5f10 100644 --- a/include/gp/algorithm/modifiers.hpp +++ b/include/gp/algorithm/modifiers.hpp @@ -1,7 +1,10 @@ #pragma once +#include +#include +#include + #include -#include "gp/algorithm/move.hpp" namespace gp { @@ -25,163 +28,4 @@ namespace gp { - /** - ********************************************************************************************** - Code extrated from cppreference.com and the libc++ Library project, licensed under MIT license - ********************************************************************************************** - **/ - - namespace detail { - template - constexpr bool is_reference_wrapper_v = false; - template - constexpr bool is_reference_wrapper_v> = true; - - template - constexpr decltype(auto) INVOKE(Type T::* f, T1&& t1, Args&&... args) - { - if constexpr (std::is_member_function_pointer_v) { - if constexpr (std::is_base_of_v>) - return (gp::forward(t1).*f)(gp::forward(args)...); - else if constexpr (is_reference_wrapper_v>) - return (t1.get().*f)(gp::forward(args)...); - else - return ((*gp::forward(t1)).*f)(gp::forward(args)...); - } else { - static_assert(std::is_member_object_pointer_v); - static_assert(sizeof...(args) == 0); - if constexpr (std::is_base_of_v>) - return gp::forward(t1).*f; - else if constexpr (is_reference_wrapper_v>) - return t1.get().*f; - else - return (*gp::forward(t1)).*f; - } - } - - template - constexpr decltype(auto) INVOKE(F&& f, Args&&... args) - { - return gp::forward(f)(gp::forward(args)...); - } - } // namespace detail - - template< class F, class... Args> - constexpr std::invoke_result_t invoke(F&& f, Args&&... args) - noexcept(std::is_nothrow_invocable_v) - { - return detail::INVOKE(gp::forward(f), gp::forward(args)...); - } - - template< class T > - struct remove_cvref { - using type = std::remove_cv_t>; - }; - - template< class T > - using remove_cvref_t = typename remove_cvref::type; - - template< class T > - T* addressof(T& arg) - { - return reinterpret_cast( - &const_cast( - reinterpret_cast(arg))); - } - - namespace detail { - template constexpr T& FUN(T& t) noexcept { return t; } - template void FUN(T&&) = delete; - } - - template - class reference_wrapper { - public: - // types - typedef T type; - - // construct/copy/destroy - template (std::declval()), - std::enable_if_t>>() - )> - constexpr reference_wrapper(U&& u) noexcept(noexcept(detail::FUN(gp::forward(u)))) - : _ptr(gp::addressof(detail::FUN(gp::forward(u)))) {} - reference_wrapper(const reference_wrapper&) noexcept = default; - - // assignment - reference_wrapper& operator=(const reference_wrapper& x) noexcept = default; - - // access - constexpr operator T& () const noexcept { return *_ptr; } - constexpr T& get() const noexcept { return *_ptr; } - - template< class... ArgTypes > - constexpr std::invoke_result_t - operator() ( ArgTypes&&... args ) const { - return gp::invoke(get(), gp::forward(args)...); - } - - private: - T* _ptr; - }; - - // deduction guides - template - reference_wrapper(T&) -> reference_wrapper; - - template - auto ref(T& vref) { - return reference_wrapper(vref); - } - - template - class __not_fn_imp { - _DecayFunc __fd; - - public: - __not_fn_imp() = delete; - - template - auto operator()(_Args&& ...__args) & - noexcept(noexcept(!gp::invoke(__fd, gp::forward<_Args>(__args)...))) - -> decltype( !gp::invoke(__fd, gp::forward<_Args>(__args)...)) - { return !gp::invoke(__fd, gp::forward<_Args>(__args)...); } - - template - auto operator()(_Args&& ...__args) && - noexcept(noexcept(!gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...))) - -> decltype( !gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...)) - { return !gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...); } - - template - auto operator()(_Args&& ...__args) const& - noexcept(noexcept(!gp::invoke(__fd, gp::forward<_Args>(__args)...))) - -> decltype( !gp::invoke(__fd, gp::forward<_Args>(__args)...)) - { return !gp::invoke(__fd, gp::forward<_Args>(__args)...); } - - - template - auto operator()(_Args&& ...__args) const&& - noexcept(noexcept(!gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...))) - -> decltype( !gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...)) - { return !gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...); } - - private: - template , __not_fn_imp>::value>> - explicit __not_fn_imp(_RawFunc&& __rf) - : __fd(gp::forward<_RawFunc>(__rf)) {} - - template - friend inline __not_fn_imp> not_fn(_RawFunc&&); - }; - - template - inline __not_fn_imp> not_fn(_RawFunc&& __fn) { - return __not_fn_imp>(gp::forward<_RawFunc>(__fn)); - } - /** - ********************************************************************************************* - */ } \ No newline at end of file diff --git a/include/gp/algorithm/move.hpp b/include/gp/algorithm/move.hpp index dff2baa..8220ffd 100644 --- a/include/gp/algorithm/move.hpp +++ b/include/gp/algorithm/move.hpp @@ -1,6 +1,7 @@ #pragma once #include "gp/algorithm/tmp_manip.hpp" +#include "gp/algorithm/cvref.hpp" #include "gp/range.hpp" namespace gp{ @@ -28,7 +29,7 @@ namespace gp{ T& rhs ) { - auto tmp = gp::move(lhs); + gp::remove_cvref_t tmp = gp::move(lhs); lhs = gp::move(rhs); rhs = gp::move(tmp); } @@ -39,7 +40,7 @@ namespace gp{ T& rhs ) { - auto tmp = gp::move(lhs); + gp::remove_cvref_t tmp = gp::move(lhs); lhs = gp::move(rhs); rhs = gp::move(tmp); } @@ -50,7 +51,7 @@ namespace gp{ T&& rhs ) { - auto tmp = gp::move(lhs); + gp::remove_cvref_t tmp = gp::move(lhs); lhs = gp::move(rhs); rhs = gp::move(tmp); } @@ -61,9 +62,9 @@ namespace gp{ T&& rhs ) { - auto tmp = lhs; - lhs = rhs; - rhs = tmp; + gp::remove_cvref_t tmp = gp::move(lhs); + lhs = gp::move(rhs); + rhs = gp::move(tmp); } template diff --git a/include/gp/algorithm/reference.hpp b/include/gp/algorithm/reference.hpp new file mode 100644 index 0000000..cdb30fa --- /dev/null +++ b/include/gp/algorithm/reference.hpp @@ -0,0 +1,159 @@ +#pragma once + +#include +#include + + +namespace gp{ + /** + ********************************************************************************************** + Code extrated from cppreference.com and the libc++ Library project, licensed under MIT license + ********************************************************************************************** + **/ + + namespace detail { + template + constexpr bool is_reference_wrapper_v = false; + template + constexpr bool is_reference_wrapper_v> = true; + + template + constexpr decltype(auto) INVOKE(Type T::* f, T1&& t1, Args&&... args) + { + if constexpr (std::is_member_function_pointer_v) { + if constexpr (std::is_base_of_v>) + return (gp::forward(t1).*f)(gp::forward(args)...); + else if constexpr (is_reference_wrapper_v>) + return (t1.get().*f)(gp::forward(args)...); + else + return ((*gp::forward(t1)).*f)(gp::forward(args)...); + } else { + static_assert(std::is_member_object_pointer_v); + static_assert(sizeof...(args) == 0); + if constexpr (std::is_base_of_v>) + return gp::forward(t1).*f; + else if constexpr (is_reference_wrapper_v>) + return t1.get().*f; + else + return (*gp::forward(t1)).*f; + } + } + + template + constexpr decltype(auto) INVOKE(F&& f, Args&&... args) + { + return gp::forward(f)(gp::forward(args)...); + } + } // namespace detail + + template< class F, class... Args> + constexpr std::invoke_result_t invoke(F&& f, Args&&... args) + noexcept(std::is_nothrow_invocable_v) + { + return detail::INVOKE(gp::forward(f), gp::forward(args)...); + } + + template< class T > + T* addressof(T& arg) + { + return reinterpret_cast( + &const_cast( + reinterpret_cast(arg))); + } + + namespace detail { + template constexpr T& FUN(T& t) noexcept { return t; } + template void FUN(T&&) = delete; + } + + template + class reference_wrapper { + public: + // types + typedef T type; + + // construct/copy/destroy + template (std::declval()), + std::enable_if_t>>() + )> + constexpr reference_wrapper(U&& u) noexcept(noexcept(detail::FUN(gp::forward(u)))) + : _ptr(gp::addressof(detail::FUN(gp::forward(u)))) {} + reference_wrapper(const reference_wrapper&) noexcept = default; + + // assignment + reference_wrapper& operator=(const reference_wrapper& x) noexcept = default; + + // access + constexpr operator T& () const noexcept { return *_ptr; } + constexpr T& get() const noexcept { return *_ptr; } + + template< class... ArgTypes > + constexpr std::invoke_result_t + operator() ( ArgTypes&&... args ) const { + return gp::invoke(get(), gp::forward(args)...); + } + + private: + T* _ptr; + }; + + // deduction guides + template + reference_wrapper(T&) -> reference_wrapper; + + template + auto ref(T& vref) { + return reference_wrapper(vref); + } + + template + class __not_fn_imp { + _DecayFunc __fd; + + public: + __not_fn_imp() = delete; + + template + auto operator()(_Args&& ...__args) & + noexcept(noexcept(!gp::invoke(__fd, gp::forward<_Args>(__args)...))) + -> decltype( !gp::invoke(__fd, gp::forward<_Args>(__args)...)) + { return !gp::invoke(__fd, gp::forward<_Args>(__args)...); } + + template + auto operator()(_Args&& ...__args) && + noexcept(noexcept(!gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...))) + -> decltype( !gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...)) + { return !gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...); } + + template + auto operator()(_Args&& ...__args) const& + noexcept(noexcept(!gp::invoke(__fd, gp::forward<_Args>(__args)...))) + -> decltype( !gp::invoke(__fd, gp::forward<_Args>(__args)...)) + { return !gp::invoke(__fd, gp::forward<_Args>(__args)...); } + + + template + auto operator()(_Args&& ...__args) const&& + noexcept(noexcept(!gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...))) + -> decltype( !gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...)) + { return !gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...); } + + private: + template , __not_fn_imp>::value>> + explicit __not_fn_imp(_RawFunc&& __rf) + : __fd(gp::forward<_RawFunc>(__rf)) {} + + template + friend inline __not_fn_imp> not_fn(_RawFunc&&); + }; + + template + inline __not_fn_imp> not_fn(_RawFunc&& __fn) { + return __not_fn_imp>(gp::forward<_RawFunc>(__fn)); + } + /** + ********************************************************************************************* + */ +} \ No newline at end of file diff --git a/include/gp/algorithm/tmp_manip.hpp b/include/gp/algorithm/tmp_manip.hpp index 824a01c..0437abd 100644 --- a/include/gp/algorithm/tmp_manip.hpp +++ b/include/gp/algorithm/tmp_manip.hpp @@ -97,7 +97,17 @@ namespace gp{ template struct r_index_at { - using type = typename either::type>::type; + using type = + typename either< + idx==sizeof...(rest), + T, + typename r_index_at::type + >::type; + }; + + template + struct first_of { + using type = U; }; template diff --git a/include/gp/function.hpp b/include/gp/function.hpp index 401289c..c6e486b 100644 --- a/include/gp/function.hpp +++ b/include/gp/function.hpp @@ -53,13 +53,7 @@ namespace gp{ } public: -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnull-dereference" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnull-dereference" function(allocator& alloc_v) -#pragma GCC diagnostic pop -#pragma clang diagnostic pop : alloc(alloc_v) , invokator(nullptr) , condestructor(nullptr) @@ -144,9 +138,6 @@ namespace gp{ } ~function(){ - if(data_size == 0) { - return; - } if(data_size <= 0) { return; } @@ -174,21 +165,34 @@ namespace gp{ alloc = rhs.alloc; invokator = rhs.invokator; condestructor = rhs.condestructor; - if(data_size) condestructor(nullptr, data_ptr); - alloc.value().get().deallocate(data_ptr); - data_ptr = rhs.data_size <= sizeof(data_ptr) + + /* Cleanup */ + + if(data_size > sizeof(data_ptr)) { + condestructor(nullptr, data_ptr); + alloc.value().get().deallocate(data_ptr); + } else if(data_size) { + condestructor(nullptr, (char*)&data_ptr); + } + + /* Reallocation */ + + data_size = rhs.data_size; + data_ptr = data_size <= sizeof(data_ptr) ? 0 : details::ensure( [&](){return alloc.has_value();}, [&](){return (char*)(alloc.value().get().allocate(rhs.data_size));} ); - data_size = rhs.data_size; - gp_config::assertion(!(alloc.has_value() && data_ptr == nullptr), "allocator failed in function"); + gp_config::assertion(!(alloc.has_value() && data_size > 8 && data_ptr != nullptr), "allocator failed in function"); + if( - data_ptr != nullptr - and rhs.data_ptr != nullptr - ) this->condestructor(data_size <= sizeof(data_ptr) ? (char*)&data_ptr : data_ptr, rhs.data_ptr); + data_size > 0 + ) this->condestructor( + data_size <= sizeof(data_ptr) ? (char*)&data_ptr : data_ptr, + data_size <= sizeof(data_ptr) ? (char*)&rhs.data_ptr : rhs.data_ptr + ); return *this; } diff --git a/include/gp/pair.hpp b/include/gp/pair.hpp index a662646..1cec317 100644 --- a/include/gp/pair.hpp +++ b/include/gp/pair.hpp @@ -44,6 +44,11 @@ namespace gp{ } }; + template + pair make_pair(T1 f, T2 s) { + return pair(f, s); + } + template bool operator==(const pair& lhs, const pair& rhs) { return lhs.first == rhs.first and lhs.second == rhs.second; diff --git a/include/gp/variant.hpp b/include/gp/variant.hpp index d39d78a..6341fb1 100644 --- a/include/gp/variant.hpp +++ b/include/gp/variant.hpp @@ -24,38 +24,58 @@ namespace gp{ gp::function dtor = {[](void*){}, nullopt}; static_assert(all_of_fixed_size::value, "not fixed"); - void buffswap(fixed_variant& oth) { - char tmp[max_size()]; - mvtor(tmp, buffer); - oth.mvtor(buffer, oth.buffer); - mvtor(oth.buffer, tmp); - } public: - template,T...>::value,int>> + fixed_variant() + : fixed_variant(typename first_of::type{}) + {} + + template,T...>::value,int> = 0> fixed_variant(U& value) : index{r_index_of::value} { using actual = gp::remove_cvref_t; - new(buffer) actual(value); - dtor = gp::function([](void* thing){((actual*)thing)->~actual();}, nullopt); - cpytor = gp::function([](void* src, void* dest){new(dest) actual(*(actual*)src);}, nullopt); - mvtor = gp::function([](void* src, void* dest){new(dest) actual(gp::move(*(actual*)src));}, nullopt); + dtor = gp::function([](void* thing){ + ((actual*)thing)->~actual(); + }, nullopt); + cpytor = gp::function([](void* src, void* dest){ + new(dest) actual(*(actual*)src); + }, nullopt); + mvtor = gp::function([](void* src, void* dest){ + new(dest) actual(gp::move(*(actual*)src)); + }, nullopt); + cpytor((char*)&value, buffer); } static_assert(list_contains_class::value, "list_contains_class doesn't work properly"); static_assert(list_contains_class::value, "list_contains_class doesn't work properly"); static_assert(list_contains_class::value, "list_contains_class doesn't work properly"); static_assert(list_contains_class::value, "list_contains_class doesn't work properly"); + static_assert(!list_contains_class::value, "list_contains_class doesn't work properly"); - template,T...>::value,int>> + template,T...>::value,int> = 0> fixed_variant(U&& value) : index{r_index_of::value} { using actual = gp::remove_cvref_t; - new(buffer) actual(std::move(value)); - dtor = gp::function([](void* thing){((actual*)thing)->~actual();}, nullopt); - cpytor = gp::function([](void* src, void* dest){new(dest) actual(*(actual*)src);}, nullopt); - mvtor = gp::function([](void* src, void* dest){new(dest) actual(gp::move(*(actual*)src));}, nullopt); + dtor = gp::function([](void* thing){ + ((actual*)thing)->~actual(); + }, nullopt); + cpytor = gp::function([](void* src, void* dest){ + new(dest) actual(*(actual*)src); + }, nullopt); + mvtor = gp::function([](void* src, void* dest){ + new(dest) actual(gp::move(*(actual*)src)); + }, nullopt); + mvtor((char*)&value, buffer); + } + + fixed_variant(const fixed_variant& oth) + : index{oth.index} + , dtor{oth.dtor} + , cpytor{oth.cpytor} + , mvtor{oth.mvtor} + { + cpytor((char*)oth.buffer, (char*)buffer); } fixed_variant(fixed_variant& oth) @@ -68,12 +88,13 @@ namespace gp{ } fixed_variant(fixed_variant&& oth) + : index{oth.index} + , dtor{oth.dtor} + , cpytor{oth.cpytor} + , mvtor{oth.mvtor} { - mvtor(buffer, oth.buffer); - gp::swap(dtor, oth.dtor); - gp::swap(cpytor, oth.cpytor); - gp::swap(mvtor, oth.mvtor); - gp::swap(index, oth.index); + oth.index = std::numeric_limits::max(); + mvtor(oth.buffer, buffer); } template @@ -100,11 +121,16 @@ namespace gp{ void operator=(fixed_variant&& value) { - buffswap(value); - gp::swap(dtor, value.dtor); - gp::swap(cpytor, value.cpytor); - gp::swap(mvtor, value.mvtor); - gp::swap(index, value.index); + if(index != std::numeric_limits::max()) + { + dtor((void*)buffer); + } + dtor = value.dtor; + cpytor = value.cpytor; + mvtor = value.mvtor; + index = value.index; + value.index = std::numeric_limits::max(); + mvtor(value.buffer, buffer); } template::value,int>::type> @@ -128,11 +154,11 @@ namespace gp{ { dtor((void*)buffer); } + new(buffer) U(gp::move(value)); index = r_index_of::value; dtor = gp::function([](void* thing){((U*)thing)->~U();}, nullopt); cpytor = gp::function([](void* src, void* dest){new(dest) U(*(U*)src);}, nullopt); mvtor = gp::function([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));}, nullopt); - mvtor(buffer, value.buffer); } ~fixed_variant() @@ -158,7 +184,7 @@ namespace gp{ } template - constexpr U& is_a() + constexpr bool is_a() { if(r_index_of::value == index) { diff --git a/tests.cpp b/tests.cpp index 9c79511..9d5732d 100644 --- a/tests.cpp +++ b/tests.cpp @@ -23,13 +23,13 @@ int main() { ++runned; int value; - try{ +// try{ value = test->run(); if(value) { std::cout << std::dec << test->name << " failed with "<< value << std::endl; } - } catch (gp::runtime_error err) { +/* } catch (gp::runtime_error err) { std::cout << test->name << " failed with an exception: " << err.what() << std::endl; value = -1; } catch (gp_config::assert_failure err) { @@ -38,7 +38,7 @@ int main() } catch (...) { std::cout << test->name << " failed with an exception" << std::endl; value = -1; - } + }*/ failed += (value != 0); } std::cout << std::dec << "Runned "< store; gp::arena alloc{&*store.begin(), store.size()}; - gp::cbor_value data{alloc}; + /*gp::cbor_value data{alloc}; auto gen = data.new_object(); - gen.emplace_back(gp::cbor_value{uint8_t(12), alloc}, gp::cbor_value{int32_t(-98), alloc}); - gen.emplace_back(gp::cbor_value{uint8_t(13), alloc}, gp::cbor_value{uint32_t(98), alloc}); - data = gen; + gen.push_back(gp::make_pair(gp::cbor_value{uint8_t(12), alloc}, gp::cbor_value{int32_t(-98), alloc})); + gen.push_back(gp::make_pair(gp::cbor_value{uint8_t(13), alloc}, gp::cbor_value{uint32_t(98), alloc})); + data = gen;*/ + + using some_int = gp::fixed_variant; + { + some_int a{16}; + some_int b = 12u; + b = a; + gp_config::assertion(b.is_a(), "b got wrong type assigned"); + } + { + some_int a{16u}; + some_int b = a; + gp_config::assertion(b.is_a(), "b got wrong type assigned"); + gp_config::assertion(b.value() == 16, "b got wrong value assigned"); + } + { + some_int a{16u}; + some_int b = gp::move(a); + gp_config::assertion(b.is_a(), "b got wrong type assigned"); + gp_config::assertion(b.value() == 16, "b got wrong value assigned"); + } + { + some_int a{16u}; + some_int b; + new(&b) some_int(a); + gp_config::assertion(b.is_a(), "b got wrong type assigned"); + gp_config::assertion(b.value() == 16, "b got wrong value assigned"); + } + { + some_int a{16u}; + some_int b; + new(&b) some_int(gp::move(a)); + gp_config::assertion(b.is_a(), "b got wrong type assigned"); + gp_config::assertion(b.value() == 16, "b got wrong value assigned"); + } + { + gp::vector vec{alloc}; + vec.emplace_back(12u); + vec.emplace_back(-16); + gp_config::assertion(vec[0].is_a(), "vec0 got wrong type assigned"); + gp_config::assertion(vec[1].is_a(), "vec1 got wrong type assigned"); + } + return 0; } };