diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 7177d7c0..e72652c1 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -9,11 +9,15 @@ on: types: - published +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: formatting: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install clang-format env: @@ -21,12 +25,12 @@ jobs: run: | wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh 15 + sudo ./llvm.sh 16 rm llvm.sh - sudo apt-get install -y --no-install-recommends clang-format-15 + sudo apt-get install -y --no-install-recommends clang-format-16 - name: Format files - run: find include test -type f -a \( -name "*.cc" -o -name "*.h" \) -print0 | xargs -0 clang-format-15 -i + run: find include test -type f -a \( -name "*.cc" -o -name "*.h" \) -print0 | xargs -0 clang-format-16 -i - name: Check for differences run: | @@ -37,29 +41,29 @@ jobs: strategy: matrix: config: - - name: GCC 10 Release - cxx: g++-10 - cc: gcc-10 + - name: GCC 11 Release + cxx: g++-11 + cc: gcc-11 mode: Release - - name: GCC 10 Debug - cxx: g++-10 - cc: gcc-10 + - name: GCC 11 Debug + cxx: g++-11 + cc: gcc-11 mode: Debug valgrind: true - - name: Clang 15 Release - cxx: clang++-15 - cc: clang-15 + - name: Clang 16 Release + cxx: clang++-16 + cc: clang-16 mode: Release cxxflags: -stdlib=libc++ ldflags: -lc++abi - - name: Clang 15 Debug - cxx: clang++-15 - cc: clang-15 + - name: Clang 16 Debug + cxx: clang++-16 + cc: clang-16 mode: Debug fuzz: true - - key: GCC 10 Sanitizer - cxx: g++-10 - cc: gcc-10 + - key: GCC 11 Sanitizer + cxx: g++-11 + cc: gcc-11 mode: Debug cflags: -fsanitize=address,undefined -fno-omit-frame-pointer cxxflags: -fsanitize=address,undefined -fno-omit-frame-pointer @@ -67,21 +71,25 @@ jobs: env: UBSAN_OPTIONS: halt_on_error=1:abort_on_error=1 steps: - - uses: actions/checkout@v2 - - uses: seanmiddleditch/gha-setup-ninja@master + - uses: actions/checkout@v3 + + - name: Install Ninja + env: + DEBIAN_FRONTEND: noninteractive + run: sudo apt-get install -y --no-install-recommends ninja-build # ==== INSTALL ==== - - name: Install - if: matrix.config.cc == 'clang-15' + - name: Install Clang + if: matrix.config.cc == 'clang-16' env: DEBIAN_FRONTEND: noninteractive run: | sudo apt-get update wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh 15 || sudo ./llvm.sh 15 workaround + sudo ./llvm.sh 16 || sudo ./llvm.sh 16 workaround rm llvm.sh - sudo apt-get install -y --no-install-recommends libstdc++-12-dev libc++-15-dev libc++abi-15-dev clang-tidy-15 libunwind-15-dev llvm-15 libfuzzer-15-dev + sudo apt-get install -y --no-install-recommends libstdc++-12-dev libc++-16-dev libc++abi-16-dev clang-tidy-16 libunwind-16-dev llvm-16 libfuzzer-16-dev # ==== BUILD ==== - name: CMake @@ -95,7 +103,7 @@ jobs: -DCMAKE_CXX_LINKER_FLAGS=${{ matrix.config.ldflags }}" \ -DCMAKE_CXX_EXE_LINKER_FLAGS="${{ matrix.config.ldflags }} \ -DCMAKE_BUILD_TYPE=${{ matrix.config.mode }} \ - -DCISTA_ZERO_OUT=${{ matrix.config.mode == 'Debug' && matrix.config.cc == 'gcc-10' }} + -DCISTA_ZERO_OUT=${{ matrix.config.mode == 'Debug' && matrix.config.cc == 'gcc-11' }} - name: Build run: cmake --build build --target cista-test cista-test-single-header @@ -127,7 +135,7 @@ jobs: # ==== DISTRIBUTION ==== - name: Upload Distribution - if: matrix.config.mode == 'Release' && matrix.config.cc == 'gcc-10' + if: matrix.config.mode == 'Release' && matrix.config.cc == 'gcc-11' uses: actions/upload-artifact@v1 with: name: cista.h @@ -135,7 +143,7 @@ jobs: # ==== RELEASE ==== - name: Upload Release - if: github.event.action == 'published' && matrix.config.mode == 'Release' && matrix.config.cc == 'gcc-10' + if: github.event.action == 'published' && matrix.config.mode == 'Release' && matrix.config.cc == 'gcc-11' uses: actions/upload-release-asset@v1.0.2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d34ba616..480e3688 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -9,6 +9,10 @@ on: types: - published +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: windows-latest @@ -23,10 +27,12 @@ jobs: CC: cl.exe steps: - - uses: actions/checkout@v2 - - uses: seanmiddleditch/gha-setup-ninja@master + - uses: actions/checkout@v3 - uses: ilammy/msvc-dev-cmd@v1 + - name: Install ninja + run: choco install ninja + - name: Build run: | cmake -GNinja -S . -B build -DCMAKE_BUILD_TYPE=${{ matrix.mode }} diff --git a/CMakeLists.txt b/CMakeLists.txt index f0d5cd88..fdc2261e 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR -Wno-weak-vtables -Wno-unneeded-member-function -Wno-unused-member-function + -Wno-unsafe-buffer-usage -Werror ) elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") diff --git a/include/cista/allocator.h b/include/cista/allocator.h new file mode 100644 index 00000000..99a6e38d --- /dev/null +++ b/include/cista/allocator.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace cista { + +template typename Ptr> +class allocator : public std::allocator { +public: + using size_type = std::size_t; + using pointer = Ptr; + using const_pointer = Ptr; + + template + struct rebind { + using other = allocator; + }; + + using std::allocator::allocator; + using std::allocator::allocate; + using std::allocator::deallocate; +}; + +} // namespace cista \ No newline at end of file diff --git a/include/cista/bit_counting.h b/include/cista/bit_counting.h old mode 100755 new mode 100644 diff --git a/include/cista/containers/pair.h b/include/cista/containers/pair.h index 42d0ae23..fdd8e188 100644 --- a/include/cista/containers/pair.h +++ b/include/cista/containers/pair.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "cista/decay.h" #include "cista/reflection/comparable.h" diff --git a/include/cista/containers/tuple.h b/include/cista/containers/tuple.h index b0fcbfdc..12ee6db6 100644 --- a/include/cista/containers/tuple.h +++ b/include/cista/containers/tuple.h @@ -212,85 +212,84 @@ constexpr decltype(auto) apply_impl(std::index_sequence, F&& f, return std::invoke(std::forward(f), get(std::forward(t))...); } -template +template >>> constexpr decltype(auto) apply(F&& f, Tuple&& t) { return apply_impl(std::make_index_sequence>{}, std::forward(f), std::forward(t)); } template -constexpr decltype(auto) apply_impl(std::index_sequence, F&& f, Tuple&& a, - Tuple&& b) { +constexpr decltype(auto) apply_impl(std::index_sequence, F&& f, + Tuple const& a, Tuple const& b) { return (std::invoke(std::forward(f), get(std::forward(a)), get(std::forward(b))), ...); } template -constexpr decltype(auto) apply(F&& f, Tuple&& a, Tuple&& b) { +constexpr decltype(auto) apply(F&& f, Tuple const& a, Tuple const& b) { return apply_impl( std::make_index_sequence>>{}, std::forward(f), std::forward(a), std::forward(b)); } template -constexpr decltype(auto) eq(std::index_sequence, T1&& a, T2&& b) { - return ((get(std::forward(a)) == get(std::forward(b))) && ...); +constexpr decltype(auto) eq(std::index_sequence, T1 const& a, + T2 const& b) { + return ((get(a) == get(b)) && ...); } template std::enable_if_t> && is_tuple_v>, bool> operator==(T1&& a, T2&& b) { return eq( - std::make_index_sequence>>{}, - std::forward(a), std::forward(b)); + std::make_index_sequence>>{}, a, + b); } template -std::enable_if_t>, bool> operator!=(Tuple&& a, - Tuple&& b) { +std::enable_if_t>, bool> operator!=(Tuple const& a, + Tuple const& b) { return !(a == b); } template -bool lt(Tuple&& a, Tuple&& b) { +bool lt(Tuple const& a, Tuple const& b) { if constexpr (Index == tuple_size_v) { return false; } else { - if (get(std::forward(a)) < - get(std::forward(b))) { + if (get(a) < get(b)) { return true; } - if (get(std::forward(b)) < - get(std::forward(a))) { + if (get(b) < get(a)) { return false; } - return lt(std::forward(a), - std::forward(b)); + return lt(a, b); } } template -std::enable_if_t>, bool> operator<(Tuple&& a, - Tuple&& b) { +std::enable_if_t>, bool> operator<(Tuple const& a, + Tuple const& b) { return lt(a, b); } template -std::enable_if_t>, bool> operator<=(Tuple&& a, - Tuple&& b) { +std::enable_if_t>, bool> operator<=(Tuple const& a, + Tuple const& b) { return !(b < a); } template -std::enable_if_t>, bool> operator>(Tuple&& a, - Tuple&& b) { +std::enable_if_t>, bool> operator>(Tuple const& a, + Tuple const& b) { return b < a; } template -std::enable_if_t>, bool> operator>=(Tuple&& a, - Tuple&& b) { +std::enable_if_t>, bool> operator>=(Tuple const& a, + Tuple const& b) { return !(a < b); } diff --git a/include/cista/containers/vector.h b/include/cista/containers/vector.h index 11783899..60added6 100644 --- a/include/cista/containers/vector.h +++ b/include/cista/containers/vector.h @@ -5,47 +5,70 @@ #include #include #include +#include #include #include #include +#include "cista/allocator.h" #include "cista/containers/ptr.h" #include "cista/is_iterable.h" #include "cista/next_power_of_2.h" #include "cista/strong.h" +#include "cista/unused_param.h" #include "cista/verify.h" namespace cista { -template +template typename Ptr, + bool IndexPointers = false, typename TemplateSizeType = std::uint32_t, + class Allocator = allocator> struct basic_vector { using size_type = base_t; + using difference_type = std::ptrdiff_t; using access_type = TemplateSizeType; + using reference = T&; + using const_reference = T const&; + using pointer = Ptr; + using const_pointer = Ptr; using value_type = T; using iterator = T*; using const_iterator = T const*; + using allocator_type = Allocator; + explicit basic_vector(allocator_type const&) noexcept {} basic_vector() noexcept = default; - explicit basic_vector(size_type const size, T init = T{}) { + + explicit basic_vector(size_type const size, T init = T{}, + Allocator const& alloc = Allocator{}) { + CISTA_UNUSED_PARAM(alloc) resize(size, std::move(init)); } - basic_vector(std::initializer_list init) { set(init.begin(), init.end()); } + + basic_vector(std::initializer_list init, + Allocator const& alloc = Allocator{}) { + CISTA_UNUSED_PARAM(alloc) + set(init.begin(), init.end()); + } template basic_vector(It begin_it, It end_it) { set(begin_it, end_it); } - basic_vector(basic_vector&& arr) noexcept - : el_(arr.el_), - used_size_(arr.used_size_), - allocated_size_(arr.allocated_size_), - self_allocated_(arr.self_allocated_) { - arr.reset(); + basic_vector(basic_vector&& o, Allocator const& alloc = Allocator{}) noexcept + : el_(o.el_), + used_size_(o.used_size_), + allocated_size_(o.allocated_size_), + self_allocated_(o.self_allocated_) { + CISTA_UNUSED_PARAM(alloc) + o.reset(); } - basic_vector(basic_vector const& arr) { set(arr); } + basic_vector(basic_vector const& o, Allocator const& alloc = Allocator{}) { + CISTA_UNUSED_PARAM(alloc) + set(o); + } basic_vector& operator=(basic_vector&& arr) noexcept { deallocate(); @@ -81,10 +104,14 @@ struct basic_vector { reset(); } + allocator_type get_allocator() const noexcept { return {}; } + T const* data() const noexcept { return begin(); } T* data() noexcept { return begin(); } T const* begin() const noexcept { return el_; } T const* end() const noexcept { return el_ + used_size_; } // NOLINT + T const* cbegin() const noexcept { return el_; } + T const* cend() const noexcept { return el_ + used_size_; } // NOLINT T* begin() noexcept { return el_; } T* end() noexcept { return el_ + used_size_; } // NOLINT @@ -266,11 +293,16 @@ struct basic_vector { used_size_ = size; } + void pop_back() noexcept(noexcept(std::declval().~T())) { + --used_size_; + el_[used_size_].~T(); + } + void clear() { - used_size_ = 0; for (auto& el : *this) { el.~T(); } + used_size_ = 0; } void reserve(size_type new_size) { @@ -374,7 +406,7 @@ struct basic_vector { self_allocated_ = false; } - Ptr el_{nullptr}; + Ptr el_{nullptr}; size_type used_size_{0U}; size_type allocated_size_{0U}; bool self_allocated_{false}; @@ -386,13 +418,13 @@ struct basic_vector { namespace raw { template -using vector = basic_vector>; +using vector = basic_vector; template -using indexed_vector = basic_vector, true>; +using indexed_vector = basic_vector; template -using vector_map = basic_vector, false, Key>; +using vector_map = basic_vector; template auto to_vec(It s, It e, UnaryOperation&& op) @@ -455,13 +487,13 @@ auto to_indexed_vec(Container const& c) namespace offset { template -using vector = basic_vector>; +using vector = basic_vector; template -using indexed_vector = basic_vector, true>; +using indexed_vector = basic_vector; template -using vector_map = basic_vector, false, Key>; +using vector_map = basic_vector; template auto to_vec(It s, It e, UnaryOperation&& op) diff --git a/include/cista/serialization.h b/include/cista/serialization.h index ed107077..2969fa8f 100755 --- a/include/cista/serialization.h +++ b/include/cista/serialization.h @@ -26,7 +26,14 @@ #include "cista/verify.h" #ifndef cista_member_offset -#define cista_member_offset(s, m) (static_cast(offsetof(s, m))) +#define cista_member_offset(Type, Member) \ + ([]() { \ + if constexpr (std::is_standard_layout_v) { \ + return static_cast<::cista::offset_t>(offsetof(Type, Member)); \ + } else { \ + return ::cista::member_offset(null(), &Type::Member); \ + } \ + }()) #endif namespace cista { @@ -38,6 +45,13 @@ cista::offset_t member_offset(T const* t, Member const* m) { reinterpret_cast(t)); } +template +offset_t member_offset(T const* t, Member T::*m) { + static_assert(std::is_trivially_copyable_v); + return (reinterpret_cast(&(t->*m)) - + reinterpret_cast(t)); +} + // ============================================================================= // SERIALIZE // ----------------------------------------------------------------------------- @@ -170,8 +184,8 @@ void serialize(Ctx& c, T const* origin, offset_t const pos) { } } -template +template typename Ptr, + bool Indexed, typename TemplateSizeType> void serialize(Ctx& c, basic_vector const* origin, offset_t const pos) { @@ -365,6 +379,13 @@ void serialize(Ctx& c, array const* origin, offset_t const pos) { } } +template +void serialize(Ctx& c, pair const* origin, offset_t const pos) { + using Type = decay_t; + serialize(c, &origin->first, pos + cista_member_offset(Type, first)); + serialize(c, &origin->second, pos + cista_member_offset(Type, second)); +} + template void serialize(Ctx& c, variant const* origin, offset_t const pos) { using Type = decay_t; @@ -386,7 +407,7 @@ void serialize(Ctx& c, optional const* origin, offset_t const pos) { template void serialize(Ctx& c, tuple const* origin, cista::offset_t const offset) { - apply( + ::cista::apply( [&](auto&&... args) { (serialize(c, &args, offset + (reinterpret_cast(&args) - @@ -681,6 +702,13 @@ void deserialize(Ctx const& c, T* el) { recurse(c, el, [&](auto* entry) { deserialize(c, entry); }); } +// --- PAIR --- +template +void recurse(Ctx&, pair* el, Fn&& fn) { + fn(&el->first); + fn(&el->second); +} + // --- OFFSET_PTR --- template void convert_endian_and_ptr(Ctx const& c, offset_ptr* el) { @@ -706,8 +734,8 @@ void recurse(Ctx& c, offset_ptr* el, Fn&& fn) { } // --- VECTOR --- -template +template typename Ptr, + bool Indexed, typename TemplateSizeType> void convert_endian_and_ptr( Ctx const& c, basic_vector* el) { deserialize(c, &el->el_); @@ -715,8 +743,8 @@ void convert_endian_and_ptr( c.convert_endian(el->used_size_); } -template +template typename Ptr, + bool Indexed, typename TemplateSizeType> void check_state(Ctx const& c, basic_vector* el) { c.check_ptr(el->el_, @@ -728,8 +756,8 @@ void check_state(Ctx const& c, c.require((el->size() == 0U) == (el->el_ == nullptr), "vec size=0 <=> ptr=0"); } -template +template typename Ptr, + bool Indexed, typename TemplateSizeType, typename Fn> void recurse(Ctx&, basic_vector* el, Fn&& fn) { for (auto& m : *el) { // NOLINT(clang-analyzer-core.NullDereference) diff --git a/include/cista/type_hash/static_type_hash.h b/include/cista/type_hash/static_type_hash.h index f4736d6f..d9f64e1a 100644 --- a/include/cista/type_hash/static_type_hash.h +++ b/include/cista/type_hash/static_type_hash.h @@ -144,6 +144,15 @@ constexpr auto static_type_hash(std::chrono::duration const*, return h; } +template +constexpr auto static_type_hash(std::pair const*, + hash_data h) noexcept { + h = h.combine(hash("pair")); + h = static_type_hash(null(), h); + h = static_type_hash(null(), h); + return h; +} + template constexpr auto static_type_hash(std::chrono::time_point const*, hash_data h) noexcept { @@ -160,8 +169,8 @@ constexpr auto static_type_hash(array const*, return h.combine(hash("array")).combine(Size); } -template +template typename Ptr, bool Indexed, + typename TemplateSizeType, std::size_t NMaxTypes> constexpr auto static_type_hash( basic_vector const*, hash_data h) noexcept { diff --git a/include/cista/type_hash/type_hash.h b/include/cista/type_hash/type_hash.h index a94a286a..886026b5 100644 --- a/include/cista/type_hash/type_hash.h +++ b/include/cista/type_hash/type_hash.h @@ -80,7 +80,16 @@ hash_t type_hash(T const& el, hash_t h, } } -template +template +hash_t type_hash(pair const&, hash_t h, + std::map& done) noexcept { + h = type_hash(A{}, h, done); + h = type_hash(B{}, h, done); + return hash_combine(h, hash("pair")); +} + +template typename Ptr, bool Indexed, + typename TemplateSizeType> hash_t type_hash(basic_vector const&, hash_t h, std::map& done) noexcept { h = hash_combine(h, hash("vector")); diff --git a/tools/doctest/doctest.h b/tools/doctest/doctest.h index 7afdc8b5..d81f6232 100644 --- a/tools/doctest/doctest.h +++ b/tools/doctest/doctest.h @@ -4,7 +4,7 @@ // // doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD // -// Copyright (c) 2016-2021 Viktor Kirilov +// Copyright (c) 2016-2023 Viktor Kirilov // // Distributed under the MIT Software License // See accompanying file LICENSE.txt or copy at @@ -42,15 +42,13 @@ #ifndef DOCTEST_LIBRARY_INCLUDED #define DOCTEST_LIBRARY_INCLUDED -#include - // ================================================================================================= // == VERSION ====================================================================================== // ================================================================================================= #define DOCTEST_VERSION_MAJOR 2 #define DOCTEST_VERSION_MINOR 4 -#define DOCTEST_VERSION_PATCH 9 +#define DOCTEST_VERSION_PATCH 11 // util we need here #define DOCTEST_TOSTR_IMPL(x) #x @@ -87,12 +85,15 @@ DOCTEST_COMPILER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000) #endif // MSVC #endif // MSVC -#if defined(__clang__) && defined(__clang_minor__) +#if defined(__clang__) && defined(__clang_minor__) && defined(__clang_patchlevel__) #define DOCTEST_CLANG DOCTEST_COMPILER(__clang_major__, __clang_minor__, __clang_patchlevel__) #elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && \ !defined(__INTEL_COMPILER) #define DOCTEST_GCC DOCTEST_COMPILER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #endif // GCC +#if defined(__INTEL_COMPILER) +#define DOCTEST_ICC DOCTEST_COMPILER(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif // ICC #ifndef DOCTEST_MSVC #define DOCTEST_MSVC 0 @@ -103,12 +104,15 @@ #ifndef DOCTEST_GCC #define DOCTEST_GCC 0 #endif // DOCTEST_GCC +#ifndef DOCTEST_ICC +#define DOCTEST_ICC 0 +#endif // DOCTEST_ICC // ================================================================================================= // == COMPILER WARNINGS HELPERS ==================================================================== // ================================================================================================= -#if DOCTEST_CLANG +#if DOCTEST_CLANG && !DOCTEST_ICC #define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) #define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH _Pragma("clang diagnostic push") #define DOCTEST_CLANG_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(clang diagnostic ignored w) @@ -154,7 +158,7 @@ // ================================================================================================= // both the header and the implementation suppress all of these, -// so it only makes sense to aggregrate them like so +// so it only makes sense to aggregate them like so #define DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH \ DOCTEST_CLANG_SUPPRESS_WARNING_PUSH \ DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") \ @@ -180,7 +184,7 @@ DOCTEST_MSVC_SUPPRESS_WARNING(4571) /* SEH related */ \ DOCTEST_MSVC_SUPPRESS_WARNING(4710) /* function not inlined */ \ DOCTEST_MSVC_SUPPRESS_WARNING(4711) /* function selected for inline expansion*/ \ - /* */ \ + /* common ones */ \ DOCTEST_MSVC_SUPPRESS_WARNING(4616) /* invalid compiler warning */ \ DOCTEST_MSVC_SUPPRESS_WARNING(4619) /* invalid compiler warning */ \ DOCTEST_MSVC_SUPPRESS_WARNING(4996) /* The compiler encountered a deprecated declaration */ \ @@ -194,6 +198,7 @@ DOCTEST_MSVC_SUPPRESS_WARNING(5026) /* move constructor was implicitly deleted */ \ DOCTEST_MSVC_SUPPRESS_WARNING(4640) /* construction of local static object not thread-safe */ \ DOCTEST_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5264) /* 'variable-name': 'const' variable is not used */ \ /* static analysis */ \ DOCTEST_MSVC_SUPPRESS_WARNING(26439) /* Function may not throw. Declare it 'noexcept' */ \ DOCTEST_MSVC_SUPPRESS_WARNING(26495) /* Always initialize a member variable */ \ @@ -238,7 +243,8 @@ DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly define DOCTEST_MSVC_SUPPRESS_WARNING(5039) /* pointer to pot. throwing function passed to extern C */ \ DOCTEST_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */ \ DOCTEST_MSVC_SUPPRESS_WARNING(5105) /* macro producing 'defined' has undefined behavior */ \ - DOCTEST_MSVC_SUPPRESS_WARNING(4738) /* storing float result in memory, loss of performance */ + DOCTEST_MSVC_SUPPRESS_WARNING(4738) /* storing float result in memory, loss of performance */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5262) /* implicit fall-through */ #define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END DOCTEST_MSVC_SUPPRESS_WARNING_POP @@ -354,6 +360,12 @@ DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly define #define DOCTEST_ALIGNMENT(x) __attribute__((aligned(x))) #endif +#ifdef DOCTEST_CONFIG_NO_CONTRADICTING_INLINE +#define DOCTEST_INLINE_NOINLINE inline +#else +#define DOCTEST_INLINE_NOINLINE inline DOCTEST_NOINLINE +#endif + #ifndef DOCTEST_NORETURN #if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) #define DOCTEST_NORETURN @@ -380,6 +392,14 @@ DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly define #endif // DOCTEST_MSVC #endif // DOCTEST_CONSTEXPR +#ifndef DOCTEST_NO_SANITIZE_INTEGER +#if DOCTEST_CLANG >= DOCTEST_COMPILER(3, 7, 0) +#define DOCTEST_NO_SANITIZE_INTEGER __attribute__((no_sanitize("integer"))) +#else +#define DOCTEST_NO_SANITIZE_INTEGER +#endif +#endif // DOCTEST_NO_SANITIZE_INTEGER + // ================================================================================================= // == FEATURE DETECTION END ======================================================================== // ================================================================================================= @@ -477,12 +497,13 @@ DOCTEST_GCC_SUPPRESS_WARNING_POP // https://github.com/doctest/doctest/issues/356 #if DOCTEST_CLANG #include +#endif // clang + #ifdef _LIBCPP_VERSION #ifndef DOCTEST_CONFIG_USE_STD_HEADERS #define DOCTEST_CONFIG_USE_STD_HEADERS #endif #endif // _LIBCPP_VERSION -#endif // clang #ifdef DOCTEST_CONFIG_USE_STD_HEADERS #ifndef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS @@ -495,38 +516,9 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END #else // DOCTEST_CONFIG_USE_STD_HEADERS -// Forward declaring 'X' in namespace std is not permitted by the C++ Standard. -DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4643) - -namespace std { // NOLINT(cert-dcl58-cpp) -typedef decltype(nullptr) nullptr_t; // NOLINT(modernize-use-using) -typedef decltype(sizeof(void*)) size_t; // NOLINT(modernize-use-using) -template -struct char_traits; -template <> -struct char_traits; -template -class basic_ostream; // NOLINT(fuchsia-virtual-inheritance) -typedef basic_ostream> ostream; // NOLINT(modernize-use-using) -template -// NOLINTNEXTLINE -basic_ostream& operator<<(basic_ostream&, const char*); -template -class basic_istream; -typedef basic_istream> istream; // NOLINT(modernize-use-using) -template -class tuple; -#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) -// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183 -template -class allocator; -template -class basic_string; -using string = basic_string, allocator>; -#endif // VS 2019 -} // namespace std - -DOCTEST_MSVC_SUPPRESS_WARNING_POP +#include +#include +#include #endif // DOCTEST_CONFIG_USE_STD_HEADERS @@ -972,7 +964,7 @@ namespace detail { struct deferred_false : types::false_type { }; // MSVS 2015 :( -#if defined(_MSC_VER) && _MSC_VER <= 1900 +#if !DOCTEST_CLANG && defined(_MSC_VER) && _MSC_VER <= 1900 template struct has_global_insertion_operator : types::false_type { }; @@ -1002,8 +994,13 @@ namespace detail { struct has_insertion_operator : types::false_type { }; #endif -template -struct has_insertion_operator(), declval()), void())> : types::true_type { }; + template + struct has_insertion_operator(), declval()), void())> : types::true_type { }; + + template + struct should_stringify_as_underlying_type { + static DOCTEST_CONSTEXPR bool value = detail::types::is_enum::value && !doctest::detail::has_insertion_operator::value; + }; DOCTEST_INTERFACE std::ostream* tlssPush(); DOCTEST_INTERFACE String tlssPop(); @@ -1065,7 +1062,7 @@ struct StringMaker : public detail::StringMakerBase< template String toString() { -#if DOCTEST_MSVC >= 0 && DOCTEST_CLANG == 0 && DOCTEST_GCC == 0 +#if DOCTEST_CLANG == 0 && DOCTEST_GCC == 0 && DOCTEST_ICC == 0 String ret = __FUNCSIG__; // class doctest::String __cdecl doctest::toString(void) String::size_type beginPos = ret.find('<'); return ret.substr(beginPos + 1, ret.size() - beginPos - static_cast(sizeof(">(void)"))); @@ -1076,7 +1073,7 @@ String toString() { #endif } -template ::value, bool>::type = true> +template ::value, bool>::type = true> String toString(const DOCTEST_REF_WRAP(T) value) { return StringMaker::convert(value); } @@ -1112,7 +1109,7 @@ DOCTEST_INTERFACE String toString(long unsigned in); DOCTEST_INTERFACE String toString(long long in); DOCTEST_INTERFACE String toString(long long unsigned in); -template ::value, bool>::type = true> +template ::value, bool>::type = true> String toString(const DOCTEST_REF_WRAP(T) value) { using UT = typename detail::types::underlying_type::type; return (DOCTEST_STRINGIFY(static_cast(value))); @@ -1164,8 +1161,18 @@ DOCTEST_MSVC_SUPPRESS_WARNING_POP template struct filldata { +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4180) static void fill(std::ostream* stream, const T* in) { - filldata::fill(stream, in); +DOCTEST_MSVC_SUPPRESS_WARNING_POP +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wmicrosoft-cast") + filldata::fill(stream, +#if DOCTEST_GCC == 0 || DOCTEST_GCC >= DOCTEST_COMPILER(4, 9, 0) + reinterpret_cast(in) +#else + *reinterpret_cast(&in) +#endif + ); +DOCTEST_CLANG_SUPPRESS_WARNING_POP } }; } @@ -1277,9 +1284,9 @@ namespace detail { template struct decay_array { using type = T*; }; template struct decay_array { using type = T*; }; - template struct not_char_pointer { static DOCTEST_CONSTEXPR value = 1; }; - template<> struct not_char_pointer { static DOCTEST_CONSTEXPR value = 0; }; - template<> struct not_char_pointer { static DOCTEST_CONSTEXPR value = 0; }; + template struct not_char_pointer { static DOCTEST_CONSTEXPR int value = 1; }; + template<> struct not_char_pointer { static DOCTEST_CONSTEXPR int value = 0; }; + template<> struct not_char_pointer { static DOCTEST_CONSTEXPR int value = 0; }; template struct can_use_op : public not_char_pointer::type> {}; #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING @@ -1328,7 +1335,11 @@ DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison") // If not it doesn't find the operator or if the operator at global scope is defined after // this template, the template won't be instantiated due to SFINAE. Once the template is not // instantiated it can look for global operator using normal conversions. +#ifdef __NVCC__ +#define SFINAE_OP(ret,op) ret +#else #define SFINAE_OP(ret,op) decltype((void)(doctest::detail::declval() op doctest::detail::declval()),ret{}) +#endif #define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \ template \ @@ -2131,13 +2142,13 @@ int registerReporter(const char* name, int priority, bool isReporter) { { \ void f(); \ }; \ - static inline DOCTEST_NOINLINE void func() { \ + static DOCTEST_INLINE_NOINLINE void func() { \ der v; \ v.f(); \ } \ DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, func, decorators) \ } \ - inline DOCTEST_NOINLINE void der::f() // NOLINT(misc-definitions-in-headers) + DOCTEST_INLINE_NOINLINE void der::f() // NOLINT(misc-definitions-in-headers) #define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, decorators) \ static void f(); \ @@ -3121,7 +3132,9 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN #include #include #include +#ifndef DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM #include +#endif // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM #include #include #include @@ -3158,9 +3171,11 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN // defines for a leaner windows.h #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#define DOCTEST_UNDEF_WIN32_LEAN_AND_MEAN #endif // WIN32_LEAN_AND_MEAN #ifndef NOMINMAX #define NOMINMAX +#define DOCTEST_UNDEF_NOMINMAX #endif // NOMINMAX // not sure what AfxWin.h is for - here I do what Catch does @@ -3241,8 +3256,14 @@ namespace { #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS throw e; #else // DOCTEST_CONFIG_NO_EXCEPTIONS +#ifdef DOCTEST_CONFIG_HANDLE_EXCEPTION + DOCTEST_CONFIG_HANDLE_EXCEPTION(e); +#else // DOCTEST_CONFIG_HANDLE_EXCEPTION +#ifndef DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM std::cerr << "doctest will terminate because it needed to throw an exception.\n" << "The message was: " << e.what() << '\n'; +#endif // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM +#endif // DOCTEST_CONFIG_HANDLE_EXCEPTION std::terminate(); #endif // DOCTEST_CONFIG_NO_EXCEPTIONS } @@ -3317,7 +3338,7 @@ namespace detail { namespace timer_large_integer { - + #if defined(DOCTEST_PLATFORM_WINDOWS) using type = ULONGLONG; #else // DOCTEST_PLATFORM_WINDOWS @@ -3779,7 +3800,7 @@ namespace Color { // clang-format off const char* assertString(assertType::Enum at) { - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4061) // enum 'x' in switch of enum 'y' is not explicitely handled + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4061) // enum 'x' in switch of enum 'y' is not explicitly handled #define DOCTEST_GENERATE_ASSERT_TYPE_CASE(assert_type) case assertType::DT_ ## assert_type: return #assert_type #define DOCTEST_GENERATE_ASSERT_TYPE_CASES(assert_type) \ DOCTEST_GENERATE_ASSERT_TYPE_CASE(WARN_ ## assert_type); \ @@ -4107,11 +4128,13 @@ namespace { return false; } + DOCTEST_NO_SANITIZE_INTEGER unsigned long long hash(unsigned long long a, unsigned long long b) { return (a << 5) + b; } // C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html + DOCTEST_NO_SANITIZE_INTEGER unsigned long long hash(const char* str) { unsigned long long hash = 5381; char c; @@ -4951,7 +4974,7 @@ namespace detail { m_string = tlssPop(); logged = true; } - + DOCTEST_ITERATE_THROUGH_REPORTERS(log_message, *this); const bool isWarn = m_severity & assertType::is_warn; @@ -5020,7 +5043,11 @@ namespace { mutable XmlWriter* m_writer = nullptr; }; +#ifndef DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM XmlWriter( std::ostream& os = std::cout ); +#else // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + XmlWriter( std::ostream& os ); +#endif // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM ~XmlWriter(); XmlWriter( XmlWriter const& ) = delete; @@ -5502,7 +5529,7 @@ namespace { test_case_start_impl(in); xml.ensureTagClosed(); } - + void test_case_reenter(const TestCaseData&) override {} void test_case_end(const CurrentTestCaseStats& st) override { @@ -5850,7 +5877,22 @@ namespace { testCaseData.addFailure(rb.m_decomp.c_str(), assertString(rb.m_at), os.str()); } - void log_message(const MessageData&) override {} + void log_message(const MessageData& mb) override { + if(mb.m_severity & assertType::is_warn) // report only failures + return; + + DOCTEST_LOCK_MUTEX(mutex) + + std::ostringstream os; + os << skipPathFromFilename(mb.m_file) << (opt.gnu_file_line ? ":" : "(") + << line(mb.m_line) << (opt.gnu_file_line ? ":" : "):") << std::endl; + + os << mb.m_string.c_str() << "\n"; + log_contexts(os); + + testCaseData.addFailure(mb.m_string.c_str(), + mb.m_severity & assertType::is_check ? "FAIL_CHECK" : "FAIL", os.str()); + } void test_case_skipped(const TestCaseData&) override {} @@ -6190,9 +6232,9 @@ namespace { separator_to_stream(); s << std::dec; - auto totwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters, static_cast(p.numAsserts))) + 1))); - auto passwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters - p.numTestCasesFailed, static_cast(p.numAsserts - p.numAssertsFailed))) + 1))); - auto failwidth = int(std::ceil(log10((std::max(p.numTestCasesFailed, static_cast(p.numAssertsFailed))) + 1))); + auto totwidth = int(std::ceil(log10(static_cast(std::max(p.numTestCasesPassingFilters, static_cast(p.numAsserts))) + 1))); + auto passwidth = int(std::ceil(log10(static_cast(std::max(p.numTestCasesPassingFilters - p.numTestCasesFailed, static_cast(p.numAsserts - p.numAssertsFailed))) + 1))); + auto failwidth = int(std::ceil(log10(static_cast(std::max(p.numTestCasesFailed, static_cast(p.numAssertsFailed))) + 1))); const bool anythingFailed = p.numTestCasesFailed > 0 || p.numAssertsFailed > 0; s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(totwidth) << p.numTestCasesPassingFilters << " | " @@ -6224,7 +6266,7 @@ namespace { subcasesStack.clear(); currentSubcaseLevel = 0; } - + void test_case_reenter(const TestCaseData&) override { subcasesStack.clear(); } @@ -6741,8 +6783,12 @@ int Context::run() { fstr.open(p->out.c_str(), std::fstream::out); p->cout = &fstr; } else { +#ifndef DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM // stdout by default p->cout = &std::cout; +#else // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + return EXIT_FAILURE; +#endif // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM } } @@ -6907,7 +6953,7 @@ int Context::run() { DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_start, tc); p->timer.start(); - + bool run_test = true; do { @@ -6948,7 +6994,7 @@ DOCTEST_MSVC_SUPPRESS_WARNING_POP run_test = false; p->failure_flags |= TestCaseFailureReason::TooManyFailedAsserts; } - + if(!p->nextSubcaseStack.empty() && run_test) DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_reenter, tc); if(p->nextSubcaseStack.empty()) @@ -7019,3 +7065,13 @@ DOCTEST_SUPPRESS_COMMON_WARNINGS_POP #endif // DOCTEST_LIBRARY_IMPLEMENTATION #endif // DOCTEST_CONFIG_IMPLEMENT + +#ifdef DOCTEST_UNDEF_WIN32_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#undef DOCTEST_UNDEF_WIN32_LEAN_AND_MEAN +#endif // DOCTEST_UNDEF_WIN32_LEAN_AND_MEAN + +#ifdef DOCTEST_UNDEF_NOMINMAX +#undef NOMINMAX +#undef DOCTEST_UNDEF_NOMINMAX +#endif // DOCTEST_UNDEF_NOMINMAX \ No newline at end of file