├── codecov.yml ├── tests ├── main.cpp ├── dr-811.cpp ├── empty_base_get.cpp ├── swap.cpp ├── alignment.cpp ├── p1951.cpp ├── libcxx │ ├── types.cpp │ ├── get_rv.cpp │ ├── dtor.cpp │ ├── copy_ctor.cpp │ ├── non_member_swap.cpp │ ├── get_const.cpp │ ├── tuple_size.cpp │ ├── test_convertible.h │ ├── get_non_const.cpp │ ├── trivial_copy_move.cpp │ ├── used_to_be_make_pair.cpp │ ├── default_ctor.cpp │ ├── default.cpp │ ├── swap.cpp │ ├── tuple_element.cpp │ ├── get_const_rv.cpp │ ├── assign_const_pair_U_V.cpp │ ├── piecewise_construct.cpp │ ├── move_ctor.cpp │ ├── comparison.cpp │ ├── implicit_deduction_guides.cpp │ ├── assign_pair.cpp │ ├── pairs_by_type.cpp │ ├── special_member_generation.cpp │ ├── ctor.brace-init.cpp │ ├── assign_tuple.cpp │ ├── default-sfinae.cpp │ ├── assign_rv_pair.cpp │ ├── const_first_const_second.cpp │ ├── assign_rv_pair_U_V.cpp │ ├── U_V.cpp │ ├── const_pair_U_V.cpp │ ├── rv_pair_U_V.cpp │ └── archetypes.h ├── reference_wrapper.cpp ├── tricky_comparisons.cpp ├── piecewise_no_copy_move.cpp ├── cppreference.cpp └── CMakeLists.txt ├── cmake ├── tight_pair-config.cmake.in ├── llvm-cov-wrapper ├── FindGcov.cmake ├── Findcodecov.cmake └── FindLcov.cmake ├── test_package ├── CMakeLists.txt ├── conanfile.py └── tight_pair-integrity.cpp ├── LICENSE ├── bench ├── plot.py └── sort-test.cpp ├── .github └── workflows │ ├── build-mingw.yml │ ├── build-msvc.yml │ ├── code-coverage.yml │ ├── build-macos.yml │ └── build-ubuntu.yml ├── conanfile.py ├── CMakeLists.txt └── README.md /codecov.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 Morwenn 2 | # SPDX-License-Identifier: MIT 3 | 4 | coverage: 5 | ignore: 6 | - "tests" 7 | -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | #define CATCH_CONFIG_MAIN 6 | #include "catch2/catch.hpp" 7 | -------------------------------------------------------------------------------- /cmake/tight_pair-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | if (NOT TARGET tight_pair::tight_pair) 4 | include(${CMAKE_CURRENT_LIST_DIR}/tight_pair-targets.cmake) 5 | endif() 6 | -------------------------------------------------------------------------------- /tests/dr-811.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | #include 6 | #include 7 | 8 | TEST_CASE( "DR 811" ) 9 | { 10 | using cruft::get; 11 | 12 | cruft::tight_pair p(0, 0); 13 | CHECK(get<0>(p) == nullptr); 14 | CHECK(get<1>(p) == nullptr); 15 | } 16 | -------------------------------------------------------------------------------- /test_package/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2021 Morwenn 2 | # SPDX-License-Identifier: MIT 3 | 4 | cmake_minimum_required(VERSION 2.8.12) 5 | 6 | project(test_package CXX) 7 | 8 | include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) 9 | conan_basic_setup(TARGETS) 10 | 11 | find_package(tight_pair REQUIRED CONFIG) 12 | 13 | add_executable(${PROJECT_NAME} tight_pair-integrity.cpp) 14 | target_link_libraries(${PROJECT_NAME} PRIVATE tight_pair::tight_pair) 15 | -------------------------------------------------------------------------------- /tests/empty_base_get.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | #include 6 | #include 7 | 8 | namespace 9 | { 10 | // Empty class with get function, which is picked instead 11 | // of ADL get with some std::tuple implementations 12 | 13 | struct foobar 14 | { 15 | template 16 | int get() { return N; } 17 | }; 18 | } 19 | 20 | TEST_CASE( "test structured bindings with base class get" ) 21 | { 22 | cruft::tight_pair tu(19, {}); 23 | auto [a, b] = tu; 24 | CHECK(a == 19); 25 | } 26 | -------------------------------------------------------------------------------- /tests/swap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | #include 6 | #include 7 | 8 | constexpr auto test_swap() 9 | -> bool 10 | { 11 | cruft::tight_pair p1(5, false); 12 | cruft::tight_pair p2(8, true); 13 | swap(p1, p2); 14 | 15 | using cruft::get; 16 | return get<0>(p1) == 8 17 | && get<1>(p1) == true 18 | && get<0>(p2) == 5 19 | && get<1>(p2) == false; 20 | } 21 | 22 | TEST_CASE( "test constexpr swap (issue #15)" ) 23 | { 24 | constexpr bool res = test_swap(); 25 | CHECK( res ); 26 | static_assert(res); 27 | } 28 | -------------------------------------------------------------------------------- /tests/alignment.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | #include 6 | #include 7 | #include 8 | 9 | namespace 10 | { 11 | struct wrap 12 | { 13 | std::uint32_t wrapped; 14 | }; 15 | } 16 | 17 | TEST_CASE( "test alignment of compressed pair" ) 18 | { 19 | using cruft::get; 20 | 21 | CHECK( alignof(cruft::tight_pair) == alignof(std::uint32_t) ); 22 | CHECK( alignof(cruft::tight_pair) == alignof(std::uint64_t) ); 23 | CHECK( alignof(cruft::tight_pair) == alignof(std::uint32_t) ); 24 | } 25 | -------------------------------------------------------------------------------- /test_package/conanfile.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (c) 2019-2021 Morwenn 4 | # SPDX-License-Identifier: MIT 5 | 6 | import os.path 7 | 8 | from conans import ConanFile, CMake, tools 9 | 10 | class TightPairTestConan(ConanFile): 11 | settings = "os", "compiler", "build_type", "arch" 12 | generators = "cmake", "cmake_find_package_multi" 13 | 14 | def build(self): 15 | cmake = CMake(self) 16 | cmake.configure() 17 | cmake.build() 18 | 19 | def test(self): 20 | if not tools.cross_building(self.settings): 21 | bin_path = os.path.join("bin", "test_package") 22 | self.run(bin_path, run_environment=True) 23 | -------------------------------------------------------------------------------- /tests/p1951.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | #include 6 | #include 7 | #include 8 | 9 | namespace 10 | { 11 | struct foo 12 | { 13 | bool construction_is_optimized; 14 | 15 | foo(std::string const&): 16 | construction_is_optimized(true) 17 | {} 18 | 19 | foo(foo const&): 20 | construction_is_optimized(false) 21 | {} 22 | }; 23 | 24 | struct bar 25 | { 26 | bar() = default; 27 | bar(bar const&) = default; 28 | }; 29 | } 30 | 31 | TEST_CASE( "P1951" ) 32 | { 33 | using cruft::get; 34 | 35 | cruft::tight_pair p("hello", {}); 36 | CHECK(get<0>(p).construction_is_optimized); 37 | } 38 | -------------------------------------------------------------------------------- /test_package/tight_pair-integrity.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct identity 11 | { 12 | template 13 | constexpr auto operator()(T&& value) const noexcept 14 | -> T&& 15 | { 16 | return std::forward(value); 17 | } 18 | }; 19 | 20 | int main() 21 | { 22 | // Store a comparison and a projection, imagine that 23 | // the Ranges TS is already in the standard library :p 24 | auto p1 = std::pair(std::less{}, identity{}); 25 | auto p2 = cruft::tight_pair(std::less{}, identity{}); 26 | 27 | // prints "2 1" on my computer 28 | std::cout << sizeof(p1) << ' ' << sizeof(p2); 29 | } 30 | -------------------------------------------------------------------------------- /tests/libcxx/types.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | TEST_CASE( "test std::tuple_element" ) 19 | { 20 | using P = cruft::tight_pair; 21 | static_assert(std::is_same_v, float>); 22 | static_assert(std::is_same_v, short*>); 23 | } 24 | -------------------------------------------------------------------------------- /tests/libcxx/get_rv.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | TEST_CASE( "get rv" ) 19 | { 20 | using P = cruft::tight_pair, short>; 21 | P p(std::unique_ptr(new int(3)), static_cast(4)); 22 | std::unique_ptr ptr = cruft::get<0>(std::move(p)); 23 | CHECK(*ptr == 3); 24 | } 25 | -------------------------------------------------------------------------------- /tests/libcxx/dtor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | TEST_CASE( "test default constructor triviality" ) 20 | { 21 | static_assert(std::is_trivially_destructible_v>); 22 | static_assert(not std::is_trivially_destructible_v>); 23 | } 24 | -------------------------------------------------------------------------------- /tests/libcxx/copy_ctor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | 17 | TEST_CASE( "copy constructor tests" ) 18 | { 19 | using cruft::get; 20 | 21 | using P1 = cruft::tight_pair; 22 | constexpr P1 p1(3, static_cast(4)); 23 | constexpr P1 p2 = p1; 24 | CHECK(get<0>(p2) == 3); 25 | CHECK(get<1>(p2)== 4); 26 | static_assert(get<0>(p2) == 3); 27 | static_assert(get<1>(p2) == 4); 28 | } 29 | -------------------------------------------------------------------------------- /tests/libcxx/non_member_swap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | 17 | TEST_CASE( "non member swap" ) 18 | { 19 | using cruft::get; 20 | { 21 | using P1 = std::pair; 22 | P1 p1(3, static_cast(4)); 23 | P1 p2(5, static_cast(6)); 24 | swap(p1, p2); 25 | CHECK(get<0>(p1)== 5); 26 | CHECK(get<1>(p1) == 6); 27 | CHECK(get<0>(p2) == 3); 28 | CHECK(get<1>(p2) == 4); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/libcxx/get_const.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | 17 | TEST_CASE( "get const" ) 18 | { 19 | { 20 | using P = cruft::tight_pair; 21 | const P p(3, static_cast(4)); 22 | CHECK(cruft::get<0>(p) == 3); 23 | CHECK(cruft::get<1>(p) == 4); 24 | } 25 | 26 | { 27 | using P = cruft::tight_pair; 28 | constexpr P p1(3, static_cast(4)); 29 | static_assert(cruft::get<0>(p1) == 3); 30 | static_assert(cruft::get<1>(p1) == 4); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2021 Morwenn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bench/plot.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import sys 4 | from collections import OrderedDict 5 | 6 | import numpy 7 | from matplotlib import pyplot 8 | 9 | algos = OrderedDict() 10 | 11 | with open(sys.argv[1]) as fd: 12 | for line in fd: 13 | pair_type, dist, algo, seconds = line.split() 14 | algos.setdefault(algo, {})[pair_type] = int(seconds) 15 | 16 | print(algos) 17 | 18 | std_times = [algo['std'] for algo in algos.values()] 19 | cruft_times = [algo['cruft'] for algo in algos.values()] 20 | 21 | ind = numpy.arange(len(algos)) + 0.25 22 | width = 0.3 23 | 24 | pyplot.xkcd() 25 | 26 | fig, ax = pyplot.subplots() 27 | bars_std = ax.bar(ind, std_times, width, color='#1f77b4', edgecolor='#1f77b4') 28 | bars_cruft = ax.bar(ind+width, cruft_times, width, color='#ff7f0e', edgecolor='#ff7f0e') 29 | 30 | # add some text for labels, title and axes ticks 31 | ax.set_ylabel('Cycles per element (fewer is better)') 32 | ax.set_title(r'Sorting $10^6$ pairs of unsigned short') 33 | ax.set_xticks(ind + width) 34 | ax.set_xticklabels(list(algos.keys())) 35 | 36 | ax.legend((bars_std[0], bars_cruft[0]), ('std::pair', 'cruft::tight_pair')) 37 | 38 | pyplot.show() 39 | -------------------------------------------------------------------------------- /tests/libcxx/tuple_size.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | 17 | TEST_CASE( "test tuple_size" ) 18 | { 19 | { 20 | using P1 = cruft::tight_pair; 21 | static_assert(std::tuple_size_v == 2); 22 | } 23 | { 24 | using P1 = const cruft::tight_pair; 25 | static_assert(std::tuple_size_v == 2); 26 | } 27 | { 28 | using P1 = volatile cruft::tight_pair; 29 | static_assert(std::tuple_size_v == 2); 30 | } 31 | { 32 | using P1 = const volatile cruft::tight_pair; 33 | static_assert(std::tuple_size_v == 2); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /cmake/llvm-cov-wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This file is part of CMake-codecov. 4 | # 5 | # Copyright (c) 6 | # 2015-2017 RWTH Aachen University, Federal Republic of Germany 7 | # 8 | # See the LICENSE file in the package base directory for details 9 | # 10 | # Written by Alexander Haase, alexander.haase@rwth-aachen.de 11 | # 12 | 13 | if [ -z "$LLVM_COV_BIN" ] 14 | then 15 | echo "LLVM_COV_BIN not set!" >& 2 16 | exit 1 17 | fi 18 | 19 | 20 | # Get LLVM version to find out. 21 | LLVM_VERSION=$($LLVM_COV_BIN -version | grep -i "LLVM version" \ 22 | | sed "s/^\([A-Za-z ]*\)\([0-9]\).\([0-9]\).*$/\2.\3/g") 23 | 24 | if [ "$1" = "-v" ] 25 | then 26 | echo "llvm-cov-wrapper $LLVM_VERSION" 27 | exit 0 28 | fi 29 | 30 | 31 | if [ -n "$LLVM_VERSION" ] 32 | then 33 | MAJOR=$(echo $LLVM_VERSION | cut -d'.' -f1) 34 | MINOR=$(echo $LLVM_VERSION | cut -d'.' -f2) 35 | 36 | if [ $MAJOR -eq 3 ] && [ $MINOR -le 4 ] 37 | then 38 | if [ -f "$1" ] 39 | then 40 | filename=$(basename "$1") 41 | extension="${filename##*.}" 42 | 43 | case "$extension" in 44 | "gcno") exec $LLVM_COV_BIN --gcno="$1" ;; 45 | "gcda") exec $LLVM_COV_BIN --gcda="$1" ;; 46 | esac 47 | fi 48 | fi 49 | 50 | if [ $MAJOR -eq 3 ] && [ $MINOR -le 5 ] 51 | then 52 | exec $LLVM_COV_BIN $@ 53 | fi 54 | fi 55 | 56 | exec $LLVM_COV_BIN gcov $@ 57 | -------------------------------------------------------------------------------- /tests/libcxx/test_convertible.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef CRUFT_TIGHT_PAIR_TEST_LIBCXX_TEST_CONVERTIBLE_H_ 15 | #define CRUFT_TIGHT_PAIR_TEST_LIBCXX_TEST_CONVERTIBLE_H_ 16 | 17 | namespace detail 18 | { 19 | template 20 | void eat_type(Tp); 21 | 22 | template 23 | constexpr auto test_convertible_imp(int) 24 | -> decltype(eat_type({std::declval()...}), true) 25 | { 26 | return true; 27 | } 28 | 29 | template 30 | constexpr auto test_convertible_imp(long) 31 | -> bool 32 | { 33 | return false; 34 | } 35 | } 36 | 37 | template 38 | constexpr bool test_convertible() 39 | { 40 | return detail::test_convertible_imp(0); 41 | } 42 | 43 | #endif // CRUFT_TIGHT_PAIR_TEST_LIBCXX_TEST_CONVERTIBLE_H_ 44 | -------------------------------------------------------------------------------- /tests/libcxx/get_non_const.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | 17 | namespace 18 | { 19 | struct S 20 | { 21 | cruft::tight_pair a; 22 | int k; 23 | constexpr S(): a{1, 2}, k(cruft::get<0>(a)) {} 24 | }; 25 | 26 | constexpr cruft::tight_pair getP() { return { 3, 4 }; } 27 | } 28 | 29 | TEST_CASE( "get non const" ) 30 | { 31 | { 32 | using P = cruft::tight_pair; 33 | P p(3, static_cast(4)); 34 | CHECK(cruft::get<0>(p) == 3); 35 | CHECK(cruft::get<1>(p) == 4); 36 | cruft::get<0>(p) = 5; 37 | cruft::get<1>(p) = 6; 38 | CHECK(cruft::get<0>(p) == 5); 39 | CHECK(cruft::get<1>(p) == 6); 40 | } 41 | 42 | { 43 | static_assert(S().k == 1); 44 | static_assert(cruft::get<1>(getP()) == 4); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /.github/workflows/build-mingw.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 Morwenn 2 | # SPDX-License-Identifier: MIT 3 | 4 | name: MinGW-w64 Builds 5 | 6 | on: 7 | push: 8 | paths: 9 | - '.github/workflows/build-mingw.yml' 10 | - 'CMakeLists.txt' 11 | - 'cmake/**' 12 | - 'include/**' 13 | - 'tests/**' 14 | pull_request: 15 | paths: 16 | - '.github/workflows/build-mingw.yml' 17 | - 'CMakeLists.txt' 18 | - 'cmake/**' 19 | - 'include/**' 20 | - 'tests/**' 21 | 22 | jobs: 23 | build: 24 | runs-on: windows-2019 25 | 26 | strategy: 27 | fail-fast: false 28 | matrix: 29 | build_type: [Debug, Release] 30 | 31 | steps: 32 | - uses: actions/checkout@v2 33 | 34 | - name: Configure CMake 35 | shell: pwsh 36 | working-directory: ${{runner.workspace}} 37 | run: | 38 | cmake -H${{github.event.repository.name}} -Bbuild ` 39 | -DCMAKE_CONFIGURATION_TYPES=${{matrix.build_type}} ` 40 | -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ` 41 | -G"MinGW Makefiles" ` 42 | 43 | - name: Build the test suite 44 | working-directory: ${{runner.workspace}}/build 45 | run: cmake --build . --config ${{matrix.build_type}} -j 2 46 | 47 | - name: Run the test suite 48 | env: 49 | CTEST_OUTPUT_ON_FAILURE: 1 50 | working-directory: ${{runner.workspace}}/build 51 | run: ctest -C ${{matrix.build_type}} 52 | -------------------------------------------------------------------------------- /.github/workflows/build-msvc.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 Morwenn 2 | # SPDX-License-Identifier: MIT 3 | 4 | name: MSVC Builds 5 | 6 | on: 7 | push: 8 | paths: 9 | - '.github/workflows/build-msvc.yml' 10 | - 'CMakeLists.txt' 11 | - 'cmake/**' 12 | - 'include/**' 13 | - 'tests/**' 14 | pull_request: 15 | paths: 16 | - '.github/workflows/build-msvc.yml' 17 | - 'CMakeLists.txt' 18 | - 'cmake/**' 19 | - 'include/**' 20 | - 'tests/**' 21 | 22 | jobs: 23 | build: 24 | runs-on: windows-2019 25 | 26 | strategy: 27 | fail-fast: false 28 | matrix: 29 | build_type: [Debug, Release] 30 | 31 | steps: 32 | - uses: actions/checkout@v2 33 | 34 | - name: Configure CMake 35 | shell: pwsh 36 | working-directory: ${{runner.workspace}} 37 | run: | 38 | cmake -H${{github.event.repository.name}} -Bbuild ` 39 | -DCMAKE_CONFIGURATION_TYPES=${{matrix.build_type}} ` 40 | -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ` 41 | -G"Visual Studio 16 2019" -A x64 ` 42 | 43 | - name: Build the test suite 44 | working-directory: ${{runner.workspace}}/build 45 | run: cmake --build . --config ${{matrix.build_type}} -j 2 46 | 47 | - name: Run the test suite 48 | env: 49 | CTEST_OUTPUT_ON_FAILURE: 1 50 | working-directory: ${{runner.workspace}}/build 51 | run: ctest -C ${{matrix.build_type}} 52 | -------------------------------------------------------------------------------- /tests/libcxx/trivial_copy_move.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace 19 | { 20 | struct Dummy 21 | { 22 | Dummy(Dummy const&) = delete; 23 | Dummy(Dummy&&) = default; 24 | }; 25 | } 26 | 27 | TEST_CASE( "trivial copy move" ) 28 | { 29 | using P = cruft::tight_pair; 30 | { 31 | static_assert(std::is_copy_constructible_v

); 32 | static_assert(std::is_trivially_copy_constructible_v

); 33 | } 34 | 35 | { 36 | static_assert(std::is_move_constructible_v

); 37 | static_assert(std::is_trivially_move_constructible_v

); 38 | } 39 | 40 | { 41 | using P1 = cruft::tight_pair; 42 | static_assert(not std::is_copy_constructible_v); 43 | static_assert(not std::is_trivially_copy_constructible_v); 44 | static_assert(std::is_move_constructible_v); 45 | static_assert(std::is_trivially_move_constructible_v); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/libcxx/used_to_be_make_pair.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | TEST_CASE( "used to be make_pair" ) 19 | { 20 | using cruft::get; 21 | { 22 | using P1 = cruft::tight_pair; 23 | P1 p1 = cruft::tight_pair(3, static_cast(4)); 24 | CHECK(get<0>(p1) == 3); 25 | CHECK(get<1>(p1) == 4); 26 | } 27 | { 28 | using P1 = cruft::tight_pair, short>; 29 | P1 p1 = cruft::tight_pair(std::unique_ptr(new int(3)), static_cast(4)); 30 | CHECK(*get<0>(p1) == 3); 31 | CHECK(get<1>(p1) == 4); 32 | } 33 | { 34 | using P1 = cruft::tight_pair, short>; 35 | P1 p1 = cruft::tight_pair(nullptr, static_cast(4)); 36 | CHECK(get<0>(p1) == nullptr); 37 | CHECK(get<1>(p1) == 4); 38 | } 39 | { 40 | using P1 = cruft::tight_pair; 41 | constexpr P1 p1 = cruft::tight_pair(3, static_cast(4)); 42 | static_assert(get<0>(p1) == 3, ""); 43 | static_assert(get<1>(p1) == 4, ""); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /conanfile.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (c) 2019-2021 Morwenn 4 | # SPDX-License-Identifier: MIT 5 | 6 | from conans import CMake, ConanFile 7 | 8 | required_conan_version = ">=1.33.0" 9 | 10 | 11 | class TightPairConan(ConanFile): 12 | name = "tight_pair" 13 | version = "1.2.0" 14 | description = "Compressed pair for C++17" 15 | topics = "conan", "tight_pair", "compressed-pair", "data-structures" 16 | url = "https://github.com/Morwenn/tight_pair" 17 | homepage = url 18 | author = "Morwenn " 19 | 20 | # Minimal exports 21 | exports = "LICENSE" 22 | exports_sources = [ 23 | "include/*", 24 | "CMakeLists.txt", 25 | "cmake/tight_pair-config.cmake.in" 26 | ] 27 | no_copy_source = True 28 | settings = "os", "compiler", "build_type", "arch" 29 | 30 | def validate(self): 31 | if self.settings.get_safe("compiler.cppstd"): 32 | tools.check_min_cppstd(self, 17) 33 | 34 | def package(self): 35 | cmake = CMake(self) 36 | cmake.definitions["BUILD_TESTING"] = "OFF" 37 | cmake.configure() 38 | cmake.install() 39 | cmake.patch_config_paths() 40 | 41 | self.copy("LICENSE", dst="licenses", ignore_case=True, keep_path=False) 42 | 43 | def package_info(self): 44 | self.cpp_info.names["cmake_find_package"] = "tight_pair" 45 | self.cpp_info.names["cmake_find_package_multi"] = "tight_pair" 46 | if self.settings.compiler == "Visual Studio": 47 | self.cpp_info.cxxflags = ["/permissive-"] 48 | 49 | def package_id(self): 50 | self.info.header_only() 51 | -------------------------------------------------------------------------------- /.github/workflows/code-coverage.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 Morwenn 2 | # SPDX-License-Identifier: MIT 3 | 4 | name: Coverage Upload to Codecov 5 | 6 | on: 7 | push: 8 | branches: 9 | - master 10 | - develop 11 | - 2.0.0-develop 12 | paths: 13 | - '.github/workflows/code-coverage.yml' 14 | - 'CMakeLists.txt' 15 | - 'cmake/**' 16 | - 'codecov.yml' 17 | - 'include/**' 18 | - 'tests/**' 19 | 20 | env: 21 | BUILD_TYPE: Debug 22 | 23 | jobs: 24 | upload-coverage: 25 | runs-on: ubuntu-latest 26 | 27 | steps: 28 | - name: Checkout project 29 | uses: actions/checkout@v2 30 | 31 | - name: Configure CMake 32 | shell: bash 33 | working-directory: ${{runner.workspace}} 34 | run: > 35 | cmake -H${{github.event.repository.name}} -Bbuild 36 | -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" 37 | -DTIGHT_PAIR_ENABLE_COVERAGE=ON 38 | -G"Unix Makefiles" 39 | 40 | - name: Build with coverage 41 | shell: bash 42 | working-directory: ${{runner.workspace}}/build 43 | run: cmake --build . --config $BUILD_TYPE -j 2 44 | 45 | - name: Run the test suite 46 | shell: bash 47 | working-directory: ${{runner.workspace}}/build 48 | run: ctest -C Release --output-on-failure 49 | 50 | - name: Create coverage info 51 | shell: bash 52 | working-directory: ${{runner.workspace}}/build 53 | run: make gcov 54 | 55 | - name: Upload coverage info 56 | uses: codecov/codecov-action@v1.2.1 57 | with: 58 | directory: ${{runner.workspace}}/build 59 | functionalities: gcov 60 | -------------------------------------------------------------------------------- /tests/libcxx/default_ctor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace 19 | { 20 | struct NoDefault 21 | { 22 | NoDefault() = delete; 23 | }; 24 | } 25 | 26 | TEST_CASE( "test default constructor" ) 27 | { 28 | using cruft::get; 29 | 30 | { 31 | using P = cruft::tight_pair; 32 | P p; 33 | CHECK(get<0>(p) == 0.0f); 34 | CHECK(get<1>(p) == nullptr); 35 | } 36 | 37 | { 38 | using P = cruft::tight_pair;; 39 | constexpr P p; 40 | static_assert(get<0>(p) == 0.0f); 41 | static_assert(get<1>(p) == nullptr); 42 | } 43 | 44 | { 45 | using P = cruft::tight_pair; 46 | static_assert(not std::is_default_constructible_v

); 47 | using P2 = cruft::tight_pair; 48 | static_assert(not std::is_default_constructible_v); 49 | } 50 | 51 | { 52 | struct Base {}; 53 | struct Derived: Base { protected: Derived() = default; }; 54 | static_assert(not std::is_default_constructible_v>); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/libcxx/default.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include "archetypes.h" 18 | 19 | TEST_CASE( "default noexcept" ) 20 | { 21 | using NonThrowingDefault = NonThrowingTypes::DefaultOnly; 22 | #if !defined(__GNUC__) || (defined(__GNUC__) && __GNUC__ >= 9) 23 | using ThrowingDefault = NonTrivialTypes::DefaultOnly; 24 | // NOTE: the behaviour for these test cases depends on whether the compiler implements 25 | // the resolution of P0003R5 which removes a noexcept special case with regard to 26 | // constant expressions, which apparently was a serendipitous change so compilers 27 | // took some time to adapt. 28 | static_assert(not std::is_nothrow_default_constructible_v>); 29 | static_assert(not std::is_nothrow_default_constructible_v>); 30 | static_assert(not std::is_nothrow_default_constructible_v>); 31 | #endif 32 | static_assert(std::is_nothrow_default_constructible_v>); 33 | } 34 | -------------------------------------------------------------------------------- /tests/libcxx/swap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace 20 | { 21 | struct S 22 | { 23 | int i; 24 | constexpr S(): i(0) {} 25 | constexpr S(int j): i(j) {} 26 | constexpr bool operator==(int x) const { return i == x; } 27 | }; 28 | 29 | constexpr bool test() 30 | { 31 | using cruft::get; 32 | { 33 | using P1 = cruft::tight_pair; 34 | P1 p1(3, static_cast(4)); 35 | P1 p2(5, static_cast(6)); 36 | p1.swap(p2); 37 | assert(get<0>(p1) == 5); 38 | assert(get<1>(p1) == 6); 39 | assert(get<0>(p2) == 3); 40 | assert(get<1>(p2) == 4); 41 | } 42 | { 43 | using P1 = cruft::tight_pair; 44 | P1 p1(3, S(4)); 45 | P1 p2(5, S(6)); 46 | p1.swap(p2); 47 | assert(get<0>(p1) == 5); 48 | assert(get<1>(p1) == 6); 49 | assert(get<0>(p2) == 3); 50 | assert(get<1>(p2) == 4); 51 | } 52 | return true; 53 | } 54 | } 55 | 56 | TEST_CASE( "swap" ) 57 | { 58 | static_assert(test()); 59 | } 60 | -------------------------------------------------------------------------------- /tests/reference_wrapper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | TEST_CASE( "test std::reference_wrapper unwrapping" ) 11 | { 12 | int a = 5; 13 | double b = 5.2; 14 | 15 | { 16 | auto p1 = cruft::tight_pair(std::ref(a), b); 17 | static_assert(std::is_same_v, int&>); 18 | static_assert(std::is_same_v, double>); 19 | 20 | auto p2 = cruft::tight_pair(a, std::ref(b)); 21 | static_assert(std::is_same_v, int>); 22 | static_assert(std::is_same_v, double&>); 23 | 24 | auto p3 = cruft::tight_pair(std::ref(a), std::ref(b)); 25 | static_assert(std::is_same_v, int&>); 26 | static_assert(std::is_same_v, double&>); 27 | } 28 | 29 | { 30 | auto p1 = cruft::tight_pair(std::cref(a), b); 31 | static_assert(std::is_same_v, int const&>); 32 | static_assert(std::is_same_v, double>); 33 | 34 | auto p2 = cruft::tight_pair(a, std::cref(b)); 35 | static_assert(std::is_same_v, int>); 36 | static_assert(std::is_same_v, double const&>); 37 | 38 | auto p3 = cruft::tight_pair(std::cref(a), std::cref(b)); 39 | static_assert(std::is_same_v, int const&>); 40 | static_assert(std::is_same_v, double const&>); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/tricky_comparisons.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | #include 6 | #include 7 | 8 | TEMPLATE_TEST_CASE( "test optimized comparison operators", "[comparisons]", 9 | unsigned char, 10 | unsigned short, 11 | unsigned int, 12 | unsigned long, 13 | unsigned long long ) 14 | { 15 | using integer_t = TestType; 16 | 17 | cruft::tight_pair p1(5, 8); 18 | cruft::tight_pair p2(12, 12); 19 | cruft::tight_pair p3(5, 8); 20 | CHECK( p1 != p2 ); 21 | CHECK( p1 == p3 ); 22 | CHECK( p2 != p3 ); 23 | } 24 | 25 | TEMPLATE_TEST_CASE( "test optimized relational operators", "[comparisons]", 26 | unsigned char, 27 | unsigned short, 28 | unsigned int, 29 | unsigned long, 30 | unsigned long long ) 31 | { 32 | using integer_t = TestType; 33 | 34 | cruft::tight_pair p1(5, 6); 35 | cruft::tight_pair p2(6, 5); 36 | CHECK( p1 < p2 ); 37 | CHECK( p1 <= p2 ); 38 | CHECK( p2 > p1 ); 39 | CHECK( p2 >= p1 ); 40 | 41 | cruft::tight_pair p3(4, 7); 42 | cruft::tight_pair p4(4, 8); 43 | CHECK( p3 < p4 ); 44 | CHECK( p3 <= p4 ); 45 | CHECK( p4 > p3 ); 46 | CHECK( p4 >= p3 ); 47 | 48 | cruft::tight_pair p5(10, 22); 49 | cruft::tight_pair p6(10, 22); 50 | CHECK( p5 == p6 ); 51 | CHECK_FALSE( p5 != p6 ); 52 | CHECK_FALSE( p5 < p6 ); 53 | CHECK( p5 <= p6 ); 54 | CHECK_FALSE( p5 > p6 ); 55 | CHECK( p5 >= p6 ); 56 | } 57 | -------------------------------------------------------------------------------- /tests/piecewise_no_copy_move.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | #include 6 | #include 7 | 8 | namespace 9 | { 10 | struct DummyA 11 | { 12 | DummyA(DummyA const&) = delete; 13 | DummyA(DummyA&&) = delete; 14 | 15 | constexpr DummyA(int a, int b): a(a), b(b) {} 16 | 17 | int a, b; 18 | }; 19 | 20 | struct DummyB 21 | { 22 | DummyB(DummyB const&) = delete; 23 | DummyB(DummyB&&) = delete; 24 | 25 | constexpr DummyB(int a, int b): a(a), b(b) {} 26 | 27 | int a, b; 28 | }; 29 | } 30 | 31 | TEST_CASE( "test that piecewise construction works with no copy/move ctor" ) 32 | { 33 | using cruft::get; 34 | 35 | constexpr cruft::tight_pair pr1( 36 | std::piecewise_construct, 37 | std::forward_as_tuple(1, 2), 38 | std::forward_as_tuple(3, 4) 39 | ); 40 | 41 | CHECK(get<0>(pr1).a == 1); 42 | CHECK(get<0>(pr1).b == 2); 43 | CHECK(get<1>(pr1).a == 3); 44 | CHECK(get<1>(pr1).b == 4); 45 | static_assert(get<0>(pr1).a == 1); 46 | static_assert(get<0>(pr1).b == 2); 47 | static_assert(get<1>(pr1).a == 3); 48 | static_assert(get<1>(pr1).b == 4); 49 | 50 | #if defined(_MSC_VER) && _MSC_VER >= 1930 51 | // MSVC has some constexpr bug before version 19.30 52 | 53 | constexpr cruft::tight_pair pr2( 54 | std::piecewise_construct, 55 | std::forward_as_tuple(1, 2), 56 | std::forward_as_tuple(3, 4) 57 | ); 58 | 59 | CHECK(get<0>(pr2).a == 1); 60 | CHECK(get<0>(pr2).b == 2); 61 | CHECK(get<1>(pr2).a == 3); 62 | CHECK(get<1>(pr2).b == 4); 63 | static_assert(get<0>(pr2).a == 1); 64 | static_assert(get<0>(pr2).b == 2); 65 | static_assert(get<1>(pr2).a == 3); 66 | static_assert(get<1>(pr2).b == 4); 67 | #endif // defined 68 | } 69 | -------------------------------------------------------------------------------- /tests/libcxx/tuple_element.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | 17 | template 18 | void test() 19 | { 20 | { 21 | using Exp1 = T1; 22 | using Exp2 = T2; 23 | using P = cruft::tight_pair; 24 | static_assert(std::is_same_v, Exp1>); 25 | static_assert(std::is_same_v, Exp2>); 26 | } 27 | { 28 | using Exp1 = const T1; 29 | using Exp2 = const T2; 30 | using P = const cruft::tight_pair; 31 | static_assert(std::is_same_v, Exp1>); 32 | static_assert(std::is_same_v, Exp2>); 33 | } 34 | { 35 | using Exp1 = volatile T1; 36 | using Exp2 = volatile T2; 37 | using P = volatile cruft::tight_pair; 38 | static_assert(std::is_same_v, Exp1>); 39 | static_assert(std::is_same_v, Exp2>); 40 | } 41 | { 42 | using Exp1 = const volatile T1; 43 | using Exp2 = const volatile T2; 44 | using P = const volatile cruft::tight_pair; 45 | static_assert(std::is_same_v, Exp1>); 46 | static_assert(std::is_same_v, Exp2>); 47 | } 48 | } 49 | 50 | TEST_CASE( "test tuple_element" ) 51 | { 52 | test(); 53 | test(); 54 | } 55 | -------------------------------------------------------------------------------- /.github/workflows/build-macos.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 Morwenn 2 | # SPDX-License-Identifier: MIT 3 | 4 | name: MacOS Builds 5 | 6 | on: 7 | push: 8 | paths: 9 | - '.github/workflows/build-macos.yml' 10 | - 'CMakeLists.txt' 11 | - 'cmake/**' 12 | - 'include/**' 13 | - 'tests/**' 14 | pull_request: 15 | paths: 16 | - '.github/workflows/build-macos.yml' 17 | - 'CMakeLists.txt' 18 | - 'cmake/**' 19 | - 'include/**' 20 | - 'tests/**' 21 | 22 | jobs: 23 | build: 24 | runs-on: macos-10.15 25 | 26 | strategy: 27 | fail-fast: false 28 | matrix: 29 | cxx: 30 | - g++-9 31 | - $(brew --prefix llvm)/bin/clang++ # Clang 11 32 | config: 33 | # Release build 34 | - build_type: Release 35 | # Debug builds 36 | - build_type: Debug 37 | sanitize: address 38 | - build_type: Debug 39 | sanitize: undefined 40 | 41 | steps: 42 | - uses: actions/checkout@v2 43 | - uses: seanmiddleditch/gha-setup-ninja@master 44 | 45 | - name: Configure CMake 46 | working-directory: ${{runner.workspace}} 47 | run: | 48 | export CXX=${{matrix.cxx}} 49 | cmake -H${{github.event.repository.name}} -Bbuild \ 50 | -DCMAKE_CONFIGURATION_TYPES=${{matrix.config.build_type}} \ 51 | -DCMAKE_BUILD_TYPE=${{matrix.config.build_type}} \ 52 | -DTIGHT_PAIR_SANITIZE=${{matrix.config.sanitize}} \ 53 | -GNinja 54 | 55 | - name: Build the test suite 56 | shell: bash 57 | working-directory: ${{runner.workspace}}/build 58 | run: cmake --build . --config ${{matrix.config.build_type}} -j 2 59 | 60 | - name: Run the test suite 61 | env: 62 | CTEST_OUTPUT_ON_FAILURE: 1 63 | working-directory: ${{runner.workspace}}/build 64 | run: ctest -C ${{matrix.config.build_type}} 65 | -------------------------------------------------------------------------------- /tests/libcxx/get_const_rv.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | TEST_CASE( "get const rv" ) 20 | { 21 | { 22 | using P = cruft::tight_pair, short>; 23 | const P p(std::unique_ptr(new int(3)), static_cast(4)); 24 | static_assert(std::is_same_v&&, decltype(cruft::get<0>(std::move(p)))>); 25 | static_assert(noexcept(cruft::get<0>(std::move(p)))); 26 | const std::unique_ptr&& ptr = cruft::get<0>(std::move(p)); 27 | CHECK(*ptr == 3); 28 | } 29 | 30 | { 31 | int x = 42; 32 | int const y = 43; 33 | cruft::tight_pair const p(x, y); 34 | static_assert(std::is_same_v(std::move(p)))>); 35 | static_assert(noexcept(cruft::get<0>(std::move(p)))); 36 | static_assert(std::is_same_v(std::move(p)))>); 37 | static_assert(noexcept(cruft::get<1>(std::move(p)))); 38 | } 39 | 40 | { 41 | int x = 42; 42 | int const y = 43; 43 | cruft::tight_pair const p(std::move(x), std::move(y)); 44 | static_assert(std::is_same_v(std::move(p)))>); 45 | static_assert(noexcept(cruft::get<0>(std::move(p)))); 46 | static_assert(std::is_same_v(std::move(p)))>); 47 | static_assert(noexcept(cruft::get<1>(std::move(p)))); 48 | } 49 | 50 | { 51 | using P = cruft::tight_pair; 52 | constexpr const P p1(3, static_cast(4)); 53 | static_assert(cruft::get<0>(std::move(p1)) == 3); 54 | static_assert(cruft::get<1>(std::move(p1)) == 4); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/libcxx/assign_const_pair_U_V.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "archetypes.h" 19 | 20 | namespace 21 | { 22 | struct CopyAssignableInt 23 | { 24 | CopyAssignableInt& operator=(int&) { return *this; } 25 | }; 26 | 27 | struct Unrelated {}; 28 | 29 | constexpr bool test() 30 | { 31 | using cruft::get; 32 | { 33 | using P1 = cruft::tight_pair; 34 | using P2 = cruft::tight_pair; 35 | P1 p1(3, static_cast(4)); 36 | P2 p2; 37 | p2 = p1; 38 | assert(get<0>(p2) == 3); 39 | assert(get<1>(p2) == 4); 40 | } 41 | 42 | { 43 | using C = ConstexprTestTypes::TestType; 44 | using P = cruft::tight_pair; 45 | using T = cruft::tight_pair; 46 | const T t(42, -42); 47 | P p(101, 101); 48 | p = t; 49 | assert(get<0>(p) == 42); 50 | assert(get<1>(p).value == -42); 51 | } 52 | 53 | 54 | { // test const requirement 55 | using T = cruft::tight_pair; 56 | using P = cruft::tight_pair; 57 | static_assert(not std::is_assignable::value); 58 | } 59 | { 60 | using T = cruft::tight_pair; 61 | using P = cruft::tight_pair; 62 | static_assert(not std::is_assignable::value); 63 | static_assert(not std::is_assignable::value); 64 | } 65 | return true; 66 | } 67 | } 68 | 69 | 70 | TEST_CASE( "assign const pair U V" ) 71 | { 72 | static_assert(test()); 73 | } 74 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017-2021 Morwenn 2 | # SPDX-License-Identifier: MIT 3 | 4 | cmake_minimum_required(VERSION 3.11.0) 5 | 6 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 7 | 8 | project(tight_pair VERSION 1.2.0 LANGUAGES CXX) 9 | 10 | include(CMakePackageConfigHelpers) 11 | include(GNUInstallDirs) 12 | 13 | # Project options 14 | option(BUILD_TESTING "Build the tight_pair test suite" ON) 15 | 16 | # Create tight_pair library and configure it 17 | add_library(tight_pair INTERFACE) 18 | target_include_directories(tight_pair INTERFACE 19 | $ 20 | $ 21 | ) 22 | 23 | target_compile_features(tight_pair INTERFACE cxx_std_17) 24 | 25 | # MSVC won't work without a stricter standard compliance 26 | if (MSVC) 27 | target_compile_options(tight_pair INTERFACE /permissive-) 28 | endif() 29 | 30 | add_library(tight_pair::tight_pair ALIAS tight_pair) 31 | 32 | # Install targets and files 33 | install( 34 | TARGETS tight_pair 35 | EXPORT tight_pair-targets 36 | DESTINATION ${CMAKE_INSTALL_LIBDIR} 37 | ) 38 | 39 | install( 40 | EXPORT tight_pair-targets 41 | NAMESPACE tight_pair:: 42 | DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tight_pair" 43 | ) 44 | 45 | install( 46 | DIRECTORY "include/" 47 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" 48 | ) 49 | 50 | configure_package_config_file( 51 | ${CMAKE_SOURCE_DIR}/cmake/tight_pair-config.cmake.in 52 | ${CMAKE_BINARY_DIR}/cmake/tight_pair-config.cmake 53 | INSTALL_DESTINATION 54 | ${CMAKE_INSTALL_LIBDIR}/cmake/tight_pair 55 | ) 56 | 57 | write_basic_package_version_file( 58 | ${CMAKE_BINARY_DIR}/cmake/tight_pair-config-version.cmake 59 | COMPATIBILITY 60 | SameMajorVersion 61 | ) 62 | 63 | install( 64 | FILES 65 | ${CMAKE_BINARY_DIR}/cmake/tight_pair-config.cmake 66 | ${CMAKE_BINARY_DIR}/cmake/tight_pair-config-version.cmake 67 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/tight_pair 68 | ) 69 | 70 | # Export target so that it can be used in subdirectories 71 | export( 72 | EXPORT tight_pair-targets 73 | FILE ${CMAKE_BINARY_DIR}/cmake/tight_pair-targets.cmake 74 | NAMESPACE tight_pair:: 75 | ) 76 | 77 | # Build tests if this is the main project 78 | if (BUILD_TESTING AND (PROJECT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)) 79 | enable_testing() 80 | add_subdirectory(tests) 81 | endif() 82 | -------------------------------------------------------------------------------- /tests/libcxx/piecewise_construct.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace 20 | { 21 | class A 22 | { 23 | int i_; 24 | char c_; 25 | 26 | public: 27 | 28 | constexpr A(int i, char c): i_(i), c_(c) {} 29 | constexpr int get_i() const { return i_; } 30 | constexpr char get_c() const { return c_; } 31 | }; 32 | 33 | class B 34 | { 35 | double d_; 36 | unsigned u1_; 37 | unsigned u2_; 38 | 39 | public: 40 | 41 | constexpr explicit B(double d, unsigned u1, unsigned u2): d_(d), u1_(u1), u2_(u2) {} 42 | constexpr double get_d() const { return d_; } 43 | constexpr unsigned get_u1() const { return u1_; } 44 | constexpr unsigned get_u2() const { return u2_; } 45 | }; 46 | 47 | constexpr bool test() 48 | { 49 | using cruft::get; 50 | { 51 | using P1 = cruft::tight_pair; 52 | using P2 = cruft::tight_pair; 53 | using P3 = cruft::tight_pair; 54 | P3 p3(std::piecewise_construct, 55 | std::tuple(3, nullptr), 56 | std::tuple(nullptr, 4)); 57 | assert(get<0>(p3) == P1(3, nullptr)); 58 | assert(get<1>(p3) == P2(nullptr, 4)); 59 | } 60 | return true; 61 | } 62 | } 63 | 64 | TEST_CASE( "piecewise construct" ) 65 | { 66 | using cruft::get; 67 | 68 | constexpr cruft::tight_pair p(std::piecewise_construct, 69 | std::make_tuple(4, 'a'), 70 | std::make_tuple(3.5, 6u, 2u)); 71 | static_assert(get<0>(p).get_i() == 4); 72 | static_assert(get<0>(p).get_c() == 'a'); 73 | static_assert(get<1>(p).get_d() == 3.5); 74 | static_assert(get<1>(p).get_u1() == 6u); 75 | static_assert(get<1>(p).get_u2() == 2u); 76 | 77 | static_assert(test()); 78 | } 79 | 80 | -------------------------------------------------------------------------------- /tests/libcxx/move_ctor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace 20 | { 21 | struct Dummy 22 | { 23 | Dummy(Dummy const&) = delete; 24 | Dummy(Dummy&&) = default; 25 | }; 26 | 27 | struct NotCopyOrMoveConstructible 28 | { 29 | NotCopyOrMoveConstructible() = default; 30 | NotCopyOrMoveConstructible(NotCopyOrMoveConstructible const&) = delete; 31 | NotCopyOrMoveConstructible(NotCopyOrMoveConstructible&&) = delete; 32 | }; 33 | } 34 | 35 | TEST_CASE( "move constructor tests" ) 36 | { 37 | using cruft::get; 38 | { 39 | using P1 = cruft::tight_pair; 40 | static_assert(std::is_move_constructible_v); 41 | P1 p1(3, static_cast(4)); 42 | P1 p2 = std::move(p1); 43 | CHECK(get<0>(p2) == 3); 44 | CHECK(get<1>(p2) == 4); 45 | } 46 | { 47 | using P = cruft::tight_pair; 48 | static_assert(not std::is_copy_constructible_v

); 49 | static_assert(std::is_move_constructible_v

); 50 | } 51 | { 52 | // When constructing a pair containing a reference, we only bind the 53 | // reference, so it doesn't matter whether the type is or isn't 54 | // copy/move constructible. 55 | { 56 | using P = cruft::tight_pair; 57 | static_assert(std::is_move_constructible

::value); 58 | 59 | NotCopyOrMoveConstructible obj; 60 | P p2{obj, 3}; 61 | P p1(std::move(p2)); 62 | CHECK(&get<0>(p1) == &obj); 63 | CHECK(&get<0>(p2) == &obj); 64 | } 65 | { 66 | using P = cruft::tight_pair; 67 | static_assert(std::is_move_constructible

::value); 68 | 69 | NotCopyOrMoveConstructible obj; 70 | P p2{std::move(obj), 3}; 71 | P p1(std::move(p2)); 72 | CHECK(&get<0>(p1) == &obj); 73 | CHECK(&get<0>(p2) == &obj); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tests/libcxx/comparison.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | 17 | TEST_CASE( "comparison" ) 18 | { 19 | { 20 | using P = cruft::tight_pair; 21 | P p1(3, static_cast(4)); 22 | P p2(3, static_cast(4)); 23 | CHECK( (p1 == p2)); 24 | CHECK(!(p1 != p2)); 25 | CHECK(!(p1 < p2)); 26 | CHECK( (p1 <= p2)); 27 | CHECK(!(p1 > p2)); 28 | CHECK( (p1 >= p2)); 29 | } 30 | { 31 | using P = cruft::tight_pair; 32 | P p1(2, static_cast(4)); 33 | P p2(3, static_cast(4)); 34 | CHECK(!(p1 == p2)); 35 | CHECK( (p1 != p2)); 36 | CHECK( (p1 < p2)); 37 | CHECK( (p1 <= p2)); 38 | CHECK(!(p1 > p2)); 39 | CHECK(!(p1 >= p2)); 40 | } 41 | { 42 | using P = cruft::tight_pair; 43 | P p1(3, static_cast(2)); 44 | P p2(3, static_cast(4)); 45 | CHECK(!(p1 == p2)); 46 | CHECK( (p1 != p2)); 47 | CHECK( (p1 < p2)); 48 | CHECK( (p1 <= p2)); 49 | CHECK(!(p1 > p2)); 50 | CHECK(!(p1 >= p2)); 51 | } 52 | { 53 | using P = cruft::tight_pair; 54 | P p1(3, static_cast(4)); 55 | P p2(2, static_cast(4)); 56 | CHECK(!(p1 == p2)); 57 | CHECK( (p1 != p2)); 58 | CHECK(!(p1 < p2)); 59 | CHECK(!(p1 <= p2)); 60 | CHECK( (p1 > p2)); 61 | CHECK( (p1 >= p2)); 62 | } 63 | { 64 | using P = cruft::tight_pair; 65 | P p1(3, static_cast(4)); 66 | P p2(3, static_cast(2)); 67 | CHECK(!(p1 == p2)); 68 | CHECK( (p1 != p2)); 69 | CHECK(!(p1 < p2)); 70 | CHECK(!(p1 <= p2)); 71 | CHECK( (p1 > p2)); 72 | CHECK( (p1 >= p2)); 73 | } 74 | { 75 | using P = cruft::tight_pair; 76 | constexpr P p1(3, static_cast(4)); 77 | constexpr P p2(3, static_cast(2)); 78 | static_assert(!(p1 == p2)); 79 | static_assert( (p1 != p2)); 80 | static_assert(!(p1 < p2)); 81 | static_assert(!(p1 <= p2)); 82 | static_assert( (p1 > p2)); 83 | static_assert( (p1 >= p2)); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /.github/workflows/build-ubuntu.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 Morwenn 2 | # SPDX-License-Identifier: MIT 3 | 4 | name: Ubuntu Builds 5 | 6 | on: 7 | push: 8 | paths: 9 | - '.github/workflows/build-ubuntu.yml' 10 | - 'CMakeLists.txt' 11 | - 'cmake/**' 12 | - 'include/**' 13 | - 'tests/**' 14 | pull_request: 15 | paths: 16 | - '.github/workflows/build-ubuntu.yml' 17 | - 'CMakeLists.txt' 18 | - 'cmake/**' 19 | - 'include/**' 20 | - 'tests/**' 21 | 22 | jobs: 23 | build: 24 | runs-on: ubuntu-18.04 25 | 26 | strategy: 27 | fail-fast: false 28 | matrix: 29 | cxx: 30 | - g++-7 31 | - clang++-6.0 32 | config: 33 | # Release build 34 | - build_type: Release 35 | # Debug builds 36 | - build_type: Debug 37 | valgrind: ON 38 | - build_type: Debug 39 | sanitize: address 40 | - build_type: Debug 41 | sanitize: undefined 42 | 43 | steps: 44 | - uses: actions/checkout@v2 45 | 46 | - name: Install GCC 47 | if: ${{matrix.cxx == 'g++-7'}} 48 | run: sudo apt-get install -y g++-7 49 | 50 | - name: Install Clang 51 | if: ${{matrix.cxx == 'clang++-6.0'}} 52 | run: sudo apt-get install -y clang-6.0 lld-6.0 53 | 54 | - name: Install Valgrind 55 | if: ${{matrix.config.valgrind == 'ON'}} 56 | run: sudo apt-get update && sudo apt-get install -y valgrind 57 | 58 | - name: Configure CMake 59 | working-directory: ${{runner.workspace}} 60 | env: 61 | CXX: ${{matrix.cxx}} 62 | run: | 63 | cmake -H${{github.event.repository.name}} -Bbuild \ 64 | -DCMAKE_CONFIGURATION_TYPES=${{matrix.config.build_type}} \ 65 | -DCMAKE_BUILD_TYPE=${{matrix.config.build_type}} \ 66 | -DTIGHT_PAIR_SANITIZE=${{matrix.config.sanitize}} \ 67 | -DTIGHT_PAIR_USE_VALGRIND=${{matrix.config.valgrind}} \ 68 | -G"Unix Makefiles" 69 | 70 | - name: Build the test suite 71 | shell: bash 72 | working-directory: ${{runner.workspace}}/build 73 | run: cmake --build . --config ${{matrix.config.build_type}} -j 2 74 | 75 | - name: Run the test suite 76 | if: ${{matrix.config.valgrind != 'ON'}} 77 | env: 78 | CTEST_OUTPUT_ON_FAILURE: 1 79 | working-directory: ${{runner.workspace}}/build 80 | run: ctest -C ${{matrix.config.build_type}} 81 | 82 | - name: Run the test suite with Memcheck 83 | if: ${{matrix.config.valgrind == 'ON'}} 84 | env: 85 | CTEST_OUTPUT_ON_FAILURE: 1 86 | working-directory: ${{runner.workspace}}/build 87 | run: | 88 | ctest -T memcheck -C ${{matrix.config.build_type}} -j 2 89 | find ./Testing/Temporary -name "MemoryChecker.*.log" -size +1300c | xargs cat; 90 | -------------------------------------------------------------------------------- /tests/libcxx/implicit_deduction_guides.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "archetypes.h" 20 | 21 | TEST_CASE( "test deduction guides" ) 22 | { 23 | // Overloads 24 | // --------------- 25 | // (1) tight_pair(const T1&, const T2&) -> tight_pair 26 | // (2) explicit tight_pair(const T1&, const T2&) -> tight_pair 27 | // (3) tight_pair(tight_pair const& t) -> decltype(t) 28 | // (4) tight_pair(tight_pair&& t) -> decltype(t) 29 | // (5) tight_pair(tight_pair const&) -> tight_pair 30 | // (6) explicit tight_pair(tight_pair const&) -> tight_pair 31 | // (7) tight_pair(tight_pair &&) -> tight_pair 32 | // (8) explicit tight_pair(tight_pair &&) -> tight_pair 33 | 34 | using E = ExplicitTestTypes::TestType; 35 | static_assert(not std::is_convertible_v); 36 | { // Testing (1) 37 | int const x = 42; 38 | cruft::tight_pair t1("abc", x); 39 | static_assert(std::is_same_v>); 40 | } 41 | /*{ // Testing (2) 42 | cruft::tight_pair p1(E{}, 42); 43 | static_assert(std::is_same_v>); 44 | 45 | const E t{}; 46 | cruft::tight_pair p2(t, E{}); 47 | static_assert(std::is_same_v>); 48 | }*/ 49 | { // Testing (3, 5) 50 | cruft::tight_pair const p(0.0, nullptr); 51 | cruft::tight_pair p1(p); 52 | static_assert(std::is_same_v>); 53 | } 54 | { // Testing (3, 6) 55 | cruft::tight_pair const p(E{}, nullptr); 56 | cruft::tight_pair p1(p); 57 | static_assert(std::is_same_v>); 58 | } 59 | { // Testing (4, 7) 60 | cruft::tight_pair p("abc", nullptr); 61 | cruft::tight_pair p1(std::move(p)); 62 | static_assert(std::is_same_v>); 63 | } 64 | { // Testing (4, 8) 65 | cruft::tight_pair p("abc", E{}); 66 | cruft::tight_pair p1(std::move(p)); 67 | static_assert(std::is_same_v>); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/cppreference.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | TEST_CASE( "test from cppreference.com examples" ) 16 | { 17 | using cruft::get; 18 | 19 | SECTION( "constructor" ) 20 | { 21 | using namespace std::string_literals; 22 | 23 | // Check value initialization 24 | cruft::tight_pair p1; 25 | CHECK(get<0>(p1) == 0); 26 | CHECK(get<1>(p1) == 0.0f); 27 | 28 | // Check initialization with two values 29 | cruft::tight_pair p2(42, 0.123); 30 | CHECK(get<0>(p2) == 42); 31 | CHECK(get<1>(p2) == 0.123); 32 | 33 | // Check implicit conversions at construction 34 | cruft::tight_pair p4(p2); 35 | CHECK(get<0>(p4) == '*'); 36 | CHECK(get<1>(p4) == 0); 37 | 38 | // Piecewise construction 39 | cruft::tight_pair, std::string> p6( 40 | std::piecewise_construct, 41 | std::forward_as_tuple(0.123, 7.7), 42 | std::forward_as_tuple(10, 'a')); 43 | CHECK(get<0>(p6) == std::complex(0.123, 7.7)); 44 | CHECK(get<1>(p6) == "aaaaaaaaaa"s); 45 | } 46 | 47 | SECTION( "swap" ) 48 | { 49 | cruft::tight_pair p1, p2; 50 | p1 = cruft::tight_pair(10, "test"); 51 | p2.swap(p1); 52 | CHECK(get<0>(p2) == 10); 53 | CHECK(get<1>(p2) == "test"); 54 | } 55 | 56 | SECTION( "make_pair" ) 57 | { 58 | int n = 1; 59 | int a[5] = {1, 2, 3, 4, 5}; 60 | 61 | // build a pair from two ints 62 | auto p1 = cruft::tight_pair(n, a[1]); 63 | CHECK(get<0>(p1) == 1); 64 | CHECK(get<1>(p1) == 2); 65 | 66 | // build a pair from a reference to int and an array (decayed to pointer) 67 | auto p2 = cruft::tight_pair(std::ref(n), a); 68 | n = 7; 69 | CHECK(get<0>(p2) == 7); 70 | CHECK(*(get<1>(p2) + 2) == 3); 71 | } 72 | 73 | SECTION( "relational operators" ) 74 | { 75 | std::vector> v1 = { {2, "baz"}, 76 | {2, "bar"}, 77 | {1, "foo"} }; 78 | std::vector> v2 = { {1, "foo"}, 79 | {2, "bar"}, 80 | {2, "baz"} }; 81 | std::sort(v1.begin(), v1.end()); 82 | 83 | CHECK(v1 == v2); 84 | } 85 | 86 | SECTION( "get" ) 87 | { 88 | auto p = cruft::tight_pair(1, 3.14); 89 | CHECK(cruft::get<0>(p) == 1); 90 | CHECK(cruft::get<1>(p) == 3.14); 91 | CHECK(cruft::get(p) == 1); 92 | CHECK(cruft::get(p) == 3.14); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tests/libcxx/assign_pair.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "archetypes.h" 21 | 22 | struct Incomplete; 23 | extern Incomplete inc_obj; 24 | 25 | namespace 26 | { 27 | struct CountAssign 28 | { 29 | int copied = 0; 30 | int moved = 0; 31 | constexpr CountAssign() = default; 32 | constexpr CountAssign& operator=(CountAssign const&) { 33 | ++copied; 34 | return *this; 35 | } 36 | constexpr CountAssign& operator=(CountAssign&&) { 37 | ++moved; 38 | return *this; 39 | } 40 | }; 41 | 42 | constexpr bool test() 43 | { 44 | using cruft::get; 45 | { 46 | using P = cruft::tight_pair; 47 | const P p1(ConstexprTestTypes::CopyOnly(), short{4}); 48 | P p2; 49 | p2 = p1; 50 | assert(get<1>(p2) == 4); 51 | } 52 | { 53 | using P = cruft::tight_pair; 54 | int x = 42; 55 | int y = 101; 56 | int x2 = -1; 57 | int y2 = 300; 58 | P p1(x, std::move(y)); 59 | P p2(x2, std::move(y2)); 60 | p1 = p2; 61 | assert(get<0>(p1) == x2); 62 | assert(get<1>(p1) == y2); 63 | } 64 | { 65 | using P = cruft::tight_pair; 66 | static_assert(not std::is_copy_assignable

::value); 67 | } 68 | { 69 | using P = cruft::tight_pair; 70 | static_assert(std::is_copy_assignable

::value); 71 | P p; 72 | P p2; 73 | p = p2; 74 | assert(get<0>(p).copied == 1); 75 | assert(get<0>(p).moved == 0); 76 | assert(get<0>(p2).copied == 0); 77 | assert(get<0>(p2).moved == 0); 78 | } 79 | { 80 | using P = cruft::tight_pair; 81 | static_assert(not std::is_copy_assignable

::value); 82 | } 83 | { 84 | using P = cruft::tight_pair >; 85 | static_assert(not std::is_copy_assignable

::value); 86 | } 87 | { 88 | using P = cruft::tight_pair; 89 | static_assert(not std::is_copy_assignable

::value); 90 | P p(42, inc_obj); 91 | assert(&get<1>(p) == &inc_obj); 92 | } 93 | 94 | return true; 95 | } 96 | } 97 | 98 | TEST_CASE( "assign pair" ) 99 | { 100 | static_assert(test()); 101 | } 102 | 103 | struct Incomplete {}; 104 | Incomplete inc_obj; 105 | -------------------------------------------------------------------------------- /tests/libcxx/pairs_by_type.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | TEST_CASE( "pairs by type" ) 21 | { 22 | using cf = std::complex; 23 | { 24 | auto t1 = cruft::tight_pair ( 42, { 1,2 } ); 25 | CHECK(cruft::get(t1) == 42); 26 | CHECK(cruft::get(t1).real() == 1); 27 | CHECK(cruft::get(t1).imag() == 2); 28 | } 29 | 30 | { 31 | const cruft::tight_pair p1 { 1, 2 }; 32 | const int& i1 = cruft::get(p1); 33 | const int& i2 = cruft::get(p1); 34 | CHECK(i1 == 1); 35 | CHECK(i2 == 2); 36 | } 37 | 38 | { 39 | using upint = std::unique_ptr; 40 | cruft::tight_pair t(upint(new int(4)), 42); 41 | upint p = cruft::get(std::move(t)); // get rvalue 42 | CHECK(*p == 4); 43 | CHECK(cruft::get(t) == nullptr); // has been moved from 44 | } 45 | 46 | { 47 | using upint = std::unique_ptr; 48 | const cruft::tight_pair t(upint(new int(4)), 42); 49 | static_assert(std::is_same_v(std::move(t)))>); 50 | static_assert(noexcept(cruft::get(std::move(t)))); 51 | static_assert(std::is_same_v(std::move(t)))>); 52 | static_assert(noexcept(cruft::get(std::move(t)))); 53 | auto&& p = cruft::get(std::move(t)); // get const rvalue 54 | auto&& i = cruft::get(std::move(t)); // get const rvalue 55 | CHECK(*p == 4); 56 | CHECK(i == 42); 57 | CHECK(cruft::get(t) != nullptr); 58 | } 59 | 60 | { 61 | int x = 42; 62 | int const y = 43; 63 | cruft::tight_pair const p(x, y); 64 | static_assert(std::is_same_v(std::move(p)))>); 65 | static_assert(noexcept(cruft::get(std::move(p)))); 66 | static_assert(std::is_same_v(std::move(p)))>); 67 | static_assert(noexcept(cruft::get(std::move(p)))); 68 | } 69 | 70 | { 71 | int x = 42; 72 | int const y = 43; 73 | cruft::tight_pair const p(std::move(x), std::move(y)); 74 | static_assert(std::is_same_v(std::move(p)))>); 75 | static_assert(noexcept(cruft::get(std::move(p)))); 76 | static_assert(std::is_same_v(std::move(p)))>); 77 | static_assert(noexcept(cruft::get(std::move(p)))); 78 | } 79 | 80 | { 81 | constexpr const cruft::tight_pair p { 1, 2 }; 82 | static_assert(cruft::get(std::move(p)) == 1); 83 | static_assert(cruft::get(std::move(p)) == 2); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/libcxx/special_member_generation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include "archetypes.h" 17 | 18 | using namespace ImplicitTypes; 19 | 20 | namespace ConstructorTest 21 | { 22 | template< 23 | typename T1, 24 | bool CanCopy = true, 25 | bool CanMove = CanCopy 26 | > 27 | void test() 28 | { 29 | using P1 = cruft::tight_pair; 30 | using P2 = cruft::tight_pair; 31 | static_assert(std::is_copy_constructible_v == CanCopy); 32 | static_assert(std::is_move_constructible_v == CanMove); 33 | static_assert(std::is_copy_constructible_v == CanCopy); 34 | static_assert(std::is_move_constructible_v == CanMove); 35 | } 36 | } 37 | 38 | inline void test_constructors_exist() 39 | { 40 | using namespace ConstructorTest; 41 | { 42 | test(); 43 | test(); 44 | test(); 45 | test(); 46 | test(); 47 | test(); 48 | } 49 | { 50 | test(); 51 | test(); 52 | test(); 53 | } 54 | { 55 | test(); 56 | test(); 57 | test(); 58 | } 59 | { 60 | // Even though CopyOnly has an explicitly deleted move constructor 61 | // pair's move constructor is only implicitly deleted and therefore 62 | // it doesn't participate in overload resolution. 63 | test(); 64 | test(); 65 | test(); 66 | } 67 | { 68 | test(); 69 | test(); 70 | test(); 71 | } 72 | } 73 | 74 | namespace AssignmentOperatorTest 75 | { 76 | template< 77 | typename T1, 78 | bool CanCopy = true, 79 | bool CanMove = CanCopy 80 | > 81 | void test() 82 | { 83 | using P1 = cruft::tight_pair; 84 | using P2 = cruft::tight_pair; 85 | static_assert(std::is_copy_assignable_v == CanCopy); 86 | static_assert(std::is_move_assignable_v == CanMove); 87 | static_assert(std::is_copy_assignable_v == CanCopy); 88 | static_assert(std::is_move_assignable_v == CanMove); 89 | } 90 | } 91 | 92 | inline void test_assignment_operator_exists() 93 | { 94 | using namespace AssignmentOperatorTest; 95 | { 96 | test(); 97 | test(); 98 | test(); 99 | test(); 100 | test(); 101 | test(); 102 | } 103 | { 104 | test(); 105 | test(); 106 | test(); 107 | } 108 | { 109 | test(); 110 | test(); 111 | test(); 112 | } 113 | { 114 | test(); 115 | test(); 116 | test(); 117 | } 118 | { 119 | test(); 120 | test(); 121 | test(); 122 | } 123 | } 124 | 125 | TEST_CASE( "special members generation" ) 126 | { 127 | test_constructors_exist(); 128 | test_assignment_operator_exists(); 129 | } 130 | -------------------------------------------------------------------------------- /tests/libcxx/ctor.brace-init.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | 17 | namespace 18 | { 19 | struct ExplicitT 20 | { 21 | constexpr explicit ExplicitT(int x): value(x) {} 22 | constexpr explicit ExplicitT(ExplicitT const& o): value(o.value) {} 23 | int value; 24 | }; 25 | 26 | struct ImplicitT 27 | { 28 | constexpr ImplicitT(int x): value(x) {} 29 | constexpr ImplicitT(ImplicitT const& o): value(o.value) {} 30 | int value; 31 | }; 32 | 33 | template({}, {}))> 34 | constexpr bool can_construct_with_brace_init(int) { return true; } 35 | template 36 | constexpr bool can_construct_with_brace_init(...) { return false; } 37 | 38 | template 39 | constexpr bool can_construct_with_ctad_brace_init(int) { return true; } 40 | template 41 | constexpr bool can_construct_with_ctad_brace_init(...) { return false; } 42 | 43 | struct BraceInit { BraceInit() = default; }; 44 | struct NoBraceInit { NoBraceInit(int); }; 45 | struct ExplicitBraceInit { explicit ExplicitBraceInit() = default; }; 46 | 47 | constexpr int explicit_vs_implicit_brace_init(cruft::tight_pair) { return 1; } 48 | constexpr int explicit_vs_implicit_brace_init(cruft::tight_pair) { return 2; } 49 | 50 | constexpr bool test() 51 | { 52 | using cruft::get; 53 | 54 | // Explicit constructor 55 | { 56 | constexpr cruft::tight_pair p1(ExplicitT{42}, {}); 57 | static_assert(get<0>(p1).value == 42); 58 | 59 | constexpr cruft::tight_pair p2{ExplicitT{42}, {}}; 60 | static_assert(get<0>(p2).value == 42); 61 | } 62 | { 63 | constexpr cruft::tight_pair p1({}, ExplicitT{42}); 64 | static_assert(get<1>(p1).value == 42); 65 | 66 | constexpr cruft::tight_pair p2{{}, ExplicitT{42}}; 67 | static_assert(get<1>(p2).value == 42); 68 | } 69 | { 70 | cruft::tight_pair p{{}, {}}; 71 | (void)p; 72 | } 73 | 74 | // Implicit constructor 75 | { 76 | constexpr cruft::tight_pair p = {42, {}}; 77 | static_assert(get<0>(p).value == 42); 78 | } 79 | { 80 | constexpr cruft::tight_pair p = {{}, 42}; 81 | static_assert(get<1>(p).value == 42); 82 | } 83 | { 84 | cruft::tight_pair p = {{}, {}}; 85 | (void)p; 86 | } 87 | 88 | // SFINAE-friendliness of some invalid cases 89 | { 90 | static_assert( can_construct_with_brace_init(0)); 91 | static_assert(not can_construct_with_brace_init(0)); 92 | 93 | // CTAD with {} should never work, since we can't possibly deduce the types 94 | static_assert(not can_construct_with_ctad_brace_init(0)); 95 | static_assert(not can_construct_with_ctad_brace_init(0)); 96 | } 97 | 98 | #ifndef __GNUC__ 99 | // Make sure there is no ambiguity between the explicit and the non-explicit constructors 100 | { 101 | static_assert(explicit_vs_implicit_brace_init({{}, {}}) == 2); 102 | } 103 | #endif 104 | 105 | return true; 106 | } 107 | } 108 | 109 | TEST_CASE( "test constructor brace init" ) 110 | { 111 | static_assert(test()); 112 | } 113 | -------------------------------------------------------------------------------- /tests/libcxx/assign_tuple.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace 22 | { 23 | struct CountingType 24 | { 25 | static int constructed; 26 | static int copy_constructed; 27 | static int move_constructed; 28 | static int assigned; 29 | static int copy_assigned; 30 | static int move_assigned; 31 | static void reset() 32 | { 33 | constructed = copy_constructed = move_constructed = 0; 34 | assigned = copy_assigned = move_assigned = 0; 35 | } 36 | 37 | CountingType(): value(0) { ++constructed; } 38 | CountingType(int v): value(v) { ++constructed; } 39 | CountingType(CountingType const& o): value(o.value) { ++constructed; ++copy_constructed; } 40 | CountingType(CountingType&& o): value(o.value) { ++constructed; ++move_constructed; o.value = -1;} 41 | 42 | CountingType& operator=(CountingType const& o) 43 | { 44 | ++assigned; 45 | ++copy_assigned; 46 | value = o.value; 47 | return *this; 48 | } 49 | 50 | CountingType& operator=(CountingType&& o) 51 | { 52 | ++assigned; 53 | ++move_assigned; 54 | value = o.value; 55 | o.value = -1; 56 | return *this; 57 | } 58 | int value; 59 | }; 60 | 61 | int CountingType::constructed; 62 | int CountingType::copy_constructed; 63 | int CountingType::move_constructed; 64 | int CountingType::assigned; 65 | int CountingType::copy_assigned; 66 | int CountingType::move_assigned; 67 | } 68 | 69 | TEST_CASE( "assign tuple" ) 70 | { 71 | using cruft::get; 72 | 73 | using C = CountingType; 74 | { 75 | using P = cruft::tight_pair; 76 | using T = std::tuple; 77 | T t(42, C{42}); 78 | P p(101, C{101}); 79 | C::reset(); 80 | p = t; 81 | CHECK(C::constructed == 0); 82 | CHECK(C::assigned == 1); 83 | CHECK(C::copy_assigned == 1); 84 | CHECK(C::move_assigned == 0); 85 | CHECK(get<0>(p) == 42); 86 | CHECK(get<1>(p).value == 42); 87 | } 88 | { 89 | using P = cruft::tight_pair; 90 | using T = std::tuple; 91 | T t(42, -42); 92 | P p(101, 101); 93 | C::reset(); 94 | p = std::move(t); 95 | CHECK(C::constructed == 0); 96 | CHECK(C::assigned == 1); 97 | CHECK(C::copy_assigned == 0); 98 | CHECK(C::move_assigned == 1); 99 | CHECK(get<0>(p) == 42); 100 | CHECK(get<1>(p).value == -42); 101 | } 102 | { 103 | using P = cruft::tight_pair; 104 | using T = std::array; 105 | T t = {42, -42}; 106 | P p{101, 101}; 107 | C::reset(); 108 | p = t; 109 | CHECK(C::constructed == 0); 110 | CHECK(C::assigned == 2); 111 | CHECK(C::copy_assigned == 2); 112 | CHECK(C::move_assigned == 0); 113 | CHECK(get<0>(p).value == 42); 114 | CHECK(get<1>(p).value == -42); 115 | } 116 | { 117 | using P = cruft::tight_pair; 118 | using T = std::array; 119 | T t = {42, -42}; 120 | P p{101, 101}; 121 | C::reset(); 122 | p = t; 123 | CHECK(C::constructed == 0); 124 | CHECK(C::assigned == 2); 125 | CHECK(C::copy_assigned == 2); 126 | CHECK(C::move_assigned == 0); 127 | CHECK(get<0>(p).value == 42); 128 | CHECK(get<1>(p).value == -42); 129 | } 130 | { 131 | using P = cruft::tight_pair; 132 | using T = std::array; 133 | T t = {42, -42}; 134 | P p{101, 101}; 135 | C::reset(); 136 | p = std::move(t); 137 | CHECK(C::constructed == 0); 138 | CHECK(C::assigned == 2); 139 | CHECK(C::copy_assigned == 0); 140 | CHECK(C::move_assigned == 2); 141 | CHECK(get<0>(p).value == 42); 142 | CHECK(get<1>(p).value == -42); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017-2021 Morwenn 2 | # SPDX-License-Identifier: MIT 3 | 4 | include(FetchContent) 5 | 6 | ######################################## 7 | # Test suite options 8 | 9 | option(TIGHT_PAIR_ENABLE_COVERAGE "Whether to produce code coverage" OFF) 10 | set(TIGHT_PAIR_SANITIZE "" CACHE STRING "Comma-separated list of options to pass to -fsanitize") 11 | option(TIGHT_PAIR_USE_VALGRIND "Whether to run the tests with Valgrind" OFF) 12 | 13 | # Apparently ENABLE_COVERAGE is needed either way 14 | if (TIGHT_PAIR_ENABLE_COVERAGE) 15 | set(ENABLE_COVERAGE ON CACHE BOOL "Enable coverage build." FORCE) 16 | endif() 17 | 18 | ######################################## 19 | # Download and configure Catch2 20 | 21 | FetchContent_Declare( 22 | catch2 23 | GIT_REPOSITORY https://github.com/catchorg/Catch2 24 | GIT_TAG v2.13.7 25 | ) 26 | 27 | FetchContent_GetProperties(catch2) 28 | if (NOT catch2_POPULATED) 29 | FetchContent_Populate(catch2) 30 | add_subdirectory(${catch2_SOURCE_DIR} ${catch2_BINARY_DIR}) 31 | list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/contrib) 32 | include(Catch) 33 | endif() 34 | 35 | ######################################## 36 | # Create and configure tests 37 | 38 | # Make one executable for the whole test suite 39 | add_executable( 40 | tight_pair-testsuite 41 | 42 | # Custom additional tests 43 | main.cpp 44 | alignment.cpp 45 | cppreference.cpp 46 | dr-811.cpp 47 | empty_base_get.cpp 48 | p1951.cpp 49 | piecewise_no_copy_move.cpp 50 | reference_wrapper.cpp 51 | swap.cpp 52 | tricky_comparisons.cpp 53 | 54 | # libc++ tests 55 | libcxx/assign_const_pair_U_V.cpp 56 | libcxx/assign_pair.cpp 57 | libcxx/assign_rv_pair.cpp 58 | libcxx/assign_rv_pair_U_V.cpp 59 | libcxx/assign_tuple.cpp 60 | libcxx/comparison.cpp 61 | libcxx/const_first_const_second.cpp 62 | libcxx/const_pair_U_V.cpp 63 | libcxx/copy_ctor.cpp 64 | libcxx/ctor.brace-init.cpp 65 | libcxx/default.cpp 66 | libcxx/default_ctor.cpp 67 | libcxx/default-sfinae.cpp 68 | libcxx/dtor.cpp 69 | libcxx/get_const.cpp 70 | libcxx/get_const_rv.cpp 71 | libcxx/get_non_const.cpp 72 | libcxx/get_rv.cpp 73 | libcxx/implicit_deduction_guides.cpp 74 | libcxx/move_ctor.cpp 75 | libcxx/non_member_swap.cpp 76 | libcxx/pairs_by_type.cpp 77 | libcxx/piecewise_construct.cpp 78 | libcxx/rv_pair_U_V.cpp 79 | libcxx/special_member_generation.cpp 80 | libcxx/swap.cpp 81 | libcxx/trivial_copy_move.cpp 82 | libcxx/tuple_element.cpp 83 | libcxx/tuple_size.cpp 84 | libcxx/types.cpp 85 | libcxx/U_V.cpp 86 | libcxx/used_to_be_make_pair.cpp 87 | ) 88 | 89 | target_link_libraries(tight_pair-testsuite 90 | PRIVATE 91 | Catch2::Catch2 92 | tight_pair::tight_pair 93 | ) 94 | 95 | # Somewhat speed up Catch2 compile times 96 | target_compile_definitions(tight_pair-testsuite 97 | PRIVATE 98 | CATCH_CONFIG_FAST_COMPILE 99 | CATCH_CONFIG_DISABLE_MATCHERS 100 | ) 101 | 102 | if (MSVC) 103 | target_compile_options(tight_pair-testsuite PRIVATE /W2) 104 | else() 105 | target_compile_options(tight_pair-testsuite 106 | PRIVATE 107 | -Wall -Wextra -Wcast-align -Winline -Wmissing-declarations -Wmissing-include-dirs 108 | -Wnon-virtual-dtor -Wodr -Wpedantic -Wredundant-decls -Wundef -Wunreachable-code 109 | $<$:-Wlogical-op -Wuseless-cast -Wzero-as-null-pointer-constant> 110 | ) 111 | endif() 112 | 113 | # Settings depending on debug/release mode 114 | target_compile_options(tight_pair-testsuite 115 | PRIVATE 116 | $<$,$>:-O0> 117 | $<$,$>:-Og> 118 | ) 119 | 120 | # Use lld or the gold linker if possible 121 | if (UNIX AND NOT APPLE) 122 | if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") 123 | set_property(TARGET tight_pair-testsuite APPEND_STRING PROPERTY LINK_FLAGS " -fuse-ld=lld") 124 | else() 125 | set_property(TARGET tight_pair-testsuite APPEND_STRING PROPERTY LINK_FLAGS " -fuse-ld=gold") 126 | endif() 127 | endif() 128 | 129 | # Optionally enable sanitizers 130 | if (UNIX AND TIGHT_PAIR_SANITIZE) 131 | target_compile_options(tight_pair-testsuite PRIVATE -fsanitize=${TIGHT_PAIR_SANITIZE}) 132 | set_property( 133 | TARGET 134 | tight_pair-testsuite 135 | APPEND_STRING PROPERTY LINK_FLAGS 136 | " -fsanitize=${TIGHT_PAIR_SANITIZE} -fno-sanitize-recover=all" 137 | ) 138 | endif() 139 | 140 | ######################################## 141 | # Configure coverage 142 | 143 | if (TIGHT_PAIR_ENABLE_COVERAGE) 144 | find_package(codecov) 145 | add_coverage(tight_pair-testsuite) 146 | 147 | # Set flags specific to coverage builds 148 | target_compile_options(tight_pair-testsuite PRIVATE --coverage) 149 | set_property(TARGET tight_pair-testsuite APPEND_STRING PROPERTY LINK_FLAGS " --coverage") 150 | 151 | list(APPEND LCOV_REMOVE_PATTERNS "'/usr/*'") 152 | coverage_evaluate() 153 | endif() 154 | 155 | ######################################## 156 | # Configure Valgrind 157 | 158 | if (TIGHT_PAIR_USE_VALGRIND) 159 | find_program(MEMORYCHECK_COMMAND valgrind REQUIRED) 160 | set(MEMORYCHECK_COMMAND_OPTIONS "--leak-check=full --track-origins=yes --error-exitcode=1 --show-reachable=no") 161 | endif() 162 | 163 | ######################################## 164 | # Discover tests 165 | 166 | include(CTest) 167 | catch_discover_tests(tight_pair-testsuite) 168 | -------------------------------------------------------------------------------- /tests/libcxx/default-sfinae.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | struct DeletedDefault 19 | { 20 | // A class with a deleted default constructor. Used to test the SFINAE 21 | // on cruft::tight_pair's default constructor. 22 | constexpr explicit DeletedDefault(int x): value(x) {} 23 | constexpr DeletedDefault() = delete; 24 | int value; 25 | }; 26 | 27 | template 28 | struct DependantType: T {}; 29 | 30 | template 31 | using DependantIsDefault = DependantType, Val>; 32 | 33 | template 34 | struct DefaultSFINAES 35 | { 36 | template< 37 | bool Dummy = false, 38 | typename = typename std::enable_if< 39 | DependantIsDefault::value 40 | >::type 41 | > 42 | constexpr DefaultSFINAES(): value() {} 43 | constexpr explicit DefaultSFINAES(T const& x): value(x) {} 44 | T value; 45 | }; 46 | 47 | struct NoDefault 48 | { 49 | constexpr NoDefault(int v): value(v) {} 50 | int value; 51 | }; 52 | 53 | template 54 | void test_not_is_default_constructible() 55 | { 56 | { 57 | using P = cruft::tight_pair; 58 | static_assert(not std::is_default_constructible_v

); 59 | static_assert(std::is_constructible_v); 60 | } 61 | { 62 | using P = cruft::tight_pair; 63 | static_assert(not std::is_default_constructible_v

); 64 | static_assert(std::is_constructible_v); 65 | } 66 | { 67 | using P = cruft::tight_pair; 68 | static_assert(not std::is_default_constructible_v

); 69 | static_assert(std::is_constructible_v); 70 | } 71 | } 72 | 73 | template 74 | void test_is_default_constructible() 75 | { 76 | { 77 | using P = cruft::tight_pair; 78 | static_assert(std::is_default_constructible_v

); 79 | } 80 | { 81 | using P = cruft::tight_pair; 82 | static_assert(std::is_default_constructible_v

); 83 | } 84 | { 85 | using P = cruft::tight_pair; 86 | static_assert(std::is_default_constructible_v

); 87 | } 88 | } 89 | 90 | template 91 | struct IllFormedDefaultImp 92 | { 93 | constexpr explicit IllFormedDefaultImp(int v): value(v) {} 94 | constexpr IllFormedDefaultImp(): value(T::DoesNotExistAndShouldNotCompile) {} 95 | int value; 96 | }; 97 | 98 | using IllFormedDefault = IllFormedDefaultImp; 99 | // A class which provides a constexpr default constructor with a valid 100 | // signature but an ill-formed body. The A compile error will be emitted if 101 | // the default constructor is instantiated. 102 | 103 | 104 | // Check that the SFINAE on the default constructor is not evaluated when 105 | // it isn't needed. If the default constructor of 'IllFormedDefault' is evaluated 106 | // in C++11, even with is_default_constructible, then this test should fail to 107 | // compile. In C++14 and greater evaluate each test is evaluated as a constant 108 | // expression. 109 | // See LWG issue #2367 110 | inline void test_illformed_default() 111 | { 112 | using cruft::get; 113 | 114 | { 115 | using P = cruft::tight_pair; 116 | static_assert(std::is_constructible_v); 117 | constexpr P p(IllFormedDefault(42), -5); 118 | static_assert(get<0>(p).value == 42 && get<1>(p) == -5); 119 | } 120 | { 121 | using P = cruft::tight_pair; 122 | static_assert(std::is_constructible_v); 123 | constexpr IllFormedDefault dd(-5); 124 | constexpr P p(42, dd); 125 | static_assert(get<0>(p) == 42 && get<1>(p).value == -5); 126 | } 127 | { 128 | using P = cruft::tight_pair; 129 | static_assert(std::is_constructible_v); 130 | constexpr P p(IllFormedDefault(42), IllFormedDefault(-5)); 131 | static_assert(get<0>(p).value == 42 && get<1>(p).value == -5); 132 | } 133 | } 134 | 135 | TEST_CASE( "default sfinae" ) 136 | { 137 | { 138 | // Check that pair can still be used even if 139 | // is_default_constructible or is_default_constructible cause 140 | // a compilation error. 141 | test_illformed_default(); 142 | } 143 | { 144 | // pair::pair() is only disable in C++11 and beyond. 145 | test_not_is_default_constructible(); 146 | test_not_is_default_constructible(); 147 | test_not_is_default_constructible>(); 148 | test_not_is_default_constructible>(); 149 | test_not_is_default_constructible(); 150 | test_not_is_default_constructible(); 151 | } 152 | { 153 | test_is_default_constructible(); 154 | test_is_default_constructible>(); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /tests/libcxx/assign_rv_pair.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "archetypes.h" 20 | 21 | namespace 22 | { 23 | struct CountAssign 24 | { 25 | int copied = 0; 26 | int moved = 0; 27 | constexpr CountAssign() = default; 28 | constexpr CountAssign& operator=(CountAssign const&) { 29 | ++copied; 30 | return *this; 31 | } 32 | constexpr CountAssign& operator=(CountAssign&&) { 33 | ++moved; 34 | return *this; 35 | } 36 | }; 37 | 38 | struct NotAssignable 39 | { 40 | NotAssignable& operator=(NotAssignable const&) = delete; 41 | NotAssignable& operator=(NotAssignable&&) = delete; 42 | }; 43 | 44 | struct MoveAssignable 45 | { 46 | MoveAssignable& operator=(MoveAssignable const&) = delete; 47 | MoveAssignable& operator=(MoveAssignable&&) = default; 48 | }; 49 | 50 | struct CopyAssignable 51 | { 52 | CopyAssignable& operator=(CopyAssignable const&) = default; 53 | CopyAssignable& operator=(CopyAssignable&&) = delete; 54 | }; 55 | 56 | constexpr bool test() 57 | { 58 | using cruft::get; 59 | { 60 | using P = cruft::tight_pair; 61 | P p1(3, 4); 62 | P p2; 63 | p2 = std::move(p1); 64 | assert(get<0>(p2).value == 3); 65 | assert(get<1>(p2) == 4); 66 | } 67 | { 68 | using P = cruft::tight_pair; 69 | int x = 42; 70 | int y = 101; 71 | int x2 = -1; 72 | int y2 = 300; 73 | P p1(x, std::move(y)); 74 | P p2(x2, std::move(y2)); 75 | p1 = std::move(p2); 76 | assert(get<0>(p1) == x2); 77 | assert(get<1>(p1) == y2); 78 | } 79 | { 80 | using P = cruft::tight_pair; 81 | static_assert(not std::is_move_assignable

