// Copyright 2023 Matt Borland // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #ifndef BOOST_DECIMAL_DETAIL_MEMCPY_HPP #define BOOST_DECIMAL_DETAIL_MEMCPY_HPP #include #ifndef BOOST_DECIMAL_BUILD_MODULE #include #include #endif // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89689 // GCC 10 added checks for length of memcpy which yields the following warning (converted to error with -Werror) // /usr/include/x86_64-linux-gnu/bits/string_fortified.h:34:33: error: // ‘void* __builtin___memcpy_chk(void*, const void*, long unsigned int, long unsigned int)’ specified size between // 18446744071562067968 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Werror=stringop-overflow=] // // memcpy is defined as taking a size_t for the count and the largest count this will recieve is the number of digits // in a 128-bit int (39) so we can safely ignore #if defined(__GNUC__) && __GNUC__ >= 10 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wstringop-overflow" # pragma GCC diagnostic ignored "-Warray-bounds" # define BOOST_DECIMAL_STRINGOP_OVERFLOW_DISABLED #endif namespace boost { namespace decimal { namespace detail { namespace impl { constexpr char* memcpy_impl(char* dest, const char* src, std::size_t count) { for (std::size_t i = 0; i < count; ++i) { dest[i] = src[i]; } return dest; } constexpr char* memset_impl(char* dest, int ch, std::size_t count) { for (std::size_t i = 0; i < count; ++i) { dest[i] = static_cast(ch); } return dest; } constexpr char* memmove_impl(char* dest, const char* src, std::size_t count) { if (dest < src || dest >= src + count) { // Non-overlapping or safe to copy forward for (std::size_t i = 0; i < count; ++i) { dest[i] = src[i]; } } else { // Overlapping, copy backward to avoid overwriting source for (std::size_t i = count; i > 0; --i) { dest[i - 1] = src[i - 1]; } } return dest; } } #if !defined(BOOST_DECIMAL_NO_CONSTEVAL_DETECTION) constexpr char* memcpy(char* dest, const char* src, std::size_t count) { if (BOOST_DECIMAL_IS_CONSTANT_EVALUATED(count)) { return impl::memcpy_impl(dest, src, count); } else { // Workaround for GCC-11 because it does not honor GCC diagnostic ignored // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431 // Hopefully the optimizer turns this into memcpy #if defined(__GNUC__) && __GNUC__ == 11 for (std::size_t i = 0; i < count; ++i) { *(dest + i) = *(src + i); } return dest; #else return static_cast(std::memcpy(dest, src, count)); #endif } } constexpr char* memset(char* dest, int ch, std::size_t count) { if (BOOST_DECIMAL_IS_CONSTANT_EVALUATED(count)) { return impl::memset_impl(dest, ch, count); } else { return static_cast(std::memset(dest, ch, count)); } } constexpr char* memmove(char* dest, const char* src, std::size_t count) { if (BOOST_DECIMAL_IS_CONSTANT_EVALUATED(count)) { return impl::memmove_impl(dest, src, count); } else { return static_cast(std::memmove(dest, src, count)); } } #else // No consteval detection constexpr char* memcpy(char* dest, const char* src, std::size_t count) { return impl::memcpy_impl(dest, src, count); } constexpr char* memset(char* dest, int ch, std::size_t count) { return impl::memset_impl(dest, ch, count); } constexpr char* memmove(char* dest, const char* src, std::size_t count) { return impl::memmove_impl(dest, src, count); } #endif } //namespace detail } //namespace decimal } //namespace boost #ifdef BOOST_DECIMAL_STRINGOP_OVERFLOW_DISABLED # pragma GCC diagnostic pop #endif #endif // BOOST_DECIMAL_DETAIL_MEMCPY_HPP