2
0
mirror of https://github.com/boostorg/compat.git synced 2026-01-20 16:32:23 +00:00

4 Commits

Author SHA1 Message Date
Peter Dimov
1a8bb0b574 Update revision history 2024-10-04 13:43:06 +03:00
Peter Dimov
c18e5f2276 Move MSVC workarounds from test/Jamfile to to_array_rvalue_test.cpp 2024-10-04 13:26:50 +03:00
Anarthal (Rubén Pérez)
d2d5cbe094 Added to_array (#14)
* Added to_array

* Suppress unused warnings

* Fix unused warnings (2)

* Workaround msvc 14.0 bug

* Workaround MSVC problems with moving arrays

* MSVC workaround in constexpr test

* Further MSVC fixes

* Disable rvalue tests for MSVC 14.0

* Incorrect argument spec

* constexpr checks

* const test

* Disable rvalues for msvc 14.1

* Docs

* Added more const tests

* Correct static_asserts

* Update type requirements in docs

* Corrected return types and conditions

* Doc updates
2024-10-04 13:06:44 +03:00
Peter Dimov
c49f822b2e Update .drone.jsonnet 2024-08-21 10:49:04 +03:00
8 changed files with 293 additions and 3 deletions

View File

@@ -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",

View File

@@ -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`.

View File

@@ -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
View 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.

View 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

View File

@@ -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 ;

View 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();
}

View 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