::value); 82 | } 83 | { 84 | // The move decays to the copy constructor 85 | using P = cruft::tight_pair; 86 | static_assert(std::is_move_assignable

::value); 87 | P p; 88 | P p2; 89 | p = std::move(p2); 90 | assert(get<0>(p).moved == 0); 91 | assert(get<0>(p).copied == 1); 92 | assert(get<0>(p2).moved == 0); 93 | assert(get<0>(p2).copied == 0); 94 | } 95 | { 96 | using P = cruft::tight_pair; 97 | static_assert(std::is_move_assignable

::value); 98 | P p; 99 | P p2; 100 | p = std::move(p2); 101 | assert(get<0>(p).moved == 1); 102 | assert(get<0>(p).copied == 0); 103 | assert(get<0>(p2).moved == 0); 104 | assert(get<0>(p2).copied == 0); 105 | } 106 | { 107 | using P1 = cruft::tight_pair; 108 | using P2 = cruft::tight_pair; 109 | using P3 = cruft::tight_pair; 110 | static_assert(not std::is_move_assignable::value); 111 | static_assert(not std::is_move_assignable::value); 112 | static_assert(not std::is_move_assignable::value); 113 | } 114 | { 115 | // We assign through the reference and don't move out of the incoming ref, 116 | // so this doesn't work (but would if the type were CopyAssignable). 117 | using P1 = cruft::tight_pair; 118 | static_assert(not std::is_move_assignable::value); 119 | 120 | // ... works if it's CopyAssignable 121 | using P2 = cruft::tight_pair; 122 | static_assert(std::is_move_assignable::value); 123 | 124 | // For rvalue-references, we can move-assign if the type is MoveAssignable 125 | // or CopyAssignable (since in the worst case the move will decay into a copy). 126 | using P3 = cruft::tight_pair; 127 | using P4 = cruft::tight_pair; 128 | static_assert(std::is_move_assignable::value); 129 | static_assert(std::is_move_assignable::value); 130 | 131 | // In all cases, we can't move-assign if the types are not assignable, 132 | // since we assign through the reference. 133 | using P5 = cruft::tight_pair; 134 | using P6 = cruft::tight_pair; 135 | static_assert(not std::is_move_assignable::value); 136 | static_assert(not std::is_move_assignable::value); 137 | } 138 | return true; 139 | } 140 | } 141 | 142 | TEST_CASE( "assign rv pair" ) 143 | { 144 | static_assert(test()); 145 | } 146 | -------------------------------------------------------------------------------- /tests/libcxx/const_first_const_second.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include "archetypes.h" 18 | #include "test_convertible.h" 19 | 20 | using namespace ImplicitTypes; // Get implicitly archetypes 21 | 22 | namespace 23 | { 24 | struct ExplicitT 25 | { 26 | constexpr explicit ExplicitT(int x): value(x) {} 27 | constexpr explicit ExplicitT(ExplicitT const& o): value(o.value) {} 28 | int value; 29 | }; 30 | 31 | struct ImplicitT 32 | { 33 | constexpr ImplicitT(int x): value(x) {} 34 | constexpr ImplicitT(ImplicitT const& o): value(o.value) {} 35 | int value; 36 | }; 37 | 38 | struct ExplicitNothrowT 39 | { 40 | explicit ExplicitNothrowT(ExplicitNothrowT const&) noexcept {} 41 | }; 42 | 43 | struct ImplicitNothrowT 44 | { 45 | ImplicitNothrowT(ImplicitNothrowT const&) noexcept {} 46 | }; 47 | 48 | template< 49 | typename T1, 50 | bool CanCopy = true, 51 | bool CanConvert = CanCopy 52 | > 53 | void test_sfinae() { 54 | using P1 = cruft::tight_pair; 55 | using P2 = cruft::tight_pair; 56 | using T1Arg = T1 const&; 57 | using T2 = int const&; 58 | static_assert(std::is_constructible_v == CanCopy); 59 | static_assert(test_convertible() == CanConvert); 60 | static_assert(std::is_constructible_v == CanCopy); 61 | static_assert(test_convertible() == CanConvert); 62 | } 63 | } 64 | 65 | TEST_CASE( "const first const second" ) 66 | { 67 | using cruft::get; 68 | 69 | { 70 | using P = cruft::tight_pair; 71 | P p(3.5f, 0); 72 | CHECK(get<0>(p) == 3.5f); 73 | CHECK(get<1>(p) == nullptr); 74 | } 75 | { 76 | using P = cruft::tight_pair; 77 | P p(1, 2); 78 | CHECK(get<0>(p).value == 1); 79 | CHECK(get<1>(p) == 2); 80 | } 81 | { 82 | test_sfinae(); 83 | test_sfinae(); 84 | test_sfinae(); 85 | test_sfinae(); 86 | test_sfinae(); 87 | test_sfinae(); 88 | test_sfinae(); 89 | test_sfinae(); 90 | } 91 | { 92 | using P = cruft::tight_pair; 93 | constexpr P p(3.5f, 0); 94 | static_assert(get<0>(p) == 3.5f); 95 | static_assert(get<1>(p) == nullptr); 96 | } 97 | { 98 | using P = cruft::tight_pair; 99 | constexpr ExplicitT e(42); 100 | constexpr int x = 10; 101 | constexpr P p(e, x); 102 | static_assert(get<0>(p).value == 42); 103 | static_assert(get<1>(p) == 10); 104 | } 105 | { 106 | using P = cruft::tight_pair; 107 | constexpr ImplicitT e(42); 108 | constexpr int x = 10; 109 | constexpr P p = {e, x}; 110 | static_assert(get<0>(p).value == 42); 111 | static_assert(get<1>(p) == 10); 112 | } 113 | } 114 | 115 | TEST_CASE( "const first const second noexcept" ) 116 | { 117 | { // explicit noexcept test 118 | static_assert(not std::is_nothrow_constructible_v, 119 | ExplicitT const&, ExplicitT const&>); 120 | static_assert(not std::is_nothrow_constructible_v, 121 | ExplicitNothrowT const&, ExplicitT const&>); 122 | static_assert(not std::is_nothrow_constructible_v, 123 | ExplicitT const&, ExplicitNothrowT const&>); 124 | static_assert( std::is_nothrow_constructible_v, 125 | ExplicitNothrowT const&, ExplicitNothrowT const&>); 126 | } 127 | { // implicit noexcept test 128 | static_assert(not std::is_nothrow_constructible_v, 129 | ImplicitT const&, ImplicitT const&>); 130 | static_assert(not std::is_nothrow_constructible_v, 131 | ImplicitNothrowT const&, ImplicitT const&>); 132 | static_assert(not std::is_nothrow_constructible_v, 133 | ImplicitT const&, ImplicitNothrowT const&>); 134 | static_assert( std::is_nothrow_constructible_v, 135 | ImplicitNothrowT const&, ImplicitNothrowT const&>); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /cmake/FindGcov.cmake: -------------------------------------------------------------------------------- 1 | # This file is part of CMake-codecov. 2 | # 3 | # Copyright (c) 4 | # 2015-2017 RWTH Aachen University, Federal Republic of Germany 5 | # 6 | # See the LICENSE file in the package base directory for details 7 | # 8 | # Written by Alexander Haase, alexander.haase@rwth-aachen.de 9 | # 10 | 11 | 12 | # include required Modules 13 | include(FindPackageHandleStandardArgs) 14 | 15 | 16 | # Search for gcov binary. 17 | set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) 18 | set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY}) 19 | 20 | get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) 21 | foreach (LANG ${ENABLED_LANGUAGES}) 22 | # Gcov evaluation is dependend on the used compiler. Check gcov support for 23 | # each compiler that is used. If gcov binary was already found for this 24 | # compiler, do not try to find it again. 25 | if (NOT GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN) 26 | get_filename_component(COMPILER_PATH "${CMAKE_${LANG}_COMPILER}" PATH) 27 | 28 | if ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "GNU") 29 | # Some distributions like OSX (homebrew) ship gcov with the compiler 30 | # version appended as gcov-x. To find this binary we'll build the 31 | # suggested binary name with the compiler version. 32 | string(REGEX MATCH "^[0-9]+" GCC_VERSION 33 | "${CMAKE_${LANG}_COMPILER_VERSION}") 34 | 35 | find_program(GCOV_BIN NAMES gcov-${GCC_VERSION} gcov 36 | HINTS ${COMPILER_PATH}) 37 | 38 | elseif ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "Clang") 39 | # Some distributions like Debian ship llvm-cov with the compiler 40 | # version appended as llvm-cov-x.y. To find this binary we'll build 41 | # the suggested binary name with the compiler version. 42 | string(REGEX MATCH "^[0-9]+.[0-9]+" LLVM_VERSION 43 | "${CMAKE_${LANG}_COMPILER_VERSION}") 44 | 45 | # llvm-cov prior version 3.5 seems to be not working with coverage 46 | # evaluation tools, but these versions are compatible with the gcc 47 | # gcov tool. 48 | if(LLVM_VERSION VERSION_GREATER 3.4) 49 | find_program(LLVM_COV_BIN NAMES "llvm-cov-${LLVM_VERSION}" 50 | "llvm-cov" HINTS ${COMPILER_PATH}) 51 | mark_as_advanced(LLVM_COV_BIN) 52 | 53 | if (LLVM_COV_BIN) 54 | find_program(LLVM_COV_WRAPPER "llvm-cov-wrapper" PATHS 55 | ${CMAKE_MODULE_PATH}) 56 | if (LLVM_COV_WRAPPER) 57 | set(GCOV_BIN "${LLVM_COV_WRAPPER}" CACHE FILEPATH "") 58 | 59 | # set additional parameters 60 | set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV 61 | "LLVM_COV_BIN=${LLVM_COV_BIN}" CACHE STRING 62 | "Environment variables for llvm-cov-wrapper.") 63 | mark_as_advanced(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV) 64 | endif () 65 | endif () 66 | endif () 67 | 68 | if (NOT GCOV_BIN) 69 | # Fall back to gcov binary if llvm-cov was not found or is 70 | # incompatible. This is the default on OSX, but may crash on 71 | # recent Linux versions. 72 | find_program(GCOV_BIN gcov HINTS ${COMPILER_PATH}) 73 | endif () 74 | endif () 75 | 76 | 77 | if (GCOV_BIN) 78 | set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN "${GCOV_BIN}" CACHE STRING 79 | "${LANG} gcov binary.") 80 | 81 | if (NOT CMAKE_REQUIRED_QUIET) 82 | message("-- Found gcov evaluation for " 83 | "${CMAKE_${LANG}_COMPILER_ID}: ${GCOV_BIN}") 84 | endif() 85 | 86 | unset(GCOV_BIN CACHE) 87 | endif () 88 | endif () 89 | endforeach () 90 | 91 | 92 | 93 | 94 | # Add a new global target for all gcov targets. This target could be used to 95 | # generate the gcov files for the whole project instead of calling -gcov 96 | # for each target. 97 | if (NOT TARGET gcov) 98 | add_custom_target(gcov) 99 | endif (NOT TARGET gcov) 100 | 101 | 102 | 103 | # This function will add gcov evaluation for target . Only sources of 104 | # this target will be evaluated and no dependencies will be added. It will call 105 | # Gcov on any source file of once and store the gcov file in the same 106 | # directory. 107 | function (add_gcov_target TNAME) 108 | set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) 109 | 110 | # We don't have to check, if the target has support for coverage, thus this 111 | # will be checked by add_coverage_target in Findcoverage.cmake. Instead we 112 | # have to determine which gcov binary to use. 113 | get_target_property(TSOURCES ${TNAME} SOURCES) 114 | set(SOURCES "") 115 | set(TCOMPILER "") 116 | foreach (FILE ${TSOURCES}) 117 | codecov_path_of_source(${FILE} FILE) 118 | if (NOT "${FILE}" STREQUAL "") 119 | codecov_lang_of_source(${FILE} LANG) 120 | if (NOT "${LANG}" STREQUAL "") 121 | list(APPEND SOURCES "${FILE}") 122 | set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) 123 | endif () 124 | endif () 125 | endforeach () 126 | 127 | # If no gcov binary was found, coverage data can't be evaluated. 128 | if (NOT GCOV_${TCOMPILER}_BIN) 129 | message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") 130 | return() 131 | endif () 132 | 133 | set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") 134 | set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") 135 | 136 | 137 | set(BUFFER "") 138 | foreach(FILE ${SOURCES}) 139 | get_filename_component(FILE_PATH "${TDIR}/${FILE}" PATH) 140 | 141 | # call gcov 142 | add_custom_command(OUTPUT ${TDIR}/${FILE}.gcov 143 | COMMAND ${GCOV_ENV} ${GCOV_BIN} ${TDIR}/${FILE}.gcno > /dev/null 144 | DEPENDS ${TNAME} ${TDIR}/${FILE}.gcno 145 | WORKING_DIRECTORY ${FILE_PATH} 146 | ) 147 | 148 | list(APPEND BUFFER ${TDIR}/${FILE}.gcov) 149 | endforeach() 150 | 151 | 152 | # add target for gcov evaluation of 153 | add_custom_target(${TNAME}-gcov DEPENDS ${BUFFER}) 154 | 155 | # add evaluation target to the global gcov target. 156 | add_dependencies(gcov ${TNAME}-gcov) 157 | endfunction (add_gcov_target) 158 | -------------------------------------------------------------------------------- /tests/libcxx/assign_rv_pair_U_V.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "archetypes.h" 19 | 20 | namespace 21 | { 22 | struct Derived: 23 | ConstexprTestTypes::MoveOnly 24 | { 25 | Derived() = default; 26 | constexpr Derived(ConstexprTestTypes::MoveOnly&&) {}; 27 | }; 28 | 29 | struct CountAssign 30 | { 31 | int copied = 0; 32 | int moved = 0; 33 | constexpr CountAssign() = default; 34 | constexpr CountAssign(const int) {}; 35 | constexpr CountAssign& operator=(CountAssign const&) { 36 | ++copied; 37 | return *this; 38 | } 39 | constexpr CountAssign& operator=(CountAssign&&) { 40 | ++moved; 41 | return *this; 42 | } 43 | }; 44 | 45 | struct CopyAssignableInt 46 | { 47 | CopyAssignableInt& operator=(int&) { return *this; } 48 | }; 49 | 50 | struct NotAssignable 51 | { 52 | NotAssignable& operator=(NotAssignable const&) = delete; 53 | NotAssignable& operator=(NotAssignable&&) = delete; 54 | }; 55 | 56 | struct MoveAssignable 57 | { 58 | MoveAssignable& operator=(MoveAssignable const&) = delete; 59 | MoveAssignable& operator=(MoveAssignable&&) = default; 60 | }; 61 | 62 | struct CopyAssignable 63 | { 64 | CopyAssignable& operator=(CopyAssignable const&) = default; 65 | CopyAssignable& operator=(CopyAssignable&&) = delete; 66 | }; 67 | 68 | constexpr bool test() 69 | { 70 | using cruft::get; 71 | { 72 | using P1 = cruft::tight_pair; 73 | using P2 = cruft::tight_pair; 74 | P1 p1(Derived(), static_cast(4)); 75 | P2 p2; 76 | p2 = std::move(p1); 77 | assert(get<1>(p2) == 4); 78 | } 79 | { 80 | using P = cruft::tight_pair; 81 | using T = cruft::tight_pair; 82 | T t(42, -42); 83 | P p(101, 101); 84 | p = std::move(t); 85 | assert(get<0>(p) == 42); 86 | assert(get<1>(p).moved == 1); 87 | assert(get<1>(p).copied == 0); 88 | assert(get<1>(t).moved == 0); 89 | assert(get<1>(t).copied == 0); 90 | } 91 | { // test const requirement 92 | using T = cruft::tight_pair; 93 | using P = cruft::tight_pair; 94 | static_assert(not std::is_assignable::value); 95 | static_assert(not std::is_assignable::value); 96 | } 97 | { 98 | // Make sure we can't move-assign from a pair containing a reference 99 | // if that type isn't copy-constructible (since otherwise we'd be 100 | // stealing the object through the reference). 101 | using P1 = cruft::tight_pair; 102 | using P2 = cruft::tight_pair; 103 | static_assert(not std::is_assignable::value); 104 | 105 | // ... but this should work since we're going to steal out of the 106 | // incoming rvalue reference. 107 | using P3 = cruft::tight_pair; 108 | using P4 = cruft::tight_pair; 109 | static_assert(std::is_assignable::value); 110 | } 111 | { 112 | // We assign through the reference and don't move out of the incoming ref, 113 | // so this doesn't work (but would if the type were CopyAssignable). 114 | { 115 | using P1 = cruft::tight_pair; 116 | using P2 = cruft::tight_pair; 117 | static_assert(not std::is_assignable::value); 118 | } 119 | 120 | // ... works if it's CopyAssignable 121 | { 122 | using P1 = cruft::tight_pair; 123 | using P2 = cruft::tight_pair; 124 | static_assert(std::is_assignable::value); 125 | } 126 | 127 | // For rvalue-references, we can move-assign if the type is MoveAssignable, 128 | // or CopyAssignable (since in the worst case the move will decay into a copy). 129 | { 130 | using P1 = cruft::tight_pair; 131 | using P2 = cruft::tight_pair; 132 | static_assert(std::is_assignable::value); 133 | 134 | using P3 = cruft::tight_pair; 135 | using P4 = cruft::tight_pair; 136 | static_assert(std::is_assignable::value); 137 | } 138 | 139 | // In all cases, we can't move-assign if the types are not assignable, 140 | // since we assign through the reference. 141 | { 142 | using P1 = cruft::tight_pair; 143 | using P2 = cruft::tight_pair; 144 | static_assert(not std::is_assignable::value); 145 | 146 | using P3 = cruft::tight_pair; 147 | using P4 = cruft::tight_pair; 148 | static_assert(not std::is_assignable::value); 149 | } 150 | } 151 | return true; 152 | } 153 | } 154 | 155 | TEST_CASE( "assign rv pair U V" ) 156 | { 157 | static_assert(test()); 158 | } 159 | -------------------------------------------------------------------------------- /tests/libcxx/U_V.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include "archetypes.h" 18 | #include "test_convertible.h" 19 | using namespace ImplicitTypes; // Get implicitly archetypes 20 | 21 | namespace 22 | { 23 | template< 24 | typename T1, 25 | typename T1Arg, 26 | bool CanCopy = true, 27 | bool CanConvert = CanCopy 28 | > 29 | void test_sfinae() 30 | { 31 | using P1 = cruft::tight_pair; 32 | using P2 = cruft::tight_pair; 33 | using T2 = int const&; 34 | static_assert(std::is_constructible_v == CanCopy); 35 | static_assert(test_convertible() == CanConvert); 36 | static_assert(std::is_constructible_v == CanCopy); 37 | static_assert(test_convertible() == CanConvert); 38 | } 39 | 40 | struct ExplicitT 41 | { 42 | constexpr explicit ExplicitT(int x): value(x) {} 43 | int value; 44 | }; 45 | 46 | struct ImplicitT 47 | { 48 | constexpr ImplicitT(int x): value(x) {} 49 | int value; 50 | }; 51 | 52 | struct ExplicitNothrowT 53 | { 54 | explicit ExplicitNothrowT(int x) noexcept: value(x) {} 55 | int value; 56 | }; 57 | 58 | struct ImplicitNothrowT 59 | { 60 | ImplicitNothrowT(int x) noexcept: value(x) {} 61 | int value; 62 | }; 63 | 64 | struct TrackInit 65 | { 66 | TrackInit() = default; 67 | constexpr TrackInit(TrackInit const&): wasCopyInit(true) {} 68 | constexpr TrackInit(TrackInit&&): wasMoveInit(true) {} 69 | bool wasMoveInit = false; 70 | bool wasCopyInit = false; 71 | }; 72 | } 73 | 74 | TEST_CASE( "test U V" ) 75 | { 76 | using cruft::get; 77 | 78 | { 79 | using P = cruft::tight_pair, short*>; 80 | P p(std::unique_ptr(new int(3)), nullptr); 81 | CHECK(*get<0>(p) == 3); 82 | CHECK(get<1>(p) == nullptr); 83 | } 84 | { 85 | // Test non-const lvalue and rvalue types 86 | test_sfinae(); 87 | test_sfinae(); 88 | test_sfinae(); 89 | test_sfinae(); 90 | test_sfinae(); 91 | test_sfinae(); 92 | test_sfinae(); 93 | test_sfinae(); 94 | test_sfinae(); 95 | test_sfinae(); 96 | test_sfinae(); 97 | test_sfinae(); 98 | test_sfinae(); 99 | test_sfinae(); 100 | test_sfinae(); 101 | test_sfinae(); 102 | } 103 | { 104 | // Test converting types 105 | test_sfinae(); 106 | test_sfinae(); 107 | test_sfinae(); 108 | test_sfinae(); 109 | test_sfinae(); 110 | test_sfinae(); 111 | test_sfinae(); 112 | test_sfinae(); 113 | } 114 | { // explicit constexpr test 115 | constexpr cruft::tight_pair p(42, 43); 116 | static_assert(get<0>(p).value == 42); 117 | static_assert(get<1>(p).value == 43); 118 | } 119 | { // implicit constexpr test 120 | constexpr cruft::tight_pair p = {42, 43}; 121 | static_assert(get<0>(p).value == 42); 122 | static_assert(get<1>(p).value == 43); 123 | } 124 | } 125 | 126 | TEST_CASE( "test U V P1951" ) 127 | { 128 | // Test support for http://wg21.link/P1951, default arguments for pair's constructor. 129 | // Basically, this turns copies for brace initialization into moves. 130 | 131 | using cruft::get; 132 | 133 | // Explicit constructor 134 | { 135 | { 136 | constexpr cruft::tight_pair p({}, 3); 137 | static_assert( get<0>(p).wasMoveInit); 138 | static_assert(not get<0>(p).wasCopyInit); 139 | } 140 | { 141 | constexpr cruft::tight_pair p(3, {}); 142 | static_assert( get<1>(p).wasMoveInit); 143 | static_assert(not get<1>(p).wasCopyInit); 144 | } 145 | } 146 | 147 | // Implicit constructor 148 | { 149 | { 150 | constexpr cruft::tight_pair p = {{}, 3}; 151 | static_assert( get<0>(p).wasMoveInit); 152 | static_assert(not get<0>(p).wasCopyInit); 153 | } 154 | { 155 | constexpr cruft::tight_pair p = {3, {}}; 156 | static_assert( get<1>(p).wasMoveInit); 157 | static_assert(not get<1>(p).wasCopyInit); 158 | } 159 | } 160 | } 161 | 162 | TEST_CASE( "test U V noexcept" ) 163 | { 164 | { // explicit noexcept test 165 | static_assert(not std::is_nothrow_constructible_v, int, int>); 166 | static_assert(not std::is_nothrow_constructible_v, int, int>); 167 | static_assert(not std::is_nothrow_constructible_v, int, int>); 168 | static_assert( std::is_nothrow_constructible_v, int, int>); 169 | } 170 | { // implicit noexcept test 171 | static_assert(not std::is_nothrow_constructible_v, int, int>); 172 | static_assert(not std::is_nothrow_constructible_v, int, int>); 173 | static_assert(not std::is_nothrow_constructible_v, int, int>); 174 | static_assert( std::is_nothrow_constructible_v, int, int>); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /bench/sort-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #ifdef _WIN32 16 | #include 17 | #define rdtsc __rdtsc 18 | #else 19 | #ifdef __i586__ 20 | static __inline__ unsigned long long rdtsc() { 21 | unsigned long long int x; 22 | __asm__ volatile(".byte 0x0f, 0x31" : "=A" (x)); 23 | return x; 24 | } 25 | #elif defined(__x86_64__) 26 | static __inline__ unsigned long long rdtsc(){ 27 | unsigned hi, lo; 28 | __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); 29 | return ((unsigned long long) lo) | (((unsigned long long) hi) << 32); 30 | } 31 | #else 32 | #error no rdtsc implementation 33 | #endif 34 | #endif 35 | 36 | template 37 | struct distribution 38 | { 39 | template 40 | using fptr_t = void(*)(OutputIterator, std::size_t); 41 | 42 | template 43 | operator fptr_t() const 44 | { 45 | return [](OutputIterator out, std::size_t size) 46 | { 47 | return Derived{}(out, size); 48 | }; 49 | } 50 | }; 51 | 52 | std::mt19937_64 engine{}; 53 | 54 | template 55 | struct shuffled: 56 | distribution> 57 | { 58 | template 59 | auto operator()(OutputIterator out, std::size_t size) const 60 | -> void 61 | { 62 | using std::get; 63 | 64 | // Pseudo-random number generator 65 | // thread_local std::mt19937_64 engine(seed); 66 | 67 | std::vector vec; 68 | for (std::size_t i = 0 ; i < size ; ++i) { 69 | vec.emplace_back(i % 16, 0); 70 | } 71 | std::shuffle(std::begin(vec), std::end(vec), engine); 72 | for (std::size_t i = 0 ; i < size ; ++i) { 73 | get<1>(vec[i]) = i; 74 | } 75 | std::shuffle(std::begin(vec), std::end(vec), engine); 76 | std::move(std::begin(vec), std::end(vec), out); 77 | } 78 | 79 | static constexpr const char* output = "shuffled.txt"; 80 | }; 81 | 82 | template class Collection, typename T> 83 | using distr_f = void (*)(std::back_insert_iterator>, std::size_t); 84 | 85 | template class Collection, typename T> 86 | using sort_f = void (*)(Collection&, std::less<>); 87 | 88 | int main() 89 | { 90 | using namespace std::chrono_literals; 91 | 92 | std::tuple< 93 | std::string, 94 | distr_f>, 95 | distr_f> 96 | > distributions[] = { 97 | { "shuffled", shuffled>(), shuffled>() }, 98 | }; 99 | 100 | std::tuple< 101 | std::string, 102 | sort_f>, 103 | sort_f> 104 | > sorts[] = { 105 | { "heap_sort", cppsort::heap_sort, cppsort::heap_sort }, 106 | { "pdq_sort", cppsort::pdq_sort, cppsort::pdq_sort }, 107 | { "quick_sort", cppsort::quick_sort, cppsort::quick_sort }, 108 | { "std_sort", cppsort::std_sort, cppsort::std_sort }, 109 | { "verge_sort", cppsort::verge_sort, cppsort::verge_sort } 110 | }; 111 | 112 | std::size_t sizes[] = { 1'000'000 }; 113 | 114 | using std::get; 115 | 116 | for (auto& distribution: distributions) { 117 | for (auto& sort: sorts) { 118 | for (auto size: sizes) { 119 | // Common seed sequence to make sure both have the same seed 120 | std::seed_seq sseq{45518, 546312, 510}; 121 | 122 | // Sort collection of std::pair 123 | { 124 | engine.seed(sseq); 125 | 126 | std::vector cycles; 127 | 128 | auto total_start = std::chrono::high_resolution_clock::now(); 129 | auto total_end = std::chrono::high_resolution_clock::now(); 130 | while (std::chrono::duration_cast(total_end - total_start) < 5s) { 131 | std::vector> collection; 132 | get<1>(distribution)(std::back_inserter(collection), size); 133 | std::uint64_t start = rdtsc(); 134 | get<1>(sort)(collection, std::less{}); 135 | std::uint64_t end = rdtsc(); 136 | assert(std::is_sorted(std::begin(collection), std::end(collection))); 137 | cycles.push_back(double(end - start) / size + 0.5); 138 | total_end = std::chrono::high_resolution_clock::now(); 139 | } 140 | 141 | std::sort(std::begin(cycles), std::end(cycles)); 142 | 143 | std::cout << "std " << get<0>(distribution) << ' ' << get<0>(sort) 144 | << ' ' << cycles[cycles.size() / 2] << '\n'; 145 | std::cerr << "std " << get<0>(distribution) << ' ' << get<0>(sort) 146 | << ' ' << cycles[cycles.size() / 2] << '\n'; 147 | } 148 | 149 | // Sort collection of cruft::tight_pair 150 | { 151 | engine.seed(sseq); 152 | 153 | std::vector cycles; 154 | 155 | auto total_start = std::chrono::high_resolution_clock::now(); 156 | auto total_end = std::chrono::high_resolution_clock::now(); 157 | while (std::chrono::duration_cast(total_end - total_start) < 5s) { 158 | std::vector> collection; 159 | get<2>(distribution)(std::back_inserter(collection), size); 160 | std::uint64_t start = rdtsc(); 161 | get<2>(sort)(collection, std::less{}); 162 | std::uint64_t end = rdtsc(); 163 | assert(std::is_sorted(std::begin(collection), std::end(collection))); 164 | cycles.push_back(double(end - start) / size + 0.5); 165 | total_end = std::chrono::high_resolution_clock::now(); 166 | } 167 | 168 | std::sort(std::begin(cycles), std::end(cycles)); 169 | 170 | std::cout << "cruft " << get<0>(distribution) << ' ' << get<0>(sort) 171 | << ' ' << cycles[cycles.size() / 2] << '\n'; 172 | std::cerr << "cruft " << get<0>(distribution) << ' ' << get<0>(sort) 173 | << ' ' << cycles[cycles.size() / 2] << '\n'; 174 | } 175 | } 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /cmake/Findcodecov.cmake: -------------------------------------------------------------------------------- 1 | # This file is part of CMake-codecov. 2 | # 3 | # Copyright (c) 4 | # 2015-2017 RWTH Aachen University, Federal Republic of Germany 5 | # 6 | # See the LICENSE file in the package base directory for details 7 | # 8 | # Written by Alexander Haase, alexander.haase@rwth-aachen.de 9 | # 10 | 11 | 12 | # Add an option to choose, if coverage should be enabled or not. If enabled 13 | # marked targets will be build with coverage support and appropriate targets 14 | # will be added. If disabled coverage will be ignored for *ALL* targets. 15 | option(ENABLE_COVERAGE "Enable coverage build." OFF) 16 | 17 | set(COVERAGE_FLAG_CANDIDATES 18 | # gcc and clang 19 | "-O0 -g -fprofile-arcs -ftest-coverage" 20 | 21 | # gcc and clang fallback 22 | "-O0 -g --coverage" 23 | ) 24 | 25 | 26 | # Add coverage support for target ${TNAME} and register target for coverage 27 | # evaluation. If coverage is disabled or not supported, this function will 28 | # simply do nothing. 29 | # 30 | # Note: This function is only a wrapper to define this function always, even if 31 | # coverage is not supported by the compiler or disabled. This function must 32 | # be defined here, because the module will be exited, if there is no coverage 33 | # support by the compiler or it is disabled by the user. 34 | function (add_coverage TNAME) 35 | # only add coverage for target, if coverage is support and enabled. 36 | if (ENABLE_COVERAGE) 37 | foreach (TNAME ${ARGV}) 38 | add_coverage_target(${TNAME}) 39 | endforeach () 40 | endif () 41 | endfunction (add_coverage) 42 | 43 | 44 | # Add global target to gather coverage information after all targets have been 45 | # added. Other evaluation functions could be added here, after checks for the 46 | # specific module have been passed. 47 | # 48 | # Note: This function is only a wrapper to define this function always, even if 49 | # coverage is not supported by the compiler or disabled. This function must 50 | # be defined here, because the module will be exited, if there is no coverage 51 | # support by the compiler or it is disabled by the user. 52 | function (coverage_evaluate) 53 | # add lcov evaluation 54 | if (LCOV_FOUND) 55 | lcov_capture_initial() 56 | lcov_capture() 57 | endif (LCOV_FOUND) 58 | endfunction () 59 | 60 | 61 | # Exit this module, if coverage is disabled. add_coverage is defined before this 62 | # return, so this module can be exited now safely without breaking any build- 63 | # scripts. 64 | if (NOT ENABLE_COVERAGE) 65 | return() 66 | endif () 67 | 68 | 69 | 70 | 71 | # Find the reuired flags foreach language. 72 | set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) 73 | set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY}) 74 | 75 | get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) 76 | foreach (LANG ${ENABLED_LANGUAGES}) 77 | # Coverage flags are not dependend on language, but the used compiler. So 78 | # instead of searching flags foreach language, search flags foreach compiler 79 | # used. 80 | set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) 81 | if (NOT COVERAGE_${COMPILER}_FLAGS) 82 | foreach (FLAG ${COVERAGE_FLAG_CANDIDATES}) 83 | if(NOT CMAKE_REQUIRED_QUIET) 84 | message(STATUS "Try ${COMPILER} code coverage flag = [${FLAG}]") 85 | endif() 86 | 87 | set(CMAKE_REQUIRED_FLAGS "${FLAG}") 88 | unset(COVERAGE_FLAG_DETECTED CACHE) 89 | 90 | if (${LANG} STREQUAL "C") 91 | include(CheckCCompilerFlag) 92 | check_c_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) 93 | 94 | elseif (${LANG} STREQUAL "CXX") 95 | include(CheckCXXCompilerFlag) 96 | check_cxx_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) 97 | 98 | elseif (${LANG} STREQUAL "Fortran") 99 | # CheckFortranCompilerFlag was introduced in CMake 3.x. To be 100 | # compatible with older Cmake versions, we will check if this 101 | # module is present before we use it. Otherwise we will define 102 | # Fortran coverage support as not available. 103 | include(CheckFortranCompilerFlag OPTIONAL 104 | RESULT_VARIABLE INCLUDED) 105 | if (INCLUDED) 106 | check_fortran_compiler_flag("${FLAG}" 107 | COVERAGE_FLAG_DETECTED) 108 | elseif (NOT CMAKE_REQUIRED_QUIET) 109 | message("-- Performing Test COVERAGE_FLAG_DETECTED") 110 | message("-- Performing Test COVERAGE_FLAG_DETECTED - Failed" 111 | " (Check not supported)") 112 | endif () 113 | endif() 114 | 115 | if (COVERAGE_FLAG_DETECTED) 116 | set(COVERAGE_${COMPILER}_FLAGS "${FLAG}" 117 | CACHE STRING "${COMPILER} flags for code coverage.") 118 | mark_as_advanced(COVERAGE_${COMPILER}_FLAGS) 119 | break() 120 | else () 121 | message(WARNING "Code coverage is not available for ${COMPILER}" 122 | " compiler. Targets using this compiler will be " 123 | "compiled without it.") 124 | endif () 125 | endforeach () 126 | endif () 127 | endforeach () 128 | 129 | set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE}) 130 | 131 | 132 | 133 | 134 | # Helper function to get the language of a source file. 135 | function (codecov_lang_of_source FILE RETURN_VAR) 136 | get_filename_component(FILE_EXT "${FILE}" EXT) 137 | string(TOLOWER "${FILE_EXT}" FILE_EXT) 138 | string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT) 139 | 140 | get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) 141 | foreach (LANG ${ENABLED_LANGUAGES}) 142 | list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP) 143 | if (NOT ${TEMP} EQUAL -1) 144 | set(${RETURN_VAR} "${LANG}" PARENT_SCOPE) 145 | return() 146 | endif () 147 | endforeach() 148 | 149 | set(${RETURN_VAR} "" PARENT_SCOPE) 150 | endfunction () 151 | 152 | 153 | # Helper function to get the relative path of the source file destination path. 154 | # This path is needed by FindGcov and FindLcov cmake files to locate the 155 | # captured data. 156 | function (codecov_path_of_source FILE RETURN_VAR) 157 | string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _source ${FILE}) 158 | 159 | # If expression was found, SOURCEFILE is a generator-expression for an 160 | # object library. Currently we found no way to call this function automatic 161 | # for the referenced target, so it must be called in the directoryso of the 162 | # object library definition. 163 | if (NOT "${_source}" STREQUAL "") 164 | set(${RETURN_VAR} "" PARENT_SCOPE) 165 | return() 166 | endif () 167 | 168 | 169 | string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" "" FILE "${FILE}") 170 | if(IS_ABSOLUTE ${FILE}) 171 | file(RELATIVE_PATH FILE ${CMAKE_CURRENT_SOURCE_DIR} ${FILE}) 172 | endif() 173 | 174 | # get the right path for file 175 | string(REPLACE ".." "__" PATH "${FILE}") 176 | 177 | set(${RETURN_VAR} "${PATH}" PARENT_SCOPE) 178 | endfunction() 179 | 180 | 181 | 182 | 183 | # Add coverage support for target ${TNAME} and register target for coverage 184 | # evaluation. 185 | function(add_coverage_target TNAME) 186 | # Check if all sources for target use the same compiler. If a target uses 187 | # e.g. C and Fortran mixed and uses different compilers (e.g. clang and 188 | # gfortran) this can trigger huge problems, because different compilers may 189 | # use different implementations for code coverage. 190 | get_target_property(TSOURCES ${TNAME} SOURCES) 191 | set(TARGET_COMPILER "") 192 | set(ADDITIONAL_FILES "") 193 | foreach (FILE ${TSOURCES}) 194 | # If expression was found, FILE is a generator-expression for an object 195 | # library. Object libraries will be ignored. 196 | string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE}) 197 | if ("${_file}" STREQUAL "") 198 | codecov_lang_of_source(${FILE} LANG) 199 | if (LANG) 200 | list(APPEND TARGET_COMPILER ${CMAKE_${LANG}_COMPILER_ID}) 201 | 202 | list(APPEND ADDITIONAL_FILES "${FILE}.gcno") 203 | list(APPEND ADDITIONAL_FILES "${FILE}.gcda") 204 | endif () 205 | endif () 206 | endforeach () 207 | 208 | list(REMOVE_DUPLICATES TARGET_COMPILER) 209 | list(LENGTH TARGET_COMPILER NUM_COMPILERS) 210 | 211 | if (NUM_COMPILERS GREATER 1) 212 | message(WARNING "Can't use code coverage for target ${TNAME}, because " 213 | "it will be compiled by incompatible compilers. Target will be " 214 | "compiled without code coverage.") 215 | return() 216 | 217 | elseif (NUM_COMPILERS EQUAL 0) 218 | message(WARNING "Can't use code coverage for target ${TNAME}, because " 219 | "it uses an unknown compiler. Target will be compiled without " 220 | "code coverage.") 221 | return() 222 | 223 | elseif (NOT DEFINED "COVERAGE_${TARGET_COMPILER}_FLAGS") 224 | # A warning has been printed before, so just return if flags for this 225 | # compiler aren't available. 226 | return() 227 | endif() 228 | 229 | 230 | # enable coverage for target 231 | set_property(TARGET ${TNAME} APPEND_STRING 232 | PROPERTY COMPILE_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}") 233 | set_property(TARGET ${TNAME} APPEND_STRING 234 | PROPERTY LINK_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}") 235 | 236 | 237 | # Add gcov files generated by compiler to clean target. 238 | set(CLEAN_FILES "") 239 | foreach (FILE ${ADDITIONAL_FILES}) 240 | codecov_path_of_source(${FILE} FILE) 241 | list(APPEND CLEAN_FILES "CMakeFiles/${TNAME}.dir/${FILE}") 242 | endforeach() 243 | 244 | set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES 245 | "${CLEAN_FILES}") 246 | 247 | 248 | add_gcov_target(${TNAME}) 249 | add_lcov_target(${TNAME}) 250 | endfunction(add_coverage_target) 251 | 252 | 253 | 254 | 255 | # Include modules for parsing the collected data and output it in a readable 256 | # format (like gcov and lcov). 257 | find_package(Gcov) 258 | find_package(Lcov) 259 | -------------------------------------------------------------------------------- /tests/libcxx/const_pair_U_V.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "archetypes.h" 19 | #include "test_convertible.h" 20 | 21 | namespace 22 | { 23 | using namespace ImplicitTypes; // Get implicitly archetypes 24 | 25 | template 26 | constexpr void test_pair_const() { 27 | using P1 = cruft::tight_pair; 28 | using P2 = cruft::tight_pair; 29 | using UP1 = cruft::tight_pair const&; 30 | using UP2 = cruft::tight_pair const&; 31 | static_assert(std::is_constructible::value == CanCopy); 32 | static_assert(test_convertible() == CanConvert); 33 | static_assert(std::is_constructible::value == CanCopy); 34 | static_assert(test_convertible() == CanConvert); 35 | } 36 | 37 | template 38 | struct DPair: 39 | cruft::tight_pair 40 | { 41 | using Base = cruft::tight_pair; 42 | using Base::Base; 43 | }; 44 | 45 | struct ExplicitT 46 | { 47 | constexpr explicit ExplicitT(int x): value(x) {} 48 | constexpr explicit ExplicitT(ExplicitT const& o): value(o.value) {} 49 | int value; 50 | }; 51 | 52 | struct ImplicitT 53 | { 54 | constexpr ImplicitT(int x): value(x) {} 55 | constexpr ImplicitT(ImplicitT const& o): value(o.value) {} 56 | int value; 57 | }; 58 | 59 | struct ExplicitNothrowT 60 | { 61 | explicit ExplicitNothrowT(int x) noexcept: value(x) {} 62 | int value; 63 | }; 64 | 65 | struct ImplicitNothrowT 66 | { 67 | ImplicitNothrowT(int x) noexcept: value(x) {} 68 | int value; 69 | }; 70 | 71 | constexpr bool test() 72 | { 73 | using cruft::get; 74 | { 75 | using P1 = cruft::tight_pair; 76 | using P2 = cruft::tight_pair; 77 | const P1 p1(3, 4); 78 | const P2 p2 = p1; 79 | assert(get<0>(p2) == 3); 80 | assert(get<1>(p2) == 4); 81 | } 82 | { 83 | // We allow derived types to use this constructor 84 | using P1 = DPair; 85 | using P2 = cruft::tight_pair; 86 | P1 p1(42, 101); 87 | P2 p2(p1); 88 | assert(get<0>(p2) == 42); 89 | assert(get<1>(p2) == 101); 90 | } 91 | { 92 | test_pair_const(); // copy construction 93 | test_pair_const(); 94 | test_pair_const(); 95 | test_pair_const(); 96 | test_pair_const(); 97 | 98 | test_pair_const(); // copy construction 100 | test_pair_const(); 101 | test_pair_const(); 102 | test_pair_const(); 103 | test_pair_const(); 104 | 105 | test_pair_const(); // copy construction 106 | test_pair_const(); 107 | test_pair_const(); 108 | 109 | test_pair_const(); // copy construction 110 | test_pair_const(); 111 | test_pair_const(); 112 | 113 | test_pair_const(); 114 | test_pair_const(); 115 | test_pair_const(); 116 | 117 | test_pair_const(); 118 | test_pair_const(); 119 | test_pair_const(); 120 | 121 | test_pair_const(); 122 | test_pair_const(); 123 | test_pair_const(); 124 | test_pair_const(); 125 | test_pair_const(); 126 | } 127 | 128 | { // Test construction of references 129 | test_pair_const(); 130 | test_pair_const(); 131 | test_pair_const(); 132 | test_pair_const(); 133 | test_pair_const(); 134 | 135 | test_pair_const(); 136 | test_pair_const(); 137 | // Unfortunately the below conversions are allowed and create dangling 138 | // references. 139 | //test_pair_const(); 140 | //test_pair_const(); 141 | //test_pair_const(); 142 | // But these are not because the converting constructor is explicit. 143 | test_pair_const(); 144 | test_pair_const(); 145 | test_pair_const(); 146 | } 147 | { 148 | test_pair_const(); 149 | test_pair_const(); 150 | test_pair_const(); 151 | test_pair_const(); 152 | 153 | test_pair_const(); 154 | test_pair_const(); 155 | test_pair_const(); 156 | test_pair_const(); 157 | test_pair_const(); 158 | 159 | test_pair_const(); 160 | test_pair_const(); 161 | test_pair_const(); 162 | test_pair_const(); 163 | test_pair_const(); 164 | 165 | test_pair_const(); 167 | test_pair_const(); 169 | test_pair_const(); 171 | test_pair_const(); 173 | } 174 | 175 | { 176 | using P1 = cruft::tight_pair; 177 | using P2 = cruft::tight_pair; 178 | constexpr P1 p1(3, 4); 179 | constexpr P2 p2 = p1; 180 | static_assert(get<0>(p2) == 3); 181 | static_assert(get<1>(p2) == 4); 182 | } 183 | { 184 | using P1 = cruft::tight_pair; 185 | using P2 = cruft::tight_pair; 186 | constexpr P1 p1(42, 101); 187 | constexpr P2 p2(p1); 188 | static_assert(get<0>(p2).value == 42); 189 | static_assert(get<1>(p2).value == 101); 190 | } 191 | { 192 | using P1 = cruft::tight_pair; 193 | using P2 = cruft::tight_pair; 194 | constexpr P1 p1(42, 101); 195 | constexpr P2 p2 = p1; 196 | static_assert(get<0>(p2).value == 42); 197 | static_assert(get<1>(p2).value == 101); 198 | } 199 | 200 | return true; 201 | } 202 | } 203 | 204 | TEST_CASE( "const pair U C" ) 205 | { 206 | static_assert(test()); 207 | } 208 | 209 | TEST_CASE( "const pair U C noexcept" ) 210 | { 211 | { // explicit noexcept test 212 | static_assert(not std::is_nothrow_constructible_v, 213 | cruft::tight_pair const&>); 214 | static_assert(not std::is_nothrow_constructible_v, 215 | cruft::tight_pair const&>); 216 | static_assert(not std::is_nothrow_constructible_v, 217 | cruft::tight_pair const&>); 218 | static_assert( std::is_nothrow_constructible_v, 219 | cruft::tight_pair const&>); 220 | } 221 | { // implicit noexcept test 222 | static_assert(not std::is_nothrow_constructible_v, 223 | cruft::tight_pair const&>); 224 | static_assert(not std::is_nothrow_constructible_v, 225 | cruft::tight_pair const&>); 226 | static_assert(not std::is_nothrow_constructible_v, 227 | cruft::tight_pair const&>); 228 | static_assert( std::is_nothrow_constructible_v, 229 | cruft::tight_pair const&>); 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Latest Release](https://img.shields.io/badge/release-1.2.0-blue.svg)](https://github.com/Morwenn/tight_pair/releases/tag/1.2.0) 2 | [![Code Coverage](https://codecov.io/gh/Morwenn/tight_pair/branch/master/graph/badge.svg)](https://codecov.io/gh/Morwenn/tight_pair) 3 | [![Pitchfork Layout](https://img.shields.io/badge/standard-PFL-orange.svg)](https://github.com/vector-of-bool/pitchfork) 4 | 5 | *This experimental project is a small single-header header-only C++17 library providing a single `tight_pair` class 6 | template and associated functions. It is not meant to be anywhere near serious, but it was a fun little project to 7 | try to design a C++17-only component, and to optimize it as possible despite the underlying layers of abstraction :)* 8 | 9 | `cruft::tight_pair` is a C++17 compressed pair class. Unlike [Boost.Compressed_Pair][boost-compressed-pair] it is 10 | modelled after [`std::pair`][std-pair], with only a few additions and a few deletions. First, a short list of what is 11 | similar to the standard library's `std::pair`, then we will have a look at what makes them different: 12 | - It supports [the same set of constructors][std-pair-pair], and most notably the *EXPLICIT* ones. 13 | - It also handles piecewise construction, which allows to build non-copyable, non-movable types. 14 | - It has a tuple-like interface through [`std::tuple_size`][std-tuple-size], [`std::tuple_element`][std-tuple-element], 15 | and and ADL-found `get`. 16 | - It works with [structured bindings][structured-bindings]. 17 | - Its `get` function also accepts types, unless the pair stores two elements of the same type. 18 | - It is trivially destructible when both elements are trivially destructible. 19 | - It unwraps an [`std::reference_wrapper`][std-reference-wrapper] as a `T&`. 20 | - It supports comparison when its elements support comparison. 21 | 22 | ## Differences from `std::pair` 23 | 24 | Now is the time to look at what actually makes this `tight_pair` different from the standard library's `std::pair`: 25 | - As its name implies, it is what is known as a *compressed pair*: a pair that privately inherits from the elements to 26 | take advantage of [empty base class optimization][ebco] (EBCO) and thus reduce the size of the pair. This kind of 27 | optimization is mostly used when storing empty function objects. 28 | 29 | ```cpp 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | // Store a comparison and a projection (see C++20) 36 | auto p1 = std::pair(std::less{}, std::identity{}); 37 | auto p2 = cruft::tight_pair(std::less{}, std::identity{}); 38 | 39 | // prints "2 1" on my computer 40 | std::cout << sizeof(p1) << ' ' << sizeof(p2); 41 | ``` 42 | 43 | Recent `std::pair` implementations might rely on the C++20 [`[[no_unique_address]]`][no-unique-address] attribute to 44 | compress empty objects. However not all compilers currently implement the compressing semantics of that attribute in 45 | order to avoid ABI surprises. 46 | 47 | - Full EBCO requires to inherit privately from the empty base members in order to pack the pair as much as possible, 48 | even when holding instances of other empty pairs. However, this causes a problem with structured bindings: the 49 | lookup looks for a class-member `get` before looking for a `get` function with ADL. Therefore, if we privately 50 | inherit from an empty class with a conforming `get` function, the structured bindings lookup will find it first 51 | but will trigger an error because it is inaccessible. 52 | 53 | To bypass this potential bug without losing its compressing abilities, `cruft::tight_pair` has in-class `get` 54 | functions equivalent to those that can be found thanks to ADL. 55 | 56 | Note: this issue was partially mitigated in C++20 by [P0961][P0961] which ensures that the compiler will only look 57 | for a member function template, which avoid tripping on a non-template member `get()` like the one available with 58 | smart pointers. That solution is however incomplete, and our own mitigation still solves potential issues. 59 | 60 | - Unlike `std::pair`, it doesn't have `first` and `second` members nor does it provide `first_type` or `second_type` 61 | type aliases. The members can only be accessed through the `get` function template, and the member types can only be 62 | retrieved through `std::tuple_element`. It was a choice to only provide a minimal tuple-like interface. 63 | 64 | - Since it is a C++17-only library, I decided not to provide an equivalent to [`std::make_pair`][std-make-pair]: the 65 | type deduction is done through deduction guides. Unlike `std::pair`, the deduction guides are the ones that handle 66 | the decaying of array and reference parameters as well as the unwrapping of `std::reference_wrapper` to `T&`. Of 67 | course it is still possible to store arrays or raw `std::reference_wrapper` instances by manually specifying the 68 | types. 69 | 70 | ```cpp 71 | int a = 5; 72 | // Creates a cruft::tight_pair 73 | auto pair = cruft::tight_pair(std::cref(a), "welcome"); 74 | ``` 75 | 76 | - I borrowed a libc++ extension which allows `cruft::tight_pair` to be constructed from any pair-like type. A pair-like 77 | type is any type `T` for which `std::tuple_size_v == 2` and a `get` function template can be found through ADL. 78 | This notably allows to directly construct a `cruft::tight_pair` from `std::pair`, `std::tuple` or 79 | `std::array`, as well as other conforming types from third-party libraries. 80 | 81 | - Piecewise construction accepts tuple-like classes instead of just instances of [`std::tuple`][std-tuple] to pass 82 | arguments to initialize the pair members. 83 | 84 | - When possible the comparison and relational operators are optimized with bit tricks to be branchless, and hopefully 85 | faster than their `std::pair` equivalents. They are currently optimized for a subset of the `unsigned` types. Here 86 | are some benchmarks results I obtained by feeding instances of `std::pair` and `cruft::tight_pair` to comparison 87 | sorts from another of my libraries: 88 | 89 | ![Benchmark sorting std::pair and cruft::tight_pair](https://i.imgur.com/4wRL5i1.png) 90 | 91 | *Of course* those benchmarks are biased: you may not always get results that good if you replace `unsigned short` by 92 | `unsigned int`, but you get the idea. The benchmarks can be found in the `bench` directory of the project, and the 93 | results have been obtained with MinGW g++ 7.1.0 with the options `-O3 -march=native`. 94 | 95 | - Most of the constructors are conditionally `noexcept` (at the time of writing, only the piecewise constructor and the 96 | one that takes a pair-like object are not `noexcept`). 97 | 98 | - Comparison and relational operators are [hidden friends][hidden-friends]. 99 | 100 | `cruft::tight_pair` also implements features library defects resolutions that were added to the standard after C++17 101 | was published: 102 | - [P1032][P1032] (C++20): make `operator=`, `swap` and the piewise constructor `constexpr`. 103 | - [P1951][P1951] (C++23): default arguments for the forwarding constructor (see paper for rationale). 104 | - [LWG2510][LWG2510]: make the default constructor conditionally `explicit`. 105 | 106 | ## Compiler support and tooling 107 | 108 | ![Ubuntu builds status](https://github.com/Morwenn/tight_pair/workflows/Ubuntu%20Builds/badge.svg?branch=master) 109 | ![Windows builds status](https://github.com/Morwenn/tight_pair/workflows/MSVC%20Builds/badge.svg?branch=master) 110 | ![MacOS builds status](https://github.com/Morwenn/tight_pair/workflows/MacOS%20Builds/badge.svg?branch=master) 111 | 112 | **tight_pair** requires C++17 support, and should work with the following compilers: 113 | * g++7 or more recent. 114 | * clang++6.0 or more recent. 115 | * Visual Studio 2019 version 16.8.3 or more recent, only with `/permissive-`. 116 | * The versions of MinGW-w64 and AppleClang equivalent to the compilers mentioned above. 117 | * Clang is notably tested with both libstdc++ and libc++. 118 | 119 | The compilers listed above are the ones used by the CI pipeline, and the library is also tested with the most recent 120 | versions of those compilers on a regular basis. All the other compiler versions in-between are untested, but should 121 | also work. Feel free to open an issue if it isn't the case. 122 | 123 | There might still be compiler errors with some corner cases that the library doesn't try to work around. The known ones 124 | are documented in a small [knowledge base][known-errors] on the GitHub wiki. 125 | 126 | *WARNING: while the library works with MSVC, the codegen tends to be pretty poor.* 127 | 128 | ## Acknowledgements 129 | 130 | I can't finish a project without stealing code around, so here are the main sources of the code that can be found in 131 | this project when I didn't write it by myself: 132 | 133 | * A great deal of code originally comes from the libc++ implementation of `std::pair` and `std::tuple` utilities. 134 | 135 | * Additional small bits of code are inspired by Microsoft STL. 136 | 137 | * All the tests that can be found in `tests/libcxx` have been ported from the libc++ testsuite and modified so that 138 | they can work with the minimal tuple-like interface of the library. 139 | 140 | * The tests in `tests/cppreference.cpp` were preliminary tests adapted from the examples on [cppreference.com][cppreference] 141 | to check that the basic features worked correctly. 142 | 143 | * The algorithm used to detect whether unsigned integer types have padding bits originally comes from the WG14 paper 144 | [N1899 - Integer Precision Bits Update][N1899] by David Svoboda. 145 | 146 | * The enumeration used to check the integer byte order of scalar types originally comes from the WG21 proposal 147 | [P0463 - `endian`, Just `endian`][P0463] by Howard Hinnant. 148 | 149 | * I also want to thank the [Godbolt online compiler explorer][godbolt] as well as people from Lounge 150 | who helped me optimize the small details down to assembly while still striving to remain standard-compliant :) 151 | 152 | 153 | [boost-compressed-pair]: https://www.boost.org/doc/libs/1_65_1/libs/utility/doc/html/compressed_pair.html 154 | [cppreference]: https://cppreference.com 155 | [ebco]: http://en.cppreference.com/w/cpp/language/ebo 156 | [godbolt]: https://godbolt.org/ 157 | [hidden-friends]: https://www.justsoftwaresolutions.co.uk/cplusplus/hidden-friends.html 158 | [known-errors]: https://github.com/Morwenn/tight_pair/wiki 159 | [LWG2510]: https://wg21.link/LWG2510 160 | [N1899]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1899.pdf 161 | [no-unique-address]: https://en.cppreference.com/w/cpp/language/attributes/no_unique_address 162 | [P0463]: https://wg21.link/P0463 163 | [P0961]: https://wg21.link/P0961 164 | [P1032]: https://wg21.link/P1032 165 | [P1951]: https://wg21.link/P1951 166 | [std-make-pair]: https://en.cppreference.com/w/cpp/utility/pair/make_pair 167 | [std-pair]: https://en.cppreference.com/w/cpp/utility/pair 168 | [std-pair-pair]: https://en.cppreference.com/w/cpp/utility/pair/pair 169 | [std-reference-wrapper]: https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper 170 | [std-tuple]: https://en.cppreference.com/w/cpp/utility/tuple 171 | [std-tuple-element]: https://en.cppreference.com/w/cpp/utility/tuple_element 172 | [std-tuple-size]: https://en.cppreference.com/w/cpp/utility/tuple_size 173 | [structured-bindings]: https://en.cppreference.com/w/cpp/language/structured_binding 174 | -------------------------------------------------------------------------------- /tests/libcxx/rv_pair_U_V.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "archetypes.h" 20 | #include "test_convertible.h" 21 | 22 | using namespace ImplicitTypes; // Get implicitly archetypes 23 | 24 | namespace 25 | { 26 | template< 27 | typename T1, 28 | typename U1, 29 | bool CanCopy = true, 30 | bool CanConvert = CanCopy 31 | > 32 | void test_pair_rv() 33 | { 34 | using P1 = cruft::tight_pair; 35 | using P2 = cruft::tight_pair; 36 | using UP1 = cruft::tight_pair&&; 37 | using UP2 = cruft::tight_pair&&; 38 | static_assert(std::is_constructible_v == CanCopy); 39 | static_assert(test_convertible() == CanConvert); 40 | static_assert(std::is_constructible_v == CanCopy); 41 | static_assert(test_convertible() == CanConvert); 42 | } 43 | 44 | struct Base 45 | { 46 | virtual ~Base() {} 47 | }; 48 | 49 | struct Derived: 50 | Base 51 | {}; 52 | 53 | 54 | template 55 | struct DPair: 56 | public cruft::tight_pair 57 | { 58 | using Base = cruft::tight_pair; 59 | using Base::Base; 60 | }; 61 | 62 | struct ExplicitT 63 | { 64 | constexpr explicit ExplicitT(int x): 65 | value(x) 66 | {} 67 | int value; 68 | }; 69 | 70 | struct ImplicitT 71 | { 72 | constexpr ImplicitT(int x): 73 | value(x) 74 | {} 75 | int value; 76 | }; 77 | 78 | struct ExplicitNothrowT 79 | { 80 | explicit ExplicitNothrowT(int x) noexcept: value(x) {} 81 | int value; 82 | }; 83 | 84 | struct ImplicitNothrowT 85 | { 86 | ImplicitNothrowT(int x) noexcept: value(x) {} 87 | int value; 88 | }; 89 | 90 | struct NotCopyOrMoveConstructible 91 | { 92 | NotCopyOrMoveConstructible() = default; 93 | NotCopyOrMoveConstructible(NotCopyOrMoveConstructible const&) = delete; 94 | NotCopyOrMoveConstructible(NotCopyOrMoveConstructible&&) = delete; 95 | }; 96 | 97 | struct NonCopyConstructible 98 | { 99 | NonCopyConstructible(NonCopyConstructible const&) = delete; 100 | NonCopyConstructible(NonCopyConstructible&&) = default; 101 | }; 102 | } 103 | 104 | TEST_CASE( "rv pair U V" ) 105 | { 106 | using cruft::get; 107 | 108 | { 109 | using P1 = cruft::tight_pair, short>; 110 | using P2 = cruft::tight_pair, long>; 111 | P1 p1(std::unique_ptr(), 4); 112 | P2 p2 = std::move(p1); 113 | CHECK(get<0>(p2) == nullptr); 114 | CHECK(get<1>(p2) == 4); 115 | } 116 | { 117 | // We allow derived types to use this constructor 118 | using P1 = DPair; 119 | using P2 = cruft::tight_pair; 120 | P1 p1(42, 101); 121 | P2 p2(std::move(p1)); 122 | CHECK(get<0>(p2) == 42); 123 | CHECK(get<1>(p2) == 101); 124 | } 125 | { 126 | test_pair_rv(); 127 | test_pair_rv(); 128 | test_pair_rv(); 129 | test_pair_rv(); 130 | test_pair_rv(); 131 | 132 | test_pair_rv(); 133 | test_pair_rv(); 134 | test_pair_rv(); 135 | test_pair_rv(); 136 | test_pair_rv(); 137 | 138 | test_pair_rv(); 139 | test_pair_rv(); 140 | test_pair_rv(); 141 | 142 | test_pair_rv(); // copy construction 143 | test_pair_rv(); 144 | test_pair_rv(); 145 | 146 | test_pair_rv(); 147 | test_pair_rv(); 148 | test_pair_rv(); 149 | 150 | test_pair_rv(); 151 | test_pair_rv(); 152 | test_pair_rv(); 153 | 154 | test_pair_rv(); 155 | test_pair_rv(); 156 | test_pair_rv(); 157 | test_pair_rv(); 158 | test_pair_rv(); 159 | } 160 | { // Test construction of references 161 | test_pair_rv(); 162 | test_pair_rv(); 163 | test_pair_rv(); 164 | test_pair_rv(); 165 | test_pair_rv(); 166 | 167 | test_pair_rv(); 168 | test_pair_rv(); 169 | // Unfortunately the below conversions are allowed and create dangling 170 | // references. 171 | //test_pair_rv(); 172 | //test_pair_rv(); 173 | //test_pair_rv(); 174 | // But these are not because the converting constructor is explicit. 175 | test_pair_rv(); 176 | test_pair_rv(); 177 | test_pair_rv(); 178 | } 179 | { 180 | test_pair_rv(); 181 | test_pair_rv(); 182 | test_pair_rv(); 183 | test_pair_rv(); 184 | 185 | test_pair_rv(); 186 | test_pair_rv(); 187 | test_pair_rv(); 188 | test_pair_rv(); 189 | test_pair_rv(); 190 | 191 | test_pair_rv(); 192 | test_pair_rv(); 193 | test_pair_rv(); 194 | test_pair_rv(); 195 | test_pair_rv(); 196 | 197 | test_pair_rv(); 198 | test_pair_rv(); 199 | test_pair_rv(); 200 | test_pair_rv(); 201 | } 202 | { 203 | // When constructing a pair containing a reference, we only bind the 204 | // reference, so it doesn't matter whether the type is or isn't 205 | // copy/move constructible. 206 | { 207 | using P1 = cruft::tight_pair; 208 | using P2 = cruft::tight_pair; 209 | static_assert(std::is_constructible::value); 210 | 211 | NotCopyOrMoveConstructible obj; 212 | P2 p2{obj, 3}; 213 | P1 p1(std::move(p2)); 214 | CHECK(&get<0>(p1) == &obj); 215 | CHECK(&get<0>(p2) == &obj); 216 | } 217 | { 218 | using P1 = cruft::tight_pair; 219 | using P2 = cruft::tight_pair; 220 | static_assert(std::is_constructible::value); 221 | 222 | NotCopyOrMoveConstructible obj; 223 | P2 p2{std::move(obj), 3}; 224 | P1 p1(std::move(p2)); 225 | CHECK(&get<0>(p1) == &obj); 226 | CHECK(&get<0>(p2) == &obj); 227 | } 228 | } 229 | { 230 | // Make sure we can't move-construct from a pair containing a reference 231 | // if that type isn't copy-constructible (since otherwise we'd be stealing 232 | // the object through the reference). 233 | using P1 = cruft::tight_pair; 234 | using P2 = cruft::tight_pair; 235 | static_assert(not std::is_constructible::value); 236 | } 237 | { // explicit constexpr test 238 | constexpr cruft::tight_pair p1(42, 43); 239 | constexpr cruft::tight_pair p2(std::move(p1)); 240 | static_assert(get<0>(p2).value == 42); 241 | static_assert(get<1>(p2).value == 43); 242 | } 243 | { // implicit constexpr test 244 | constexpr cruft::tight_pair p1(42, 43); 245 | constexpr cruft::tight_pair p2 = std::move(p1); 246 | static_assert(get<0>(p2).value == 42); 247 | static_assert(get<1>(p2).value == 43); 248 | } 249 | } 250 | 251 | TEST_CASE( "rv pair U V noexcept" ) 252 | { 253 | { // explicit noexcept test 254 | static_assert(not std::is_nothrow_constructible_v, 255 | cruft::tight_pair&&>); 256 | static_assert(not std::is_nothrow_constructible_v, 257 | cruft::tight_pair&&>); 258 | static_assert(not std::is_nothrow_constructible_v, 259 | cruft::tight_pair&&>); 260 | static_assert( std::is_nothrow_constructible_v, 261 | cruft::tight_pair&&>); 262 | } 263 | { // implicit noexcept test 264 | static_assert(not std::is_nothrow_constructible_v, 265 | cruft::tight_pair&&>); 266 | static_assert(not std::is_nothrow_constructible_v, 267 | cruft::tight_pair&&>); 268 | static_assert(not std::is_nothrow_constructible_v, 269 | cruft::tight_pair&&>); 270 | static_assert( std::is_nothrow_constructible_v, 271 | cruft::tight_pair&&>); 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /cmake/FindLcov.cmake: -------------------------------------------------------------------------------- 1 | # This file is part of CMake-codecov. 2 | # 3 | # Copyright (c) 4 | # 2015-2017 RWTH Aachen University, Federal Republic of Germany 5 | # 6 | # See the LICENSE file in the package base directory for details 7 | # 8 | # Written by Alexander Haase, alexander.haase@rwth-aachen.de 9 | # 10 | 11 | 12 | # configuration 13 | set(LCOV_DATA_PATH "${CMAKE_BINARY_DIR}/lcov/data") 14 | set(LCOV_DATA_PATH_INIT "${LCOV_DATA_PATH}/init") 15 | set(LCOV_DATA_PATH_CAPTURE "${LCOV_DATA_PATH}/capture") 16 | set(LCOV_HTML_PATH "${CMAKE_BINARY_DIR}/lcov/html") 17 | 18 | 19 | 20 | 21 | # Search for Gcov which is used by Lcov. 22 | find_package(Gcov) 23 | 24 | 25 | 26 | 27 | # This function will add lcov evaluation for target . Only sources of 28 | # this target will be evaluated and no dependencies will be added. It will call 29 | # geninfo on any source file of once and store the info file in the same 30 | # directory. 31 | # 32 | # Note: This function is only a wrapper to define this function always, even if 33 | # coverage is not supported by the compiler or disabled. This function must 34 | # be defined here, because the module will be exited, if there is no coverage 35 | # support by the compiler or it is disabled by the user. 36 | function (add_lcov_target TNAME) 37 | if (LCOV_FOUND) 38 | # capture initial coverage data 39 | lcov_capture_initial_tgt(${TNAME}) 40 | 41 | # capture coverage data after execution 42 | lcov_capture_tgt(${TNAME}) 43 | endif () 44 | endfunction (add_lcov_target) 45 | 46 | 47 | 48 | 49 | # include required Modules 50 | include(FindPackageHandleStandardArgs) 51 | 52 | # Search for required lcov binaries. 53 | find_program(LCOV_BIN lcov) 54 | find_program(GENINFO_BIN geninfo) 55 | find_program(GENHTML_BIN genhtml) 56 | find_package_handle_standard_args(lcov 57 | REQUIRED_VARS LCOV_BIN GENINFO_BIN GENHTML_BIN 58 | ) 59 | 60 | # enable genhtml C++ demangeling, if c++filt is found. 61 | set(GENHTML_CPPFILT_FLAG "") 62 | find_program(CPPFILT_BIN c++filt) 63 | if (NOT CPPFILT_BIN STREQUAL "") 64 | set(GENHTML_CPPFILT_FLAG "--demangle-cpp") 65 | endif (NOT CPPFILT_BIN STREQUAL "") 66 | 67 | # enable no-external flag for lcov, if available. 68 | if (GENINFO_BIN AND NOT DEFINED GENINFO_EXTERN_FLAG) 69 | set(FLAG "") 70 | execute_process(COMMAND ${GENINFO_BIN} --help OUTPUT_VARIABLE GENINFO_HELP) 71 | string(REGEX MATCH "external" GENINFO_RES "${GENINFO_HELP}") 72 | if (GENINFO_RES) 73 | set(FLAG "--no-external") 74 | endif () 75 | 76 | set(GENINFO_EXTERN_FLAG "${FLAG}" 77 | CACHE STRING "Geninfo flag to exclude system sources.") 78 | endif () 79 | 80 | # If Lcov was not found, exit module now. 81 | if (NOT LCOV_FOUND) 82 | return() 83 | endif (NOT LCOV_FOUND) 84 | 85 | 86 | 87 | 88 | # Create directories to be used. 89 | file(MAKE_DIRECTORY ${LCOV_DATA_PATH_INIT}) 90 | file(MAKE_DIRECTORY ${LCOV_DATA_PATH_CAPTURE}) 91 | 92 | set(LCOV_REMOVE_PATTERNS "") 93 | 94 | # This function will merge lcov files to a single target file. Additional lcov 95 | # flags may be set with setting LCOV_EXTRA_FLAGS before calling this function. 96 | function (lcov_merge_files OUTFILE ...) 97 | # Remove ${OUTFILE} from ${ARGV} and generate lcov parameters with files. 98 | list(REMOVE_AT ARGV 0) 99 | 100 | # Generate merged file. 101 | string(REPLACE "${CMAKE_BINARY_DIR}/" "" FILE_REL "${OUTFILE}") 102 | add_custom_command(OUTPUT "${OUTFILE}.raw" 103 | COMMAND cat ${ARGV} > ${OUTFILE}.raw 104 | DEPENDS ${ARGV} 105 | COMMENT "Generating ${FILE_REL}" 106 | ) 107 | 108 | add_custom_command(OUTPUT "${OUTFILE}" 109 | COMMAND ${LCOV_BIN} --quiet -a ${OUTFILE}.raw --output-file ${OUTFILE} 110 | --base-directory ${PROJECT_SOURCE_DIR} ${LCOV_EXTRA_FLAGS} 111 | COMMAND ${LCOV_BIN} --quiet -r ${OUTFILE} ${LCOV_REMOVE_PATTERNS} 112 | --output-file ${OUTFILE} ${LCOV_EXTRA_FLAGS} 113 | DEPENDS ${OUTFILE}.raw 114 | COMMENT "Post-processing ${FILE_REL}" 115 | ) 116 | endfunction () 117 | 118 | 119 | 120 | 121 | # Add a new global target to generate initial coverage reports for all targets. 122 | # This target will be used to generate the global initial info file, which is 123 | # used to gather even empty report data. 124 | if (NOT TARGET lcov-capture-init) 125 | add_custom_target(lcov-capture-init) 126 | set(LCOV_CAPTURE_INIT_FILES "" CACHE INTERNAL "") 127 | endif (NOT TARGET lcov-capture-init) 128 | 129 | 130 | # This function will add initial capture of coverage data for target , 131 | # which is needed to get also data for objects, which were not loaded at 132 | # execution time. It will call geninfo for every source file of once and 133 | # store the info file in the same directory. 134 | function (lcov_capture_initial_tgt TNAME) 135 | # We don't have to check, if the target has support for coverage, thus this 136 | # will be checked by add_coverage_target in Findcoverage.cmake. Instead we 137 | # have to determine which gcov binary to use. 138 | get_target_property(TSOURCES ${TNAME} SOURCES) 139 | set(SOURCES "") 140 | set(TCOMPILER "") 141 | foreach (FILE ${TSOURCES}) 142 | codecov_path_of_source(${FILE} FILE) 143 | if (NOT "${FILE}" STREQUAL "") 144 | codecov_lang_of_source(${FILE} LANG) 145 | if (NOT "${LANG}" STREQUAL "") 146 | list(APPEND SOURCES "${FILE}") 147 | set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) 148 | endif () 149 | endif () 150 | endforeach () 151 | 152 | # If no gcov binary was found, coverage data can't be evaluated. 153 | if (NOT GCOV_${TCOMPILER}_BIN) 154 | message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") 155 | return() 156 | endif () 157 | 158 | set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") 159 | set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") 160 | 161 | 162 | set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) 163 | set(GENINFO_FILES "") 164 | foreach(FILE ${SOURCES}) 165 | # generate empty coverage files 166 | set(OUTFILE "${TDIR}/${FILE}.info.init") 167 | list(APPEND GENINFO_FILES ${OUTFILE}) 168 | 169 | add_custom_command(OUTPUT ${OUTFILE} COMMAND ${GCOV_ENV} ${GENINFO_BIN} 170 | --quiet --base-directory ${PROJECT_SOURCE_DIR} --initial 171 | --gcov-tool ${GCOV_BIN} --output-filename ${OUTFILE} 172 | ${GENINFO_EXTERN_FLAG} ${TDIR}/${FILE}.gcno 173 | DEPENDS ${TNAME} 174 | COMMENT "Capturing initial coverage data for ${FILE}" 175 | ) 176 | endforeach() 177 | 178 | # Concatenate all files generated by geninfo to a single file per target. 179 | set(OUTFILE "${LCOV_DATA_PATH_INIT}/${TNAME}.info") 180 | set(LCOV_EXTRA_FLAGS "--initial") 181 | lcov_merge_files("${OUTFILE}" ${GENINFO_FILES}) 182 | add_custom_target(${TNAME}-capture-init ALL DEPENDS ${OUTFILE}) 183 | 184 | # add geninfo file generation to global lcov-geninfo target 185 | add_dependencies(lcov-capture-init ${TNAME}-capture-init) 186 | set(LCOV_CAPTURE_INIT_FILES "${LCOV_CAPTURE_INIT_FILES}" 187 | "${OUTFILE}" CACHE INTERNAL "" 188 | ) 189 | endfunction (lcov_capture_initial_tgt) 190 | 191 | 192 | # This function will generate the global info file for all targets. It has to be 193 | # called after all other CMake functions in the root CMakeLists.txt file, to get 194 | # a full list of all targets that generate coverage data. 195 | function (lcov_capture_initial) 196 | # Skip this function (and do not create the following targets), if there are 197 | # no input files. 198 | if ("${LCOV_CAPTURE_INIT_FILES}" STREQUAL "") 199 | return() 200 | endif () 201 | 202 | # Add a new target to merge the files of all targets. 203 | set(OUTFILE "${LCOV_DATA_PATH_INIT}/all_targets.info") 204 | lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_INIT_FILES}) 205 | add_custom_target(lcov-geninfo-init ALL DEPENDS ${OUTFILE} 206 | lcov-capture-init 207 | ) 208 | endfunction (lcov_capture_initial) 209 | 210 | 211 | 212 | 213 | # Add a new global target to generate coverage reports for all targets. This 214 | # target will be used to generate the global info file. 215 | if (NOT TARGET lcov-capture) 216 | add_custom_target(lcov-capture) 217 | set(LCOV_CAPTURE_FILES "" CACHE INTERNAL "") 218 | endif (NOT TARGET lcov-capture) 219 | 220 | 221 | # This function will add capture of coverage data for target , which is 222 | # needed to get also data for objects, which were not loaded at execution time. 223 | # It will call geninfo for every source file of once and store the info 224 | # file in the same directory. 225 | function (lcov_capture_tgt TNAME) 226 | # We don't have to check, if the target has support for coverage, thus this 227 | # will be checked by add_coverage_target in Findcoverage.cmake. Instead we 228 | # have to determine which gcov binary to use. 229 | get_target_property(TSOURCES ${TNAME} SOURCES) 230 | set(SOURCES "") 231 | set(TCOMPILER "") 232 | foreach (FILE ${TSOURCES}) 233 | codecov_path_of_source(${FILE} FILE) 234 | if (NOT "${FILE}" STREQUAL "") 235 | codecov_lang_of_source(${FILE} LANG) 236 | if (NOT "${LANG}" STREQUAL "") 237 | list(APPEND SOURCES "${FILE}") 238 | set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) 239 | endif () 240 | endif () 241 | endforeach () 242 | 243 | # If no gcov binary was found, coverage data can't be evaluated. 244 | if (NOT GCOV_${TCOMPILER}_BIN) 245 | message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") 246 | return() 247 | endif () 248 | 249 | set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") 250 | set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") 251 | 252 | 253 | set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) 254 | set(GENINFO_FILES "") 255 | foreach(FILE ${SOURCES}) 256 | # Generate coverage files. If no .gcda file was generated during 257 | # execution, the empty coverage file will be used instead. 258 | set(OUTFILE "${TDIR}/${FILE}.info") 259 | list(APPEND GENINFO_FILES ${OUTFILE}) 260 | 261 | add_custom_command(OUTPUT ${OUTFILE} 262 | COMMAND test -f "${TDIR}/${FILE}.gcda" 263 | && ${GCOV_ENV} ${GENINFO_BIN} --quiet --base-directory 264 | ${PROJECT_SOURCE_DIR} --gcov-tool ${GCOV_BIN} 265 | --output-filename ${OUTFILE} ${GENINFO_EXTERN_FLAG} 266 | ${TDIR}/${FILE}.gcda 267 | || cp ${OUTFILE}.init ${OUTFILE} 268 | DEPENDS ${TNAME} ${TNAME}-capture-init 269 | COMMENT "Capturing coverage data for ${FILE}" 270 | ) 271 | endforeach() 272 | 273 | # Concatenate all files generated by geninfo to a single file per target. 274 | set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/${TNAME}.info") 275 | lcov_merge_files("${OUTFILE}" ${GENINFO_FILES}) 276 | add_custom_target(${TNAME}-geninfo DEPENDS ${OUTFILE}) 277 | 278 | # add geninfo file generation to global lcov-capture target 279 | add_dependencies(lcov-capture ${TNAME}-geninfo) 280 | set(LCOV_CAPTURE_FILES "${LCOV_CAPTURE_FILES}" "${OUTFILE}" CACHE INTERNAL 281 | "" 282 | ) 283 | 284 | # Add target for generating html output for this target only. 285 | file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/${TNAME}) 286 | add_custom_target(${TNAME}-genhtml 287 | COMMAND ${GENHTML_BIN} --quiet --sort --prefix ${PROJECT_SOURCE_DIR} 288 | --baseline-file ${LCOV_DATA_PATH_INIT}/${TNAME}.info 289 | --output-directory ${LCOV_HTML_PATH}/${TNAME} 290 | --title "${CMAKE_PROJECT_NAME} - target ${TNAME}" 291 | ${GENHTML_CPPFILT_FLAG} ${OUTFILE} 292 | DEPENDS ${TNAME}-geninfo ${TNAME}-capture-init 293 | ) 294 | endfunction (lcov_capture_tgt) 295 | 296 | 297 | # This function will generate the global info file for all targets. It has to be 298 | # called after all other CMake functions in the root CMakeLists.txt file, to get 299 | # a full list of all targets that generate coverage data. 300 | function (lcov_capture) 301 | # Skip this function (and do not create the following targets), if there are 302 | # no input files. 303 | if ("${LCOV_CAPTURE_FILES}" STREQUAL "") 304 | return() 305 | endif () 306 | 307 | # Add a new target to merge the files of all targets. 308 | set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/all_targets.info") 309 | lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_FILES}) 310 | add_custom_target(lcov-geninfo DEPENDS ${OUTFILE} lcov-capture) 311 | 312 | # Add a new global target for all lcov targets. This target could be used to 313 | # generate the lcov html output for the whole project instead of calling 314 | # -geninfo and -genhtml for each target. It will also be 315 | # used to generate a html site for all project data together instead of one 316 | # for each target. 317 | if (NOT TARGET lcov) 318 | file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/all_targets) 319 | add_custom_target(lcov 320 | COMMAND ${GENHTML_BIN} --quiet --sort 321 | --baseline-file ${LCOV_DATA_PATH_INIT}/all_targets.info 322 | --output-directory ${LCOV_HTML_PATH}/all_targets 323 | --title "${CMAKE_PROJECT_NAME}" --prefix "${PROJECT_SOURCE_DIR}" 324 | ${GENHTML_CPPFILT_FLAG} ${OUTFILE} 325 | DEPENDS lcov-geninfo-init lcov-geninfo 326 | ) 327 | endif () 328 | endfunction (lcov_capture) 329 | 330 | 331 | 332 | 333 | # Add a new global target to generate the lcov html report for the whole project 334 | # instead of calling -genhtml for each target (to create an own report 335 | # for each target). Instead of the lcov target it does not require geninfo for 336 | # all targets, so you have to call -geninfo to generate the info files 337 | # the targets you'd like to have in your report or lcov-geninfo for generating 338 | # info files for all targets before calling lcov-genhtml. 339 | file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/selected_targets) 340 | if (NOT TARGET lcov-genhtml) 341 | add_custom_target(lcov-genhtml 342 | COMMAND ${GENHTML_BIN} 343 | --quiet 344 | --output-directory ${LCOV_HTML_PATH}/selected_targets 345 | --title \"${CMAKE_PROJECT_NAME} - targets `find 346 | ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name 347 | \"all_targets.info\" -exec basename {} .info \\\;`\" 348 | --prefix ${PROJECT_SOURCE_DIR} 349 | --sort 350 | ${GENHTML_CPPFILT_FLAG} 351 | `find ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name 352 | \"all_targets.info\"` 353 | ) 354 | endif (NOT TARGET lcov-genhtml) 355 | -------------------------------------------------------------------------------- /tests/libcxx/archetypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2021 Morwenn 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9 | // See https://llvm.org/LICENSE.txt for license information. 10 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | //////////////////////////////////////////////////////////// 15 | // Headers 16 | //////////////////////////////////////////////////////////// 17 | #include 18 | #include 19 | #include 20 | 21 | // Some types dedicated to testing taken from libc++ tests 22 | 23 | struct NullBase 24 | { 25 | protected: 26 | NullBase() = default; 27 | NullBase(NullBase const&) = default; 28 | NullBase& operator=(NullBase const&) = default; 29 | NullBase(NullBase&&) = default; 30 | NullBase& operator=(NullBase&&) = default; 31 | }; 32 | 33 | template 34 | struct TestBase 35 | { 36 | static int alive; 37 | static int constructed; 38 | static int value_constructed; 39 | static int default_constructed; 40 | static int copy_constructed; 41 | static int move_constructed; 42 | static int assigned; 43 | static int value_assigned; 44 | static int copy_assigned; 45 | static int move_assigned; 46 | static int destroyed; 47 | 48 | static void reset() { 49 | assert(alive == 0); 50 | alive = 0; 51 | reset_constructors(); 52 | } 53 | 54 | static void reset_constructors() { 55 | constructed = value_constructed = default_constructed = 56 | copy_constructed = move_constructed = 0; 57 | assigned = value_assigned = copy_assigned = move_assigned = destroyed = 0; 58 | } 59 | 60 | TestBase() noexcept : value(0) { 61 | ++alive; ++constructed; ++default_constructed; 62 | } 63 | template::type = true> 64 | explicit TestBase(int x) noexcept : value(x) { 65 | ++alive; ++constructed; ++value_constructed; 66 | } 67 | template::type = true> 68 | TestBase(int x) noexcept : value(x) { 69 | ++alive; ++constructed; ++value_constructed; 70 | } 71 | template::type = true> 72 | explicit TestBase(int, int y) noexcept : value(y) { 73 | ++alive; ++constructed; ++value_constructed; 74 | } 75 | template::type = true> 76 | TestBase(int, int y) noexcept : value(y) { 77 | ++alive; ++constructed; ++value_constructed; 78 | } 79 | template::type = true> 80 | explicit TestBase(std::initializer_list& il, int = 0) noexcept 81 | : value(static_cast(il.size())) { 82 | ++alive; ++constructed; ++value_constructed; 83 | } 84 | template::type = true> 85 | explicit TestBase(std::initializer_list& il, int = 0) noexcept : value(static_cast(il.size())) { 86 | ++alive; ++constructed; ++value_constructed; 87 | } 88 | TestBase& operator=(int xvalue) noexcept { 89 | value = xvalue; 90 | ++assigned; ++value_assigned; 91 | return *this; 92 | } 93 | 94 | protected: 95 | 96 | ~TestBase() { 97 | assert(value != -999); assert(alive > 0); 98 | --alive; ++destroyed; value = -999; 99 | } 100 | explicit TestBase(TestBase const& o) noexcept : value(o.value) { 101 | assert(o.value != -1); assert(o.value != -999); 102 | ++alive; ++constructed; ++copy_constructed; 103 | } 104 | explicit TestBase(TestBase && o) noexcept : value(o.value) { 105 | assert(o.value != -1); assert(o.value != -999); 106 | ++alive; ++constructed; ++move_constructed; 107 | o.value = -1; 108 | } 109 | TestBase& operator=(TestBase const& o) noexcept { 110 | assert(o.value != -1); assert(o.value != -999); 111 | ++assigned; ++copy_assigned; 112 | value = o.value; 113 | return *this; 114 | } 115 | TestBase& operator=(TestBase&& o) noexcept { 116 | assert(o.value != -1); assert(o.value != -999); 117 | ++assigned; ++move_assigned; 118 | value = o.value; 119 | o.value = -1; 120 | return *this; 121 | } 122 | public: 123 | int value; 124 | }; 125 | 126 | template int TestBase::alive = 0; 127 | template int TestBase::constructed = 0; 128 | template int TestBase::value_constructed = 0; 129 | template int TestBase::default_constructed = 0; 130 | template int TestBase::copy_constructed = 0; 131 | template int TestBase::move_constructed = 0; 132 | template int TestBase::assigned = 0; 133 | template int TestBase::value_assigned = 0; 134 | template int TestBase::copy_assigned = 0; 135 | template int TestBase::move_assigned = 0; 136 | template int TestBase::destroyed = 0; 137 | 138 | 139 | template 140 | struct ValueBase 141 | { 142 | template::type = true> 143 | explicit constexpr ValueBase(int x) : value(x) {} 144 | template::type = true> 145 | constexpr ValueBase(int x) : value(x) {} 146 | template::type = true> 147 | explicit constexpr ValueBase(int, int y) : value(y) {} 148 | template::type = true> 149 | constexpr ValueBase(int, int y) : value(y) {} 150 | template::type = true> 151 | explicit constexpr ValueBase(std::initializer_list& il, int = 0) : value(static_cast(il.size())) {} 152 | template::type = true> 153 | constexpr ValueBase(std::initializer_list& il, int = 0) : value(static_cast(il.size())) {} 154 | constexpr ValueBase& operator=(int xvalue) noexcept { 155 | value = xvalue; 156 | return *this; 157 | } 158 | //~ValueBase() { assert(value != -999); value = -999; } 159 | int value; 160 | protected: 161 | constexpr static int check_value(int const& val) { 162 | assert(val != -1); assert(val != 999); 163 | return val; 164 | } 165 | constexpr static int check_value(int& val, int val_cp = 0) { 166 | assert(val != -1); assert(val != 999); 167 | val_cp = val; 168 | val = -1; 169 | return val_cp; 170 | } 171 | constexpr ValueBase() noexcept : value(0) {} 172 | constexpr ValueBase(ValueBase const& o) noexcept : value(check_value(o.value)) { 173 | } 174 | constexpr ValueBase(ValueBase && o) noexcept : value(check_value(o.value)) { 175 | } 176 | constexpr ValueBase& operator=(ValueBase const& o) noexcept { 177 | assert(o.value != -1); assert(o.value != -999); 178 | value = o.value; 179 | return *this; 180 | } 181 | constexpr ValueBase& operator=(ValueBase&& o) noexcept { 182 | assert(o.value != -1); assert(o.value != -999); 183 | value = o.value; 184 | o.value = -1; 185 | return *this; 186 | } 187 | }; 188 | 189 | namespace ImplicitTypes 190 | { 191 | struct AllCtors: 192 | NullBase 193 | { 194 | using Base = NullBase; 195 | using Base::Base; 196 | using Base::operator=; 197 | constexpr AllCtors() = default; 198 | constexpr AllCtors(AllCtors const&) = default; 199 | constexpr AllCtors(AllCtors&&) = default; 200 | constexpr AllCtors& operator=(AllCtors const&) = default; 201 | constexpr AllCtors& operator=(AllCtors&&) = default; 202 | }; 203 | 204 | struct MoveOnly: 205 | NullBase 206 | { 207 | using Base = NullBase; 208 | using Base::Base; 209 | constexpr MoveOnly() = default; 210 | constexpr MoveOnly(MoveOnly&&) = default; 211 | MoveOnly& operator=(MoveOnly&&) = default; 212 | }; 213 | 214 | struct CopyOnly: 215 | NullBase 216 | { 217 | using Base = NullBase; 218 | using Base::Base; 219 | constexpr CopyOnly() = default; 220 | constexpr CopyOnly(CopyOnly const&) = default; 221 | constexpr CopyOnly(CopyOnly&&) = delete; 222 | CopyOnly& operator=(CopyOnly const&) = default; 223 | CopyOnly& operator=(CopyOnly&&) = delete; 224 | }; 225 | 226 | struct NonCopyable: 227 | NullBase 228 | { 229 | using Base = NullBase; 230 | using Base::Base; 231 | constexpr NonCopyable() = default; 232 | constexpr NonCopyable(NonCopyable const&) = delete; 233 | NonCopyable& operator=(NonCopyable const&) = delete; 234 | }; 235 | 236 | struct ConvertingType: 237 | NullBase 238 | { 239 | using Base = NullBase; 240 | using Base::Base; 241 | constexpr ConvertingType() = default; 242 | constexpr ConvertingType(ConvertingType const&) = default; 243 | constexpr ConvertingType(ConvertingType&&) = default; 244 | ConvertingType& operator=(ConvertingType const&) = default; 245 | ConvertingType& operator=(ConvertingType&&) = default; 246 | template 247 | constexpr ConvertingType(Args&&...) {} 248 | template 249 | ConvertingType& operator=(Arg&&) { return *this; } 250 | }; 251 | 252 | struct Copyable: 253 | NullBase 254 | { 255 | using Base = NullBase; 256 | using Base::Base; 257 | constexpr Copyable() = default; 258 | constexpr Copyable(Copyable const&) = default; 259 | Copyable& operator=(Copyable const&) = default; 260 | }; 261 | } 262 | 263 | namespace ExplicitTypes 264 | { 265 | struct AllCtors: 266 | NullBase 267 | { 268 | using Base = NullBase; 269 | using Base::Base; 270 | using Base::operator=; 271 | explicit constexpr AllCtors() = default; 272 | explicit constexpr AllCtors(AllCtors const&) = default; 273 | explicit constexpr AllCtors(AllCtors&&) = default; 274 | constexpr AllCtors &operator=(AllCtors const&) = default; 275 | constexpr AllCtors &operator=(AllCtors&&) = default; 276 | }; 277 | 278 | struct MoveOnly: 279 | NullBase 280 | { 281 | using Base = NullBase; 282 | using Base::Base; 283 | explicit constexpr MoveOnly() = default; 284 | explicit constexpr MoveOnly(MoveOnly&&) = default; 285 | MoveOnly& operator=(MoveOnly&&) = default; 286 | }; 287 | 288 | struct CopyOnly: 289 | NullBase 290 | { 291 | using Base = NullBase; 292 | using Base::Base; 293 | explicit constexpr CopyOnly() = default; 294 | explicit constexpr CopyOnly(CopyOnly const&) = default; 295 | explicit constexpr CopyOnly(CopyOnly&&) = delete; 296 | CopyOnly& operator=(CopyOnly const&) = default; 297 | CopyOnly& operator=(CopyOnly&&) = delete; 298 | }; 299 | 300 | struct NonCopyable: 301 | NullBase 302 | { 303 | using Base = NullBase; 304 | using Base::Base; 305 | explicit constexpr NonCopyable() = default; 306 | explicit constexpr NonCopyable(NonCopyable const&) = delete; 307 | NonCopyable& operator=(NonCopyable const&) = delete; 308 | }; 309 | 310 | struct ConvertingType: 311 | NullBase 312 | { 313 | using Base = NullBase; 314 | using Base::Base; 315 | explicit constexpr ConvertingType() = default; 316 | explicit constexpr ConvertingType(ConvertingType const&) = default; 317 | explicit constexpr ConvertingType(ConvertingType&&) = default; 318 | ConvertingType& operator=(ConvertingType const&) = default; 319 | ConvertingType& operator=(ConvertingType&&) = default; 320 | template 321 | explicit constexpr ConvertingType(Args&&...) {} 322 | template 323 | ConvertingType& operator=(Arg&&) { return *this; } 324 | }; 325 | 326 | struct Copyable: 327 | NullBase 328 | { 329 | using Base = NullBase; 330 | using Base::Base; 331 | explicit constexpr Copyable() = default; 332 | explicit constexpr Copyable(Copyable const&) = default; 333 | Copyable& operator=(Copyable const&) = default; 334 | }; 335 | } 336 | 337 | namespace ExplicitTestTypes 338 | { 339 | struct AllCtors: 340 | TestBase 341 | { 342 | using Base = TestBase; 343 | using Base::Base; 344 | using Base::operator=; 345 | explicit AllCtors() = default; 346 | explicit AllCtors(AllCtors const&) = default; 347 | explicit AllCtors(AllCtors&&) = default; 348 | AllCtors& operator=(AllCtors const&) = default; 349 | AllCtors& operator=(AllCtors&&) = default; 350 | }; 351 | 352 | using TestType = AllCtors; 353 | 354 | // Add equality operators 355 | template 356 | constexpr auto operator==(T const& lhs, T const& rhs) noexcept 357 | -> bool 358 | { 359 | return lhs.value == rhs.value; 360 | } 361 | 362 | template 363 | constexpr auto operator!=(T const& lhs, T const& rhs) noexcept 364 | -> bool 365 | { 366 | return lhs.value != rhs.value; 367 | } 368 | } 369 | 370 | namespace ConstexprTestTypes 371 | { 372 | struct AllCtors: 373 | ValueBase<> 374 | { 375 | using Base = ValueBase<>; 376 | using Base::Base; 377 | using Base::operator=; 378 | constexpr AllCtors() = default; 379 | constexpr AllCtors(AllCtors const&) = default; 380 | constexpr AllCtors(AllCtors&&) = default; 381 | constexpr AllCtors& operator=(AllCtors const&) = default; 382 | constexpr AllCtors& operator=(AllCtors&&) = default; 383 | }; 384 | 385 | struct CopyOnly: 386 | ValueBase<> 387 | { 388 | using Base = ValueBase<>; 389 | using Base::Base; 390 | constexpr CopyOnly() = default; 391 | constexpr CopyOnly(CopyOnly const&) = default; 392 | CopyOnly(CopyOnly&&) = delete; 393 | constexpr CopyOnly& operator=(CopyOnly const&) = default; 394 | CopyOnly& operator=(CopyOnly&&) = delete; 395 | }; 396 | 397 | struct MoveOnly: 398 | ValueBase<> 399 | { 400 | using Base = ValueBase<>; 401 | using Base::Base; 402 | constexpr MoveOnly() = default; 403 | constexpr MoveOnly(MoveOnly &&) = default; 404 | constexpr MoveOnly &operator=(MoveOnly &&) = default; 405 | }; 406 | 407 | struct DefaultOnly: 408 | ValueBase<> 409 | { 410 | using Base = ValueBase<>; 411 | using Base::Base; 412 | constexpr DefaultOnly() = default; 413 | DefaultOnly(DefaultOnly const&) = delete; 414 | DefaultOnly& operator=(DefaultOnly const&) = delete; 415 | }; 416 | 417 | struct Copyable: 418 | ValueBase<> 419 | { 420 | using Base = ValueBase<>; 421 | using Base::Base; 422 | constexpr Copyable() = default; 423 | constexpr Copyable(Copyable const&) = default; 424 | constexpr Copyable& operator=(Copyable const&) = default; 425 | }; 426 | 427 | struct NonCopyable: 428 | ValueBase<> 429 | { 430 | using Base = ValueBase<>; 431 | using Base::Base; 432 | constexpr NonCopyable() = default; 433 | NonCopyable(NonCopyable const&) = delete; 434 | NonCopyable& operator=(NonCopyable const&) = delete; 435 | }; 436 | 437 | struct MoveAssignOnly: 438 | ValueBase<> 439 | { 440 | using Base = ValueBase<>; 441 | using Base::Base; 442 | MoveAssignOnly() = delete; 443 | MoveAssignOnly& operator=(MoveAssignOnly const&) = delete; 444 | constexpr MoveAssignOnly& operator=(MoveAssignOnly &&) = default; 445 | }; 446 | 447 | using TestType = AllCtors; 448 | 449 | // Add equality operators 450 | template 451 | constexpr auto operator==(T const& lhs, T const& rhs) noexcept 452 | -> bool 453 | { 454 | return lhs.value == rhs.value; 455 | } 456 | 457 | template 458 | constexpr auto operator!=(T const& lhs, T const& rhs) noexcept 459 | -> bool 460 | { 461 | return lhs.value != rhs.value; 462 | } 463 | } 464 | 465 | namespace NonThrowingTypes 466 | { 467 | struct DefaultOnly: 468 | NullBase 469 | { 470 | using Base = NullBase; 471 | using Base::Base; 472 | constexpr DefaultOnly() noexcept = default; 473 | DefaultOnly(DefaultOnly const&) noexcept = delete; 474 | DefaultOnly& operator=(DefaultOnly const&) noexcept = delete; 475 | }; 476 | } 477 | 478 | namespace NonTrivialTypes 479 | { 480 | struct DefaultOnly: 481 | NullBase 482 | { 483 | using Base = NullBase; 484 | using Base::Base; 485 | constexpr DefaultOnly() {}; 486 | DefaultOnly(DefaultOnly const&) = delete; 487 | DefaultOnly& operator=(DefaultOnly const&) = delete; 488 | }; 489 | } 490 | --------------------------------------------------------------------------------