diff --git a/include/gp/containers/vector.hpp b/include/gp/containers/vector.hpp index 8c15d13..6956423 100644 --- a/include/gp/containers/vector.hpp +++ b/include/gp/containers/vector.hpp @@ -67,6 +67,8 @@ namespace gp{ , cap(oth.cap) , alloc(oth.alloc) { + oth.sz = 0; + oth.cap = 0; oth.ary = nullptr; } @@ -81,10 +83,12 @@ namespace gp{ gp_config::assertion(reserve(oth.size()), "could not reserve space on assign"); for(size_t i = 0; i < gp::min(sz, oth.sz); ++i) { + if constexpr (!std::is_trivially_destructible_v) ary[i]->~T(); new(ary+i) T(oth[i]); } if(sz < oth.sz) { for(size_t i = sz; i < oth.sz; ++i) { + if constexpr (!std::is_trivially_destructible_v) ary[i]->~T(); new(ary+i) T(oth[i]); } } else if(sz > oth.sz) { @@ -123,10 +127,14 @@ namespace gp{ size_t idx = 0; for(auto& elem : oth) { new(ary+idx) T(gp::move(elem)); + ++idx; elem.~T(); } + gp_config::assertion(alloc.get().deallocate(oth.ary), "could not deallocate"); sz = idx; oth.sz = 0; + oth.capacity = 0; + oth.ary = nullptr; } return *this; } @@ -147,6 +155,7 @@ namespace gp{ { if(ary) { + if constexpr (!std::is_trivially_destructible_v) for(auto& elem : *this) { elem.~T(); } diff --git a/tests.cpp b/tests.cpp index 0d3cbc7..dbcf701 100644 --- a/tests.cpp +++ b/tests.cpp @@ -10,7 +10,7 @@ alignas(2048) gp::array static_mapper::store; gp::buddy<> static_mapper::impl = gp::buddy<>{store.begin().data, store.size()}; -static_logging_segment<128> logger; +static_logging_segment<1024> logger; void log_failure(const char* failure) { log_segment("FAILURE", failure, std::numeric_limits::max()); diff --git a/tests/issue15_test.cpp b/tests/issue15_test.cpp new file mode 100644 index 0000000..349bae2 --- /dev/null +++ b/tests/issue15_test.cpp @@ -0,0 +1,236 @@ +#include "test_scaffold.h" +#include "gp/containers/array.hpp" +#include "gp/containers/vector.hpp" +#include "gp/ipc/envelope/cbor.hpp" +#include "gp/algorithms/tmp_manip.hpp" +#include "gp/functional/monostates.hpp" +#include "gp/utils/allocators/allocator.hpp" +#include +#include + +extern void print_logs(); + +struct std_allocator : gp::allocator { + using dbg_map = std::unordered_map; + [[no_unique_address]] dbg_map debug_info; + + /** + * @brief Allocates memory + * + * @param sz the amount of bytes to allocate + * + * @return the allocated memory as a pointer on success + * @return nullptr if it failed allocating + */ + virtual void* allocate(size_t sz) { + auto v = new char[sz]; + log_segment("data allocated", (std::to_string(sz) + " bytes @"+std::to_string((uintptr_t)v)).c_str()); + debug_info[v] = sz; + return v; + } + + /** + * @brief Deallocates memory + * + * @param ptr the memory to deallocate + * + * @return true if the memory was successfully deallocated + * @return false if the memory was not deallocated + */ + virtual bool deallocate(void* ptr) { + log_segment("data deallocated", "Trying deallocation"); + log_segment("data deallocated", ("Target: @" + std::to_string((uintptr_t)ptr)).c_str()); + + if(!debug_info.contains(ptr)) + gp_config::assertion(false, "Double free detected"); + print_logs(); + + delete (char*)ptr; + log_segment("data deallocated", (std::to_string(debug_info[ptr]) + " bytes @"+std::to_string((uintptr_t)ptr)).c_str()); + debug_info.erase(ptr); + return true; + } + + /** + * @brief Tries to reallocate memory + * + * @param ptr The memory to reallocate + * @param sz The new size we want to give the memory + * + * @return true if reallocation was successful + * @return false if the reallocation failed + */ + virtual bool try_reallocate(void*, size_t) { + return false; + } + + virtual ~std_allocator() = default; +}; + +std_allocator allocator; + +enum class co_state { + waiting_receive, + waiting_send, + data_received, + data_sent +}; + +typedef gp::array identifier_t; +using fd_t = int; + +struct packet_info { + uint64_t attempts = 0; + uint64_t sequence = 0; + identifier_t co_id; + gp::vector data{allocator}; +}; + +gp::vector& push_as_cbor(gp::vector& src, identifier_t& value) { + gp::push_as_cbor(src, gp::cbor_tag_initiator{.as_integer = 37}); + gp::push_as_cbor(src, value.as_buffer()); + return src; +} + +gp::vector& push_as_cbor(gp::vector& src, packet_info& value) { + push_as_cbor(src, gp::cbor_tag_initiator{.as_integer = 1994}); + push_as_cbor(src, gp::cbor_array_initiator{4}); + push_as_cbor(src, value.sequence); + push_as_cbor(src, value.attempts); + push_as_cbor(src, value.co_id); + push_as_cbor(src, value.data.as_buffer()); + return src; +} + +namespace gp { template<> +gp::pair, parsing_state> read_cbor(parsing_state state, gp::allocator& alloc) { + size_t seq, attempts; + identifier_t uuid; + gp::vector data{alloc}; + bool ok = true; + + auto array_parser = [&](parsing_state state, allocator& alloc){ + for(size_t idx : {0,1,2,3}) + switch(idx) { + case 0:{ + auto [v ,new_state] = read_cbor(state, alloc); + if(v.has_value()) { + seq = v.value(); + return new_state; + } + }break; + case 1:{ + auto [v ,new_state] = read_cbor(state, alloc); + if(v.has_value()) { + attempts = v.value(); + return new_state; + } + }break; + case 2:{ + auto [tg ,nc_state] = read_cbor(state, alloc); + if(!tg.has_value()) break; + if(tg.value().as_integer != 37) break; + + auto [v ,new_state] = read_cbor>(nc_state, alloc); + if(v.has_value()) { + for(size_t idx : {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}) { + uuid[idx] = v.value()[idx]; + } + return new_state; + } + }break; + case 3:{ + auto [v ,new_state] = read_cbor>(state, alloc); + if(v.has_value()) { + data = v.value(); + return new_state; + } + }break; + } + ok &= false; + log_segment("ok", ok ? "true" : "false"); + return state; + }; + + parsing_state nc_state = state; + { + auto [value, new_state] = read_cbor(nc_state, alloc); + if(!value.has_value()) return {gp::nullopt, state}; + nc_state = new_state; + } + { + auto new_state = read_cbor_array(nc_state, alloc, array_parser, [&](size_t sz){ + ok &= sz == 4; + log_segment("ok", ok ? "true" : "false"); + return ok; + }); + if(ok && new_state.size() != nc_state.size()) { + log_segment("INFO", "Parsing terminated successfully"); + return {packet_info{.attempts = attempts, .sequence = seq, .data = gp::move(data)}, new_state}; + } + else + return {nullopt, state}; + } +}} + +struct packet_info_serialization_test : public test_scaffold { + packet_info_serialization_test() { + name = __FILE__ "@packet_info_serialization_test"; + } + + virtual int run() { + packet_info item; + item.sequence = 1; + item.attempts = 2; + for(auto& c : item.co_id) c = 1; + for(auto idx : {0,1,2,3,4,5,6,7,8,9}) item.data.push_back(idx); + + gp::vector serialized(allocator); + + push_as_cbor(serialized, item); + + log_segment("size", std::to_string(serialized.size()).c_str()); + + gp_config::assertion(serialized.size() == 36, "serialization of the wrong size"); + + return 0; + } +}; + +append_test packet_info_serialization_test_impl(new packet_info_serialization_test()); + + + +struct packet_info_deserialization_test : public test_scaffold { + packet_info_deserialization_test() { + name = __FILE__ "@packet_info_deserialization_test"; + } + + virtual int run() { + packet_info item; + item.sequence = 1; + item.attempts = 2; + for(auto& c : item.co_id) c = 1; + for(auto idx : {0,1,2,3,4,5,6,7,8,9}) item.data.push_back(idx); + + gp::vector serialized(allocator); + + push_as_cbor(serialized, item); + + log_segment("size", std::to_string(serialized.size()).c_str()); + + gp_config::assertion(serialized.size() == 36, "serialization of the wrong size"); + + auto [value, state] = gp::read_cbor(serialized.as_buffer(), allocator); + + gp_config::assertion(value.has_value(), "deserialization failed"); + gp_config::assertion(!state.size(), "unprocessed state remains"); + gp_config::assertion(value.value().sequence == item.sequence, "comparison failed step 1"); + gp_config::assertion(value.value().attempts == item.attempts, "comparison failed step 2"); + gp_config::assertion(value.value().co_id == item.co_id, "comparison failed step 3"); + gp_config::assertion(value.value().data == item.data, "comparison failed step 4"); + return 0; + } +}; + +append_test packet_info_deserialization_test_impl(new packet_info_deserialization_test()); \ No newline at end of file