diff --git a/cmake/configuration.cmake b/cmake/configuration.cmake index ccd26e4e..c5987354 100644 --- a/cmake/configuration.cmake +++ b/cmake/configuration.cmake @@ -161,15 +161,44 @@ endif () set (HIBF_UNINITIALISED_RESIZE_TEST_SOURCE "#include + #include #include - struct my_vector : public std::vector + struct my_vector : public std::vector { - void resize_for_overwrite(size_t const size) + using base_t = std::vector; + + #ifdef _LIBCPP_VERSION + inline void resize_for_overwrite(size_t const size) + { + struct fake_vector + { + using allocator_t = typename base_t::allocator_type; + using pointer = typename std::allocator_traits::pointer; + + pointer begin; + pointer end; + std::__compressed_pair end_cap; + }; + + static_assert(sizeof(fake_vector) == sizeof(base_t)); + static_assert(alignof(fake_vector) == alignof(base_t)); + + if (size > base_t::capacity()) + base_t::reserve(size); + + fake_vector & vec = reinterpret_cast(*this); + vec.end = vec.begin + size; + } + #else + inline void resize_for_overwrite(size_t const size) { - this->_M_create_storage(size); - this->_M_impl._M_finish = this->_M_impl._M_end_of_storage; + if (size > base_t::capacity()) + base_t::reserve(size); + + this->_M_impl._M_finish = this->_M_impl._M_start + size; } + #endif }; int main() @@ -222,7 +251,6 @@ else () # CMake's check_ipo_supported uses hardcoded lto flags # macOS GCC supports -flto-auto, but not the hardcoded flag "-fno-fat-lto-objects" if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Darwin") - set (HIBF_LTO_FLAGS "-flto=auto -ffat-lto-objects") else () set (HIBF_LTO_FLAGS "-flto=auto") diff --git a/include/hibf/misc/bit_vector.hpp b/include/hibf/misc/bit_vector.hpp index aae2ef00..5afc55af 100644 --- a/include/hibf/misc/bit_vector.hpp +++ b/include/hibf/misc/bit_vector.hpp @@ -918,15 +918,56 @@ class bit_vector : //!\endcond private: +// If nothing else works: Just use `resize`. +#ifndef HIBF_UNINITIALISED_RESIZE HIBF_CONSTEXPR_VECTOR inline void resize_for_overwrite(size_t const size) { -#ifdef HIBF_UNINITIALISED_RESIZE - this->_M_create_storage(size); - this->_M_impl._M_finish = this->_M_impl._M_end_of_storage; -#else base_t::resize(size); -#endif } +#else +// libc++: reinterpret_cast to a struct that has the same layout as std::vector. +// All internal members are private. +# if defined(_LIBCPP_VERSION) + inline void resize_for_overwrite(size_t const size) + { + struct fake_vector + { + using allocator_t = typename base_t::allocator_type; + using pointer = typename std::allocator_traits::pointer; + + pointer begin; + pointer end; + std::__compressed_pair end_cap; + }; + + static_assert(sizeof(fake_vector) == sizeof(base_t)); + static_assert(alignof(fake_vector) == alignof(base_t)); + + if (size > base_t::capacity()) + base_t::reserve(size); + +// Annotate the new memory as contiguous container for llvm's address sanitizer. +# ifndef _LIBCPP_HAS_NO_ASAN + __sanitizer_annotate_contiguous_container(base_t::data(), + base_t::data() + base_t::capacity(), + base_t::data() + base_t::size(), + base_t::data() + size); +# endif + + fake_vector & vec = reinterpret_cast(*this); + vec.end = vec.begin + size; + } +// libstdc++: The internal members are protected, so we can access them. +# else + HIBF_CONSTEXPR_VECTOR inline void resize_for_overwrite(size_t const size) + { + if (size > base_t::capacity()) + base_t::reserve(size); + + this->_M_impl._M_finish = this->_M_impl._M_start + size; + } +# endif +#endif //!\brief Performs the binary bitwise-operation on the underlying chunks. template