Found while running libc++'s tests with MSVC's STL. * `libcxx/test/std/algorithms/alg.modifying.operations/alg.unique/ranges_unique_copy.pass.cpp` + Fix MSVC "warning C4389: '`==`': signed/unsigned mismatch". + This was x86-specific for me. The LHS is `int` and the RHS is `size_t`. We know the `array`'s size, so `static_cast<int>` is certainly safe, and this matches the following `numberOfProj` comparisons. * `libcxx/test/std/containers/sequences/insert_range_sequence_containers.h` + Fix MSVC "warning C4267: 'argument': conversion from '`size_t`' to '`const int`', possible loss of data". + `test_case.index` is `size_t`:b85f1f9b18/libcxx/test/std/containers/insert_range_helpers.h (L65-L68)+ But the container's `difference_type` is `int`:b85f1f9b18/libcxx/test/support/test_allocator.h (L65-L76)+ I introduced an alias `D` to make the long line more readable. * `libcxx/test/std/containers/unord/unord.map/eq.different_hash.pass.cpp` * `libcxx/test/std/containers/unord/unord.multimap/eq.different_hash.pass.cpp` * `libcxx/test/std/containers/unord/unord.multiset/eq.different_hash.pass.cpp` * `libcxx/test/std/containers/unord/unord.set/eq.different_hash.pass.cpp` + Fix MSVC "warning C6297: Arithmetic overflow. Results might not be an expected value." + This warning is almost annoying enough to outright disable, but we use similar `static_cast`s to deal with sign/truncation warnings elsewhere, because there's some value in ensuring that product code is clean with respect to these warnings. If there were many more occurrences, then disabling the warning would be appropriate. + Cleanup: Change 2 inconsistently unqualified occurrences of `size_t` to `std::size_t`. * `libcxx/test/std/containers/views/mdspan/layout_stride/index_operator.pass.cpp` + Fix MSVC "warning C4244: 'initializing': conversion from '`__int64`' to '`size_t`', possible loss of data". + This was x86-specific for me. The `args` are indeed `int64_t`, and we're storing the result in `size_t`, so we should cast. * `libcxx/test/std/ranges/range.utility/range.utility.conv/container.h` + Fix MSVC "warning C4244: 'initializing': conversion from '`ptrdiff_t`' to '`int`', possible loss of data". + Fix MSVC "warning C4267: 'initializing': conversion from '`size_t`' to '`int`', possible loss of data". + We're initializing `int size_`, so we should explicitly cast from pointer subtraction and `std::ranges::size`. * `libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp` * `libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared_for_overwrite.pass.cpp` * `libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.default_init.pass.cpp` + Fix MSVC "warning C4309: 'initializing': truncation of constant value". + MSVC emits this warning because `0xDE` is outside the range of `char` (signed by default in our implementation). * `libcxx/test/support/concat_macros.h` + Fix MSVC "warning C4244: 'argument': conversion from '`char16_t`' to '`const char`', possible loss of data". + Fix MSVC "warning C4244: 'argument': conversion from '`unsigned int`' to '`const char`', possible loss of data". + This code was very recently introduced by @mordante in #73395.
802 lines
30 KiB
C++
802 lines
30 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SUPPORT_INSERT_RANGE_SEQUENCE_CONTAINERS_H
|
|
#define SUPPORT_INSERT_RANGE_SEQUENCE_CONTAINERS_H
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <concepts>
|
|
#include <cstddef>
|
|
#include <initializer_list>
|
|
#include <ranges>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
#include "../exception_safety_helpers.h"
|
|
#include "../from_range_helpers.h"
|
|
#include "../insert_range_helpers.h"
|
|
#include "MoveOnly.h"
|
|
#include "almost_satisfies_types.h"
|
|
#include "count_new.h"
|
|
#include "min_allocator.h"
|
|
#include "test_allocator.h"
|
|
#include "test_iterators.h"
|
|
#include "test_macros.h"
|
|
#include "type_algorithms.h"
|
|
|
|
template <class Container, class Range>
|
|
concept HasInsertRange = requires (Container& c, Range&& range) {
|
|
c.insert_range(c.end(), range);
|
|
};
|
|
|
|
template <template <class...> class Container, class T, class U>
|
|
constexpr bool test_constraints_insert_range() {
|
|
// Input range with the same value type.
|
|
static_assert(HasInsertRange<Container<T>, InputRange<T>>);
|
|
// Input range with a convertible value type.
|
|
static_assert(HasInsertRange<Container<T>, InputRange<U>>);
|
|
// Input range with a non-convertible value type.
|
|
static_assert(!HasInsertRange<Container<T>, InputRange<Empty>>);
|
|
// Not an input range.
|
|
static_assert(!HasInsertRange<Container<T>, InputRangeNotDerivedFrom>);
|
|
static_assert(!HasInsertRange<Container<T>, InputRangeNotIndirectlyReadable>);
|
|
static_assert(!HasInsertRange<Container<T>, InputRangeNotInputOrOutputIterator>);
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class Container, class Range>
|
|
concept HasAppendRange = requires (Container& c, Range&& range) {
|
|
c.append_range(range);
|
|
};
|
|
|
|
template <template <class...> class Container, class T, class U>
|
|
constexpr bool test_constraints_append_range() {
|
|
// Input range with the same value type.
|
|
static_assert(HasAppendRange<Container<T>, InputRange<T>>);
|
|
// Input range with a convertible value type.
|
|
static_assert(HasAppendRange<Container<T>, InputRange<U>>);
|
|
// Input range with a non-convertible value type.
|
|
static_assert(!HasAppendRange<Container<T>, InputRange<Empty>>);
|
|
// Not an input range.
|
|
static_assert(!HasAppendRange<Container<T>, InputRangeNotDerivedFrom>);
|
|
static_assert(!HasAppendRange<Container<T>, InputRangeNotIndirectlyReadable>);
|
|
static_assert(!HasAppendRange<Container<T>, InputRangeNotInputOrOutputIterator>);
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class Container, class Range>
|
|
concept HasPrependRange = requires (Container& c, Range&& range) {
|
|
c.prepend_range(range);
|
|
};
|
|
|
|
template <template <class...> class Container, class T, class U>
|
|
constexpr bool test_constraints_prepend_range() {
|
|
// Input range with the same value type.
|
|
static_assert(HasPrependRange<Container<T>, InputRange<T>>);
|
|
// Input range with a convertible value type.
|
|
static_assert(HasPrependRange<Container<T>, InputRange<U>>);
|
|
// Input range with a non-convertible value type.
|
|
static_assert(!HasPrependRange<Container<T>, InputRange<Empty>>);
|
|
// Not an input range.
|
|
static_assert(!HasPrependRange<Container<T>, InputRangeNotDerivedFrom>);
|
|
static_assert(!HasPrependRange<Container<T>, InputRangeNotIndirectlyReadable>);
|
|
static_assert(!HasPrependRange<Container<T>, InputRangeNotInputOrOutputIterator>);
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class Container, class Range>
|
|
concept HasAssignRange = requires (Container& c, Range&& range) {
|
|
c.assign_range(range);
|
|
};
|
|
|
|
template <template <class...> class Container, class T, class U>
|
|
constexpr bool test_constraints_assign_range() {
|
|
// Input range with the same value type.
|
|
static_assert(HasAssignRange<Container<T>, InputRange<T>>);
|
|
// Input range with a convertible value type.
|
|
static_assert(HasAssignRange<Container<T>, InputRange<U>>);
|
|
// Input range with a non-convertible value type.
|
|
static_assert(!HasAssignRange<Container<T>, InputRange<Empty>>);
|
|
// Not an input range.
|
|
static_assert(!HasAssignRange<Container<T>, InputRangeNotDerivedFrom>);
|
|
static_assert(!HasAssignRange<Container<T>, InputRangeNotIndirectlyReadable>);
|
|
static_assert(!HasAssignRange<Container<T>, InputRangeNotInputOrOutputIterator>);
|
|
|
|
return true;
|
|
}
|
|
|
|
// Empty container.
|
|
|
|
template <class T>
|
|
TestCase<T> constexpr EmptyContainer_EmptyRange {
|
|
.initial = {}, .index = 0, .input = {}, .expected = {}
|
|
};
|
|
// Note: specializations for `bool` still use `vector<int>` for inputs. This is to avoid dealing with `vector<bool>` and
|
|
// its iterators over proxy types.
|
|
template <> constexpr TestCase<int> EmptyContainer_EmptyRange<bool> {
|
|
.initial = {}, .index = 0, .input = {}, .expected = {}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> EmptyContainer_OneElementRange;
|
|
template <> constexpr TestCase<int> EmptyContainer_OneElementRange<int> {
|
|
.initial = {}, .index = 0, .input = {5}, .expected = {5}
|
|
};
|
|
template <> constexpr TestCase<char> EmptyContainer_OneElementRange<char> {
|
|
.initial = {}, .index = 0, .input = "a", .expected = "a"
|
|
};
|
|
template <> constexpr TestCase<int> EmptyContainer_OneElementRange<bool> {
|
|
.initial = {}, .index = 0, .input = {true}, .expected = {true}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> EmptyContainer_MidRange;
|
|
template <> constexpr TestCase<int> EmptyContainer_MidRange<int> {
|
|
.initial = {}, .index = 0, .input = {5, 3, 1, 7, 9}, .expected = {5, 3, 1, 7, 9}
|
|
};
|
|
template <> constexpr TestCase<char> EmptyContainer_MidRange<char> {
|
|
.initial = {}, .index = 0, .input = "aeiou", .expected = "aeiou"
|
|
};
|
|
template <> constexpr TestCase<int> EmptyContainer_MidRange<bool> {
|
|
.initial = {}, .index = 0, .input = {1, 1, 0, 1, 1}, .expected = {1, 1, 0, 1, 1}
|
|
};
|
|
|
|
// One-element container.
|
|
|
|
template <class T> constexpr TestCase<T> OneElementContainer_Begin_EmptyRange;
|
|
template <> constexpr TestCase<int> OneElementContainer_Begin_EmptyRange<int> {
|
|
.initial = {3}, .index = 0, .input = {}, .expected = {3}
|
|
};
|
|
template <> constexpr TestCase<char> OneElementContainer_Begin_EmptyRange<char> {
|
|
.initial = "B", .index = 0, .input = {}, .expected = "B"
|
|
};
|
|
template <> constexpr TestCase<int> OneElementContainer_Begin_EmptyRange<bool> {
|
|
.initial = {0}, .index = 0, .input = {}, .expected = {0}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> OneElementContainer_End_EmptyRange;
|
|
template <> constexpr TestCase<int> OneElementContainer_End_EmptyRange<int> {
|
|
.initial = {3}, .index = 1, .input = {}, .expected = {3}
|
|
};
|
|
template <> constexpr TestCase<char> OneElementContainer_End_EmptyRange<char> {
|
|
.initial = "B", .index = 1, .input = {}, .expected = "B"
|
|
};
|
|
template <> constexpr TestCase<int> OneElementContainer_End_EmptyRange<bool> {
|
|
.initial = {0}, .index = 1, .input = {}, .expected = {0}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> OneElementContainer_Begin_OneElementRange;
|
|
template <> constexpr TestCase<int> OneElementContainer_Begin_OneElementRange<int> {
|
|
.initial = {3}, .index = 0, .input = {-5}, .expected = {-5, 3}
|
|
};
|
|
template <> constexpr TestCase<char> OneElementContainer_Begin_OneElementRange<char> {
|
|
.initial = "B", .index = 0, .input = "a", .expected = "aB"
|
|
};
|
|
template <> constexpr TestCase<int> OneElementContainer_Begin_OneElementRange<bool> {
|
|
.initial = {0}, .index = 0, .input = {1}, .expected = {1, 0}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> OneElementContainer_End_OneElementRange;
|
|
template <> constexpr TestCase<int> OneElementContainer_End_OneElementRange<int> {
|
|
.initial = {3}, .index = 1, .input = {-5}, .expected = {3, -5}
|
|
};
|
|
template <> constexpr TestCase<char> OneElementContainer_End_OneElementRange<char> {
|
|
.initial = "B", .index = 1, .input = "a", .expected = "Ba"
|
|
};
|
|
template <> constexpr TestCase<int> OneElementContainer_End_OneElementRange<bool> {
|
|
.initial = {0}, .index = 1, .input = {1}, .expected = {0, 1}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> OneElementContainer_Begin_MidRange;
|
|
template <> constexpr TestCase<int> OneElementContainer_Begin_MidRange<int> {
|
|
.initial = {3}, .index = 0, .input = {-5, -3, -1, -7, -9}, .expected = {-5, -3, -1, -7, -9, 3}
|
|
};
|
|
template <> constexpr TestCase<char> OneElementContainer_Begin_MidRange<char> {
|
|
.initial = "B", .index = 0, .input = "aeiou", .expected = "aeiouB"
|
|
};
|
|
template <> constexpr TestCase<int> OneElementContainer_Begin_MidRange<bool> {
|
|
.initial = {0}, .index = 0, .input = {1, 1, 0, 1, 1}, .expected = {1, 1, 0, 1, 1, 0}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> OneElementContainer_End_MidRange;
|
|
template <> constexpr TestCase<int> OneElementContainer_End_MidRange<int> {
|
|
.initial = {3}, .index = 1, .input = {-5, -3, -1, -7, -9}, .expected = {3, -5, -3, -1, -7, -9}
|
|
};
|
|
template <> constexpr TestCase<char> OneElementContainer_End_MidRange<char> {
|
|
.initial = "B", .index = 1, .input = "aeiou", .expected = "Baeiou"
|
|
};
|
|
template <> constexpr TestCase<int> OneElementContainer_End_MidRange<bool> {
|
|
.initial = {0}, .index = 1, .input = {1, 1, 0, 1, 1}, .expected = {0, 1, 1, 0, 1, 1}
|
|
};
|
|
|
|
// Full container / empty range.
|
|
|
|
template <class T> constexpr TestCase<T> FullContainer_Begin_EmptyRange;
|
|
template <> constexpr TestCase<int> FullContainer_Begin_EmptyRange<int> {
|
|
.initial = {11, 29, 35, 14, 84}, .index = 0, .input = {}, .expected = {11, 29, 35, 14, 84}
|
|
};
|
|
template <> constexpr TestCase<char> FullContainer_Begin_EmptyRange<char> {
|
|
.initial = "_BCD_", .index = 0, .input = {}, .expected = "_BCD_"
|
|
};
|
|
template <> constexpr TestCase<int> FullContainer_Begin_EmptyRange<bool> {
|
|
.initial = {0, 0, 1, 0, 0}, .index = 0, .input = {}, .expected = {0, 0, 1, 0, 0}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> FullContainer_Mid_EmptyRange;
|
|
template <> constexpr TestCase<int> FullContainer_Mid_EmptyRange<int> {
|
|
.initial = {11, 29, 35, 14, 84}, .index = 2, .input = {}, .expected = {11, 29, 35, 14, 84}
|
|
};
|
|
template <> constexpr TestCase<char> FullContainer_Mid_EmptyRange<char> {
|
|
.initial = "_BCD_", .index = 2, .input = {}, .expected = "_BCD_"
|
|
};
|
|
template <> constexpr TestCase<int> FullContainer_Mid_EmptyRange<bool> {
|
|
.initial = {0, 0, 1, 0, 0}, .index = 2, .input = {}, .expected = {0, 0, 1, 0, 0}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> FullContainer_End_EmptyRange;
|
|
template <> constexpr TestCase<int> FullContainer_End_EmptyRange<int> {
|
|
.initial = {11, 29, 35, 14, 84}, .index = 5, .input = {}, .expected = {11, 29, 35, 14, 84}
|
|
};
|
|
template <> constexpr TestCase<char> FullContainer_End_EmptyRange<char> {
|
|
.initial = "_BCD_", .index = 5, .input = {}, .expected = "_BCD_"
|
|
};
|
|
template <> constexpr TestCase<int> FullContainer_End_EmptyRange<bool> {
|
|
.initial = {0, 0, 1, 0, 0}, .index = 5, .input = {}, .expected = {0, 0, 1, 0, 0}
|
|
};
|
|
|
|
// Full container / one-element range.
|
|
|
|
template <class T> constexpr TestCase<T> FullContainer_Begin_OneElementRange;
|
|
template <> constexpr TestCase<int> FullContainer_Begin_OneElementRange<int> {
|
|
.initial = {11, 29, 35, 14, 84}, .index = 0, .input = {-5}, .expected = {-5, 11, 29, 35, 14, 84}
|
|
};
|
|
template <> constexpr TestCase<char> FullContainer_Begin_OneElementRange<char> {
|
|
.initial = "_BCD_", .index = 0, .input = "a", .expected = "a_BCD_"
|
|
};
|
|
template <> constexpr TestCase<int> FullContainer_Begin_OneElementRange<bool> {
|
|
.initial = {0, 0, 1, 0, 0}, .index = 0, .input = {1}, .expected = {1, 0, 0, 1, 0, 0}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> FullContainer_Mid_OneElementRange;
|
|
template <> constexpr TestCase<int> FullContainer_Mid_OneElementRange<int> {
|
|
.initial = {11, 29, 35, 14, 84}, .index = 2, .input = {-5}, .expected = {11, 29, -5, 35, 14, 84}
|
|
};
|
|
template <> constexpr TestCase<char> FullContainer_Mid_OneElementRange<char> {
|
|
.initial = "_BCD_", .index = 2, .input = "a", .expected = "_BaCD_"
|
|
};
|
|
template <> constexpr TestCase<int> FullContainer_Mid_OneElementRange<bool> {
|
|
.initial = {0, 0, 1, 0, 0}, .index = 2, .input = {1}, .expected = {0, 0, 1, 1, 0, 0}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> FullContainer_End_OneElementRange;
|
|
template <> constexpr TestCase<int> FullContainer_End_OneElementRange<int> {
|
|
.initial = {11, 29, 35, 14, 84}, .index = 5, .input = {-5}, .expected = {11, 29, 35, 14, 84, -5}
|
|
};
|
|
template <> constexpr TestCase<char> FullContainer_End_OneElementRange<char> {
|
|
.initial = "_BCD_", .index = 5, .input = "a", .expected = "_BCD_a"
|
|
};
|
|
template <> constexpr TestCase<int> FullContainer_End_OneElementRange<bool> {
|
|
.initial = {0, 0, 1, 0, 0}, .index = 5, .input = {1}, .expected = {0, 0, 1, 0, 0, 1}
|
|
};
|
|
|
|
// Full container / mid-sized range.
|
|
|
|
template <class T> constexpr TestCase<T> FullContainer_Begin_MidRange;
|
|
template <> constexpr TestCase<int> FullContainer_Begin_MidRange<int> {
|
|
.initial = {11, 29, 35, 14, 84},
|
|
.index = 0,
|
|
.input = {-5, -3, -1, -7, -9},
|
|
.expected = {-5, -3, -1, -7, -9, 11, 29, 35, 14, 84}
|
|
};
|
|
template <> constexpr TestCase<char> FullContainer_Begin_MidRange<char> {
|
|
.initial = "_BCD_",
|
|
.index = 0,
|
|
.input = "aeiou",
|
|
.expected = "aeiou_BCD_"
|
|
};
|
|
template <> constexpr TestCase<int> FullContainer_Begin_MidRange<bool> {
|
|
.initial = {0, 0, 1, 0, 1},
|
|
.index = 0,
|
|
.input = {1, 1, 0, 1, 1},
|
|
.expected = {1, 1, 0, 1, 1, 0, 0, 1, 0, 1}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> FullContainer_Mid_MidRange;
|
|
template <> constexpr TestCase<int> FullContainer_Mid_MidRange<int> {
|
|
.initial = {11, 29, 35, 14, 84},
|
|
.index = 2,
|
|
.input = {-5, -3, -1, -7, -9},
|
|
.expected = {11, 29, -5, -3, -1, -7, -9, 35, 14, 84}
|
|
};
|
|
template <> constexpr TestCase<char> FullContainer_Mid_MidRange<char> {
|
|
.initial = "_BCD_",
|
|
.index = 2,
|
|
.input = "aeiou",
|
|
.expected = "_BaeiouCD_"
|
|
};
|
|
template <> constexpr TestCase<int> FullContainer_Mid_MidRange<bool> {
|
|
.initial = {0, 0, 1, 0, 1},
|
|
.index = 2,
|
|
.input = {1, 1, 0, 1, 1},
|
|
.expected = {0, 0, 1, 1, 0, 1, 1, 1, 0, 1}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> FullContainer_End_MidRange;
|
|
template <> constexpr TestCase<int> FullContainer_End_MidRange<int> {
|
|
.initial = {11, 29, 35, 14, 84},
|
|
.index = 5,
|
|
.input = {-5, -3, -1, -7, -9},
|
|
.expected = {11, 29, 35, 14, 84, -5, -3, -1, -7, -9}
|
|
};
|
|
template <> constexpr TestCase<char> FullContainer_End_MidRange<char> {
|
|
.initial = "_BCD_",
|
|
.index = 5,
|
|
.input = "aeiou",
|
|
.expected = "_BCD_aeiou"
|
|
};
|
|
template <> constexpr TestCase<int> FullContainer_End_MidRange<bool> {
|
|
.initial = {0, 0, 1, 0, 1},
|
|
.index = 5,
|
|
.input = {1, 1, 0, 1, 1},
|
|
.expected = {0, 0, 1, 0, 1, 1, 1, 0, 1, 1}
|
|
};
|
|
|
|
// Full container / long range.
|
|
|
|
template <class T> constexpr TestCase<T> FullContainer_Begin_LongRange;
|
|
template <> constexpr TestCase<int> FullContainer_Begin_LongRange<int> {
|
|
.initial = {11, 29, 35, 14, 84},
|
|
.index = 0,
|
|
.input = {-5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48},
|
|
.expected = {
|
|
-5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48, 11, 29, 35, 14, 84
|
|
}
|
|
};
|
|
template <> constexpr TestCase<char> FullContainer_Begin_LongRange<char> {
|
|
.initial = "_BCD_",
|
|
.index = 0,
|
|
.input = "aeiouqwxyz5781964203",
|
|
.expected = "aeiouqwxyz5781964203_BCD_"
|
|
};
|
|
template <> constexpr TestCase<int> FullContainer_Begin_LongRange<bool> {
|
|
.initial = {0, 0, 1, 0, 0},
|
|
.index = 0,
|
|
.input = {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
|
|
.expected = {
|
|
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
|
|
}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> FullContainer_Mid_LongRange;
|
|
template <> constexpr TestCase<int> FullContainer_Mid_LongRange<int> {
|
|
.initial = {11, 29, 35, 14, 84},
|
|
.index = 2,
|
|
.input = {-5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48},
|
|
.expected = {
|
|
11, 29, -5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48, 35, 14, 84
|
|
}
|
|
};
|
|
template <> constexpr TestCase<char> FullContainer_Mid_LongRange<char> {
|
|
.initial = "_BCD_",
|
|
.index = 2,
|
|
.input = "aeiouqwxyz5781964203",
|
|
.expected = "_Baeiouqwxyz5781964203CD_"
|
|
};
|
|
template <> constexpr TestCase<int> FullContainer_Mid_LongRange<bool> {
|
|
.initial = {0, 0, 1, 0, 0},
|
|
.index = 2,
|
|
.input = {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
|
|
.expected = {
|
|
0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0
|
|
}
|
|
};
|
|
|
|
template <class T> constexpr TestCase<T> FullContainer_End_LongRange;
|
|
template <> constexpr TestCase<int> FullContainer_End_LongRange<int> {
|
|
.initial = {11, 29, 35, 14, 84},
|
|
.index = 5,
|
|
.input = {-5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48},
|
|
.expected = {
|
|
11, 29, 35, 14, 84, -5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48
|
|
}
|
|
};
|
|
template <> constexpr TestCase<char> FullContainer_End_LongRange<char> {
|
|
.initial = "_BCD_",
|
|
.index = 5,
|
|
.input = "aeiouqwxyz5781964203",
|
|
.expected = "_BCD_aeiouqwxyz5781964203"
|
|
};
|
|
template <> constexpr TestCase<int> FullContainer_End_LongRange<bool> {
|
|
.initial = {0, 0, 1, 0, 1},
|
|
.index = 5,
|
|
.input = {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
|
|
.expected = {
|
|
0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
|
|
}
|
|
};
|
|
|
|
// Sequence containers tests.
|
|
|
|
template <class Container, class Iter, class Sent, class Validate>
|
|
constexpr void test_sequence_insert_range(Validate validate) {
|
|
using T = typename Container::value_type;
|
|
using D = typename Container::difference_type;
|
|
auto get_pos = [](auto& c, auto& test_case) { return std::ranges::next(c.begin(), static_cast<D>(test_case.index)); };
|
|
|
|
auto test = [&](auto& test_case) {
|
|
Container c(test_case.initial.begin(), test_case.initial.end());
|
|
auto in = wrap_input<Iter, Sent>(test_case.input);
|
|
auto pos = get_pos(c, test_case);
|
|
|
|
auto result = c.insert_range(pos, in);
|
|
assert(result == get_pos(c, test_case));
|
|
validate(c);
|
|
return std::ranges::equal(c, test_case.expected);
|
|
};
|
|
|
|
{ // Empty container.
|
|
// empty_c.insert_range(end, empty_range)
|
|
assert(test(EmptyContainer_EmptyRange<T>));
|
|
// empty_c.insert_range(end, one_element_range)
|
|
assert(test(EmptyContainer_OneElementRange<T>));
|
|
// empty_c.insert_range(end, mid_range)
|
|
assert(test(EmptyContainer_MidRange<T>));
|
|
}
|
|
|
|
{ // One-element container.
|
|
// one_element_c.insert_range(begin, empty_range)
|
|
assert(test(OneElementContainer_Begin_EmptyRange<T>));
|
|
// one_element_c.insert_range(end, empty_range)
|
|
assert(test(OneElementContainer_End_EmptyRange<T>));
|
|
// one_element_c.insert_range(begin, one_element_range)
|
|
assert(test(OneElementContainer_Begin_OneElementRange<T>));
|
|
// one_element_c.insert_range(end, one_element_range)
|
|
assert(test(OneElementContainer_End_OneElementRange<T>));
|
|
// one_element_c.insert_range(begin, mid_range)
|
|
assert(test(OneElementContainer_Begin_MidRange<T>));
|
|
// one_element_c.insert_range(end, mid_range)
|
|
assert(test(OneElementContainer_End_MidRange<T>));
|
|
}
|
|
|
|
{ // Full container.
|
|
// full_container.insert_range(begin, empty_range)
|
|
assert(test(FullContainer_Begin_EmptyRange<T>));
|
|
// full_container.insert_range(mid, empty_range)
|
|
assert(test(FullContainer_Mid_EmptyRange<T>));
|
|
// full_container.insert_range(end, empty_range)
|
|
assert(test(FullContainer_End_EmptyRange<T>));
|
|
// full_container.insert_range(begin, one_element_range)
|
|
assert(test(FullContainer_Begin_OneElementRange<T>));
|
|
// full_container.insert_range(end, one_element_range)
|
|
assert(test(FullContainer_Mid_OneElementRange<T>));
|
|
// full_container.insert_range(end, one_element_range)
|
|
assert(test(FullContainer_End_OneElementRange<T>));
|
|
// full_container.insert_range(begin, mid_range)
|
|
assert(test(FullContainer_Begin_MidRange<T>));
|
|
// full_container.insert_range(mid, mid_range)
|
|
assert(test(FullContainer_Mid_MidRange<T>));
|
|
// full_container.insert_range(end, mid_range)
|
|
assert(test(FullContainer_End_MidRange<T>));
|
|
// full_container.insert_range(begin, long_range)
|
|
assert(test(FullContainer_Begin_LongRange<T>));
|
|
// full_container.insert_range(mid, long_range)
|
|
assert(test(FullContainer_Mid_LongRange<T>));
|
|
// full_container.insert_range(end, long_range)
|
|
assert(test(FullContainer_End_LongRange<T>));
|
|
}
|
|
}
|
|
|
|
template <class Container, class Iter, class Sent, class Validate>
|
|
constexpr void test_sequence_prepend_range(Validate validate) {
|
|
using T = typename Container::value_type;
|
|
|
|
auto test = [&](auto& test_case) {
|
|
Container c(test_case.initial.begin(), test_case.initial.end());
|
|
auto in = wrap_input<Iter, Sent>(test_case.input);
|
|
|
|
c.prepend_range(in);
|
|
validate(c);
|
|
return std::ranges::equal(c, test_case.expected);
|
|
};
|
|
|
|
{ // Empty container.
|
|
// empty_c.prepend_range(empty_range)
|
|
assert(test(EmptyContainer_EmptyRange<T>));
|
|
// empty_c.prepend_range(one_element_range)
|
|
assert(test(EmptyContainer_OneElementRange<T>));
|
|
// empty_c.prepend_range(mid_range)
|
|
assert(test(EmptyContainer_MidRange<T>));
|
|
}
|
|
|
|
{ // One-element container.
|
|
// one_element_c.prepend_range(empty_range)
|
|
assert(test(OneElementContainer_Begin_EmptyRange<T>));
|
|
// one_element_c.prepend_range(one_element_range)
|
|
assert(test(OneElementContainer_Begin_OneElementRange<T>));
|
|
// one_element_c.prepend_range(mid_range)
|
|
assert(test(OneElementContainer_Begin_MidRange<T>));
|
|
}
|
|
|
|
{ // Full container.
|
|
// full_container.prepend_range(empty_range)
|
|
assert(test(FullContainer_Begin_EmptyRange<T>));
|
|
// full_container.prepend_range(one_element_range)
|
|
assert(test(FullContainer_Begin_OneElementRange<T>));
|
|
// full_container.prepend_range(mid_range)
|
|
assert(test(FullContainer_Begin_MidRange<T>));
|
|
// full_container.prepend_range(long_range)
|
|
assert(test(FullContainer_Begin_LongRange<T>));
|
|
}
|
|
}
|
|
|
|
template <class Container, class Iter, class Sent, class Validate>
|
|
constexpr void test_sequence_append_range(Validate validate) {
|
|
using T = typename Container::value_type;
|
|
|
|
auto test = [&](auto& test_case) {
|
|
Container c(test_case.initial.begin(), test_case.initial.end());
|
|
auto in = wrap_input<Iter, Sent>(test_case.input);
|
|
|
|
c.append_range(in);
|
|
validate(c);
|
|
return std::ranges::equal(c, test_case.expected);
|
|
};
|
|
|
|
{ // Empty container.
|
|
// empty_c.append_range(empty_range)
|
|
assert(test(EmptyContainer_EmptyRange<T>));
|
|
// empty_c.append_range(one_element_range)
|
|
assert(test(EmptyContainer_OneElementRange<T>));
|
|
// empty_c.append_range(mid_range)
|
|
assert(test(EmptyContainer_MidRange<T>));
|
|
}
|
|
|
|
{ // One-element container.
|
|
// one_element_c.append_range(empty_range)
|
|
assert(test(OneElementContainer_End_EmptyRange<T>));
|
|
// one_element_c.append_range(one_element_range)
|
|
assert(test(OneElementContainer_End_OneElementRange<T>));
|
|
// one_element_c.append_range(mid_range)
|
|
assert(test(OneElementContainer_End_MidRange<T>));
|
|
}
|
|
|
|
{ // Full container.
|
|
// full_container.append_range(empty_range)
|
|
assert(test(FullContainer_End_EmptyRange<T>));
|
|
// full_container.append_range(one_element_range)
|
|
assert(test(FullContainer_End_OneElementRange<T>));
|
|
// full_container.append_range(mid_range)
|
|
assert(test(FullContainer_End_MidRange<T>));
|
|
// full_container.append_range(long_range)
|
|
assert(test(FullContainer_End_LongRange<T>));
|
|
}
|
|
}
|
|
|
|
template <class Container, class Iter, class Sent, class Validate>
|
|
constexpr void test_sequence_assign_range(Validate validate) {
|
|
using T = typename Container::value_type;
|
|
|
|
auto& initial_empty = EmptyContainer_EmptyRange<T>.initial;
|
|
auto& initial_one_element = OneElementContainer_Begin_EmptyRange<T>.initial;
|
|
auto& initial_full = FullContainer_Begin_EmptyRange<T>.initial;
|
|
auto& input_empty = FullContainer_Begin_EmptyRange<T>.input;
|
|
auto& input_one_element = FullContainer_Begin_OneElementRange<T>.input;
|
|
auto& input_mid_range = FullContainer_Begin_MidRange<T>.input;
|
|
auto& input_long_range = FullContainer_Begin_LongRange<T>.input;
|
|
|
|
auto test = [&](auto& initial, auto& input) {
|
|
Container c(initial.begin(), initial.end());
|
|
auto in = wrap_input<Iter, Sent>(input);
|
|
|
|
c.assign_range(in);
|
|
validate(c);
|
|
return std::ranges::equal(c, input);
|
|
};
|
|
|
|
{ // Empty container.
|
|
// empty_container.assign_range(empty_range)
|
|
assert(test(initial_empty, input_empty));
|
|
// empty_container.assign_range(one_element_range)
|
|
assert(test(initial_empty, input_one_element));
|
|
// empty_container.assign_range(mid_range)
|
|
assert(test(initial_empty, input_mid_range));
|
|
// empty_container.assign_range(long_range)
|
|
assert(test(initial_empty, input_long_range));
|
|
}
|
|
|
|
{ // One-element container.
|
|
// one_element_container.assign_range(empty_range)
|
|
assert(test(initial_one_element, input_empty));
|
|
// one_element_container.assign_range(one_element_range)
|
|
assert(test(initial_one_element, input_one_element));
|
|
// one_element_container.assign_range(mid_range)
|
|
assert(test(initial_one_element, input_mid_range));
|
|
// one_element_container.assign_range(long_range)
|
|
assert(test(initial_one_element, input_long_range));
|
|
}
|
|
|
|
{ // Full container.
|
|
// full_container.assign_range(empty_range)
|
|
assert(test(initial_full, input_empty));
|
|
// full_container.assign_range(one_element_range)
|
|
assert(test(initial_full, input_one_element));
|
|
// full_container.assign_range(mid_range)
|
|
assert(test(initial_full, input_mid_range));
|
|
// full_container.assign_range(long_range)
|
|
assert(test(initial_full, input_long_range));
|
|
}
|
|
}
|
|
|
|
// Move-only types.
|
|
|
|
template <template <class ...> class Container>
|
|
constexpr void test_sequence_insert_range_move_only() {
|
|
MoveOnly input[5];
|
|
std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
|
|
|
|
Container<MoveOnly> c;
|
|
c.insert_range(c.end(), in);
|
|
}
|
|
|
|
template <template <class ...> class Container>
|
|
constexpr void test_sequence_prepend_range_move_only() {
|
|
MoveOnly input[5];
|
|
std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
|
|
|
|
Container<MoveOnly> c;
|
|
c.prepend_range(in);
|
|
}
|
|
|
|
template <template <class ...> class Container>
|
|
constexpr void test_sequence_append_range_move_only() {
|
|
MoveOnly input[5];
|
|
std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
|
|
|
|
Container<MoveOnly> c;
|
|
c.append_range(in);
|
|
}
|
|
|
|
template <template <class ...> class Container>
|
|
constexpr void test_sequence_assign_range_move_only() {
|
|
MoveOnly input[5];
|
|
std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
|
|
|
|
Container<MoveOnly> c;
|
|
c.assign_range(in);
|
|
}
|
|
|
|
// Exception safety.
|
|
|
|
template <template <class ...> class Container>
|
|
void test_insert_range_exception_safety_throwing_copy() {
|
|
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
|
constexpr int ThrowOn = 3;
|
|
using T = ThrowingCopy<ThrowOn>;
|
|
test_exception_safety_throwing_copy<ThrowOn, /*Size=*/5>([](T* from, T* to) {
|
|
Container<T> c;
|
|
c.insert_range(c.end(), std::ranges::subrange(from, to));
|
|
});
|
|
#endif
|
|
}
|
|
|
|
template <template <class ...> class Container, class T>
|
|
void test_insert_range_exception_safety_throwing_allocator() {
|
|
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
|
T in[] = {0, 1};
|
|
|
|
try {
|
|
ThrowingAllocator<T> alloc;
|
|
|
|
globalMemCounter.reset();
|
|
Container<T, ThrowingAllocator<T>> c(alloc);
|
|
c.insert_range(c.end(), in);
|
|
assert(false); // The function call above should throw.
|
|
|
|
} catch (int) {
|
|
assert(globalMemCounter.new_called == globalMemCounter.delete_called);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
template <template <class ...> class Container>
|
|
void test_prepend_range_exception_safety_throwing_copy() {
|
|
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
|
constexpr int ThrowOn = 3;
|
|
using T = ThrowingCopy<ThrowOn>;
|
|
test_exception_safety_throwing_copy<ThrowOn, /*Size=*/5>([](T* from, T* to) {
|
|
Container<T> c;
|
|
c.prepend_range(std::ranges::subrange(from, to));
|
|
});
|
|
#endif
|
|
}
|
|
|
|
template <template <class ...> class Container, class T>
|
|
void test_prepend_range_exception_safety_throwing_allocator() {
|
|
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
|
T in[] = {0, 1};
|
|
|
|
try {
|
|
ThrowingAllocator<T> alloc;
|
|
|
|
globalMemCounter.reset();
|
|
Container<T, ThrowingAllocator<T>> c(alloc);
|
|
c.prepend_range(in);
|
|
assert(false); // The function call above should throw.
|
|
|
|
} catch (int) {
|
|
assert(globalMemCounter.new_called == globalMemCounter.delete_called);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
template <template <class ...> class Container>
|
|
void test_append_range_exception_safety_throwing_copy() {
|
|
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
|
constexpr int ThrowOn = 3;
|
|
using T = ThrowingCopy<ThrowOn>;
|
|
test_exception_safety_throwing_copy<ThrowOn, /*Size=*/5>([](T* from, T* to) {
|
|
Container<T> c;
|
|
c.append_range(std::ranges::subrange(from, to));
|
|
});
|
|
#endif
|
|
}
|
|
|
|
template <template <class ...> class Container, class T>
|
|
void test_append_range_exception_safety_throwing_allocator() {
|
|
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
|
T in[] = {0, 1};
|
|
|
|
try {
|
|
ThrowingAllocator<T> alloc;
|
|
|
|
globalMemCounter.reset();
|
|
Container<T, ThrowingAllocator<T>> c(alloc);
|
|
c.append_range(in);
|
|
assert(false); // The function call above should throw.
|
|
|
|
} catch (int) {
|
|
assert(globalMemCounter.new_called == globalMemCounter.delete_called);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
template <template <class ...> class Container>
|
|
void test_assign_range_exception_safety_throwing_copy() {
|
|
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
|
constexpr int ThrowOn = 3;
|
|
using T = ThrowingCopy<ThrowOn>;
|
|
test_exception_safety_throwing_copy<ThrowOn, /*Size=*/5>([](T* from, T* to) {
|
|
Container<T> c;
|
|
c.assign_range(std::ranges::subrange(from, to));
|
|
});
|
|
#endif
|
|
}
|
|
|
|
template <template <class ...> class Container, class T>
|
|
void test_assign_range_exception_safety_throwing_allocator() {
|
|
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
|
T in[] = {0, 1};
|
|
|
|
try {
|
|
ThrowingAllocator<T> alloc;
|
|
|
|
globalMemCounter.reset();
|
|
Container<T, ThrowingAllocator<T>> c(alloc);
|
|
c.assign_range(in);
|
|
assert(false); // The function call above should throw.
|
|
|
|
} catch (int) {
|
|
assert(globalMemCounter.new_called == globalMemCounter.delete_called);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#endif // SUPPORT_INSERT_RANGE_SEQUENCE_CONTAINERS_H
|