/* xspan -- a minimally invasive checked memory smart pointer This file is part of the UPX executable compressor. Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer All Rights Reserved. UPX and the UCL library are free software; you can redistribute them and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Markus F.X.J. Oberhumer */ #pragma once #if WITH_XSPAN #if 1 #define XSPAN_NAMESPACE_NAME XSpan #define XSPAN_NAMESPACE_BEGIN namespace XSPAN_NAMESPACE_NAME { #define XSPAN_NAMESPACE_END } #define XSPAN_NS(x) XSPAN_NAMESPACE_NAME ::x #else #define XSPAN_NAMESPACE_BEGIN /*empty*/ #define XSPAN_NAMESPACE_END /*empty*/ #define XSPAN_NS(x) ::x #endif XSPAN_NAMESPACE_BEGIN // HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience noinline void xspan_fail_nullptr(); noinline void xspan_fail_nullbase(); noinline void xspan_fail_not_same_base(); noinline void xspan_fail_range_nullptr(); noinline void xspan_fail_range_nullbase(); noinline void xspan_fail_range_range(); void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes); // help constructor to distinguish between number of elements and bytes struct XSpanCount { explicit forceinline XSpanCount(size_t n) noexcept : count(n) {} size_t count; // public }; struct XSpanSizeInBytes { explicit forceinline XSpanSizeInBytes(size_t bytes) noexcept : size_in_bytes(bytes) {} size_t size_in_bytes; // public }; template struct TypeForSizeOf { typedef T type; }; template <> struct TypeForSizeOf { typedef char type; }; template <> struct TypeForSizeOf { typedef const char type; }; template struct ValueForSizeOf { static const size_t value = sizeof(typename TypeForSizeOf::type); }; ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf::value == 1) ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf::value == 1) ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf::value == 1) ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf::value == 1) ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf::value == 4) #ifndef xspan_mem_size_impl template inline size_t xspan_mem_size_impl(size_t n) { #ifdef UPX_VERSION_HEX // check for overflow and sane limits return mem_size(sizeof(T), n); #else return sizeof(T) * n; #endif } #endif template inline size_t xspan_mem_size(size_t n) { return xspan_mem_size_impl::type>(n); } template inline void xspan_mem_size_assert_ptrdiff(ptrdiff_t n) { if (n >= 0) (void) xspan_mem_size((size_t) n); else (void) xspan_mem_size((size_t) -n); } #if __cplusplus >= 201103L && 0 // unfortunately doesnt't work with some older versions of libstdc++ // (TODO later: we now require C++17, so this now probably works on all supported platforms) template struct XSpan_is_convertible : public std::is_convertible {}; #else // manual implementation namespace detail { // helper for "void" template struct XSpan_void_to_T { typedef U type; }; template struct XSpan_void_to_T { typedef typename std::remove_const::type type; }; template struct XSpan_void_to_T { typedef T type; }; template struct XSpan_ptr_is_convertible : public std::false_type {}; template struct XSpan_ptr_is_convertible : public std::true_type {}; template struct XSpan_ptr_is_convertible : public std::true_type {}; } // namespace detail template struct XSpan_is_convertible : public detail::XSpan_ptr_is_convertible::type> {}; #endif #if DEBUG // need extra parenthesis because the C preprocessor does not understand C++ templates // char => char ACC_COMPILE_TIME_ASSERT_HEADER((XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((!XSpan_is_convertible::value)) // void => void ACC_COMPILE_TIME_ASSERT_HEADER((XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((!XSpan_is_convertible::value)) // char => void ACC_COMPILE_TIME_ASSERT_HEADER((XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((!XSpan_is_convertible::value)) // void => char ACC_COMPILE_TIME_ASSERT_HEADER((!XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((!XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((!XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((!XSpan_is_convertible::value)) // char => int ACC_COMPILE_TIME_ASSERT_HEADER((!XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((!XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((!XSpan_is_convertible::value)) ACC_COMPILE_TIME_ASSERT_HEADER((!XSpan_is_convertible::value)) #endif /************************************************************************* // PtrOrSpanOrNull // PtrOrSpan // Span // Ptr **************************************************************************/ // forward declarations template struct PtrOrSpanOrNull; template struct PtrOrSpan; template struct Span; template struct Ptr; // XSpanInternalDummyArg: some type that is hard to match by accident class XSpanInternalDummyArgFake; // not implemented on purpose #if 0 typedef XSpanInternalDummyArgFake *XSpanInternalDummyArg; #define XSpanInternalDummyArgInit nullptr #else struct XSpanInternalDummyArg { explicit forceinline XSpanInternalDummyArg(int, XSpanInternalDummyArgFake *) noexcept {} }; #define XSpanInternalDummyArgInit (XSPAN_NS(XSpanInternalDummyArg)(0, nullptr)) #endif XSPAN_NAMESPACE_END #ifndef XSPAN_DELETED_FUNCTION #define XSPAN_DELETED_FUNCTION = delete #endif // function/method constraints #define XSPAN_REQUIRES_CONVERTIBLE_ONE_DIRECTION(From, To, RType) \ typename std::enable_if::value, RType > ::type #define XSPAN_REQUIRES_CONVERTIBLE_ANY_DIRECTION(A, B, RType) \ typename std::enable_if::value || \ XSPAN_NS(XSpan_is_convertible)::value, \ RType > ::type // note: these use "T" and "U" #define XSPAN_REQUIRES_CONVERTIBLE_R(RType) XSPAN_REQUIRES_CONVERTIBLE_ONE_DIRECTION(U, T, RType) #define XSPAN_REQUIRES_CONVERTIBLE_A \ XSPAN_REQUIRES_CONVERTIBLE_R(XSPAN_NS(XSpanInternalDummyArg)) = XSpanInternalDummyArgInit #define XSPAN_REQUIRES_CONVERTIBLE_T XSPAN_REQUIRES_CONVERTIBLE_R(XSPAN_NS(XSpanInternalDummyArg)) // note: these use "T" and "U" #define XSPAN_REQUIRES_SIZE_1_R(RType) \ typename std::enable_if::value &&XSPAN_NS( \ ValueForSizeOf)::value == 1 && \ XSPAN_NS(ValueForSizeOf)::value == 1, \ RType > ::type #define XSPAN_REQUIRES_SIZE_1_A \ XSPAN_REQUIRES_SIZE_1_R(XSPAN_NS(XSpanInternalDummyArg)) = XSpanInternalDummyArgInit #include "xspan_impl_ptr_or_null.h" #include "xspan_impl_ptr_or_span.h" #include "xspan_impl_span.h" #include "xspan_impl_ptr.h" #undef XSPAN_REQUIRES_CONVERTIBLE_ONE_DIRECTION #undef XSPAN_REQUIRES_CONVERTIBLE_ANY_DIRECTION #undef XSPAN_REQUIRES_CONVERTIBLE_A #undef XSPAN_REQUIRES_CONVERTIBLE_R #undef XSPAN_REQUIRES_CONVERTIBLE_T #undef XSPAN_REQUIRES_SIZE_1_A #undef XSPAN_REQUIRES_SIZE_1_R #endif // WITH_XSPAN /* vim:set ts=4 sw=4 et: */