mirror of
https://github.com/boostorg/compat.git
synced 2026-01-20 16:32:23 +00:00
Compare commits
4 Commits
feature/mo
...
feature/pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a8bb0b574 | ||
|
|
c18e5f2276 | ||
|
|
d2d5cbe094 | ||
|
|
c49f822b2e |
@@ -32,6 +32,8 @@ local linux_pipeline(name, image, environment, packages = "", sources = [], arch
|
||||
commands:
|
||||
[
|
||||
'set -e',
|
||||
'uname -a',
|
||||
'echo $DRONE_STAGE_MACHINE',
|
||||
'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -',
|
||||
] +
|
||||
(if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
|
||||
@@ -123,21 +125,21 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9 ARM64 UBSAN",
|
||||
"Linux 20.04 GCC 9* ARM64 UBSAN",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' } + ubsan,
|
||||
arch="arm64",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9 ARM64 ASAN",
|
||||
"Linux 20.04 GCC 9* ARM64 ASAN",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' } + asan,
|
||||
arch="arm64",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9 S390x UBSAN",
|
||||
"Linux 20.04 GCC 9* S390x UBSAN",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' } + ubsan,
|
||||
arch="s390x",
|
||||
|
||||
@@ -8,6 +8,10 @@ https://www.boost.org/LICENSE_1_0.txt
|
||||
# Revision History
|
||||
:idprefix: changelog_
|
||||
|
||||
## Changes in 1.87.0
|
||||
|
||||
* Added `to_array.hpp` (contributed by Ruben Perez Hidalgo.)
|
||||
|
||||
## Changes in 1.86.0
|
||||
|
||||
* Added `bind_front.hpp`, `bind_back.hpp`, `invoke.hpp`, `mem_fn.hpp`, `integer_sequence.hpp` and `type_traits.hpp`.
|
||||
|
||||
@@ -12,4 +12,5 @@ include::invoke.adoc[]
|
||||
include::latch.adoc[]
|
||||
include::mem_fn.adoc[]
|
||||
include::shared_lock.adoc[]
|
||||
include::to_array.adoc[]
|
||||
include::type_traits.adoc[]
|
||||
|
||||
72
doc/compat/to_array.adoc
Normal file
72
doc/compat/to_array.adoc
Normal file
@@ -0,0 +1,72 @@
|
||||
////
|
||||
Copyright 2024 Ruben Perez Hidalgo
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#to_array]
|
||||
# <boost/compat/to_array.hpp>
|
||||
:idprefix: ref_to_array_
|
||||
|
||||
## Description
|
||||
|
||||
The header `<boost/compat/to_array.hpp>` implements, in a portable way, the C++20
|
||||
`std::to_array` function, present in the `<array>` header.
|
||||
|
||||
`to_array` creates a `std::array` from a single-dimensional C array,
|
||||
performing an element-wise copy or move.
|
||||
|
||||
## Example
|
||||
|
||||
```cpp
|
||||
int input [] = {1, 2, 3};
|
||||
std::array<int, 3> output = boost::compat::to_array(input);
|
||||
assert((
|
||||
output == std::array<int, 3>{{1, 2, 3}}
|
||||
));
|
||||
```
|
||||
|
||||
## Synopsis
|
||||
|
||||
```cpp
|
||||
namespace boost
|
||||
{
|
||||
namespace compat
|
||||
{
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr std::array<remove_cv_t<T>, N> to_array(T (&a)[N]);
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr std::array<remove_cv_t<T>, N> to_array(T (&&a)[N]);
|
||||
|
||||
} // namespace compat
|
||||
} // namespace boost
|
||||
```
|
||||
|
||||
## to_array
|
||||
|
||||
```cpp
|
||||
template <class T, std::size_t N>
|
||||
constexpr std::array<remove_cv_t<T>, N> to_array(T (&&a)[N]);
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
Effects:;; Creates an array of `N` elements by copying elements in `a`.
|
||||
For every `i` in `0, ..., N-1`, copy-initializes the i-th element
|
||||
in the output array from `a[i]`.
|
||||
Type requirements:;; `std::is_constructible_v<remove_cv_t<T>, T&> && !std::is_array_v<T>`.
|
||||
Otherwise, the overload is ill-formed.
|
||||
|
||||
|
||||
```cpp
|
||||
template <class T, std::size_t N>
|
||||
constexpr std::array<remove_cvref_t<T>, N> to_array(T (&a)[N]);
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
Effects:;; Creates an array of `N` elements by moving elements in `a`.
|
||||
For every `i` in `0, ..., N-1`, move-initializes the i-th element
|
||||
in the output array from `std::move(a[i])`.
|
||||
Type requirements:;; `std::is_constructible_v<remove_cv_t<T>, T&&> && !std::is_array_v<T>`.
|
||||
Otherwise, the overload is ill-formed.
|
||||
60
include/boost/compat/to_array.hpp
Normal file
60
include/boost/compat/to_array.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef BOOST_COMPAT_TO_ARRAY_HPP_INCLUDED
|
||||
#define BOOST_COMPAT_TO_ARRAY_HPP_INCLUDED
|
||||
|
||||
// Copyright 2024 Ruben Perez Hidalgo
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/compat/integer_sequence.hpp>
|
||||
#include <boost/compat/type_traits.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace compat {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T, std::size_t N, std::size_t... I>
|
||||
constexpr std::array<remove_cv_t<T>, N> to_array_lvalue(T (&a)[N], index_sequence<I...>)
|
||||
{
|
||||
return {{a[I]...}};
|
||||
}
|
||||
|
||||
template <class T, std::size_t N, std::size_t... I>
|
||||
constexpr std::array<remove_cv_t<T>, N> to_array_rvalue(T (&&a)[N], index_sequence<I...>)
|
||||
{
|
||||
return {{std::move(a[I])...}};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr std::array<remove_cv_t<T>, N> to_array(T (&a)[N])
|
||||
{
|
||||
static_assert(
|
||||
std::is_constructible<remove_cv_t<T>, T&>::value,
|
||||
"This overload requires the resulting element type to be constructible from T&"
|
||||
);
|
||||
static_assert(!std::is_array<T>::value, "to_array does not work for multi-dimensional C arrays");
|
||||
return detail::to_array_lvalue(a, make_index_sequence<N>{});
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr std::array<remove_cv_t<T>, N> to_array(T (&&a)[N])
|
||||
{
|
||||
static_assert(
|
||||
std::is_constructible<remove_cv_t<T>, T&&>::value,
|
||||
"This overload requires the resulting element type to be constructible from T&&"
|
||||
);
|
||||
static_assert(!std::is_array<T>::value, "to_array does not work for multi-dimensional C arrays");
|
||||
return detail::to_array_rvalue(static_cast<T(&&)[N]>(a), make_index_sequence<N>{});
|
||||
}
|
||||
|
||||
} // namespace compat
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_COMPAT_TO_ARRAY_HPP_INCLUDED
|
||||
@@ -112,3 +112,6 @@ run function_ref_mfn_test.cpp ;
|
||||
run function_ref_fn_noexcept_test.cpp ;
|
||||
run function_ref_mfn_noexcept_test.cpp ;
|
||||
run function_ref_obj_noexcept_test.cpp ;
|
||||
|
||||
run to_array_lvalue_test.cpp ;
|
||||
run to_array_rvalue_test.cpp ;
|
||||
|
||||
60
test/to_array_lvalue_test.cpp
Normal file
60
test/to_array_lvalue_test.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright 2024 Ruben Perez Hidalgo.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/compat/to_array.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
namespace compat = boost::compat;
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
// regular C array
|
||||
int input[] = {1, 2};
|
||||
auto output = compat::to_array(input);
|
||||
static_assert(std::is_same<decltype(output), std::array<int, 2>>::value, "");
|
||||
BOOST_TEST_EQ(output[0], 1);
|
||||
BOOST_TEST_EQ(output[1], 2);
|
||||
}
|
||||
{
|
||||
// regular C array, const
|
||||
const int input[] = {1, 2};
|
||||
auto output = compat::to_array(input);
|
||||
static_assert(std::is_same<decltype(output), std::array<int, 2>>::value, "");
|
||||
BOOST_TEST_EQ(output[0], 1);
|
||||
BOOST_TEST_EQ(output[1], 2);
|
||||
}
|
||||
{
|
||||
// values not moved
|
||||
const std::vector<int> vec{1, 2};
|
||||
std::vector<int> input[]{vec};
|
||||
auto output = compat::to_array(input);
|
||||
static_assert(std::is_same<decltype(output), std::array<std::vector<int>, 1>>::value, "");
|
||||
BOOST_TEST_ALL_EQ(output[0].begin(), output[0].end(), vec.begin(), vec.end());
|
||||
BOOST_TEST_ALL_EQ(input[0].begin(), input[0].end(), vec.begin(), vec.end()); // input not modified
|
||||
}
|
||||
{
|
||||
// const values work
|
||||
const std::vector<int> vec{1, 2};
|
||||
const std::vector<int> input[]{vec};
|
||||
auto output = compat::to_array(input);
|
||||
static_assert(std::is_same<decltype(output), std::array<std::vector<int>, 1>>::value, "");
|
||||
BOOST_TEST_ALL_EQ(output[0].begin(), output[0].end(), vec.begin(), vec.end());
|
||||
BOOST_TEST_ALL_EQ(input[0].begin(), input[0].end(), vec.begin(), vec.end()); // input not modified
|
||||
}
|
||||
{
|
||||
// constexpr check
|
||||
constexpr int input[] = {1, 2, 3};
|
||||
constexpr auto output = compat::to_array(input);
|
||||
static_assert(std::is_same<decltype(output), const std::array<int, 3>>::value, "");
|
||||
BOOST_TEST_EQ(output[0], 1);
|
||||
BOOST_TEST_EQ(output[1], 2);
|
||||
BOOST_TEST_EQ(output[2], 3);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
88
test/to_array_rvalue_test.cpp
Normal file
88
test/to_array_rvalue_test.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
// Copyright 2024 Ruben Perez Hidalgo.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/compat/to_array.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#if defined(BOOST_MSVC) && BOOST_MSVC < 1910
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC < 1910" )
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
namespace compat = boost::compat;
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
// regular C array
|
||||
int input[] = {5, 6};
|
||||
auto output = compat::to_array(std::move(input));
|
||||
static_assert(std::is_same<decltype(output), std::array<int, 2>>::value, "");
|
||||
BOOST_TEST_EQ(output[0], 5);
|
||||
BOOST_TEST_EQ(output[1], 6);
|
||||
}
|
||||
{
|
||||
// regular C array, const
|
||||
const int input[] = {5, 6};
|
||||
auto output = compat::to_array(std::move(input));
|
||||
static_assert(std::is_same<decltype(output), std::array<int, 2>>::value, "");
|
||||
BOOST_TEST_EQ(output[0], 5);
|
||||
BOOST_TEST_EQ(output[1], 6);
|
||||
}
|
||||
{
|
||||
// values moved
|
||||
const std::vector<int> vec{1, 2};
|
||||
std::vector<int> input[]{vec};
|
||||
auto output = compat::to_array(std::move(input));
|
||||
static_assert(std::is_same<decltype(output), std::array<std::vector<int>, 1>>::value, "");
|
||||
BOOST_TEST_ALL_EQ(output[0].begin(), output[0].end(), vec.begin(), vec.end());
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1920)
|
||||
BOOST_TEST(input[0].empty()); // input left in a moved-from state
|
||||
#endif
|
||||
}
|
||||
{
|
||||
// const values work (although they don't result in an effective move)
|
||||
const std::vector<int> vec{1, 2};
|
||||
const std::vector<int> input[]{vec};
|
||||
auto output = compat::to_array(std::move(input));
|
||||
static_assert(std::is_same<decltype(output), std::array<std::vector<int>, 1>>::value, "");
|
||||
BOOST_TEST_ALL_EQ(output[0].begin(), output[0].end(), vec.begin(), vec.end());
|
||||
BOOST_TEST_ALL_EQ(input[0].begin(), input[0].end(), vec.begin(), vec.end()); // input not modified
|
||||
}
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1920)
|
||||
{
|
||||
// move-only types work
|
||||
std::unique_ptr<int> input[] = {std::unique_ptr<int>{new int(42)}};
|
||||
int* ptr = input[0].get();
|
||||
auto output = compat::to_array(std::move(input));
|
||||
static_assert(std::is_same<decltype(output), std::array<std::unique_ptr<int>, 1>>::value, "");
|
||||
BOOST_TEST_EQ(output[0].get(), ptr);
|
||||
BOOST_TEST_EQ(input[0].get(), nullptr); // input left in a moved-from state
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
// constexpr check
|
||||
constexpr int input[] = {1, 2, 3};
|
||||
constexpr auto output = compat::to_array(std::move(input));
|
||||
static_assert(std::is_same<decltype(output), const std::array<int, 3>>::value, "");
|
||||
BOOST_TEST_EQ(output[0], 1);
|
||||
BOOST_TEST_EQ(output[1], 2);
|
||||
BOOST_TEST_EQ(output[2], 3);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user